diff --git a/dist/pixi.js b/dist/pixi.js deleted file mode 100644 index 2e6b3f4..0000000 --- a/dist/pixi.js +++ /dev/null @@ -1,19896 +0,0 @@ -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.PIXI=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o", - "Richard Davey " - ], - "main": "./src/index.js", - "homepage": "http://goodboydigital.com/", - "bugs": "https://github.com/GoodBoyDigital/pixi.js/issues", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/GoodBoyDigital/pixi.js.git" - }, - "scripts": { - "test": "gulp test", - "docs": "./node_modules/.bin/jsdoc -c ./gulp/util/jsdoc.conf.json" - }, - "devDependencies": { - "browserify": "^8.0.2", - "chai": "^1.10.0", - "del": "^1.1.0", - "gulp": "^3.8.10", - "gulp-jshint": "^1.9.0", - "gulp-plumber": "^0.6.6", - "gulp-rename": "^1.2.0", - "gulp-uglify": "^1.0.2", - "gulp-util": "^3.0.1", - "ink-docstrap": "^0.4.12", - "jsdoc": "^3.3.0-alpha13", - "jshint-summary": "^0.4.0", - "karma": "^0.12.28", - "karma-firefox-launcher": "^0.1.0", - "karma-mocha": "^0.1.10", - "karma-spec-reporter": "^0.0.16", - "mocha": "^2.1.0", - "require-dir": "^0.1.0", - "run-sequence": "^1.0.2", - "vinyl-buffer": "^1.0.0", - "vinyl-source-stream": "^1.0.0", - "watchify": "^2.2.1" - }, - "dependencies": { - "webgl-enabled": "^1.0.2" - } -} - -},{}],4:[function(require,module,exports){ -/** - * Constant values used in pixi - * - * @mixin const - */ -module.exports = { - /** - * Constant to identify the WEBGL Renderer Type - * - * @static - * @constant - * @property {number} WEBGL_RENDERER - */ - WEBGL_RENDERER: 1, - - /** - * Constant to identify the CANVAS Renderer Type - * - * @static - * @constant - * @property {number} CANVAS_RENDERER - */ - CANVAS_RENDERER: 2, - - /** - * String of the current PIXI version - * - * @static - * @constant - * @property {string} VERSION - */ - VERSION: require('../../package.json').version, - - /** - * Various blend modes supported by PIXI. IMPORTANT - The WebGL renderer only supports - * the NORMAL, ADD, MULTIPLY and SCREEN blend modes. Anything else will silently act like - * NORMAL. - * - * @static - * @constant - * @property {object} blendModes - * @property {number} blendModes.NORMAL - * @property {number} blendModes.ADD - * @property {number} blendModes.MULTIPLY - * @property {number} blendModes.SCREEN - * @property {number} blendModes.OVERLAY - * @property {number} blendModes.DARKEN - * @property {number} blendModes.LIGHTEN - * @property {number} blendModes.COLOR_DODGE - * @property {number} blendModes.COLOR_BURN - * @property {number} blendModes.HARD_LIGHT - * @property {number} blendModes.SOFT_LIGHT - * @property {number} blendModes.DIFFERENCE - * @property {number} blendModes.EXCLUSION - * @property {number} blendModes.HUE - * @property {number} blendModes.SATURATION - * @property {number} blendModes.COLOR - * @property {number} blendModes.LUMINOSITY - */ - blendModes: { - NORMAL: 0, - ADD: 1, - MULTIPLY: 2, - SCREEN: 3, - OVERLAY: 4, - DARKEN: 5, - LIGHTEN: 6, - COLOR_DODGE: 7, - COLOR_BURN: 8, - HARD_LIGHT: 9, - SOFT_LIGHT: 10, - DIFFERENCE: 11, - EXCLUSION: 12, - HUE: 13, - SATURATION: 14, - COLOR: 15, - LUMINOSITY: 16 - }, - - /** - * The scale modes that are supported by pixi. - * - * The DEFAULT scale mode affects the default scaling mode of future operations. - * It can be re-assigned to either LINEAR or NEAREST, depending upon suitability. - * - * @static - * @constant - * @property {object} scaleModes - * @property {number} scaleModes.DEFAULT=LINEAR - * @property {number} scaleModes.LINEAR Smooth scaling - * @property {number} scaleModes.NEAREST Pixelating scaling - */ - scaleModes: { - DEFAULT: 0, - LINEAR: 0, - NEAREST: 1 - }, - - /** - * The prefix that denotes a URL is for a retina asset - * - * @static - * @constant - * @property {string} RETINA_PREFIX - */ - RETINA_PREFIX: '@2x', - - /** - * The default render options if none are supplied to {@link PIXI.WebGLRenderer} - * or {@link PIXI.CanvasRenderer}. - * - * @static - * @constant - * @property {object} defaultRenderOptions - * @property {HTMLCanvasElement} defaultRenderOptions.view=null - * @property {boolean} defaultRenderOptions.transparent=false - * @property {boolean} defaultRenderOptions.antialias=false - * @property {boolean} defaultRenderOptions.preserveDrawingBuffer=false - * @property {number} defaultRenderOptions.resolution=1 - * @property {number} defaultRenderOptions.backgroundColor=0x000000 - * @property {boolean} defaultRenderOptions.clearBeforeRender=true - * @property {boolean} defaultRenderOptions.autoResize=false - */ - defaultRenderOptions: { - view: null, - resolution: 1, - antialias: false, - autoResize: false, - transparent: false, - backgroundColor: 0x000000, - clearBeforeRender: true, - preserveDrawingBuffer: false - }, - - /** - * Constants that identify shapes, mainly to prevent `instanceof` calls. - * - * @static - * @constant - * @property {object} SHAPES - * @property {object} SHAPES.POLY=0 - * @property {object} SHAPES.RECT=1 - * @property {object} SHAPES.CIRC=2 - * @property {object} SHAPES.ELIP=3 - * @property {object} SHAPES.RREC=4 - */ - SHAPES: { - POLY: 0, - RECT: 1, - CIRC: 2, - ELIP: 3, - RREC: 4 - } -}; - -},{"../../package.json":3}],5:[function(require,module,exports){ -var math = require('../math'); - -/** - * The base class for all objects that are rendered on the screen. - * This is an abstract class and should not be used on its own rather it should be extended. - * - * @class - * @namespace PIXI - */ -function DisplayObject() { - /** - * The coordinate of the object relative to the local coordinates of the parent. - * - * @member {Point} - */ - this.position = new math.Point(); - - /** - * The scale factor of the object. - * - * @member {Point} - */ - this.scale = new math.Point(1, 1); - - /** - * The pivot point of the displayObject that it rotates around - * - * @member {Point} - */ - this.pivot = new math.Point(0, 0); - - /** - * The rotation of the object in radians. - * - * @member {number} - */ - this.rotation = 0; - - /** - * The opacity of the object. - * - * @member {number} - */ - this.alpha = 1; - - /** - * The visibility of the object. If false the object will not be drawn, and - * the updateTransform function will not be called. - * - * @member {boolean} - */ - this.visible = true; - - /** - * Can this object be rendered, if false the object will not be drawn but the updateTransform - * methods will still be called. - * - * @member {boolean} - */ - this.renderable = false; - - /** - * The display object container that contains this display object. - * - * @member {DisplayObjectContainer} - * @readOnly - */ - this.parent = null; - - /** - * The multiplied alpha of the displayObject - * - * @member {number} - * @readOnly - */ - this.worldAlpha = 1; - - /** - * Current transform of the object based on world (parent) factors - * - * @member {Matrix} - * @readOnly - */ - this.worldTransform = new math.Matrix(); - - /** - * The area the filter is applied to. This is used as more of an optimisation - * rather than figuring out the dimensions of the displayObject each frame you can set this rectangle - * - * @member {Rectangle} - */ - this.filterArea = null; - - /** - * cached sin rotation - * - * @member {number} - * @private - */ - this._sr = 0; - - /** - * cached cos rotation - * - * @member {number} - * @private - */ - this._cr = 1; - - /** - * The original, cached bounds of the object - * - * @member {Rectangle} - * @private - */ - this._bounds = new math.Rectangle(0, 0, 1, 1); - - /** - * The most up-to-date bounds of the object - * - * @member {Rectangle} - * @private - */ - this._currentBounds = null; - - /** - * The original, cached mask of the object - * - * @member {Rectangle} - * @private - */ - this._mask = null; - - /** - * Cached internal flag. - * - * @member {boolean} - * @private - */ - this._cacheIsDirty = false; -} - -// constructor -DisplayObject.prototype.constructor = DisplayObject; -module.exports = DisplayObject; - -Object.defineProperties(DisplayObject.prototype, { - /** - * The position of the displayObject on the x axis relative to the local coordinates of the parent. - * - * @member {number} - * @memberof DisplayObject# - */ - x: { - get: function () { - return this.position.x; - }, - set: function (value) { - this.position.x = value; - } - }, - - /** - * The position of the displayObject on the y axis relative to the local coordinates of the parent. - * - * @member {number} - * @memberof DisplayObject# - */ - y: { - get: function () { - return this.position.y; - }, - set: function (value) { - this.position.y = value; - } - }, - - /** - * Indicates if the sprite is globally visible. - * - * @member {boolean} - * @memberof DisplayObject# - * @readonly - */ - worldVisible: { - get: function () { - var item = this; - - do { - if (!item.visible) { - return false; - } - - item = item.parent; - } while(item); - - return true; - } - }, - - /** - * Sets a mask for the displayObject. A mask is an object that limits the visibility of an object to the shape of the mask applied to it. - * In PIXI a regular mask must be a PIXI.Graphics object. This allows for much faster masking in canvas as it utilises shape clipping. - * To remove a mask, set this property to null. - * - * @member {Graphics} - * @memberof DisplayObject# - */ - mask: { - get: function () { - return this._mask; - }, - set: function (value) { - if (this._mask) { - this._mask.isMask = false; - } - - this._mask = value; - - if (this._mask) { - this._mask.isMask = true; - } - } - }, - - /** - * Sets the filters for the displayObject. - * * IMPORTANT: This is a webGL only feature and will be ignored by the canvas renderer. - * To remove filters simply set this property to 'null' - * - * @member {Filter[]} - * @memberof DisplayObject# - */ - filters: { - get: function () { - return this._filters; - }, - set: function (value) { - if (value) { - // now put all the passes in one place.. - var passes = []; - - for (var i = 0; i < value.length; i++) { - var filterPasses = value[i].passes; - - for (var j = 0; j < filterPasses.length; j++) { - passes.push(filterPasses[j]); - } - } - - // TODO change this as it is legacy - this._filterBlock = { target: this, filterPasses: passes }; - } - - this._filters = value; - } - } -}); - -/* - * Updates the object transform for rendering - * - * TODO - Optimization pass! - * - * @private - */ -DisplayObject.prototype.updateTransform = function () { - if (!this.parent) { - return; - } - - // create some matrix refs for easy access - var pt = this.parent.worldTransform; - var wt = this.worldTransform; - - // temporary matrix variables - var a, b, c, d, tx, ty; - - // so if rotation is between 0 then we can simplify the multiplication process.. - if (this.rotation % math.PI_2) { - // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes - if (this.rotation !== this.rotationCache) { - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); - } - - // get the matrix values of the displayobject based on its transform properties.. - a = this._cr * this.scale.x; - b = this._sr * this.scale.x; - c = -this._sr * this.scale.y; - d = this._cr * this.scale.y; - tx = this.position.x; - ty = this.position.y; - - // check for pivot.. not often used so geared towards that fact! - if (this.pivot.x || this.pivot.y) { - tx -= this.pivot.x * a + this.pivot.y * c; - ty -= this.pivot.x * b + this.pivot.y * d; - } - - // concat the parent matrix with the objects transform. - wt.a = a * pt.a + b * pt.c; - wt.b = a * pt.b + b * pt.d; - wt.c = c * pt.a + d * pt.c; - wt.d = c * pt.b + d * pt.d; - wt.tx = tx * pt.a + ty * pt.c + pt.tx; - wt.ty = tx * pt.b + ty * pt.d + pt.ty; - } - else { - // lets do the fast version as we know there is no rotation.. - a = this.scale.x; - d = this.scale.y; - - tx = this.position.x - this.pivot.x * a; - ty = this.position.y - this.pivot.y * d; - - wt.a = a * pt.a; - wt.b = a * pt.b; - wt.c = d * pt.c; - wt.d = d * pt.d; - wt.tx = tx * pt.a + ty * pt.c + pt.tx; - wt.ty = tx * pt.b + ty * pt.d + pt.ty; - } - - // multiply the alphas.. - this.worldAlpha = this.alpha * this.parent.worldAlpha; -}; - -// performance increase to avoid using call.. (10x faster) -DisplayObject.prototype.displayObjectUpdateTransform = DisplayObject.prototype.updateTransform; - -/** - * Retrieves the bounds of the displayObject as a rectangle object - * - * @param matrix {Matrix} - * @return {Rectangle} the rectangular bounding area - */ -DisplayObject.prototype.getBounds = function (/* matrix */) { - return math.Rectangle.EMPTY; -}; - -/** - * Retrieves the local bounds of the displayObject as a rectangle object - * - * @return {Rectangle} the rectangular bounding area - */ -DisplayObject.prototype.getLocalBounds = function () { - return this.getBounds(math.Matrix.IDENTITY); -}; - -/** - * Calculates the global position of the display object - * - * @param position {Point} The world origin to calculate from - * @return {Point} A point object representing the position of this object - */ -DisplayObject.prototype.toGlobal = function (position) { - // don't need to u[date the lot - this.displayObjectUpdateTransform(); - return this.worldTransform.apply(position); -}; - -/** - * Calculates the local position of the display object relative to another point - * - * @param position {Point} The world origin to calculate from - * @param [from] {DisplayObject} The DisplayObject to calculate the global position from - * @return {Point} A point object representing the position of this object - */ -DisplayObject.prototype.toLocal = function (position, from) { - if (from) { - position = from.toGlobal(position); - } - - // don't need to update the lot - this.displayObjectUpdateTransform(); - return this.worldTransform.applyInverse(position); -}; - -/** - * Renders the object using the WebGL renderer - * - * @param renderer {WebGLRenderer} The renderer - * @private - */ -DisplayObject.prototype.renderWebGL = function (/* renderer */) { - // OVERWRITE; -}; - -/** - * Renders the object using the Canvas renderer - * - * @param renderer {CanvasRenderer} The renderer - * @private - */ -DisplayObject.prototype.renderCanvas = function (/* renderer */) { - // OVERWRITE; -}; - -},{"../math":12}],6:[function(require,module,exports){ -var math = require('../math'), - DisplayObject = require('./DisplayObject'), - RenderTexture = require('../textures/RenderTexture'), - // Sprite = require('./Sprite'), - _tempMatrix = new math.Matrix(); - -/** - * A DisplayObjectContainer represents a collection of display objects. - * It is the base class of all display objects that act as a container for other objects. - * - * @class - * @extends DisplayObject - * @namespace PIXI - */ -function DisplayObjectContainer() { - DisplayObject.call(this); - - /** - * The array of children of this container. - * - * @member {DisplayObject[]} - * @readonly - */ - this.children = []; - - /** - * Cached internal flag. - * - * @member {boolean} - * @private - */ - this._cacheAsBitmap = false; - - this._cachedSprite = null; -} - -// constructor -DisplayObjectContainer.prototype = Object.create(DisplayObject.prototype); -DisplayObjectContainer.prototype.constructor = DisplayObjectContainer; -module.exports = DisplayObjectContainer; - -Object.defineProperties(DisplayObjectContainer.prototype, { - /** - * The width of the displayObjectContainer, setting this will actually modify the scale to achieve the value set - * - * @member {number} - * @memberof DisplayObjectContainer# - */ - width: { - get: function () { - return this.scale.x * this.getLocalBounds().width; - }, - set: function (value) { - - var width = this.getLocalBounds().width; - - if(width !== 0) { - this.scale.x = value / width; - } - else { - this.scale.x = 1; - } - - - this._width = value; - } - }, - - /** - * The height of the displayObjectContainer, setting this will actually modify the scale to achieve the value set - * - * @member {number} - * @memberof DisplayObjectContainer# - */ - height: { - get: function () { - return this.scale.y * this.getLocalBounds().height; - }, - set: function (value) { - - var height = this.getLocalBounds().height; - - if (height !== 0) { - this.scale.y = value / height ; - } - else { - this.scale.y = 1; - } - - this._height = value; - } - }, - - /** - * Set if this display object is cached as a bitmap. - * This basically takes a snap shot of the display object as it is at that moment. It can provide a performance benefit for complex static displayObjects. - * To remove simply set this property to 'null' - * - * @member {boolean} - * @memberof DisplayObject# - */ - cacheAsBitmap: { - get: function () { - return this._cacheAsBitmap; - }, - set: function (value) { - if (this._cacheAsBitmap === value) { - return; - } - - if (value) { - this._generateCachedSprite(); - } - else { - this._destroyCachedSprite(); - } - - this._cacheAsBitmap = value; - } - } -}); - -/** - * Adds a child to the container. - * - * @param child {DisplayObject} The DisplayObject to add to the container - * @return {DisplayObject} The child that was added. - */ -DisplayObjectContainer.prototype.addChild = function (child) { - return this.addChildAt(child, this.children.length); -}; - -/** - * Adds a child to the container at a specified index. If the index is out of bounds an error will be thrown - * - * @param child {DisplayObject} The child to add - * @param index {Number} The index to place the child in - * @return {DisplayObject} The child that was added. - */ -DisplayObjectContainer.prototype.addChildAt = function (child, index) { - // prevent adding self as child - if (child === this) { - return; - } - - if (index >= 0 && index <= this.children.length) { - if (child.parent) { - child.parent.removeChild(child); - } - - child.parent = this; - - this.children.splice(index, 0, child); - - return child; - } - else { - throw new Error(child + 'addChildAt: The index '+ index +' supplied is out of bounds ' + this.children.length); - } -}; - -/** - * Swaps the position of 2 Display Objects within this container. - * - * @param child {DisplayObject} - * @param child2 {DisplayObject} - */ -DisplayObjectContainer.prototype.swapChildren = function (child, child2) { - if (child === child2) { - return; - } - - var index1 = this.getChildIndex(child); - var index2 = this.getChildIndex(child2); - - if (index1 < 0 || index2 < 0) { - throw new Error('swapChildren: Both the supplied DisplayObjects must be a child of the caller.'); - } - - this.children[index1] = child2; - this.children[index2] = child; -}; - -/** - * Returns the index position of a child DisplayObject instance - * - * @param child {DisplayObject} The DisplayObject instance to identify - * @return {Number} The index position of the child display object to identify - */ -DisplayObjectContainer.prototype.getChildIndex = function (child) { - var index = this.children.indexOf(child); - - if (index === -1) { - throw new Error('The supplied DisplayObject must be a child of the caller'); - } - - return index; -}; - -/** - * Changes the position of an existing child in the display object container - * - * @param child {DisplayObject} The child DisplayObject instance for which you want to change the index number - * @param index {Number} The resulting index number for the child display object - */ -DisplayObjectContainer.prototype.setChildIndex = function (child, index) { - if (index < 0 || index >= this.children.length) { - throw new Error('The supplied index is out of bounds'); - } - - var currentIndex = this.getChildIndex(child); - - this.children.splice(currentIndex, 1); //remove from old position - this.children.splice(index, 0, child); //add at new position -}; - -/** - * Returns the child at the specified index - * - * @param index {Number} The index to get the child from - * @return {DisplayObject} The child at the given index, if any. - */ -DisplayObjectContainer.prototype.getChildAt = function (index) { - if (index < 0 || index >= this.children.length) { - throw new Error('getChildAt: Supplied index ' + index + ' does not exist in the child list, or the supplied DisplayObject must be a child of the caller'); - } - - return this.children[index]; -}; - -/** - * Removes a child from the container. - * - * @param child {DisplayObject} The DisplayObject to remove - * @return {DisplayObject} The child that was removed. - */ -DisplayObjectContainer.prototype.removeChild = function (child) { - var index = this.children.indexOf(child); - - if (index === -1) { - return; - } - - return this.removeChildAt(index); -}; - -/** - * Removes a child from the specified index position. - * - * @param index {Number} The index to get the child from - * @return {DisplayObject} The child that was removed. - */ -DisplayObjectContainer.prototype.removeChildAt = function (index) { - var child = this.getChildAt(index); - - child.parent = null; - this.children.splice(index, 1); - - return child; -}; - -/** - * Removes all children from this container that are within the begin and end indexes. - * - * @param beginIndex {Number} The beginning position. Default value is 0. - * @param endIndex {Number} The ending position. Default value is size of the container. - */ -DisplayObjectContainer.prototype.removeChildren = function (beginIndex, endIndex) { - var begin = beginIndex || 0; - var end = typeof endIndex === 'number' ? endIndex : this.children.length; - var range = end - begin; - - if (range > 0 && range <= end) { - var removed = this.children.splice(begin, range); - - for (var i = 0; i < removed.length; ++i) { - removed[i].parent = null; - } - - return removed; - } - else if (range === 0 && this.children.length === 0) { - return []; - } - else { - throw new RangeError('removeChildren: numeric values are outside the acceptable range.'); - } -}; - -/** - * Generates and updates the cached sprite for this object. - * - */ -DisplayObjectContainer.prototype.updateCachedSprite = function () { - this._generateCachedSprite(); -}; - -/** - * Useful function that returns a texture of the displayObject object that can then be used to create sprites - * This can be quite useful if your displayObject is static / complicated and needs to be reused multiple times. - * - * @param resolution {Number} The resolution of the texture being generated - * @param scaleMode {Number} See {{#crossLink "PIXI/scaleModes:property"}}PIXI.scaleModes{{/crossLink}} for possible values - * @param renderer {CanvasRenderer|WebGLRenderer} The renderer used to generate the texture. - * @return {Texture} a texture of the graphics object - */ -DisplayObjectContainer.prototype.generateTexture = function (resolution, scaleMode, renderer) { - var bounds = this.getLocalBounds(); - - var renderTexture = new RenderTexture(renderer, bounds.width | 0, bounds.height | 0, renderer, scaleMode, resolution); - - _tempMatrix.tx = -bounds.x; - _tempMatrix.ty = -bounds.y; - - renderTexture.render(this, _tempMatrix); - - return renderTexture; -}; - -/* - * Updates the transform on all children of this container for rendering - * - * @private - */ -DisplayObjectContainer.prototype.updateTransform = function () { - if (!this.visible) { - return; - } - - this.displayObjectUpdateTransform(); - - if (this._cacheAsBitmap) { - return; - } - - for (var i = 0, j = this.children.length; i < j; ++i) { - this.children[i].updateTransform(); - } -}; - -// performance increase to avoid using call.. (10x faster) -DisplayObjectContainer.prototype.displayObjectContainerUpdateTransform = DisplayObjectContainer.prototype.updateTransform; - -/** - * Retrieves the bounds of the displayObjectContainer as a rectangle. The bounds calculation takes all visible children into consideration. - * - * @return {Rectangle} The rectangular bounding area - */ -DisplayObjectContainer.prototype.getBounds = function () { - if (this.children.length === 0) { - return math.Rectangle.EMPTY; - } - - // TODO the bounds have already been calculated this render session so return what we have - - var minX = Infinity; - var minY = Infinity; - - var maxX = -Infinity; - var maxY = -Infinity; - - var childBounds; - var childMaxX; - var childMaxY; - - var childVisible = false; - - for (var i = 0, j = this.children.length; i < j; ++i) { - var child = this.children[i]; - - if (!child.visible) { - continue; - } - - childVisible = true; - - childBounds = this.children[i].getBounds(); - - minX = minX < childBounds.x ? minX : childBounds.x; - minY = minY < childBounds.y ? minY : childBounds.y; - - childMaxX = childBounds.width + childBounds.x; - childMaxY = childBounds.height + childBounds.y; - - maxX = maxX > childMaxX ? maxX : childMaxX; - maxY = maxY > childMaxY ? maxY : childMaxY; - } - - if (!childVisible) { - return math.Rectangle.EMPTY; - } - - this._bounds.x = minX; - this._bounds.y = minY; - this._bounds.width = maxX - minX; - this._bounds.height = maxY - minY; - - // TODO: store a reference so that if this function gets called again in the render cycle we do not have to recalculate - //this._currentBounds = bounds; - - return this._bounds; -}; - -/** - * Retrieves the non-global local bounds of the displayObjectContainer as a rectangle. - * The calculation takes all visible children into consideration. - * - * @return {Rectangle} The rectangular bounding area - */ -DisplayObjectContainer.prototype.getLocalBounds = function () { - var matrixCache = this.worldTransform; - - this.worldTransform = math.Matrix.IDENTITY; - - for (var i = 0, j = this.children.length; i < j; ++i) { - this.children[i].updateTransform(); - } - - this.worldTransform = matrixCache; - - return this.getBounds(); -}; - -/** - * Renders the object using the WebGL renderer - * - * TODO - Optimization pass! - * - * @param renderer {WebGLRenderer} The renderer - */ -DisplayObjectContainer.prototype.renderWebGL = function (renderer) { - // if the object is not visible or the alpha is 0 then no need to render this element - if (!this.visible || this.alpha <= 0) { - return; - } - - if (this._cacheAsBitmap) { - this._renderCachedSprite(renderer); - return; - } - - var i, j; - - // do a quick check to see if this element has a mask or a filter. - if (this._mask || this._filters) { - // push filter first as we need to ensure the stencil buffer is correct for any masking - if (this._filters) { - renderer.spriteBatch.flush(); - renderer.filterManager.pushFilter(this._filterBlock); - } - - if (this._mask) { - renderer.spriteBatch.stop(); - renderer.maskManager.pushMask(this.mask, renderer); - renderer.spriteBatch.start(); - } - - // add this object to the batch, only rendered if it has a texture. - if (this.texture) { - renderer.spriteBatch.render(this); - } - - // now loop through the children and make sure they get rendered - for (i = 0, j = this.children.length; i < j; i++) { - this.children[i].renderWebGL(renderer); - } - - // time to stop the sprite batch as either a mask element or a filter draw will happen next - renderer.spriteBatch.stop(); - - if (this._mask) { - renderer.maskManager.popMask(this._mask, renderer); - } - - if (this._filters) { - renderer.filterManager.popFilter(); - } - - renderer.spriteBatch.start(); - } - else { - if (this.texture) { - renderer.spriteBatch.render(this); - } - - // simple render children! - for (i = 0, j = this.children.length; i < j; ++i) { - this.children[i].renderWebGL(renderer); - } - - } -}; - -/** - * Renders the object using the Canvas renderer - * - * @param renderer {CanvasRenderer} The renderer - */ -DisplayObjectContainer.prototype.renderCanvas = function (renderer) { - if (!this.visible || this.alpha <= 0) { - return; - } - - if (this._cacheAsBitmap) { - this._renderCachedSprite(renderer); - return; - } - - if (this._mask) { - renderer.maskManager.pushMask(this._mask, renderer); - } - - for (var i = 0, j = this.children.length; i < j; ++i) { - this.children[i].renderCanvas(renderer); - } - - if (this._mask) { - renderer.maskManager.popMask(renderer); - } -}; - -/** - * Internal method. - * - * @param renderer {WebGLRenderer|CanvasRenderer} The renderer - * @private - */ -DisplayObjectContainer.prototype._renderCachedSprite = function (renderer) { - this._cachedSprite.worldAlpha = this.worldAlpha; - - if (renderer.gl) { - this._cachedSprite.renderWebGL(renderer); - } - else { - this._cachedSprite.renderCanvas(renderer); - } -}; - -/** - * Internal method. - * - * @private - */ -DisplayObjectContainer.prototype._generateCachedSprite = function () { - var bounds = this.getLocalBounds(); - - if (!this._cachedSprite) { - // TODO - RenderTexture now *requires* a renderer instance, so this is like broken - // because `renderer` isn't actually in scope here :P - var renderTexture = new RenderTexture(renderer, bounds.width | 0, bounds.height | 0); - - this._cachedSprite = new Sprite(renderTexture); - this._cachedSprite.worldTransform = this.worldTransform; - } - else { - this._cachedSprite.texture.resize(bounds.width | 0, bounds.height | 0); - } - - var tempFilters = this._filters; - this._filters = null; - - this._cachedSprite.filters = tempFilters; - - _tempMatrix.tx = -bounds.x; - _tempMatrix.ty = -bounds.y; - - this._cachedSprite.texture.render(this, _tempMatrix, true); - - this._cachedSprite.anchor.x = -(bounds.x / bounds.width); - this._cachedSprite.anchor.y = -(bounds.y / bounds.height); - - this._filters = tempFilters; -}; - -/** - * Destroys the cached sprite. - * - * @private - */ -DisplayObjectContainer.prototype._destroyCachedSprite = function () { - if (!this._cachedSprite) { - return; - } - - // TODO: Pool this sprite - this._cachedSprite.destroy(true, true); - this._cachedSprite = null; -}; - -},{"../math":12,"../textures/RenderTexture":43,"./DisplayObject":5}],7:[function(require,module,exports){ -var math = require('../math'), - Texture = require('../textures/Texture'), - DisplayObjectContainer = require('./DisplayObjectContainer'), - CanvasTinter = require('../renderers/canvas/utils/CanvasTinter'), - utils = require('../utils'), - CONST = require('../const'); - -/** - * The Sprite object is the base for all textured objects that are rendered to the screen - * - * A sprite can be created directly from an image like this: - * - * ```js - * var sprite = new Sprite.fromImage('assets/image.png'); - * ``` - * - * @class Sprite - * @extends DisplayObjectContainer - * @namespace PIXI - * @param texture {Texture} The texture for this sprite - */ -function Sprite(texture) { - DisplayObjectContainer.call(this); - - /** - * The anchor sets the origin point of the texture. - * The default is 0,0 this means the texture's origin is the top left - * Setting than anchor to 0.5,0.5 means the textures origin is centered - * Setting the anchor to 1,1 would mean the textures origin points will be the bottom right corner - * - * @member {Point} - */ - this.anchor = new math.Point(); - - /** - * The texture that the sprite is using - * - * @member {Texture} - * @private - */ - this._texture = null; - - /** - * The width of the sprite (this is initially set by the texture) - * - * @member {number} - * @private - */ - this._width = 0; - - /** - * The height of the sprite (this is initially set by the texture) - * - * @member {number} - * @private - */ - this._height = 0; - - /** - * The tint applied to the sprite. This is a hex value. A value of 0xFFFFFF will remove any tint effect. - * - * @member {number} - * @default 0xFFFFFF - */ - this.tint = 0xFFFFFF; - - /** - * The blend mode to be applied to the sprite. Set to CONST.blendModes.NORMAL to remove any blend mode. - * - * @member {number} - * @default CONST.blendModes.NORMAL; - */ - this.blendMode = CONST.blendModes.NORMAL; - - /** - * The shader that will be used to render the sprite. Set to null to remove a current shader. - * - * @member {AbstractFilter} - */ - this.shader = null; - - this.renderable = true; - - // call texture setter - this.texture = texture || Texture.EMPTY; -} - -Sprite.prototype.destroy = function (destroyTexture, destroyBaseTexture) { - DisplayObjectContainer.prototype.destroy.call(this); - - this.anchor = null; - - if (destroyTexture) { - this._texture.destroy(destroyBaseTexture); - } - - this._texture = null; - this.shader = null; -}; - -// constructor -Sprite.prototype = Object.create(DisplayObjectContainer.prototype); -Sprite.prototype.constructor = Sprite; -module.exports = Sprite; - -Object.defineProperties(Sprite.prototype, { - /** - * The width of the sprite, setting this will actually modify the scale to achieve the value set - * - * @member - * @memberof Sprite# - */ - width: { - get: function () { - return this.scale.x * this.texture.frame.width; - }, - set: function (value) { - this.scale.x = value / this.texture.frame.width; - this._width = value; - } - }, - - /** - * The height of the sprite, setting this will actually modify the scale to achieve the value set - * - * @member - * @memberof Sprite# - */ - height: { - get: function () { - return this.scale.y * this.texture.frame.height; - }, - set: function (value) { - this.scale.y = value / this.texture.frame.height; - this._height = value; - } - }, - - /** - * The height of the sprite, setting this will actually modify the scale to achieve the value set - * - * @member - * @memberof Sprite# - */ - texture: { - get: function () { - return this._texture; - }, - set: function (value) { - if (this._texture === value) { - return; - } - - this._texture = value; - this.cachedTint = 0xFFFFFF; - - if (value) { - // wait for the texture to load - if (value.baseTexture.hasLoaded) { - this._onTextureUpdate(); - } - else { - value.once('update', this._onTextureUpdate.bind(this)); - } - } - } - }, -}); - -/** - * When the texture is updated, this event will fire to update the scale and frame - * - * @private - */ -Sprite.prototype._onTextureUpdate = function () { - // so if _width is 0 then width was not set.. - if (this._width) { - this.scale.x = this._width / this.texture.frame.width; - } - - if (this._height) { - this.scale.y = this._height / this.texture.frame.height; - } -}; - -/** - * Returns the bounds of the Sprite as a rectangle. The bounds calculation takes the worldTransform into account. - * - * @param matrix {Matrix} the transformation matrix of the sprite - * @return {Rectangle} the framing rectangle - */ -Sprite.prototype.getBounds = function (matrix) { - var width = this.texture.frame.width; - var height = this.texture.frame.height; - - var w0 = width * (1-this.anchor.x); - var w1 = width * -this.anchor.x; - - var h0 = height * (1-this.anchor.y); - var h1 = height * -this.anchor.y; - - var worldTransform = matrix || this.worldTransform ; - - var a = worldTransform.a; - var b = worldTransform.b; - var c = worldTransform.c; - var d = worldTransform.d; - var tx = worldTransform.tx; - var ty = worldTransform.ty; - - var minX, - maxX, - minY, - maxY; - - if(b === 0 && c === 0) - { - // scale may be negative! - if (a < 0) { - a *= -1; - } - - if (d < 0) { - d *= -1; - } - - // this means there is no rotation going on right? RIGHT? - // if thats the case then we can avoid checking the bound values! yay - minX = a * w1 + tx; - maxX = a * w0 + tx; - minY = d * h1 + ty; - maxY = d * h0 + ty; - } - else - { - var x1 = a * w1 + c * h1 + tx; - var y1 = d * h1 + b * w1 + ty; - - var x2 = a * w0 + c * h1 + tx; - var y2 = d * h1 + b * w0 + ty; - - var x3 = a * w0 + c * h0 + tx; - var y3 = d * h0 + b * w0 + ty; - - var x4 = a * w1 + c * h0 + tx; - var y4 = d * h0 + b * w1 + ty; - - minX = x1; - minX = x2 < minX ? x2 : minX; - minX = x3 < minX ? x3 : minX; - minX = x4 < minX ? x4 : minX; - - minY = y1; - minY = y2 < minY ? y2 : minY; - minY = y3 < minY ? y3 : minY; - minY = y4 < minY ? y4 : minY; - - maxX = x1; - maxX = x2 > maxX ? x2 : maxX; - maxX = x3 > maxX ? x3 : maxX; - maxX = x4 > maxX ? x4 : maxX; - - maxY = y1; - maxY = y2 > maxY ? y2 : maxY; - maxY = y3 > maxY ? y3 : maxY; - maxY = y4 > maxY ? y4 : maxY; - } - - var bounds = this._bounds; - - bounds.x = minX; - bounds.width = maxX - minX; - - bounds.y = minY; - bounds.height = maxY - minY; - - // store a reference so that if this function gets called again in the render cycle we do not have to recalculate - this._currentBounds = bounds; - - return bounds; -}; - -/** -* Renders the object using the Canvas renderer -* -* @param renderer {CanvasRenderer} The renderer -*/ -Sprite.prototype.renderCanvas = function (renderer) { - if (!this.visible || this.alpha <= 0 || this.texture.crop.width <= 0 || this.texture.crop.height <= 0) { - return; - } - - if (this.blendMode !== renderer.currentBlendMode) { - renderer.currentBlendMode = this.blendMode; - renderer.context.globalCompositeOperation = renderer.blendModes[renderer.currentBlendMode]; - } - - if (this._mask) { - renderer.maskManager.pushMask(this._mask, renderer); - } - - // Ignore null sources - if (this.texture.valid) { - var resolution = this.texture.baseTexture.resolution / renderer.resolution; - - renderer.context.globalAlpha = this.worldAlpha; - - // If smoothingEnabled is supported and we need to change the smoothing property for this texture - if (renderer.smoothProperty && renderer.scaleMode !== this.texture.baseTexture.scaleMode) { - renderer.scaleMode = this.texture.baseTexture.scaleMode; - renderer.context[renderer.smoothProperty] = (renderer.scaleMode === CONST.scaleModes.LINEAR); - } - - // If the texture is trimmed we offset by the trim x/y, otherwise we use the frame dimensions - var dx = (this.texture.trim ? this.texture.trim.x : 0) - (this.anchor.x * this.texture.trim.width); - var dy = (this.texture.trim ? this.texture.trim.y : 0) - (this.anchor.y * this.texture.trim.height); - - // Allow for pixel rounding - if (renderer.roundPixels) { - renderer.context.setTransform( - this.worldTransform.a, - this.worldTransform.b, - this.worldTransform.c, - this.worldTransform.d, - (this.worldTransform.tx * renderer.resolution) | 0, - (this.worldTransform.ty * renderer.resolution) | 0 - ); - - dx = dx | 0; - dy = dy | 0; - } - else { - renderer.context.setTransform( - this.worldTransform.a, - this.worldTransform.b, - this.worldTransform.c, - this.worldTransform.d, - this.worldTransform.tx * renderer.resolution, - this.worldTransform.ty * renderer.resolution - ); - } - - if (this.tint !== 0xFFFFFF) { - if (this.cachedTint !== this.tint) { - this.cachedTint = this.tint; - - // TODO clean up caching - how to clean up the caches? - this.tintedTexture = CanvasTinter.getTintedTexture(this, this.tint); - } - - renderer.context.drawImage( - this.tintedTexture, - 0, - 0, - this.texture.crop.width, - this.texture.crop.height, - dx / resolution, - dy / resolution, - this.texture.crop.width / resolution, - this.texture.crop.height / resolution - ); - } - else { - renderer.context.drawImage( - this.texture.baseTexture.source, - this.texture.crop.x, - this.texture.crop.y, - this.texture.crop.width, - this.texture.crop.height, - dx / resolution, - dy / resolution, - this.texture.crop.width / resolution, - this.texture.crop.height / resolution - ); - } - } - - for (var i = 0, j = this.children.length; i < j; i++) { - this.children[i].renderCanvas(renderer); - } - - if (this._mask) { - renderer.maskManager.popMask(renderer); - } -}; - -// some helper functions.. - -/** - * Helper function that creates a sprite that will contain a texture from the TextureCache based on the frameId - * The frame ids are created when a Texture packer file has been loaded - * - * @static - * @param frameId {String} The frame Id of the texture in the cache - * @return {Sprite} A new Sprite using a texture from the texture cache matching the frameId - */ -Sprite.fromFrame = function (frameId) { - var texture = utils.TextureCache[frameId]; - - if (!texture) { - throw new Error('The frameId "' + frameId + '" does not exist in the texture cache' + this); - } - - return new Sprite(texture); -}; - -/** - * Helper function that creates a sprite that will contain a texture based on an image url - * If the image is not in the texture cache it will be loaded - * - * @static - * @param imageId {String} The image url of the texture - * @return {Sprite} A new Sprite using a texture from the texture cache matching the image id - */ -Sprite.fromImage = function (imageId, crossorigin, scaleMode) { - return new Sprite(Texture.fromImage(imageId, crossorigin, scaleMode)); -}; - -},{"../const":4,"../math":12,"../renderers/canvas/utils/CanvasTinter":24,"../textures/Texture":44,"../utils":50,"./DisplayObjectContainer":6}],8:[function(require,module,exports){ -var DisplayObjectContainer = require('./DisplayObjectContainer'), - WebGLFastSpriteBatch = require('../renderers/webgl/utils/WebGLFastSpriteBatch'); - -/** - * The SpriteBatch class is a really fast version of the DisplayObjectContainer built solely for speed, - * so use when you need a lot of sprites or particles. The tradeoff of the SpriteBatch is that advanced - * functionality will not work. SpriteBatch implements only the basic object transform (position, scale, rotation). - * Any other functionality like tinting, masking, etc will not work on sprites in this batch. - * - * It's extremely easy to use : - * - * ```js - * var container = new SpriteBatch(); - * - * for(var i = 0; i < 100; ++i) { - * var sprite = new PIXI.Sprite.fromImage("myImage.png"); - * container.addChild(sprite); - * } - * ``` - * - * And here you have a hundred sprites that will be renderer at the speed of light. - * - * @class - * @namespace PIXI - */ - -//TODO RENAME to PARTICLE CONTAINER? -function SpriteBatch() { - DisplayObjectContainer.call(this); -} - -SpriteBatch.prototype = Object.create(DisplayObjectContainer.prototype); -SpriteBatch.prototype.constructor = SpriteBatch; -module.exports = SpriteBatch; - -/** - * Updates the object transform for rendering - * - * @private - */ -SpriteBatch.prototype.updateTransform = function () { - // TODO don't need to! - this.displayObjectUpdateTransform(); - // PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); -}; - -/** - * Renders the object using the WebGL renderer - * - * @param renderer {WebGLRenderer} The webgl renderer - * @private - */ -SpriteBatch.prototype.renderWebGL = function (renderer) { - if (!this.visible || this.alpha <= 0 || !this.children.length) { - return; - } - - renderer.spriteBatch.stop(); - - renderer.shaderManager.setShader(renderer.shaderManager.fastShader); - - renderer.fastSpriteBatch.begin(this); - renderer.fastSpriteBatch.render(this); - - renderer.spriteBatch.start(); -}; - -/** - * Renders the object using the Canvas renderer - * - * @param renderer {CanvasRenderer} The canvas renderer - * @private - */ -SpriteBatch.prototype.renderCanvas = function (renderer) { - if (!this.visible || this.alpha <= 0 || !this.children.length) { - return; - } - - var context = renderer.context; - var transform = this.worldTransform; - var isRotated = true; - - context.globalAlpha = this.worldAlpha; - - this.displayObjectUpdateTransform(); - - for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i]; - - if (!child.visible) { - continue; - } - - var frame = child.texture.frame; - - context.globalAlpha = this.worldAlpha * child.alpha; - - if (child.rotation % (Math.PI * 2) === 0) { - // this is the fastest way to optimise! - if rotation is 0 then we can avoid any kind of setTransform call - if (isRotated) { - context.setTransform( - transform.a, - transform.b, - transform.c, - transform.d, - transform.tx, - transform.ty - ); - - isRotated = false; - } - - context.drawImage( - child.texture.baseTexture.source, - frame.x, - frame.y, - frame.width, - frame.height, - ((child.anchor.x) * (-frame.width * child.scale.x) + child.position.x + 0.5) | 0, - ((child.anchor.y) * (-frame.height * child.scale.y) + child.position.y + 0.5) | 0, - frame.width * child.scale.x, - frame.height * child.scale.y - ); - } - else { - if (!isRotated) { - isRotated = true; - } - - child.displayObjectUpdateTransform(); - - var childTransform = child.worldTransform; - - if (renderer.roundPixels) { - context.setTransform( - childTransform.a, - childTransform.b, - childTransform.c, - childTransform.d, - childTransform.tx | 0, - childTransform.ty | 0 - ); - } - else { - context.setTransform( - childTransform.a, - childTransform.b, - childTransform.c, - childTransform.d, - childTransform.tx, - childTransform.ty - ); - } - - context.drawImage( - child.texture.baseTexture.source, - frame.x, - frame.y, - frame.width, - frame.height, - ((child.anchor.x) * (-frame.width) + 0.5) | 0, - ((child.anchor.y) * (-frame.height) + 0.5) | 0, - frame.width, - frame.height - ); - } - } -}; - -},{"../renderers/webgl/utils/WebGLFastSpriteBatch":38,"./DisplayObjectContainer":6}],9:[function(require,module,exports){ -/** - * @file Main export of the PIXI core library - * @author Mat Groves - * @copyright 2013-2015 GoodBoyDigital - * @license {@link https://github.com/GoodBoyDigital/pixi.js/blob/master/LICENSE|MIT License} - */ - -/** - * @namespace PIXI - */ -var core = module.exports = { - CONST: require('./const'), - - // utils - utils: require('./utils'), - math: require('./math'), - - // display - DisplayObject: require('./display/DisplayObject'), - DisplayObjectContainer: require('./display/DisplayObjectContainer'), - Sprite: require('./display/Sprite'), - SpriteBatch: require('./display/SpriteBatch'), - - // primitives - Graphics: require('./primitives/Graphics'), - GraphicsData: require('./primitives/GraphicsData'), - - // textures - Texture: require('./textures/Texture'), - BaseTexture: require('./textures/BaseTexture'), - RenderTexture: require('./textures/RenderTexture'), - VideoBaseTexture: require('./textures/VideoBaseTexture'), - - // renderers - canvas - CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasGraphics: require('./renderers/canvas/utils/CanvasGraphics'), - CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), - - // renderers - webgl - WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), - WebGLGraphics: require('./renderers/webgl/utils/WebGLGraphics'), - - /** - * This helper function will automatically detect which renderer you should be using. - * WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by - * the browser then this function will return a canvas renderer - * - * @param width=800 {number} the width of the renderers view - * @param height=600 {number} the height of the renderers view - * @param [options] {object} The optional renderer parameters - * @param [options.view] {HTMLCanvasElement} the canvas to use as a view, optional - * @param [options.transparent=false] {boolean} If the render view is transparent, default false - * @param [options.antialias=false] {boolean} sets antialias (only applicable in chrome at the moment) - * @param [options.preserveDrawingBuffer=false] {boolean} enables drawing buffer preservation, enable this if you - * need to call toDataUrl on the webgl context - * @param [options.resolution=1] {number} the resolution of the renderer retina would be 2 - * @param [noWebGL=false] {Boolean} prevents selection of WebGL renderer, even if such is present - * - * @return {WebGLRenderer|CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer - */ - autoDetectRenderer: function (width, height, options, noWebGL) { - width = width || 800; - height = height || 600; - - if (!noWebGL && require('webgl-enabled')()) { - return new core.WebGLRenderer(width, height, options); - } - - return new core.CanvasRenderer(width, height, options); - }, - - /** - * This helper function will automatically detect which renderer you should be using. This function is very - * similar to the autoDetectRenderer function except that is will return a canvas renderer for android. - * Even thought both android chrome supports webGL the canvas implementation perform better at the time of writing. - * This function will likely change and update as webGL performance improves on these devices. - * - * @param width=800 {number} the width of the renderers view - * @param height=600 {number} the height of the renderers view - * @param [options] {object} The optional renderer parameters - * @param [options.view] {HTMLCanvasElement} the canvas to use as a view, optional - * @param [options.transparent=false] {boolean} If the render view is transparent, default false - * @param [options.antialias=false] {boolean} sets antialias (only applicable in chrome at the moment) - * @param [options.preserveDrawingBuffer=false] {boolean} enables drawing buffer preservation, enable this if you - * need to call toDataUrl on the webgl context - * @param [options.resolution=1] {number} the resolution of the renderer retina would be 2 - * - * @return {WebGLRenderer|CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer - */ - autoDetectRecommendedRenderer: function (width, height, options) { - var isAndroid = /Android/i.test(navigator.userAgent); - - return core.autoDetectRenderer(width, height, options, isAndroid); - } -}; - -},{"./const":4,"./display/DisplayObject":5,"./display/DisplayObjectContainer":6,"./display/Sprite":7,"./display/SpriteBatch":8,"./math":12,"./primitives/Graphics":18,"./primitives/GraphicsData":19,"./renderers/canvas/CanvasRenderer":20,"./renderers/canvas/utils/CanvasBuffer":21,"./renderers/canvas/utils/CanvasGraphics":22,"./renderers/webgl/WebGLRenderer":25,"./renderers/webgl/utils/WebGLGraphics":39,"./textures/BaseTexture":42,"./textures/RenderTexture":43,"./textures/Texture":44,"./textures/VideoBaseTexture":46,"./utils":50,"webgl-enabled":2}],10:[function(require,module,exports){ -var Point = require('./Point'); - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class - * @namespace PIXI - */ -function Matrix() { - /** - * @member {number} - * @default 1 - */ - this.a = 1; - - /** - * @member {number} - * @default 0 - */ - this.b = 0; - - /** - * @member {number} - * @default 0 - */ - this.c = 0; - - /** - * @member {number} - * @default 1 - */ - this.d = 1; - - /** - * @member {number} - * @default 0 - */ - this.tx = 0; - - /** - * @member {number} - * @default 0 - */ - this.ty = 0; -} - -Matrix.prototype.constructor = Matrix; -module.exports = Matrix; - -/** - * Creates a Matrix object based on the given array. The Element to Matrix mapping order is as follows: - * - * a = array[0] - * b = array[1] - * c = array[3] - * d = array[4] - * tx = array[2] - * ty = array[5] - * - * @param array {number[]} The array that the matrix will be populated from. - */ -Matrix.prototype.fromArray = function (array) { - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object. - * - * @param transpose {boolean} Whether we need to transpose the matrix or not - * @return {number[]} the newly created array which contains the matrix - */ -Matrix.prototype.toArray = function (transpose) { - if (!this.array) { - this.array = new Float32Array(9); - } - - var array = this.array; - - if (transpose) { - array[0] = this.a; - array[1] = this.b; - array[2] = 0; - array[3] = this.c; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else { - array[0] = this.a; - array[1] = this.c; - array[2] = this.tx; - array[3] = this.b; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transformation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed through this matrix - */ -Matrix.prototype.apply = function (pos, newPos) { - newPos = newPos || new Point(); - - newPos.x = this.a * pos.x + this.c * pos.y + this.tx; - newPos.y = this.b * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transformation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed through this matrix - */ -Matrix.prototype.applyInverse = function (pos, newPos) { - newPos = newPos || new Point(); - - var id = 1 / (this.a * this.d + this.c * -this.b); - - newPos.x = this.d * id * pos.x + -this.c * id * pos.y + (this.ty * this.c - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y + -this.b * id * pos.x + (-this.ty * this.a + this.tx * this.b) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * - * @param {number} x - * @param {number} y - * @return {Matrix} This matrix. Good for chaining method calls. - */ -Matrix.prototype.translate = function (x, y) { - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * - * @param {number} x The amount to scale horizontally - * @param {number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - */ -Matrix.prototype.scale = function (x, y) { - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * - * @param {number} angle - The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - */ -Matrix.prototype.rotate = function (angle) { - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - -/** - * Appends the given Matrix to this Matrix. - * - * @param {Matrix} matrix - * @return {Matrix} This matrix. Good for chaining method calls. - */ -Matrix.prototype.append = function (matrix) { - var a1 = this.a; - var b1 = this.b; - var c1 = this.c; - var d1 = this.d; - - this.a = matrix.a * a1 + matrix.b * c1; - this.b = matrix.a * b1 + matrix.b * d1; - this.c = matrix.c * a1 + matrix.d * c1; - this.d = matrix.c * b1 + matrix.d * d1; - - this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; - this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; - - return this; -}; - -/** - * Resets this Matix to an identity (default) matrix. - * - * @return {Matrix} This matrix. Good for chaining method calls. - */ -Matrix.prototype.identity = function () { - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; - - return this; -}; - -Matrix.IDENTITY = new Matrix(); - -},{"./Point":11}],11:[function(require,module,exports){ -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents - * the horizontal axis and y represents the vertical axis. - * - * @class - * @namespace PIXI - * @param [x=0] {number} position of the point on the x axis - * @param [y=0] {number} position of the point on the y axis - */ -function Point(x, y) { - /** - * @member {number} - * @default 0 - */ - this.x = x || 0; - - /** - * @member {number} - * @default 0 - */ - this.y = y || 0; -} - -Point.prototype.constructor = Point; -module.exports = Point; - -/** - * Creates a clone of this point - * - * @return {Point} a copy of the point - */ -Point.prototype.clone = function () { - return new Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is omitted, both x and y will be set to x. - * - * @param [x=0] {number} position of the point on the x axis - * @param [y=0] {number} position of the point on the y axis - */ -Point.prototype.set = function (x, y) { - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -},{}],12:[function(require,module,exports){ -/** - * @namespace PIXI.math - */ -module.exports = { - /** - * @property {number} PI_2 - Math.PI x 2 - * @constant - * @static - */ - PI_2: Math.PI * 2, - - /** - * @property {number} RAD_TO_DEG - Constant conversion factor for converting radians to degrees - * @constant - * @static - */ - RAD_TO_DEG: 180 / Math.PI, - - /** - * @property {Number} DEG_TO_RAD - Constant conversion factor for converting degrees to radians - * @constant - * @static - */ - DEG_TO_RAD: Math.PI / 180, - - Point: require('./Point'), - Matrix: require('./Matrix'), - - Circle: require('./shapes/Circle'), - Ellipse: require('./shapes/Ellipse'), - Polygon: require('./shapes/Polygon'), - Rectangle: require('./shapes/Rectangle'), - RoundedRectangle: require('./shapes/RoundedRectangle') -}; - -},{"./Matrix":10,"./Point":11,"./shapes/Circle":13,"./shapes/Ellipse":14,"./shapes/Polygon":15,"./shapes/Rectangle":16,"./shapes/RoundedRectangle":17}],13:[function(require,module,exports){ -var Rectangle = require('./Rectangle'), - CONST = require('../../const'); - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class - * @namespace PIXI - * @param x {number} The X coordinate of the center of this circle - * @param y {number} The Y coordinate of the center of this circle - * @param radius {number} The radius of the circle - */ -function Circle(x, y, radius) { - /** - * @member {number} - * @default 0 - */ - this.x = x || 0; - - /** - * @member {number} - * @default 0 - */ - this.y = y || 0; - - /** - * @member {number} - * @default 0 - */ - this.radius = radius || 0; - - /** - * The type of the object, mainly used to avoid `instanceof` checks - * - * @member {number} - */ - this.type = CONST.SHAPES.CIRC; -} - -Circle.prototype.constructor = Circle; -module.exports = Circle; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the Circle - */ -Circle.prototype.clone = function () { - return new Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x and y coordinates given are contained within this circle - * - * @method contains - * @param x {number} The X coordinate of the point to test - * @param y {number} The Y coordinate of the point to test - * @return {boolean} Whether the x/y coordinates are within this Circle - */ -Circle.prototype.contains = function (x, y) { - if (this.radius <= 0) { - return false; - } - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -Circle.prototype.getBounds = function () { - return new Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -},{"../../const":4,"./Rectangle":16}],14:[function(require,module,exports){ -var Rectangle = require('./Rectangle'), - CONST = require('../../const'); - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class - * @namespace PIXI - * @param x {number} The X coordinate of the center of the ellipse - * @param y {number} The Y coordinate of the center of the ellipse - * @param width {number} The half width of this ellipse - * @param height {number} The half height of this ellipse - */ -function Ellipse(x, y, width, height) { - /** - * @member {number} - * @default 0 - */ - this.x = x || 0; - - /** - * @member {number} - * @default 0 - */ - this.y = y || 0; - - /** - * @member {number} - * @default 0 - */ - this.width = width || 0; - - /** - * @member {number} - * @default 0 - */ - this.height = height || 0; - - /** - * The type of the object, mainly used to avoid `instanceof` checks - * - * @member {number} - */ - this.type = CONST.SHAPES.ELIP; -} - -Ellipse.prototype.constructor = Ellipse; -module.exports = Ellipse; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -Ellipse.prototype.clone = function () { - return new Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates given are contained within this ellipse - * - * @method contains - * @param x {number} The X coordinate of the point to test - * @param y {number} The Y coordinate of the point to test - * @return {boolean} Whether the x/y coords are within this ellipse - */ -Ellipse.prototype.contains = function (x, y) { - if (this.width <= 0 || this.height <= 0) { - return false; - } - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -Ellipse.prototype.getBounds = function () { - return new Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -},{"../../const":4,"./Rectangle":16}],15:[function(require,module,exports){ -var Point = require('../Point'), - CONST = require('../../const'); - -/** - * @class - * @namespace PIXI - * @param points* {Point[]|number[]|Point...|number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new Polygon(new Point(), new Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -function Polygon(points) { - //if points isn't an array, use arguments as the array - if (!(points instanceof Array)) { - points = Array.prototype.slice.call(arguments); - } - - //if this is a flat array of numbers, convert it to points - if (points[0] instanceof Point) { - var p = []; - for (var i = 0, il = points.length; i < il; i++) { - p.push(points[i].x, points[i].y); - } - - points = p; - } - - this.closed = true; - - /** - * An array of the points of this polygon - * - * @member {Point[]} - */ - this.points = points; - - /** - * The type of the object, mainly used to avoid `instanceof` checks - * - * @member {number} - */ - this.type = CONST.SHAPES.POLY; -} - -Polygon.prototype.constructor = Polygon; -module.exports = Polygon; - -/** - * Creates a clone of this polygon - * - * @return {Polygon} a copy of the polygon - */ -Polygon.prototype.clone = function () { - return new Polygon(this.points.slice()); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this polygon - * - * @param x {number} The X coordinate of the point to test - * @param y {number} The Y coordinate of the point to test - * @return {boolean} Whether the x/y coordinates are within this polygon - */ -Polygon.prototype.contains = function (x, y) { - var inside = false; - - // use some raycasting to test hits - // https://github.com/substack/point-in-polygon/blob/master/index.js - var length = this.points.length / 2; - - for (var i = 0, j = length - 1; i < length; j = i++) { - var xi = this.points[i * 2], yi = this.points[i * 2 + 1], - xj = this.points[j * 2], yj = this.points[j * 2 + 1], - intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if (intersect) { - inside = !inside; - } - } - - return inside; -}; - -},{"../../const":4,"../Point":11}],16:[function(require,module,exports){ -var CONST = require('../../const'); - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class - * @namespace PIXI - * @param x {number} The X coordinate of the upper-left corner of the rectangle - * @param y {number} The Y coordinate of the upper-left corner of the rectangle - * @param width {number} The overall width of this rectangle - * @param height {number} The overall height of this rectangle - */ -function Rectangle(x, y, width, height) { - /** - * @member {number} - * @default 0 - */ - this.x = x || 0; - - /** - * @member {number} - * @default 0 - */ - this.y = y || 0; - - /** - * @member {number} - * @default 0 - */ - this.width = width || 0; - - /** - * @member {number} - * @default 0 - */ - this.height = height || 0; - - /** - * The type of the object, mainly used to avoid `instanceof` checks - * - * @member {number} - */ - this.type = CONST.SHAPES.RECT; -} - -Rectangle.prototype.constructor = Rectangle; -module.exports = Rectangle; - -/** - * A constant empty rectangle. - * - * @static - * @constant - */ -Rectangle.EMPTY = new Rectangle(0, 0, 0, 0); - - -/** - * Creates a clone of this Rectangle - * - * @return {Rectangle} a copy of the rectangle - */ -Rectangle.prototype.clone = function () { - return new Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates given are contained within this Rectangle - * - * @param x {number} The X coordinate of the point to test - * @param y {number} The Y coordinate of the point to test - * @return {boolean} Whether the x/y coordinates are within this Rectangle - */ -Rectangle.prototype.contains = function (x, y) { - if (this.width <= 0 || this.height <= 0) { - return false; - } - - if (x >= this.x && x <= this.x + this.width) { - if (y >= this.y && y <= this.y + this.height) { - return true; - } - } - - return false; -}; - -},{"../../const":4}],17:[function(require,module,exports){ -var CONST = require('../../const'); - -/** - * The Rounded Rectangle object is an area defined by its position and has nice rounded corners, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class - * @namespace PIXI - * @param x {number} The X coordinate of the upper-left corner of the rounded rectangle - * @param y {number} The Y coordinate of the upper-left corner of the rounded rectangle - * @param width {number} The overall width of this rounded rectangle - * @param height {number} The overall height of this rounded rectangle - * @param radius {number} Controls the radius of the rounded corners - */ -function RoundedRectangle(x, y, width, height, radius) { - /** - * @member {number} - * @default 0 - */ - this.x = x || 0; - - /** - * @member {number} - * @default 0 - */ - this.y = y || 0; - - /** - * @member {number} - * @default 0 - */ - this.width = width || 0; - - /** - * @member {number} - * @default 0 - */ - this.height = height || 0; - - /** - * @member {number} - * @default 20 - */ - this.radius = radius || 20; - - /** - * The type of the object, mainly used to avoid `instanceof` checks - * - * @member {number} - */ - this.type = CONST.SHAPES.RREC; -} - -RoundedRectangle.prototype.constructor = RoundedRectangle; -module.exports = RoundedRectangle; - -/** - * Creates a clone of this Rounded Rectangle - * - * @return {RoundedRectangle} a copy of the rounded rectangle - */ -RoundedRectangle.prototype.clone = function () { - return new RoundedRectangle(this.x, this.y, this.width, this.height, this.radius); -}; - -/** - * Checks whether the x and y coordinates given are contained within this Rounded Rectangle - * - * @param x {number} The X coordinate of the point to test - * @param y {number} The Y coordinate of the point to test - * @return {boolean} Whether the x/y coordinates are within this Rounded Rectangle - */ -RoundedRectangle.prototype.contains = function (x, y) { - if (this.width <= 0 || this.height <= 0) { - return false; - } - - if (x >= this.x && x <= this.x + this.width) { - if (y >= this.y && y <= this.y + this.height) { - return true; - } - } - - return false; -}; - -},{"../../const":4}],18:[function(require,module,exports){ -var DisplayObjectContainer = require('../display/DisplayObjectContainer'), - Sprite = require('../display/Sprite'), - Texture = require('../textures/Texture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), - CanvasGraphics = require('../renderers/canvas/utils/CanvasGraphics'), - WebGLGraphics = require('../renderers/webgl/utils/WebGLGraphics'), - GraphicsData = require('./GraphicsData'), - math = require('../math'), - CONST = require('../const'); - -/** - * The Graphics class contains methods used to draw primitive shapes such as lines, circles and - * rectangles to the display, and color and fill them. - * - * @class - * @extends DisplayObjectContainer - * @namespace PIXI - */ -function Graphics() { - DisplayObjectContainer.call(this); - - this.renderable = true; - - /** - * The alpha value used when filling the Graphics object. - * - * @member {number} - * @default 1 - */ - this.fillAlpha = 1; - - /** - * The width (thickness) of any lines drawn. - * - * @member {number} - * @default 0 - */ - this.lineWidth = 0; - - /** - * The color of any lines drawn. - * - * @member {string} - * @default 0 - */ - this.lineColor = 0; - - /** - * Graphics data - * - * @member {GraphicsData[]} - * @private - */ - this.graphicsData = []; - - /** - * The tint applied to the graphic shape. This is a hex value. Apply a value of 0xFFFFFF to reset the tint. - * - * @member {number} - * @default 0xFFFFFF - */ - this.tint = 0xFFFFFF; - - /** - * The blend mode to be applied to the graphic shape. Apply a value of blendModes.NORMAL to reset the blend mode. - * - * @member {number} - * @default CONST.blendModes.NORMAL; - */ - this.blendMode = CONST.blendModes.NORMAL; - - /** - * Current path - * - * @member {GraphicsData} - * @private - */ - this.currentPath = null; - - /** - * Array containing some WebGL-related properties used by the WebGL renderer. - * - * @member {object} - * @private - */ - // TODO - _webgl should use a prototype object, not a random undocumented object... - this._webGL = {}; - - /** - * Whether this shape is being used as a mask. - * - * @member {boolean} - */ - this.isMask = false; - - /** - * The bounds' padding used for bounds calculation. - * - * @member {number} - */ - this.boundsPadding = 0; - - /** - * A cache of the local bounds to prevent recalculation. - * - * @member {Rectangle} - * @private - */ - this._localBounds = new math.Rectangle(0,0,1,1); - - /** - * Used to detect if the graphics object has changed. If this is set to true then the graphics - * object will be recalculated. - * - * @member {boolean} - * @private - */ - this.dirty = true; - - /** - * Used to detect if the WebGL graphics object has changed. If this is set to true then the - * graphics object will be recalculated. - * - * @member {boolean} - * @private - */ - this.glDirty = false; - - /** - * Used to detect if the cached sprite object needs to be updated. - * - * @member {boolean} - * @private - */ - this.cachedSpriteDirty = false; -} - -// constructor -Graphics.prototype = Object.create(DisplayObjectContainer.prototype); -Graphics.prototype.constructor = Graphics; -module.exports = Graphics; - -Object.defineProperties(Graphics.prototype, { - /** - * When cacheAsBitmap is set to true the graphics object will be rendered as if it was a sprite. - * This is useful if your graphics element does not change often, as it will speed up the rendering - * of the object in exchange for taking up texture memory. It is also useful if you need the graphics - * object to be anti-aliased, because it will be rendered using canvas. This is not recommended if - * you are constantly redrawing the graphics element. - * - * @member {boolean} - * @memberof Graphics# - * @default false - * @private - */ - cacheAsBitmap: { - get: function () { - return this._cacheAsBitmap; - }, - set: function (value) { - this._cacheAsBitmap = value; - - if (this._cacheAsBitmap) { - this._generateCachedSprite(); - } - else { - this.destroyCachedSprite(); - this.dirty = true; - } - } - } -}); - -/** - * Creates a new Graphics object with the same values as this one. - * - * @return {Graphics} - */ -GraphicsData.prototype.clone = function () { - var clone = new Graphics(); - - clone.renderable = this.renderable; - clone.fillAlpha = this.fillAlpha; - clone.lineWidth = this.lineWidth; - clone.lineColor = this.lineColor; - clone.tint = this.tint; - clone.blendMode = this.blendMode; - clone.isMask = this.isMask; - clone.boundsPadding = this.boundsPadding; - clone.dirty = this.dirty; - clone.glDirty = this.glDirty; - clone.cachedSpriteDirty = this.cachedSpriteDirty; - - // copy graphics data - for (var i = 0; i < this.graphicsData.length; ++i) { - clone.graphicsData.push(this.graphicsData.clone()); - } - - clone.currentPath = clone.graphicsData[clone.graphicsData.length - 1]; - - clone.updateLocalBounds(); - - return clone; -}; - -/** - * Specifies the line style used for subsequent calls to Graphics methods such as the lineTo() method or the drawCircle() method. - * - * @param lineWidth {number} width of the line to draw, will update the objects stored style - * @param color {number} color of the line to draw, will update the objects stored style - * @param alpha {number} alpha of the line to draw, will update the objects stored style - * @return {Graphics} - */ -Graphics.prototype.lineStyle = function (lineWidth, color, alpha) { - this.lineWidth = lineWidth || 0; - this.lineColor = color || 0; - this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - - if (this.currentPath) { - if (this.currentPath.shape.points.length) { - // halfway through a line? start a new one! - this.drawShape( new math.Polygon( this.currentPath.shape.points.slice(-2) )); - } - else { - // otherwise its empty so lets just set the line properties - this.currentPath.lineWidth = this.lineWidth; - this.currentPath.lineColor = this.lineColor; - this.currentPath.lineAlpha = this.lineAlpha; - } - } - - return this; -}; - -/** - * Moves the current drawing position to x, y. - * - * @param x {number} the X coordinate to move to - * @param y {number} the Y coordinate to move to - * @return {Graphics} - */ -Graphics.prototype.moveTo = function (x, y) { - this.drawShape(new math.Polygon([x,y])); - - return this; -}; - -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * The current drawing position is then set to (x, y). - * - * @param x {number} the X coordinate to draw to - * @param y {number} the Y coordinate to draw to - * @return {Graphics} - */ -Graphics.prototype.lineTo = function (x, y) { - this.currentPath.shape.points.push(x, y); - this.dirty = true; - - return this; -}; - -/** - * Calculate the points for a quadratic bezier curve and then draws it. - * Based on: https://stackoverflow.com/questions/785097/how-do-i-implement-a-bezier-curve-in-c - * - * @param cpX {number} Control point x - * @param cpY {number} Control point y - * @param toX {number} Destination point x - * @param toY {number} Destination point y - * @return {Graphics} - */ -Graphics.prototype.quadraticCurveTo = function (cpX, cpY, toX, toY) { - if (this.currentPath) { - if (this.currentPath.shape.points.length === 0) { - this.currentPath.shape.points = [0, 0]; - } - } - else { - this.moveTo(0,0); - } - - var xa, - ya, - n = 20, - points = this.currentPath.shape.points; - - if (points.length === 0) { - this.moveTo(0, 0); - } - - var fromX = points[points.length-2]; - var fromY = points[points.length-1]; - - var j = 0; - for (var i = 1; i <= n; ++i) { - j = i / n; - - xa = fromX + ( (cpX - fromX) * j ); - ya = fromY + ( (cpY - fromY) * j ); - - points.push( xa + ( ((cpX + ( (toX - cpX) * j )) - xa) * j ), - ya + ( ((cpY + ( (toY - cpY) * j )) - ya) * j ) ); - } - - this.dirty = true; - - return this; -}; - -/** - * Calculate the points for a bezier curve and then draws it. - * - * @param cpX {number} Control point x - * @param cpY {number} Control point y - * @param cpX2 {number} Second Control point x - * @param cpY2 {number} Second Control point y - * @param toX {number} Destination point x - * @param toY {number} Destination point y - * @return {Graphics} - */ -Graphics.prototype.bezierCurveTo = function (cpX, cpY, cpX2, cpY2, toX, toY) { - if (this.currentPath) { - if (this.currentPath.shape.points.length === 0) { - this.currentPath.shape.points = [0, 0]; - } - } - else { - this.moveTo(0,0); - } - - var n = 20, - dt, - dt2, - dt3, - t2, - t3, - points = this.currentPath.shape.points; - - var fromX = points[points.length-2]; - var fromY = points[points.length-1]; - - var j = 0; - - for (var i = 1; i <= n; ++i) { - j = i / n; - - dt = (1 - j); - dt2 = dt * dt; - dt3 = dt2 * dt; - - t2 = j * j; - t3 = t2 * j; - - points.push( dt3 * fromX + 3 * dt2 * j * cpX + 3 * dt * t2 * cpX2 + t3 * toX, - dt3 * fromY + 3 * dt2 * j * cpY + 3 * dt * t2 * cpY2 + t3 * toY); - } - - this.dirty = true; - - return this; -}; - -/** - * The arcTo() method creates an arc/curve between two tangents on the canvas. - * - * "borrowed" from https://code.google.com/p/fxcanvas/ - thanks google! - * - * @param x1 {number} The x-coordinate of the beginning of the arc - * @param y1 {number} The y-coordinate of the beginning of the arc - * @param x2 {number} The x-coordinate of the end of the arc - * @param y2 {number} The y-coordinate of the end of the arc - * @param radius {number} The radius of the arc - * @return {Graphics} - */ -Graphics.prototype.arcTo = function (x1, y1, x2, y2, radius) { - if (this.currentPath) { - if (this.currentPath.shape.points.length === 0) { - this.currentPath.shape.points.push(x1, y1); - } - } - else { - this.moveTo(x1, y1); - } - - var points = this.currentPath.shape.points, - fromX = points[points.length-2], - fromY = points[points.length-1], - a1 = fromY - y1, - b1 = fromX - x1, - a2 = y2 - y1, - b2 = x2 - x1, - mm = Math.abs(a1 * b2 - b1 * a2); - - if (mm < 1.0e-8 || radius === 0) { - if (points[points.length-2] !== x1 || points[points.length-1] !== y1) { - points.push(x1, y1); - } - } - else { - var dd = a1 * a1 + b1 * b1, - cc = a2 * a2 + b2 * b2, - tt = a1 * a2 + b1 * b2, - k1 = radius * Math.sqrt(dd) / mm, - k2 = radius * Math.sqrt(cc) / mm, - j1 = k1 * tt / dd, - j2 = k2 * tt / cc, - cx = k1 * b2 + k2 * b1, - cy = k1 * a2 + k2 * a1, - px = b1 * (k2 + j1), - py = a1 * (k2 + j1), - qx = b2 * (k1 + j2), - qy = a2 * (k1 + j2), - startAngle = Math.atan2(py - cy, px - cx), - endAngle = Math.atan2(qy - cy, qx - cx); - - this.arc(cx + x1, cy + y1, radius, startAngle, endAngle, b1 * a2 > b2 * a1); - } - - this.dirty = true; - - return this; -}; - -/** - * The arc method creates an arc/curve (used to create circles, or parts of circles). - * - * @param cx {number} The x-coordinate of the center of the circle - * @param cy {number} The y-coordinate of the center of the circle - * @param radius {number} The radius of the circle - * @param startAngle {number} The starting angle, in radians (0 is at the 3 o'clock position of the arc's circle) - * @param endAngle {number} The ending angle, in radians - * @param anticlockwise {boolean} Optional. Specifies whether the drawing should be counterclockwise or clockwise. False is default, and indicates clockwise, while true indicates counter-clockwise. - * @return {Graphics} - */ -Graphics.prototype.arc = function (cx, cy, radius, startAngle, endAngle, anticlockwise) { - var startX = cx + Math.cos(startAngle) * radius; - var startY = cy + Math.sin(startAngle) * radius; - var points; - - // TODO - This if-else makes no sense. It uses currentPath in the else where it doesn't exist... - if (this.currentPath) { - points = this.currentPath.shape.points; - - if (points.length === 0) { - points.push(startX, startY); - } - else if (points[points.length-2] !== startX || points[points.length-1] !== startY) { - points.push(startX, startY); - } - } - else { - this.moveTo(startX, startY); - points = this.currentPath.shape.points; - } - - if (startAngle === endAngle) { - return this; - } - - if (!anticlockwise && endAngle <= startAngle) { - endAngle += Math.PI * 2; - } - else if (anticlockwise && startAngle <= endAngle) { - startAngle += Math.PI * 2; - } - - var sweep = anticlockwise ? (startAngle - endAngle) *-1 : (endAngle - startAngle); - var segs = (Math.abs(sweep)/ (Math.PI * 2)) * 40; - - if (sweep === 0) { - return this; - } - - var theta = sweep/(segs*2); - var theta2 = theta*2; - - var cTheta = Math.cos(theta); - var sTheta = Math.sin(theta); - - var segMinus = segs - 1; - - var remainder = ( segMinus % 1 ) / segMinus; - - for (var i = 0; i <= segMinus; ++i) { - var real = i + remainder * i; - var angle = ((theta) + startAngle + (theta2 * real)); - - var c = Math.cos(angle); - var s = -Math.sin(angle); - - points.push(( (cTheta * c) + (sTheta * s) ) * radius + cx, - ( (cTheta * -s) + (sTheta * c) ) * radius + cy); - } - - this.dirty = true; - - return this; -}; - -/** - * Specifies a simple one-color fill that subsequent calls to other Graphics methods - * (such as lineTo() or drawCircle()) use when drawing. - * - * @param color {number} the color of the fill - * @param alpha {number} the alpha of the fill - * @return {Graphics} - */ -Graphics.prototype.beginFill = function (color, alpha) { - this.filling = true; - this.fillColor = color || 0; - this.fillAlpha = (alpha === undefined) ? 1 : alpha; - - if (this.currentPath) { - if (this.currentPath.shape.points.length <= 2) { - this.currentPath.fill = this.filling; - this.currentPath.fillColor = this.fillColor; - this.currentPath.fillAlpha = this.fillAlpha; - } - } - return this; -}; - -/** - * Applies a fill to the lines and shapes that were added since the last call to the beginFill() method. - * - * @return {Graphics} - */ -Graphics.prototype.endFill = function () { - this.filling = false; - this.fillColor = null; - this.fillAlpha = 1; - - return this; -}; - -/** - * - * @param x {number} The X coord of the top-left of the rectangle - * @param y {number} The Y coord of the top-left of the rectangle - * @param width {number} The width of the rectangle - * @param height {number} The height of the rectangle - * @return {Graphics} - */ -Graphics.prototype.drawRect = function ( x, y, width, height ) { - this.drawShape(new math.Rectangle(x,y, width, height)); - - return this; -}; - -/** - * - * @param x {number} The X coord of the top-left of the rectangle - * @param y {number} The Y coord of the top-left of the rectangle - * @param width {number} The width of the rectangle - * @param height {number} The height of the rectangle - * @param radius {number} Radius of the rectangle corners - */ -Graphics.prototype.drawRoundedRect = function ( x, y, width, height, radius ) { - this.drawShape(new math.RoundedRectangle(x, y, width, height, radius)); - - return this; -}; - -/** - * Draws a circle. - * - * @param x {number} The X coordinate of the center of the circle - * @param y {number} The Y coordinate of the center of the circle - * @param radius {number} The radius of the circle - * @return {Graphics} - */ -Graphics.prototype.drawCircle = function (x, y, radius) { - this.drawShape(new math.Circle(x,y, radius)); - - return this; -}; - -/** - * Draws an ellipse. - * - * @param x {number} The X coordinate of the center of the ellipse - * @param y {number} The Y coordinate of the center of the ellipse - * @param width {number} The half width of the ellipse - * @param height {number} The half height of the ellipse - * @return {Graphics} - */ -Graphics.prototype.drawEllipse = function (x, y, width, height) { - this.drawShape(new math.Ellipse(x, y, width, height)); - - return this; -}; - -/** - * Draws a polygon using the given path. - * - * @param path {Array} The path data used to construct the polygon. - * @return {Graphics} - */ -Graphics.prototype.drawPolygon = function (path) { - if (!(path instanceof Array)) { - path = Array.prototype.slice.call(arguments); - } - - this.drawShape(new math.Polygon(path)); - - return this; -}; - -/** - * Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings. - * - * @return {Graphics} - */ -Graphics.prototype.clear = function () { - this.lineWidth = 0; - this.filling = false; - - this.dirty = true; - this.clearDirty = true; - this.graphicsData = []; - - return this; -}; - -/** - * Useful function that returns a texture of the graphics object that can then be used to create sprites - * This can be quite useful if your geometry is complicated and needs to be reused multiple times. - * - * @param resolution {number} The resolution of the texture being generated - * @param scaleMode {number} Should be one of the scaleMode consts - * @return {Texture} a texture of the graphics object - */ -Graphics.prototype.generateTexture = function (resolution, scaleMode) { - resolution = resolution || 1; - - var bounds = this.getBounds(); - - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); - - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); - texture.baseTexture.resolution = resolution; - - canvasBuffer.context.scale(resolution, resolution); - - canvasBuffer.context.translate(-bounds.x,-bounds.y); - - CanvasGraphics.renderGraphics(this, canvasBuffer.context); - - return texture; -}; - -/** - * Renders the object using the WebGL renderer - * - * @param renderer {WebGLRenderer} - */ -Graphics.prototype.renderWebGL = function (renderer) { - // if the sprite is not visible or the alpha is 0 then no need to render this element - if (!this.visible || this.alpha <= 0 || this.isMask === true) { - return; - } - - if (this._cacheAsBitmap) { - if (this.dirty || this.cachedSpriteDirty) { - this._generateCachedSprite(); - - // we will also need to update the texture on the gpu too! - this.updateCachedSpriteTexture(); - - this.cachedSpriteDirty = false; - this.dirty = false; - } - - this._cachedSprite.worldAlpha = this.worldAlpha; - - Sprite.prototype.renderWebGL.call(this._cachedSprite, renderer); - - return; - } - else { - renderer.spriteBatch.stop(); - renderer.blendModeManager.setBlendMode(this.blendMode); - - if (this._mask) { - renderer.maskManager.pushMask(this._mask, renderer); - } - - if (this._filters) { - renderer.filterManager.pushFilter(this._filterBlock); - } - - // check blend mode - if (this.blendMode !== renderer.spriteBatch.currentBlendMode) { - renderer.spriteBatch.currentBlendMode = this.blendMode; - - var blendModeWebGL = renderer.blendModes[renderer.spriteBatch.currentBlendMode]; - - renderer.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); - } - - // check if the webgl graphic needs to be updated - if (this.glDirty) { - this.dirty = true; - this.glDirty = false; - } - - WebGLGraphics.renderGraphics(this, renderer); - - // only render if it has children! - if (this.children.length) { - renderer.spriteBatch.start(); - - // simple render children! - for (var i = 0, j = this.children.length; i < j; ++i) { - this.children[i].renderWebGL(renderer); - } - - renderer.spriteBatch.stop(); - } - - if (this._filters) { - renderer.filterManager.popFilter(); - } - - if (this._mask) { - renderer.maskManager.popMask(this.mask, renderer); - } - - renderer.drawCount++; - - renderer.spriteBatch.start(); - } -}; - -/** - * Renders the object using the Canvas renderer - * - * @param renderer {CanvasRenderer} - * @private - */ -Graphics.prototype.renderCanvas = function (renderer) { - // if the sprite is not visible or the alpha is 0 then no need to render this element - if (!this.visible || this.alpha <= 0 || this.isMask === true) { - return; - } - - if (this._cacheAsBitmap) { - if (this.dirty || this.cachedSpriteDirty) { - this._generateCachedSprite(); - - // we will also need to update the texture - this.updateCachedSpriteTexture(); - - this.cachedSpriteDirty = false; - this.dirty = false; - } - - this._cachedSprite.alpha = this.alpha; - - Sprite.prototype.renderCanvas.call(this._cachedSprite, renderer); - - return; - } - else { - var context = renderer.context; - var transform = this.worldTransform; - - if (this.blendMode !== renderer.currentBlendMode) { - renderer.currentBlendMode = this.blendMode; - context.globalCompositeOperation = renderer.blendModes[renderer.currentBlendMode]; - } - - if (this._mask) { - renderer.maskManager.pushMask(this._mask, renderer); - } - - var resolution = renderer.resolution; - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - - CanvasGraphics.renderGraphics(this, context); - - for (var i = 0, j = this.children.length; i < j; ++i) { - this.children[i].renderCanvas(renderer); - } - - if (this._mask) { - renderer.maskManager.popMask(renderer); - } - } -}; - -/** - * Retrieves the bounds of the graphic shape as a rectangle object - * - * @return {Rectangle} the rectangular bounding area - */ -Graphics.prototype.getBounds = function (matrix) { - // return an empty object if the item is a mask! - if (this.isMask) { - return math.Rectangle.EMPTY; - } - - if (this.dirty) { - this.updateLocalBounds(); - - this.glDirty = true; - this.cachedSpriteDirty = true; - this.dirty = false; - } - - var bounds = this._localBounds; - - var w0 = bounds.x; - var w1 = bounds.width + bounds.x; - - var h0 = bounds.y; - var h1 = bounds.height + bounds.y; - - var worldTransform = matrix || this.worldTransform; - - var a = worldTransform.a; - var b = worldTransform.b; - var c = worldTransform.c; - var d = worldTransform.d; - var tx = worldTransform.tx; - var ty = worldTransform.ty; - - var x1 = a * w1 + c * h1 + tx; - var y1 = d * h1 + b * w1 + ty; - - var x2 = a * w0 + c * h1 + tx; - var y2 = d * h1 + b * w0 + ty; - - var x3 = a * w0 + c * h0 + tx; - var y3 = d * h0 + b * w0 + ty; - - var x4 = a * w1 + c * h0 + tx; - var y4 = d * h0 + b * w1 + ty; - - var maxX = x1; - var maxY = y1; - - var minX = x1; - var minY = y1; - - minX = x2 < minX ? x2 : minX; - minX = x3 < minX ? x3 : minX; - minX = x4 < minX ? x4 : minX; - - minY = y2 < minY ? y2 : minY; - minY = y3 < minY ? y3 : minY; - minY = y4 < minY ? y4 : minY; - - maxX = x2 > maxX ? x2 : maxX; - maxX = x3 > maxX ? x3 : maxX; - maxX = x4 > maxX ? x4 : maxX; - - maxY = y2 > maxY ? y2 : maxY; - maxY = y3 > maxY ? y3 : maxY; - maxY = y4 > maxY ? y4 : maxY; - - this._bounds.x = minX; - this._bounds.width = maxX - minX; - - this._bounds.y = minY; - this._bounds.height = maxY - minY; - - return this._bounds; -}; - -/** - * Update the bounds of the object - * - */ -Graphics.prototype.updateLocalBounds = function () { - var minX = Infinity; - var maxX = -Infinity; - - var minY = Infinity; - var maxY = -Infinity; - - if (this.graphicsData.length) { - var shape, points, x, y, w, h; - - for (var i = 0; i < this.graphicsData.length; i++) { - var data = this.graphicsData[i]; - var type = data.type; - var lineWidth = data.lineWidth; - shape = data.shape; - - if (type === CONST.SHAPES.RECT || type === CONST.SHAPES.RREC) { - x = shape.x - lineWidth/2; - y = shape.y - lineWidth/2; - w = shape.width + lineWidth; - h = shape.height + lineWidth; - - minX = x < minX ? x : minX; - maxX = x + w > maxX ? x + w : maxX; - - minY = y < minY ? y : minY; - maxY = y + h > maxY ? y + h : maxY; - } - else if (type === CONST.SHAPES.CIRC) { - x = shape.x; - y = shape.y; - w = shape.radius + lineWidth/2; - h = shape.radius + lineWidth/2; - - minX = x - w < minX ? x - w : minX; - maxX = x + w > maxX ? x + w : maxX; - - minY = y - h < minY ? y - h : minY; - maxY = y + h > maxY ? y + h : maxY; - } - else if (type === CONST.SHAPES.ELIP) { - x = shape.x; - y = shape.y; - w = shape.width + lineWidth/2; - h = shape.height + lineWidth/2; - - minX = x - w < minX ? x - w : minX; - maxX = x + w > maxX ? x + w : maxX; - - minY = y - h < minY ? y - h : minY; - maxY = y + h > maxY ? y + h : maxY; - } - else { - // POLY - points = shape.points; - - for (var j = 0; j < points.length; j += 2) { - x = points[j]; - y = points[j+1]; - - minX = x-lineWidth < minX ? x-lineWidth : minX; - maxX = x+lineWidth > maxX ? x+lineWidth : maxX; - - minY = y-lineWidth < minY ? y-lineWidth : minY; - maxY = y+lineWidth > maxY ? y+lineWidth : maxY; - } - } - } - } - else { - minX = 0; - maxX = 0; - minY = 0; - maxY = 0; - } - - var padding = this.boundsPadding; - - this._localBounds.x = minX - padding; - this._localBounds.width = (maxX - minX) + padding * 2; - - this._localBounds.y = minY - padding; - this._localBounds.height = (maxY - minY) + padding * 2; -}; - -/** - * Generates the cached sprite when the sprite has cacheAsBitmap = true - * - * @private - */ -Graphics.prototype._generateCachedSprite = function () { - var bounds = this.getLocalBounds(); - - if (!this._cachedSprite) { - var canvasBuffer = new CanvasBuffer(bounds.width, bounds.height); - var texture = Texture.fromCanvas(canvasBuffer.canvas); - - this._cachedSprite = new Sprite(texture); - this._cachedSprite.buffer = canvasBuffer; - - this._cachedSprite.worldTransform = this.worldTransform; - } - else { - this._cachedSprite.buffer.resize(bounds.width, bounds.height); - } - - // leverage the anchor to account for the offset of the element - this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); - this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); - - // this._cachedSprite.buffer.context.save(); - this._cachedSprite.buffer.context.translate(-bounds.x,-bounds.y); - - // make sure we set the alpha of the graphics to 1 for the render.. - this.worldAlpha = 1; - - // now render the graphic.. - CanvasGraphics.renderGraphics(this, this._cachedSprite.buffer.context); - - this._cachedSprite.alpha = this.alpha; -}; - -/** - * Updates texture size based on canvas size - * - * @private - */ -Graphics.prototype.updateCachedSpriteTexture = function () { - var cachedSprite = this._cachedSprite; - var texture = cachedSprite.texture; - var canvas = cachedSprite.buffer.canvas; - - texture.baseTexture.width = canvas.width; - texture.baseTexture.height = canvas.height; - texture.crop.width = texture.frame.width = canvas.width; - texture.crop.height = texture.frame.height = canvas.height; - - cachedSprite._width = canvas.width; - cachedSprite._height = canvas.height; - - // update the dirty base textures - texture.baseTexture.dirty(); -}; - -/** - * Destroys a previous cached sprite. - * - */ -Graphics.prototype.destroyCachedSprite = function () { - this._cachedSprite.texture.destroy(true); - - // let the gc collect the unused sprite - // TODO could be object pooled! - this._cachedSprite = null; -}; - -/** - * Draws the given shape to this Graphics object. Can be any of Circle, Rectangle, Ellipse, Line or Polygon. - * - * @param {Circle|Rectangle|Ellipse|Line|Polygon} shape The Shape object to draw. - * @return {GraphicsData} The generated GraphicsData object. - */ -Graphics.prototype.drawShape = function (shape) { - if (this.currentPath) { - // check current path! - if (this.currentPath.shape.points.length <= 2) { - this.graphicsData.pop(); - } - } - - this.currentPath = null; - - var data = new GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); - - this.graphicsData.push(data); - - if (data.type === CONST.SHAPES.POLY) { - data.shape.closed = this.filling; - this.currentPath = data; - } - - this.dirty = true; - - return data; -}; - -},{"../const":4,"../display/DisplayObjectContainer":6,"../display/Sprite":7,"../math":12,"../renderers/canvas/utils/CanvasBuffer":21,"../renderers/canvas/utils/CanvasGraphics":22,"../renderers/webgl/utils/WebGLGraphics":39,"../textures/Texture":44,"./GraphicsData":19}],19:[function(require,module,exports){ -/** - * A GraphicsData object. - * - * @class - * @namespace PIXI - */ -function GraphicsData(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) { - this.lineWidth = lineWidth; - this.lineColor = lineColor; - this.lineAlpha = lineAlpha; - this._lineTint = lineColor; - - this.fillColor = fillColor; - this.fillAlpha = fillAlpha; - this._fillTint = fillColor; - this.fill = fill; - - this.shape = shape; - this.type = shape.type; -} - -GraphicsData.prototype.constructor = GraphicsData; -module.exports = GraphicsData; - -/** - * Creates a new GraphicsData object with the same values as this one. - * - * @return {GraphicsData} - */ -GraphicsData.prototype.clone = function () { - return new GraphicsData( - this.lineWidth, - this.lineColor, - this.lineAlpha, - this.fillColor, - this.fillAlpha, - this.fill, - this.shape - ); -}; - -},{}],20:[function(require,module,exports){ -var CanvasMaskManager = require('./utils/CanvasMaskManager'), - utils = require('../../utils'), - CONST = require('../../const'); - -/** - * The CanvasRenderer draws the scene and all its content onto a 2d canvas. This renderer should be used for browsers that do not support webGL. - * Don't forget to add the CanvasRenderer.view to your DOM or you will not see anything :) - * - * @class - * @namespace PIXI - * @param [width=800] {number} the width of the canvas view - * @param [height=600] {number} the height of the canvas view - * @param [options] {object} The optional renderer parameters - * @param [options.view] {HTMLCanvasElement} the canvas to use as a view, optional - * @param [options.transparent=false] {boolean} If the render view is transparent, default false - * @param [options.autoResize=false] {boolean} If the render view is automatically resized, default false - * @param [options.resolution=1] {number} the resolution of the renderer retina would be 2 - * @param [options.clearBeforeRender=true] {boolean} This sets if the CanvasRenderer will clear the canvas or not before the new render pass. - */ -function CanvasRenderer(width, height, options) { - utils.sayHello('Canvas'); - - if (options) { - for (var i in CONST.defaultRenderOptions) { - if (typeof options[i] === 'undefined') { - options[i] = CONST.defaultRenderOptions[i]; - } - } - } - else { - options = CONST.defaultRenderOptions; - } - - /** - * The renderer type. - * - * @member {number} - */ - this.type = CONST.CANVAS_RENDERER; - - /** - * The resolution of the canvas. - * - * @member {number} - */ - this.resolution = options.resolution; - - /** - * This sets if the CanvasRenderer will clear the canvas or not before the new render pass. - * If the scene is NOT transparent Pixi will use a canvas sized fillRect operation every frame to set the canvas background color. - * If the scene is transparent Pixi will use clearRect to clear the canvas every frame. - * Disable this by setting this to false. For example if your game has a canvas filling background image you often don't need this set. - * - * @member {boolean} - * @default - */ - this.clearBeforeRender = options.clearBeforeRender; - - /** - * The background color as a number. - * - * @member {number} - * @private - */ - this._backgroundColor = 0x000000; - - /** - * The background color as a string. - * - * @member {string} - * @private - */ - this._backgroundColorString = '#000000'; - - this.backgroundColor = options.backgroundColor || this._backgroundColor; // run bg color setter - - /** - * Whether the render view is transparent - * - * @member {boolean} - */ - this.transparent = options.transparent; - - /** - * Whether the render view should be resized automatically - * - * @member {boolean} - */ - this.autoResize = options.autoResize || false; - - - /** - * The width of the canvas view - * - * @member {number} - * @default 800 - */ - this.width = width || 800; - - /** - * The height of the canvas view - * - * @member {number} - * @default 600 - */ - this.height = height || 600; - - this.width *= this.resolution; - this.height *= this.resolution; - - /** - * The canvas element that everything is drawn to. - * - * @member {HTMLCanvasElement} - */ - this.view = options.view || document.createElement('canvas'); - - /** - * The canvas 2d context that everything is drawn with - * @member {CanvasRenderingContext2D} - */ - this.context = this.view.getContext('2d', { alpha: this.transparent }); - - /** - * Boolean flag controlling canvas refresh. - * - * @member {boolean} - */ - this.refresh = true; - - this.view.width = this.width * this.resolution; - this.view.height = this.height * this.resolution; - - /** - * Internal var. - * - * @member {number} - */ - this.count = 0; - - /** - * Instance of a CanvasMaskManager, handles masking when using the canvas renderer - * @member {CanvasMaskManager} - */ - this.maskManager = new CanvasMaskManager(); - - /** - * If true Pixi will Math.floor() x/y values when rendering, stopping pixel interpolation. - * Handy for crisp pixel art and speed on legacy devices. - * - * @member {boolean} - */ - this.roundPixels = false; - - this.scaleMode = null; - - this.smoothProperty = null; - - if (this.context.imageSmoothingEnabled) { - this.smoothProperty = 'imageSmoothingEnabled'; - } - else if (this.context.webkitImageSmoothingEnabled) { - this.smoothProperty = 'webkitImageSmoothingEnabled'; - } - else if (this.context.mozImageSmoothingEnabled) { - this.smoothProperty = 'mozImageSmoothingEnabled'; - } - else if (this.context.oImageSmoothingEnabled) { - this.smoothProperty = 'oImageSmoothingEnabled'; - } - else if (this.context.msImageSmoothingEnabled) { - this.smoothProperty = 'msImageSmoothingEnabled'; - } - - this.currentBlendMode = CONST.blendModes.NORMAL; - - this.blendModes = null; - - this._mapBlendModes(); - - this.resize(width, height); -} - -// constructor -CanvasRenderer.prototype.constructor = CanvasRenderer; -module.exports = CanvasRenderer; - -Object.defineProperties(CanvasRenderer.prototype, { - /** - * The background color to fill if not transparent - * - * @member {number} - * @memberof CanvasRenderer# - */ - backgroundColor: { - get: function () { - return this._backgroundColor; - }, - set: function (val) { - this._backgroundColor = val; - this._backgroundColorString = utils.hex2string(val); - } - } -}); - -/** - * Renders the object to this canvas view - * - * @param object {DisplayObject} the object to be rendered - */ -CanvasRenderer.prototype.render = function (object) { - object.updateTransform(); - - this.context.setTransform(1,0,0,1,0,0); - - this.context.globalAlpha = 1; - - this.currentBlendMode = CONST.blendModes.NORMAL; - this.context.globalCompositeOperation = this.blendModes[CONST.blendModes.NORMAL]; - - if (navigator.isCocoonJS && this.view.screencanvas) { - this.context.fillStyle = 'black'; - this.context.clear(); - } - - if (this.clearBeforeRender) { - if (this.transparent) { - this.context.clearRect(0, 0, this.width, this.height); - } - else { - this.context.fillStyle = this._backgroundColorString; - this.context.fillRect(0, 0, this.width , this.height); - } - } - - this.renderDisplayObject(object); -}; - -/** - * Removes everything from the renderer and optionally removes the Canvas DOM element. - * - * @param [removeView=false] {boolean} Removes the Canvas element from the DOM. - */ -CanvasRenderer.prototype.destroy = function (removeView) { - if (removeView && this.view.parent) { - this.view.parent.removeChild(this.view); - } - - this.view = null; - this.context = null; - this.maskManager = null; -}; - -/** - * Resizes the canvas view to the specified width and height - * - * @param width {number} the new width of the canvas view - * @param height {number} the new height of the canvas view - */ -CanvasRenderer.prototype.resize = function (width, height) { - this.width = width * this.resolution; - this.height = height * this.resolution; - - this.view.width = this.width; - this.view.height = this.height; - - if (this.autoResize) { - this.view.style.width = this.width / this.resolution + 'px'; - this.view.style.height = this.height / this.resolution + 'px'; - } -}; - -/** - * Renders a display object - * - * @param displayObject {DisplayObject} The displayObject to render - * @private - */ -CanvasRenderer.prototype.renderDisplayObject = function (displayObject) { - displayObject.renderCanvas(this); -}; - -/** - * Maps Pixi blend modes to canvas blend modes. - * - * @private - */ -CanvasRenderer.prototype._mapBlendModes = function () { - if (!this.blendModes) { - this.blendModes = {}; - - if (utils.canUseNewCanvasBlendModes()) { - this.blendModes[CONST.blendModes.NORMAL] = 'source-over'; - this.blendModes[CONST.blendModes.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.blendModes.MULTIPLY] = 'multiply'; - this.blendModes[CONST.blendModes.SCREEN] = 'screen'; - this.blendModes[CONST.blendModes.OVERLAY] = 'overlay'; - this.blendModes[CONST.blendModes.DARKEN] = 'darken'; - this.blendModes[CONST.blendModes.LIGHTEN] = 'lighten'; - this.blendModes[CONST.blendModes.COLOR_DODGE] = 'color-dodge'; - this.blendModes[CONST.blendModes.COLOR_BURN] = 'color-burn'; - this.blendModes[CONST.blendModes.HARD_LIGHT] = 'hard-light'; - this.blendModes[CONST.blendModes.SOFT_LIGHT] = 'soft-light'; - this.blendModes[CONST.blendModes.DIFFERENCE] = 'difference'; - this.blendModes[CONST.blendModes.EXCLUSION] = 'exclusion'; - this.blendModes[CONST.blendModes.HUE] = 'hue'; - this.blendModes[CONST.blendModes.SATURATION] = 'saturation'; - this.blendModes[CONST.blendModes.COLOR] = 'color'; - this.blendModes[CONST.blendModes.LUMINOSITY] = 'luminosity'; - } - else { - // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' - this.blendModes[CONST.blendModes.NORMAL] = 'source-over'; - this.blendModes[CONST.blendModes.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.blendModes.MULTIPLY] = 'source-over'; - this.blendModes[CONST.blendModes.SCREEN] = 'source-over'; - this.blendModes[CONST.blendModes.OVERLAY] = 'source-over'; - this.blendModes[CONST.blendModes.DARKEN] = 'source-over'; - this.blendModes[CONST.blendModes.LIGHTEN] = 'source-over'; - this.blendModes[CONST.blendModes.COLOR_DODGE] = 'source-over'; - this.blendModes[CONST.blendModes.COLOR_BURN] = 'source-over'; - this.blendModes[CONST.blendModes.HARD_LIGHT] = 'source-over'; - this.blendModes[CONST.blendModes.SOFT_LIGHT] = 'source-over'; - this.blendModes[CONST.blendModes.DIFFERENCE] = 'source-over'; - this.blendModes[CONST.blendModes.EXCLUSION] = 'source-over'; - this.blendModes[CONST.blendModes.HUE] = 'source-over'; - this.blendModes[CONST.blendModes.SATURATION] = 'source-over'; - this.blendModes[CONST.blendModes.COLOR] = 'source-over'; - this.blendModes[CONST.blendModes.LUMINOSITY] = 'source-over'; - } - } -}; - -},{"../../const":4,"../../utils":50,"./utils/CanvasMaskManager":23}],21:[function(require,module,exports){ -/** - * Creates a Canvas element of the given size. - * - * @class - * @namespace PIXI - * @param width {number} the width for the newly created canvas - * @param height {number} the height for the newly created canvas - */ -function CanvasBuffer(width, height) { - /** - * The Canvas object that belongs to this CanvasBuffer. - * - * @member {HTMLCanvasElement} - */ - this.canvas = document.createElement('canvas'); - - /** - * A CanvasRenderingContext2D object representing a two-dimensional rendering context. - * - * @member {CanvasRenderingContext2D} - */ - this.context = this.canvas.getContext('2d'); - - this.canvas.width = width; - this.canvas.height = height; -} - -CanvasBuffer.prototype.constructor = CanvasBuffer; -module.exports = CanvasBuffer; - -Object.defineProperties(CanvasBuffer.prototype, { - /** - * The width of the canvas buffer in pixels. - * - * @member {number} - * @memberof CanvasBuffer# - */ - width: { - get: function () { - return this.canvas.width; - }, - set: function (val) { - this.canvas.width = val; - } - }, - /** - * The height of the canvas buffer in pixels. - * - * @member {number} - * @memberof CanvasBuffer# - */ - height: { - get: function () { - return this.canvas.height; - }, - set: function (val) { - this.canvas.height = val; - } - } -}); - -/** - * Clears the canvas that was created by the CanvasBuffer class. - * - * @private - */ -CanvasBuffer.prototype.clear = function () { - this.context.setTransform(1, 0, 0, 1, 0, 0); - this.context.clearRect(0,0, this.canvas.width, this.canvas.height); -}; - -/** - * Resizes the canvas to the specified width and height. - * - * @param width {number} the new width of the canvas - * @param height {number} the new height of the canvas - */ -CanvasBuffer.prototype.resize = function (width, height) { - this.canvas.width = width; - this.canvas.height = height; -}; - -},{}],22:[function(require,module,exports){ -var CONST = require('../../../const'); - -/** - * A set of functions used by the canvas renderer to draw the primitive graphics data. - * - * @namespace PIXI - */ -var CanvasGraphics = module.exports = {}; - -/* - * Renders a Graphics object to a canvas. - * - * @param graphics {Graphics} the actual graphics object to render - * @param context {CanvasRenderingContext2D} the 2d drawing method of the canvas - */ -CanvasGraphics.renderGraphics = function (graphics, context) { - var worldAlpha = graphics.worldAlpha; - - if (graphics.dirty) { - this.updateGraphicsTint(graphics); - graphics.dirty = false; - } - - for (var i = 0; i < graphics.graphicsData.length; i++) { - var data = graphics.graphicsData[i]; - var shape = data.shape; - - var fillColor = data._fillTint; - var lineColor = data._lineTint; - - context.lineWidth = data.lineWidth; - - if (data.type === CONST.SHAPES.POLY) { - context.beginPath(); - - var points = shape.points; - - context.moveTo(points[0], points[1]); - - for (var j=1; j < points.length/2; j++) { - context.lineTo(points[j * 2], points[j * 2 + 1]); - } - - if (shape.closed) { - context.lineTo(points[0], points[1]); - } - - // if the first and last point are the same close the path - much neater :) - if (points[0] === points[points.length-2] && points[1] === points[points.length-1]) { - context.closePath(); - } - - if (data.fill) { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = '#' + ('00000' + ( fillColor | 0).toString(16)).substr(-6); - context.fill(); - } - if (data.lineWidth) { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeStyle = '#' + ('00000' + ( lineColor | 0).toString(16)).substr(-6); - context.stroke(); - } - } - else if (data.type === CONST.SHAPES.RECT) { - - if (data.fillColor || data.fillColor === 0) { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = '#' + ('00000' + ( fillColor | 0).toString(16)).substr(-6); - context.fillRect(shape.x, shape.y, shape.width, shape.height); - - } - if (data.lineWidth) { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeStyle = '#' + ('00000' + ( lineColor | 0).toString(16)).substr(-6); - context.strokeRect(shape.x, shape.y, shape.width, shape.height); - } - } - else if (data.type === CONST.SHAPES.CIRC) { - // TODO - need to be Undefined! - context.beginPath(); - context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); - context.closePath(); - - if (data.fill) { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = '#' + ('00000' + ( fillColor | 0).toString(16)).substr(-6); - context.fill(); - } - if (data.lineWidth) { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeStyle = '#' + ('00000' + ( lineColor | 0).toString(16)).substr(-6); - context.stroke(); - } - } - else if (data.type === CONST.SHAPES.ELIP) { - // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - - var w = shape.width * 2; - var h = shape.height * 2; - - var x = shape.x - w/2; - var y = shape.y - h/2; - - context.beginPath(); - - var kappa = 0.5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - context.moveTo(x, ym); - context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - - context.closePath(); - - if (data.fill) { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = '#' + ('00000' + ( fillColor | 0).toString(16)).substr(-6); - context.fill(); - } - if (data.lineWidth) { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeStyle = '#' + ('00000' + ( lineColor | 0).toString(16)).substr(-6); - context.stroke(); - } - } - else if (data.type === CONST.SHAPES.RREC) { - var rx = shape.x; - var ry = shape.y; - var width = shape.width; - var height = shape.height; - var radius = shape.radius; - - var maxRadius = Math.min(width, height) / 2 | 0; - radius = radius > maxRadius ? maxRadius : radius; - - context.beginPath(); - context.moveTo(rx, ry + radius); - context.lineTo(rx, ry + height - radius); - context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height); - context.lineTo(rx + width - radius, ry + height); - context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius); - context.lineTo(rx + width, ry + radius); - context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry); - context.lineTo(rx + radius, ry); - context.quadraticCurveTo(rx, ry, rx, ry + radius); - context.closePath(); - - if (data.fillColor || data.fillColor === 0) { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = '#' + ('00000' + ( fillColor | 0).toString(16)).substr(-6); - context.fill(); - - } - if (data.lineWidth) { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeStyle = '#' + ('00000' + ( lineColor | 0).toString(16)).substr(-6); - context.stroke(); - } - } - } -}; - -/* - * Renders a graphics mask - * - * @private - * @param graphics {Graphics} the graphics which will be used as a mask - * @param context {CanvasRenderingContext2D} the context 2d method of the canvas - */ -CanvasGraphics.renderGraphicsMask = function (graphics, context) { - var len = graphics.graphicsData.length; - - if (len === 0) { - return; - } - - context.beginPath(); - - for (var i = 0; i < len; i++) { - var data = graphics.graphicsData[i]; - var shape = data.shape; - - if (data.type === CONST.SHAPES.POLY) { - - var points = shape.points; - - context.moveTo(points[0], points[1]); - - for (var j=1; j < points.length/2; j++) { - context.lineTo(points[j * 2], points[j * 2 + 1]); - } - - // if the first and last point are the same close the path - much neater :) - if (points[0] === points[points.length-2] && points[1] === points[points.length-1]) { - context.closePath(); - } - - } - else if (data.type === CONST.SHAPES.RECT) { - context.rect(shape.x, shape.y, shape.width, shape.height); - context.closePath(); - } - else if (data.type === CONST.SHAPES.CIRC) { - // TODO - need to be Undefined! - context.arc(shape.x, shape.y, shape.radius, 0, 2 * Math.PI); - context.closePath(); - } - else if (data.type === CONST.SHAPES.ELIP) { - - // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - - var w = shape.width * 2; - var h = shape.height * 2; - - var x = shape.x - w/2; - var y = shape.y - h/2; - - var kappa = 0.5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - context.moveTo(x, ym); - context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - context.closePath(); - } - else if (data.type === CONST.SHAPES.RREC) { - - var rx = shape.x; - var ry = shape.y; - var width = shape.width; - var height = shape.height; - var radius = shape.radius; - - var maxRadius = Math.min(width, height) / 2 | 0; - radius = radius > maxRadius ? maxRadius : radius; - - context.moveTo(rx, ry + radius); - context.lineTo(rx, ry + height - radius); - context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height); - context.lineTo(rx + width - radius, ry + height); - context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius); - context.lineTo(rx + width, ry + radius); - context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry); - context.lineTo(rx + radius, ry); - context.quadraticCurveTo(rx, ry, rx, ry + radius); - context.closePath(); - } - } -}; - -CanvasGraphics.updateGraphicsTint = function (graphics) { - if (graphics.tint === 0xFFFFFF) { - return; - } - - var tintR = (graphics.tint >> 16 & 0xFF) / 255; - var tintG = (graphics.tint >> 8 & 0xFF) / 255; - var tintB = (graphics.tint & 0xFF)/ 255; - - for (var i = 0; i < graphics.graphicsData.length; i++) { - var data = graphics.graphicsData[i]; - - var fillColor = data.fillColor | 0; - var lineColor = data.lineColor | 0; - - /* - var colorR = (fillColor >> 16 & 0xFF) / 255; - var colorG = (fillColor >> 8 & 0xFF) / 255; - var colorB = (fillColor & 0xFF) / 255; - - colorR *= tintR; - colorG *= tintG; - colorB *= tintB; - - fillColor = ((colorR*255 << 16) + (colorG*255 << 8) + colorB*255); - - colorR = (lineColor >> 16 & 0xFF) / 255; - colorG = (lineColor >> 8 & 0xFF) / 255; - colorB = (lineColor & 0xFF) / 255; - - colorR *= tintR; - colorG *= tintG; - colorB *= tintB; - - lineColor = ((colorR*255 << 16) + (colorG*255 << 8) + colorB*255); - */ - - // super inline cos im an optimization NAZI :) - data._fillTint = (((fillColor >> 16 & 0xFF) / 255 * tintR*255 << 16) + ((fillColor >> 8 & 0xFF) / 255 * tintG*255 << 8) + (fillColor & 0xFF) / 255 * tintB*255); - data._lineTint = (((lineColor >> 16 & 0xFF) / 255 * tintR*255 << 16) + ((lineColor >> 8 & 0xFF) / 255 * tintG*255 << 8) + (lineColor & 0xFF) / 255 * tintB*255); - - } -}; - - -},{"../../../const":4}],23:[function(require,module,exports){ -var CanvasGraphics = require('./CanvasGraphics'); - -/** - * A set of functions used to handle masking. - * - * @class - * @namespace PIXI - */ -function CanvasMaskManager() {} - -CanvasMaskManager.prototype.constructor = CanvasMaskManager; -module.exports = CanvasMaskManager; - -/** - * This method adds it to the current stack of masks. - * - * @param maskData {object} the maskData that will be pushed - * @param renderer {WebGLRenderer|CanvasRenderer} The renderer context to use. - */ -CanvasMaskManager.prototype.pushMask = function (maskData, renderer) { - renderer.context.save(); - - var cacheAlpha = maskData.alpha; - var transform = maskData.worldTransform; - var resolution = renderer.resolution; - - renderer.context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - - CanvasGraphics.renderGraphicsMask(maskData, renderer.context); - - renderer.context.clip(); - - maskData.worldAlpha = cacheAlpha; -}; - -/** - * Restores the current drawing context to the state it was before the mask was applied. - * - * @param renderer {WebGLRenderer|CanvasRenderer} The renderer context to use. - */ -CanvasMaskManager.prototype.popMask = function (renderer) { - renderer.context.restore(); -}; - -},{"./CanvasGraphics":22}],24:[function(require,module,exports){ -var utils = require('../../../utils'); - -/** - * Utility methods for Sprite/Texture tinting. - * - * @namespace PIXI - */ -var CanvasTinter = module.exports = {}; - -/** - * Basically this method just needs a sprite and a color and tints the sprite with the given color. - * - * @param sprite {Sprite} the sprite to tint - * @param color {number} the color to use to tint the sprite with - * @return {HTMLCanvasElement} The tinted canvas - */ -CanvasTinter.getTintedTexture = function (sprite, color) { - var texture = sprite.texture; - - color = CanvasTinter.roundColor(color); - - var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - texture.tintCache = texture.tintCache || {}; - - if (texture.tintCache[stringColor]) { - return texture.tintCache[stringColor]; - } - - // clone texture.. - var canvas = CanvasTinter.canvas || document.createElement('canvas'); - - //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); - CanvasTinter.tintMethod(texture, color, canvas); - - if (CanvasTinter.convertTintToImage) { - // is this better? - var tintImage = new Image(); - tintImage.src = canvas.toDataURL(); - - texture.tintCache[stringColor] = tintImage; - } - else { - texture.tintCache[stringColor] = canvas; - // if we are not converting the texture to an image then we need to lose the reference to the canvas - CanvasTinter.canvas = null; - } - - return canvas; -}; - -/** - * Tint a texture using the 'multiply' operation. - * - * @param texture {Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithMultiply = function (texture, color, canvas) { - var context = canvas.getContext( '2d' ); - - var crop = texture.crop; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'multiply'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - context.globalCompositeOperation = 'destination-atop'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); -}; - -/** - * Tint a texture using the 'overlay' operation. - * - * @param texture {Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithOverlay = function (texture, color, canvas) { - var context = canvas.getContext( '2d' ); - - var crop = texture.crop; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'destination-atop'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - // context.globalCompositeOperation = 'copy'; -}; - -/** - * Tint a texture pixel per pixel. - * - * @param texture {Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithPerPixel = function (texture, color, canvas) { - var context = canvas.getContext( '2d' ); - - var crop = texture.crop; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - var rgbValues = utils.hex2rgb(color); - var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; - - var pixelData = context.getImageData(0, 0, crop.width, crop.height); - - var pixels = pixelData.data; - - for (var i = 0; i < pixels.length; i += 4) { - pixels[i+0] *= r; - pixels[i+1] *= g; - pixels[i+2] *= b; - } - - context.putImageData(pixelData, 0, 0); -}; - -/** - * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. - * - * @param color {number} the color to round, should be a hex color - */ -CanvasTinter.roundColor = function (color) { - var step = CanvasTinter.cacheStepsPerColorChannel; - - var rgbValues = utils.hex2rgb(color); - - rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); - rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); - rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); - - return utils.rgb2hex(rgbValues); -}; - -/** - * Number of steps which will be used as a cap when rounding colors. - * - * @member - */ -CanvasTinter.cacheStepsPerColorChannel = 8; - -/** - * Tint cache boolean flag. - * - * @member - */ -CanvasTinter.convertTintToImage = false; - -/** - * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. - * - * @member - */ -CanvasTinter.canUseMultiply = utils.canUseNewCanvasBlendModes(); - -/** - * The tinting method that will be used. - * - */ -CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; - -},{"../../../utils":50}],25:[function(require,module,exports){ -var WebGLSpriteBatch = require('./utils/WebGLSpriteBatch'), - WebGLFastSpriteBatch = require('./utils/WebGLFastSpriteBatch'), - WebGLShaderManager = require('./managers/WebGLShaderManager'), - WebGLMaskManager = require('./managers/WebGLMaskManager'), - WebGLFilterManager = require('./managers/WebGLFilterManager'), - WebGLStencilManager = require('./managers/WebGLStencilManager'), - WebGLBlendModeManager = require('./managers/WebGLBlendModeManager'), - math = require('../../math'), - utils = require('../../utils'), - CONST = require('../../const'); - -/** - * The WebGLRenderer draws the scene and all its content onto a webGL enabled canvas. This renderer - * should be used for browsers that support webGL. This Render works by automatically managing webGLBatchs. - * So no need for Sprite Batches or Sprite Clouds. - * Don't forget to add the view to your DOM or you will not see anything :) - * - * @class - * @namespace PIXI - * @param [width=0] {number} the width of the canvas view - * @param [height=0] {number} the height of the canvas view - * @param [options] {object} The optional renderer parameters - * @param [options.view] {HTMLCanvasElement} the canvas to use as a view, optional - * @param [options.transparent=false] {boolean} If the render view is transparent, default false - * @param [options.autoResize=false] {boolean} If the render view is automatically resized, default false - * @param [options.antialias=false] {boolean} sets antialias (only applicable in chrome at the moment) - * @param [options.preserveDrawingBuffer=false] {boolean} enables drawing buffer preservation, enable this if you need to call toDataUrl on the webgl context - * @param [options.resolution=1] {number} the resolution of the renderer retina would be 2 - */ -function WebGLRenderer(width, height, options) { - utils.sayHello('webGL'); - - if (options) { - for (var i in CONST.defaultRenderOptions) { - if (typeof options[i] === 'undefined') { - options[i] = CONST.defaultRenderOptions[i]; - } - } - } - else { - options = CONST.defaultRenderOptions; - } - - this.uuid = utils.uuid(); - - /** - * @member {number} - */ - this.type = CONST.WEBGL_RENDERER; - - /** - * The resolution of the renderer - * - * @member {number} - * @default 1 - */ - this.resolution = options.resolution; - - // do a catch.. only 1 webGL renderer.. - - /** - * Whether the render view is transparent - * - * @member {boolean} - */ - this.transparent = options.transparent; - - /** - * The background color as a number. - * - * @member {number} - * @private - */ - this._backgroundColor = 0x000000; - - /** - * The background color as an [R, G, B] array. - * - * @member {number[]} - * @private - */ - this._backgroundColorRgb = [0, 0, 0]; - - this.backgroundColor = options.backgroundColor || this._backgroundColor; // run bg color setter - - /** - * Whether the render view should be resized automatically - * - * @member {boolean} - */ - this.autoResize = options.autoResize || false; - - /** - * The value of the preserveDrawingBuffer flag affects whether or not the contents of the stencil buffer is retained after rendering. - * - * @member {boolean} - */ - this.preserveDrawingBuffer = options.preserveDrawingBuffer; - - /** - * This sets if the WebGLRenderer will clear the context texture or not before the new render pass. If true: - * If the renderer is NOT transparent, Pixi will clear to alpha (0, 0, 0, 0). - * If the renderer is transparent, Pixi will clear to the target Stage's background color. - * Disable this by setting this to false. For example: if your game has a canvas filling background image, you often don't need this set. - * - * @member {boolean} - * @default - */ - this.clearBeforeRender = options.clearBeforeRender; - - /** - * The width of the canvas view - * - * @member {number} - * @default 800 - */ - this.width = width || 800; - - /** - * The height of the canvas view - * - * @member {number} - * @default 600 - */ - this.height = height || 600; - - /** - * The canvas element that everything is drawn to - * - * @member {HTMLCanvasElement} - */ - this.view = options.view || document.createElement( 'canvas' ); - - // deal with losing context.. - - /** - * @member {Function} - */ - this.contextLostBound = this.handleContextLost.bind(this); - - /** - * @member {Function} - */ - this.contextRestoredBound = this.handleContextRestored.bind(this); - - this.view.addEventListener('webglcontextlost', this.contextLostBound, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - - /** - * @member {object} - * @private - */ - this._contextOptions = { - alpha: this.transparent, - antialias: options.antialias, // SPEED UP?? - premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', - stencil:true, - preserveDrawingBuffer: options.preserveDrawingBuffer - }; - - /** - * @member {Point} - */ - this.projection = new math.Point(); - - /** - * @member {Point} - */ - this.offset = new math.Point(0, 0); - - /** - * Counter for the number of draws made each frame - * - * @member {number} - */ - this.drawCount = 0; - - // time to create the render managers! each one focuses on managing a state in webGL - - /** - * Deals with managing the shader programs and their attribs - * @member {WebGLShaderManager} - */ - this.shaderManager = new WebGLShaderManager(this); - - /** - * Manages the rendering of sprites - * @member {WebGLSpriteBatch} - */ - this.spriteBatch = new WebGLSpriteBatch(this); - - /** - * Manages the rendering of sprites - * @member {WebGLFastSpriteBatch} - */ - this.fastSpriteBatch = new WebGLFastSpriteBatch(this); - - /** - * Manages the masks using the stencil buffer - * @member {WebGLMaskManager} - */ - this.maskManager = new WebGLMaskManager(this); - - /** - * Manages the filters - * @member {WebGLFilterManager} - */ - this.filterManager = new WebGLFilterManager(this); - - /** - * Manages the stencil buffer - * @member {WebGLStencilManager} - */ - this.stencilManager = new WebGLStencilManager(this); - - /** - * Manages the blendModes - * @member {WebGLBlendModeManager} - */ - this.blendModeManager = new WebGLBlendModeManager(this); - - this.blendModes = null; - - this._boundUpdateTexture = this.updateTexture.bind(this); - this._boundDestroyTexture = this.destroyTexture.bind(this); - - // time init the context.. - this._initContext(); - - // map some webGL blend modes.. - this._mapBlendModes(); -} - -// constructor -WebGLRenderer.prototype.constructor = WebGLRenderer; -module.exports = WebGLRenderer; - -utils.eventTarget.mixin(WebGLRenderer.prototype); - -Object.defineProperties(WebGLRenderer.prototype, { - /** - * The background color to fill if not transparent - * - * @member {number} - * @memberof WebGLRenderer# - */ - backgroundColor: { - get: function () { - return this._backgroundColor; - }, - set: function (val) { - this._backgroundColor = val; - utils.hex2rgb(val, this._backgroundColorRgb); - } - } -}); - -/** - * - * @private - */ -WebGLRenderer.prototype._initContext = function () { - var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); - this.gl = gl; - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer'); - } - - this.glContextId = WebGLRenderer.glContextId++; - gl.id = this.glContextId; - gl.renderer = this; - - // set up the default pixi settings.. - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); - - this.emit('context', gl); - - // now resize and we are good to go! - this.resize(this.width, this.height); -}; - -/** - * Renders the object to its webGL view - * - * @param object {DisplayObject} the object to be rendered - */ -WebGLRenderer.prototype.render = function (object) { - // no point rendering if our context has been blown up! - if (this.gl.isContextLost()) { - return; - } - - // update the scene graph - object.updateTransform(); - - var gl = this.gl; - - // -- Does this need to be set every frame? -- // - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if (this.clearBeforeRender) { - if (this.transparent) { - gl.clearColor(0, 0, 0, 0); - } - else { - gl.clearColor(this._backgroundColorRgb[0], this._backgroundColorRgb[1], this._backgroundColorRgb[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - } - - this.renderDisplayObject(object, this.projection); -}; - -/** - * Renders a Display Object. - * - * @param displayObject {DisplayObject} The DisplayObject to render - * @param projection {Point} The projection - * @param buffer {Array} a standard WebGL buffer - */ -WebGLRenderer.prototype.renderDisplayObject = function (displayObject, projection, buffer) { - this.blendModeManager.setBlendMode(CONST.blendModes.NORMAL); - - // reset the render session data.. - this.drawCount = 0; - - // make sure to flip the Y if using a render texture.. - this.flipY = buffer ? -1 : 1; - - // set the default projection - this.projection = projection; - - //set the default offset - this.offset = this.offset; - - // start the sprite batch - this.spriteBatch.begin(); - - // start the filter manager - this.filterManager.begin(buffer); - - // render the scene! - displayObject.renderWebGL(this); - - // finish the sprite batch - this.spriteBatch.end(); -}; - -/** - * Resizes the webGL view to the specified width and height. - * - * @param width {number} the new width of the webGL view - * @param height {number} the new height of the webGL view - */ -WebGLRenderer.prototype.resize = function (width, height) { - this.width = width * this.resolution; - this.height = height * this.resolution; - - this.view.width = this.width; - this.view.height = this.height; - - if (this.autoResize) { - this.view.style.width = this.width / this.resolution + 'px'; - this.view.style.height = this.height / this.resolution + 'px'; - } - - this.gl.viewport(0, 0, this.width, this.height); - - this.projection.x = this.width / 2 / this.resolution; - this.projection.y = -this.height / 2 / this.resolution; -}; - -/** - * Updates and/or Creates a WebGL texture for the renderer's context. - * - * @param texture {BaseTexture|Texture} the texture to update - */ -WebGLRenderer.prototype.updateTexture = function (texture) { - texture = texture.baseTexture || texture; - - if (!texture.hasLoaded) { - return; - } - - var gl = this.gl; - - if (!texture._glTextures[gl.id]) { - texture._glTextures[gl.id] = gl.createTexture(); - texture.on('update', this._boundUpdateTexture); - texture.on('dispose', this._boundDestroyTexture); - } - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - - if (texture.mipmap && utils.isPowerOfTwo(texture.width, texture.height)) { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR_MIPMAP_LINEAR : gl.NEAREST_MIPMAP_NEAREST); - gl.generateMipmap(gl.TEXTURE_2D); - } - else { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - } - - if (!texture._powerOf2) { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - return texture._glTextures[gl.id]; -}; - -WebGLRenderer.prototype.destroyTexture = function (texture) { - texture = texture.baseTexture || texture; - - if (!texture.hasLoaded) { - return; - } - - if (texture._glTextures[this.gl.id]) { - this.gl.deleteTexture(texture._glTextures[this.gl.id]); - } -}; - -/** - * Handles a lost webgl context - * - * @param event {Event} - * @private - */ -WebGLRenderer.prototype.handleContextLost = function (event) { - event.preventDefault(); -}; - -/** - * Handles a restored webgl context - * - * @param event {Event} - * @private - */ -WebGLRenderer.prototype.handleContextRestored = function () { - this._initContext(); - - // empty all the ol gl textures as they are useless now - for (var key in utils.TextureCache) { - var texture = utils.TextureCache[key].baseTexture; - texture._glTextures = []; - } -}; - -/** - * Removes everything from the renderer (event listeners, spritebatch, etc...) - * - * @param [removeView=false] {boolean} Removes the Canvas element from the DOM. - */ -WebGLRenderer.prototype.destroy = function (removeView) { - if (removeView && this.view.parent) { - this.view.parent.removeChild(this.view); - } - - // remove listeners - this.view.removeEventListener('webglcontextlost', this.contextLostBound); - this.view.removeEventListener('webglcontextrestored', this.contextRestoredBound); - - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager.destroy(); - this.spriteBatch.destroy(); - this.maskManager.destroy(); - this.filterManager.destroy(); - - - // this.uuid = utils.uuid(); - // this.type = CONST.WEBGL_RENDERER; - - // this.resolution = options.resolution; - // this.transparent = options.transparent; - - this._backgroundColor = 0x000000; - this._backgroundColorRgb = null; - - // this.backgroundColor = null; - // this.autoResize = options.autoResize || false; - // this.preserveDrawingBuffer = options.preserveDrawingBuffer; - // this.clearBeforeRender = options.clearBeforeRender; - // this.width = width || 800; - // this.height = height || 600; - - this.view = null; - - this.contextLostBound = null; - this.contextRestoredBound = null; - - this._contextOptions = null; - - this.projection = null; - this.offset = null; - this.drawCount = 0; - - this.shaderManager = null; - this.spriteBatch = null; - this.maskManager = null; - this.filterManager = null; - this.stencilManager = null; - this.blendModeManager = null; - - this.blendModes = null; - - this.gl = null; - this.blendModes = null; -}; - -/** - * Maps Pixi blend modes to WebGL blend modes. - * - * @private - */ -WebGLRenderer.prototype._mapBlendModes = function () { - var gl = this.gl; - - if (!this.blendModes) { - this.blendModes = {}; - - this.blendModes[CONST.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - this.blendModes[CONST.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - this.blendModes[CONST.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } -}; - -WebGLRenderer.glContextId = 0; - -},{"../../const":4,"../../math":12,"../../utils":50,"./managers/WebGLBlendModeManager":26,"./managers/WebGLFilterManager":27,"./managers/WebGLMaskManager":29,"./managers/WebGLShaderManager":30,"./managers/WebGLStencilManager":31,"./utils/WebGLFastSpriteBatch":38,"./utils/WebGLSpriteBatch":41}],26:[function(require,module,exports){ -var WebGLManager = require('./WebGLManager'); - -/** - * @class - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this manager works for. - */ -function WebGLBlendModeManager(renderer) { - WebGLManager.call(this, renderer); - - /** - * @member {number} - */ - this.currentBlendMode = 99999; -} - -WebGLBlendModeManager.prototype = Object.create(WebGLManager.prototype); -WebGLBlendModeManager.prototype.constructor = WebGLBlendModeManager; -module.exports = WebGLBlendModeManager; - -/** - * Sets-up the given blendMode from WebGL's point of view. - * - * @param blendMode {number} the blendMode, should be a Pixi const, such as BlendModes.ADD - */ -WebGLBlendModeManager.prototype.setBlendMode = function (blendMode) { - if (this.currentBlendMode === blendMode) { - return false; - } - - this.currentBlendMode = blendMode; - - var mode = this.renderer.blendModes[this.currentBlendMode]; - this.renderer.gl.blendFunc(mode[0], mode[1]); - - return true; -}; - -},{"./WebGLManager":28}],27:[function(require,module,exports){ -var WebGLManager = require('./WebGLManager'), - FilterTexture = require('../utils/FilterTexture'), - Shader = require('../shaders/Shader'); - -/** - * @class - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this manager works for. - */ -function WebGLFilterManager(renderer) { - WebGLManager.call(this, renderer); - - /** - * @member {any[]} - */ - this.filterStack = []; - - /** - * @member {any[]]} - */ - this.texturePool = []; - - /** - * @member {number} - */ - this.offsetX = 0; - - /** - * @member {number} - */ - this.offsetY = 0; - - // listen for context and update necessary buffers - var self = this; - this.renderer.on('context', function () { - self.texturePool.length = 0; - self.initShaderBuffers(); - }); -} - -WebGLFilterManager.prototype = Object.create(WebGLManager.prototype); -WebGLFilterManager.prototype.constructor = WebGLFilterManager; -module.exports = WebGLFilterManager; - -/** - * @param renderer {WebGLRenderer} - * @param buffer {ArrayBuffer} - */ -WebGLFilterManager.prototype.begin = function (buffer) { - this.defaultShader = this.renderer.shaderManager.defaultShader; - - this.width = this.renderer.projection.x * 2; - this.height = -this.renderer.projection.y * 2; - - this.buffer = buffer; -}; - -/** - * Applies the filter and adds it to the current filter stack. - * - * @param filterBlock {object} the filter that will be pushed to the current filter stack - */ -WebGLFilterManager.prototype.pushFilter = function (filterBlock) { - var gl = this.renderer.gl; - - var projection = this.renderer.projection; - var offset = this.renderer.offset; - - filterBlock._filterArea = filterBlock.target.filterArea || filterBlock.target.getBounds(); - - // filter program - // OPTIMISATION - the first filter is free if its a simple color change? - this.filterStack.push(filterBlock); - - var filter = filterBlock.filterPasses[0]; - - this.offsetX += filterBlock._filterArea.x; - this.offsetY += filterBlock._filterArea.y; - - var texture = this.texturePool.pop(); - if (!texture) { - texture = new FilterTexture(this.renderer.gl, this.width, this.height); - } - else { - texture.resize(this.width, this.height); - } - - gl.bindTexture(gl.TEXTURE_2D, texture.texture); - - var filterArea = filterBlock._filterArea;// filterBlock.target.getBounds();///filterBlock.target.filterArea; - - var padding = filter.padding; - filterArea.x -= padding; - filterArea.y -= padding; - filterArea.width += padding * 2; - filterArea.height += padding * 2; - - var localX = filterArea.x, - localY = filterArea.y; - - if (filterArea.x < 0) { - filterArea.width += filterArea.x; - filterArea.x = 0; - } - - if (filterArea.y < 0) { - filterArea.height += filterArea.y; - filterArea.y = 0; - } - - if (localX + filterArea.width > this.width) { - filterArea.width = this.width - localX; - } - - if (localY + filterArea.height > this.height) { - filterArea.height = this.height - localY; - } - - if (filterArea.width < 0) { - filterArea.width = 0; - } - - if (filterArea.height < 0) { - filterArea.height = 0; - } - - //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, filterArea.width, filterArea.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - gl.bindFramebuffer(gl.FRAMEBUFFER, texture.frameBuffer); - - // set view port - gl.viewport(0, 0, filterArea.width, filterArea.height); - - projection.x = filterArea.width/2; - projection.y = -filterArea.height/2; - - offset.x = -filterArea.x; - offset.y = -filterArea.y; - - // update projection - // now restore the regular shader.. - // this.renderer.shaderManager.setShader(this.defaultShader); - //gl.uniform2f(this.defaultShader.projectionVector, filterArea.width/2, -filterArea.height/2); - //gl.uniform2f(this.defaultShader.offsetVector, -filterArea.x, -filterArea.y); - - gl.colorMask(true, true, true, true); - gl.clearColor(0,0,0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); - - filterBlock._glFilterTexture = texture; - -}; - -/** - * Removes the last filter from the filter stack and doesn't return it. - * - */ -WebGLFilterManager.prototype.popFilter = function () { - var gl = this.renderer.gl; - - var filterBlock = this.filterStack.pop(); - var filterArea = filterBlock._filterArea; - var texture = filterBlock._glFilterTexture; - var projection = this.renderer.projection; - var offset = this.renderer.offset; - - if (filterBlock.filterPasses.length > 1) { - gl.viewport(0, 0, filterArea.width, filterArea.height); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - - this.vertexArray[0] = 0; - this.vertexArray[1] = filterArea.height; - - this.vertexArray[2] = filterArea.width; - this.vertexArray[3] = filterArea.height; - - this.vertexArray[4] = 0; - this.vertexArray[5] = 0; - - this.vertexArray[6] = filterArea.width; - this.vertexArray[7] = 0; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - // now set the uvs.. - this.uvArray[2] = filterArea.width/this.width; - this.uvArray[5] = filterArea.height/this.height; - this.uvArray[6] = filterArea.width/this.width; - this.uvArray[7] = filterArea.height/this.height; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); - - var inputTexture = texture; - var outputTexture = this.texturePool.pop(); - if (!outputTexture) { - outputTexture = new FilterTexture(this.renderer.gl, this.width, this.height); - } - outputTexture.resize(this.width, this.height); - - // need to clear this FBO as it may have some left over elements from a previous filter. - gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); - gl.clear(gl.COLOR_BUFFER_BIT); - - gl.disable(gl.BLEND); - - for (var i = 0; i < filterBlock.filterPasses.length-1; i++) { - var filterPass = filterBlock.filterPasses[i]; - - gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); - - // set texture - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, inputTexture.texture); - - // draw texture.. - //filterPass.applyFilterPass(filterArea.width, filterArea.height); - this.applyFilterPass(filterPass, filterArea, filterArea.width, filterArea.height); - - // swap the textures.. - var temp = inputTexture; - inputTexture = outputTexture; - outputTexture = temp; - } - - gl.enable(gl.BLEND); - - texture = inputTexture; - this.texturePool.push(outputTexture); - } - - var filter = filterBlock.filterPasses[filterBlock.filterPasses.length-1]; - - this.offsetX -= filterArea.x; - this.offsetY -= filterArea.y; - - var sizeX = this.width; - var sizeY = this.height; - - var offsetX = 0; - var offsetY = 0; - - var buffer = this.buffer; - - // time to render the filters texture to the previous scene - if (this.filterStack.length === 0) { - gl.colorMask(true, true, true, true);//this.transparent); - } - else { - var currentFilter = this.filterStack[this.filterStack.length-1]; - filterArea = currentFilter._filterArea; - - sizeX = filterArea.width; - sizeY = filterArea.height; - - offsetX = filterArea.x; - offsetY = filterArea.y; - - buffer = currentFilter._glFilterTexture.frameBuffer; - } - - // TODO need to remove these global elements.. - projection.x = sizeX/2; - projection.y = -sizeY/2; - - offset.x = offsetX; - offset.y = offsetY; - - filterArea = filterBlock._filterArea; - - var x = filterArea.x-offsetX; - var y = filterArea.y-offsetY; - - // update the buffers.. - // make sure to flip the y! - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - - this.vertexArray[0] = x; - this.vertexArray[1] = y + filterArea.height; - - this.vertexArray[2] = x + filterArea.width; - this.vertexArray[3] = y + filterArea.height; - - this.vertexArray[4] = x; - this.vertexArray[5] = y; - - this.vertexArray[6] = x + filterArea.width; - this.vertexArray[7] = y; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - - this.uvArray[2] = filterArea.width/this.width; - this.uvArray[5] = filterArea.height/this.height; - this.uvArray[6] = filterArea.width/this.width; - this.uvArray[7] = filterArea.height/this.height; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); - - gl.viewport(0, 0, sizeX, sizeY); - - // bind the buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, buffer ); - - // set the blend mode! - //gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) - - // set texture - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, texture.texture); - - // apply! - this.applyFilterPass(filter, filterArea, sizeX, sizeY); - - // now restore the regular shader.. should happen automatically now.. - // this.renderer.shaderManager.setShader(this.defaultShader); - // gl.uniform2f(this.defaultShader.projectionVector, sizeX/2, -sizeY/2); - // gl.uniform2f(this.defaultShader.offsetVector, -offsetX, -offsetY); - - // return the texture to the pool - this.texturePool.push(texture); - filterBlock._glFilterTexture = null; -}; - - -/** - * Applies the filter to the specified area. - * - * @param filter {AbstractFilter} the filter that needs to be applied - * @param filterArea {Texture} TODO - might need an update - * @param width {number} the horizontal range of the filter - * @param height {number} the vertical range of the filter - */ -WebGLFilterManager.prototype.applyFilterPass = function (filter, filterArea, width, height) { - // use program - var gl = this.renderer.gl; - - var shader = filter.shaders[gl.id]; - - if (!shader) { - shader = new Shader(gl); - - shader.fragmentSrc = filter.fragmentSrc; - shader.uniforms = filter.uniforms; - shader.init(); - - filter.shaders[gl.id] = shader; - } - - // set the shader - this.renderer.shaderManager.setShader(shader); - -// gl.useProgram(shader.program); - - gl.uniform2f(shader.projectionVector, width/2, -height/2); - gl.uniform2f(shader.offsetVector, 0,0); - - if (filter.uniforms.dimensions) { - filter.uniforms.dimensions.value[0] = this.width;//width; - filter.uniforms.dimensions.value[1] = this.height;//height; - filter.uniforms.dimensions.value[2] = this.vertexArray[0]; - filter.uniforms.dimensions.value[3] = this.vertexArray[5];//filterArea.height; - } - - shader.syncUniforms(); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); - gl.vertexAttribPointer(shader.aColor, 2, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - // draw the filter... - gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - - this.renderer.drawCount++; -}; - -/** - * Initialises the shader buffers. - * - */ -WebGLFilterManager.prototype.initShaderBuffers = function () { - var gl = this.renderer.gl; - - // create some buffers - this.vertexBuffer = gl.createBuffer(); - this.uvBuffer = gl.createBuffer(); - this.colorBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - - // bind and upload the vertexs.. - // keep a reference to the vertexFloatData.. - this.vertexArray = new Float32Array([0.0, 0.0, - 1.0, 0.0, - 0.0, 1.0, - 1.0, 1.0]); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.vertexArray, gl.STATIC_DRAW); - - // bind and upload the uv buffer - this.uvArray = new Float32Array([0.0, 0.0, - 1.0, 0.0, - 0.0, 1.0, - 1.0, 1.0]); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.uvArray, gl.STATIC_DRAW); - - this.colorArray = new Float32Array([1.0, 0xFFFFFF, - 1.0, 0xFFFFFF, - 1.0, 0xFFFFFF, - 1.0, 0xFFFFFF]); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.colorArray, gl.STATIC_DRAW); - - // bind and upload the index - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 1, 3, 2]), gl.STATIC_DRAW); - -}; - -/** - * Destroys the filter and removes it from the filter stack. - * - */ -WebGLFilterManager.prototype.destroy = function () { - var gl = this.renderer.gl; - - this.filterStack = null; - - this.offsetX = 0; - this.offsetY = 0; - - // destroy textures - for (var i = 0; i < this.texturePool.length; i++) { - this.texturePool[i].destroy(); - } - - this.texturePool = null; - - //destroy buffers.. - gl.deleteBuffer(this.vertexBuffer); - gl.deleteBuffer(this.uvBuffer); - gl.deleteBuffer(this.colorBuffer); - gl.deleteBuffer(this.indexBuffer); - - this.renderer = null; -}; - -},{"../shaders/Shader":35,"../utils/FilterTexture":37,"./WebGLManager":28}],28:[function(require,module,exports){ -/** - * @class - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this manager works for. - */ -function WebGLManager(renderer) { - /** - * The renderer this manager works for. - * - * @member {WebGLRenderer} - */ - this.renderer = renderer; -} - -WebGLManager.prototype.constructor = WebGLManager; -module.exports = WebGLManager; - -WebGLManager.prototype.destroy = function () { - this.renderer = null; -}; - -},{}],29:[function(require,module,exports){ -var WebGLManager = require('./WebGLManager'), - WebGLGraphics = require('../utils/WebGLGraphics'); - -/** - * @class - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this manager works for. - */ -function WebGLMaskManager(renderer) { - WebGLManager.call(this, renderer); -} - -WebGLMaskManager.prototype = Object.create(WebGLManager.prototype); -WebGLMaskManager.prototype.constructor = WebGLMaskManager; -module.exports = WebGLMaskManager; - -/** - * Applies the Mask and adds it to the current filter stack. - * - * @param maskData {any[]} - */ -WebGLMaskManager.prototype.pushMask = function (maskData) { - if (maskData.dirty) { - WebGLGraphics.updateGraphics(maskData, this.renderer.gl); - } - - if (!maskData._webGL[this.renderer.gl.id].data.length) { - return; - } - - this.renderer.stencilManager.pushStencil(maskData, maskData._webGL[this.renderer.gl.id].data[0], this.renderer); -}; - -/** - * Removes the last filter from the filter stack and doesn't return it. - * - * @param maskData {any[]} - */ -WebGLMaskManager.prototype.popMask = function (maskData) { - this.renderer.stencilManager.popStencil(maskData, maskData._webGL[this.renderer.gl.id].data[0], this.renderer); -}; - -},{"../utils/WebGLGraphics":39,"./WebGLManager":28}],30:[function(require,module,exports){ -var WebGLManager = require('./WebGLManager'), - PrimitiveShader = require('../shaders/PrimitiveShader'), - ComplexPrimitiveShader = require('../shaders/ComplexPrimitiveShader'), - Shader = require('../shaders/Shader'), - FastShader = require('../shaders/FastShader'), - StripShader = require('../shaders/StripShader'); - -/** - * @class - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this manager works for. - */ -function WebGLShaderManager(renderer) { - WebGLManager.call(this, renderer); - - /** - * @member {number} - */ - this.maxAttibs = 10; - - /** - * @member {any[]} - */ - this.attribState = []; - - /** - * @member {any[]} - */ - this.tempAttribState = []; - - for (var i = 0; i < this.maxAttibs; i++) { - this.attribState[i] = false; - } - - /** - * @member {any[]} - */ - this.stack = []; - - /** - * @member {number} - * @private - */ - this._currentId = -1; - - /** - * @member {Shader} - * @private - */ - this.currentShader = null; - - // this shader is used for rendering primitives - this.primitiveShader = null; - - // this shader is used for rendering triangle strips - this.complexPrimitiveShader = null; - - // this shader is used for the default sprite rendering - this.defaultShader = null; - - // this shader is used for the fast sprite rendering - this.fastShader = null; - - // the next one is used for rendering triangle strips - this.stripShader = null; - - // listen for context and update necessary shaders - var self = this; - this.renderer.on('context', function (event) { - var gl = event.data; - - // this shader is used for rendering primitives - self.primitiveShader = new PrimitiveShader(gl); - - // this shader is used for rendering triangle strips - self.complexPrimitiveShader = new ComplexPrimitiveShader(gl); - - // this shader is used for the default sprite rendering - self.defaultShader = new Shader(gl); - - // this shader is used for the fast sprite rendering - self.fastShader = new FastShader(gl); - - // the next one is used for rendering triangle strips - self.stripShader = new StripShader(gl); - - self.setShader(self.defaultShader); - }); -} - -WebGLShaderManager.prototype = Object.create(WebGLManager.prototype); -WebGLShaderManager.prototype.constructor = WebGLShaderManager; -module.exports = WebGLShaderManager; - -/** - * Takes the attributes given in parameters. - * - * @param attribs {Array} attribs - */ -WebGLShaderManager.prototype.setAttribs = function (attribs) { - // reset temp state - var i; - - for (i = 0; i < this.tempAttribState.length; i++) { - this.tempAttribState[i] = false; - } - - // set the new attribs - for (var a in attribs) { - this.tempAttribState[attribs[a]] = true; - } - - var gl = this.renderer.gl; - - for (i = 0; i < this.attribState.length; i++) { - if (this.attribState[i] !== this.tempAttribState[i]) { - this.attribState[i] = this.tempAttribState[i]; - - if (this.attribState[i]) { - gl.enableVertexAttribArray(i); - } - else { - gl.disableVertexAttribArray(i); - } - } - } -}; - -/** - * Sets the current shader. - * - * @param shader {Any} - */ -WebGLShaderManager.prototype.setShader = function (shader) { - if (this._currentId === shader.uuid) { - return false; - } - - this._currentId = shader.uuid; - - this.currentShader = shader; - - this.renderer.gl.useProgram(shader.program); - this.setAttribs(shader.attributes); - - return true; -}; - -/** - * Destroys this object. - * - */ -WebGLShaderManager.prototype.destroy = function () { - this.attribState = null; - - this.tempAttribState = null; - - this.primitiveShader.destroy(); - this.primitiveShader = null; - - this.complexPrimitiveShader.destroy(); - this.complexPrimitiveShader = null; - - this.defaultShader.destroy(); - this.defaultShader = null; - - this.fastShader.destroy(); - this.fastShader = null; - - this.stripShader.destroy(); - this.stripShader = null; - - this.renderer = null; -}; - -},{"../shaders/ComplexPrimitiveShader":32,"../shaders/FastShader":33,"../shaders/PrimitiveShader":34,"../shaders/Shader":35,"../shaders/StripShader":36,"./WebGLManager":28}],31:[function(require,module,exports){ -var WebGLManager = require('./WebGLManager'), - utils = require('../../../utils'); - -/** - * @class - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this manager works for. - */ -function WebGLStencilManager(renderer) { - WebGLManager.call(this, renderer); - - this.stencilStack = []; - this.reverse = true; - this.count = 0; -} - -WebGLStencilManager.prototype = Object.create(WebGLManager.prototype); -WebGLStencilManager.prototype.constructor = WebGLStencilManager; -module.exports = WebGLStencilManager; - -/** - * Applies the Mask and adds it to the current filter stack. - * - * @param graphics {Graphics} - * @param webGLData {any[]} - */ -WebGLStencilManager.prototype.pushStencil = function (graphics, webGLData) { - var gl = this.renderer.gl; - - this.bindGraphics(graphics, webGLData, this.renderer); - - if (this.stencilStack.length === 0) { - gl.enable(gl.STENCIL_TEST); - gl.clear(gl.STENCIL_BUFFER_BIT); - this.reverse = true; - this.count = 0; - } - - this.stencilStack.push(webGLData); - - var level = this.count; - - gl.colorMask(false, false, false, false); - - gl.stencilFunc(gl.ALWAYS,0,0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.INVERT); - - // draw the triangle strip! - - if (webGLData.mode === 1) { - gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 ); - - if (this.reverse) { - gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); - } - else { - gl.stencilFunc(gl.EQUAL,level, 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); - } - - // draw a quad to increment.. - gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_SHORT, ( webGLData.indices.length - 4 ) * 2 ); - - if (this.reverse) { - gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF); - } - else { - gl.stencilFunc(gl.EQUAL,level+1, 0xFF); - } - - this.reverse = !this.reverse; - } - else { - if (!this.reverse) { - gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); - } - else { - gl.stencilFunc(gl.EQUAL,level, 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); - } - - gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - - if (!this.reverse) { - gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF); - } - else { - gl.stencilFunc(gl.EQUAL,level+1, 0xFF); - } - } - - gl.colorMask(true, true, true, true); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - - this.count++; -}; - -/** - * TODO this does not belong here! - * - * @param graphics {Graphics} - * @param webGLData {Array} - */ -WebGLStencilManager.prototype.bindGraphics = function (graphics, webGLData) { - //if (this._currentGraphics === graphics)return; - this._currentGraphics = graphics; - - var gl = this.renderer.gl; - - // bind the graphics object.. - var projection = this.renderer.projection, - offset = this.renderer.offset, - shader;// = this.renderer.shaderManager.primitiveShader; - - if (webGLData.mode === 1) { - shader = this.renderer.shaderManager.complexPrimitiveShader; - - this.renderer.shaderManager.setShader(shader); - - gl.uniform1f(shader.flipY, this.renderer.flipY); - - gl.uniformMatrix3fv(shader.translationMatrix, false, graphics.worldTransform.toArray(true)); - - gl.uniform2f(shader.projectionVector, projection.x, -projection.y); - gl.uniform2f(shader.offsetVector, -offset.x, -offset.y); - - gl.uniform3fv(shader.tintColor, utils.hex2rgb(graphics.tint)); - gl.uniform3fv(shader.color, webGLData.color); - - gl.uniform1f(shader.alpha, graphics.worldAlpha * webGLData.alpha); - - gl.bindBuffer(gl.ARRAY_BUFFER, webGLData.buffer); - - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 4 * 2, 0); - - - // now do the rest.. - // set the index buffer! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webGLData.indexBuffer); - } - else { - //this.renderer.shaderManager.activatePrimitiveShader(); - shader = this.renderer.shaderManager.primitiveShader; - this.renderer.shaderManager.setShader( shader ); - - gl.uniformMatrix3fv(shader.translationMatrix, false, graphics.worldTransform.toArray(true)); - - gl.uniform1f(shader.flipY, this.renderer.flipY); - gl.uniform2f(shader.projectionVector, projection.x, -projection.y); - gl.uniform2f(shader.offsetVector, -offset.x, -offset.y); - - gl.uniform3fv(shader.tintColor, utils.hex2rgb(graphics.tint)); - - gl.uniform1f(shader.alpha, graphics.worldAlpha); - - gl.bindBuffer(gl.ARRAY_BUFFER, webGLData.buffer); - - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 4 * 6, 0); - gl.vertexAttribPointer(shader.aColor, 4, gl.FLOAT, false,4 * 6, 2 * 4); - - // set the index buffer! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webGLData.indexBuffer); - } -}; - -/** - * @param graphics {Graphics} - * @param webGLData {Array} - */ -WebGLStencilManager.prototype.popStencil = function (graphics, webGLData) { - var gl = this.renderer.gl; - - this.stencilStack.pop(); - - this.count--; - - if (this.stencilStack.length === 0) { - // the stack is empty! - gl.disable(gl.STENCIL_TEST); - - } - else { - - var level = this.count; - - this.bindGraphics(graphics, webGLData, this.renderer); - - gl.colorMask(false, false, false, false); - - if (webGLData.mode === 1) { - this.reverse = !this.reverse; - - if (this.reverse) { - gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); - } - else { - gl.stencilFunc(gl.EQUAL,level+1, 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); - } - - // draw a quad to increment.. - gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_SHORT, ( webGLData.indices.length - 4 ) * 2 ); - - gl.stencilFunc(gl.ALWAYS,0,0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.INVERT); - - // draw the triangle strip! - gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 ); - - if (!this.reverse) { - gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF); - } - else { - gl.stencilFunc(gl.EQUAL,level, 0xFF); - } - - } - else { - // console.log("<<>>") - if (!this.reverse) { - gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); - } - else { - gl.stencilFunc(gl.EQUAL,level+1, 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); - } - - gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - - if (!this.reverse) { - gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF); - } - else { - gl.stencilFunc(gl.EQUAL,level, 0xFF); - } - } - - gl.colorMask(true, true, true, true); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - - - } -}; - -/** - * Destroys the mask stack. - * - */ -WebGLStencilManager.prototype.destroy = function () { - this.renderer = null; - this.stencilStack = null; -}; - -},{"../../../utils":50,"./WebGLManager":28}],32:[function(require,module,exports){ -var Shader = require('./Shader'); - -/** - * @class - * @namespace PIXI - * @param gl {WebGLContext} the current WebGL drawing context - */ -function ComplexPrimitiveShader(gl) { - Shader.call(this, - gl, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - // 'attribute vec2 aTextureCoord;', - // 'attribute vec4 aColor;', - - 'uniform mat3 translationMatrix;', - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - - 'uniform vec3 tint;', - 'uniform float alpha;', - 'uniform vec3 color;', - 'uniform float flipY;', - 'varying vec4 vColor;', - - 'void main(void) {', - ' vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);', - ' v -= offsetVector.xyx;', - ' gl_Position = vec4( v.x / projectionVector.x -1.0, (v.y / projectionVector.y * -flipY) + flipY , 0.0, 1.0);', - ' vColor = vec4(color * alpha * tint, alpha);',//" * vec4(tint * alpha, alpha);', - '}' - ].join('\n'), - // fragment shader - [ - 'precision mediump float;', - - 'varying vec4 vColor;', - - 'void main(void) {', - ' gl_FragColor = vColor;', - '}' - ].join('\n'), - // custom uniforms - { - tint: { type: '3f', value: [0, 0, 0] }, - flipY: { type: '1f', value: 0 }, - alpha: { type: '1f', value: 0 }, - translationMatrix: { type: 'mat3', value: new Float32Array(9) } - } - ); -} - -ComplexPrimitiveShader.prototype = Object.create(Shader.prototype); -ComplexPrimitiveShader.prototype.constructor = ComplexPrimitiveShader; -module.exports = ComplexPrimitiveShader; - -},{"./Shader":35}],33:[function(require,module,exports){ -var Shader = require('./Shader'); - -/** - * @class - * @extends Shader - * @namespace PIXI - * @param gl {WebGLContext} the current WebGL drawing context - */ -function FastShader(gl) { - Shader.call(this, - gl, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute vec4 aColor;', - - 'attribute vec2 aPositionCoord;', - 'attribute vec2 aScale;', - 'attribute float aRotation;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform mat3 uMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void) {', - ' vec2 v;', - ' vec2 sv = aVertexPosition * aScale;', - ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', - ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', - ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', - ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', - ' vColor = aColor;', - '}' - ].join('\n'), - // fragment shader, use default - null, - // custom uniforms - { - uMatrix: { type: 'mat3', value: new Float32Array(9) } - }, - // custom attributes - { - aPositionCoord: 0, - aRotation: 0, - aScale: 0 - } - ); -} - -FastShader.prototype = Object.create(Shader.prototype); -FastShader.prototype.constructor = FastShader; -module.exports = FastShader; - -},{"./Shader":35}],34:[function(require,module,exports){ -var Shader = require('./Shader'); - -/** - * @class - * @namespace PIXI - * @param gl {WebGLContext} the current WebGL drawing context - */ -function PrimitiveShader(gl) { - Shader.call(this, - gl, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - // 'attribute vec2 aTextureCoord;', - 'attribute vec4 aColor;', - - 'uniform mat3 translationMatrix;', - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform float alpha;', - 'uniform float flipY;', - 'uniform vec3 tint;', - - 'varying vec4 vColor;', - - 'void main(void) {', - ' vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);', - ' v -= offsetVector.xyx;', - ' gl_Position = vec4( v.x / projectionVector.x -1.0, (v.y / projectionVector.y * -flipY) + flipY , 0.0, 1.0);', - ' vColor = aColor * vec4(tint * alpha, alpha);', - '}' - ].join('\n'), - // fragment shader - [ - 'precision mediump float;', - - 'varying vec4 vColor;', - - 'void main(void) {', - ' gl_FragColor = vColor;', - '}' - ].join('\n'), - // custom uniforms - { - tint: { type: '3f', value: [0, 0, 0] }, - flipY: { type: '1f', value: 0 }, - alpha: { type: '1f', value: 0 }, - translationMatrix: { type: 'mat3', value: new Float32Array(9) } - } - ); -} - -PrimitiveShader.prototype = Object.create(Shader.prototype); -PrimitiveShader.prototype.constructor = PrimitiveShader; -module.exports = PrimitiveShader; - -},{"./Shader":35}],35:[function(require,module,exports){ -var utils = require('../../../utils'); - -/** - * @class - * @namespace PIXI - * @param [fragmentSrc] {string} The source of the fragment shader. - * @param [vertexSrc] {string} The source of the vertex shader. - */ -function Shader(gl, vertexSrc, fragmentSrc, customUniforms, customAttributes) { - /** - * @member {number} - * @readonly - */ - this.uuid = utils.uuid(); - - /** - * @member {WebGLContext} - * @readonly - */ - this.gl = gl; - - /** - * The WebGL program. - * @member {WebGLProgram} - * @readonly - */ - this.program = null; - - this.uniforms = { - uSampler: { type: 'sampler2D', value: 0 }, - projectionVector: { type: '2f', value: { x: 0, y: 0 } }, - offsetVector: { type: '2f', value: { x: 0, y: 0 } }, - dimensions: { type: '4f', value: new Float32Array(4) } - }; - - for (var u in customUniforms) { - this.uniforms[u] = customUniforms[u]; - } - - this.attributes = { - aVertexPosition: 0, - aTextureCoord: 0, - aColor: 0 - }; - - for (var a in customAttributes) { - this.attributes[a] = customAttributes[a]; - } - - this.textureCount = 0; - - /** - * The vertex shader. - * @member {Array} - */ - this.vertexSrc = vertexSrc || [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute vec4 aColor;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void) {', - ' gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - ' vColor = vec4(aColor.rgb * aColor.a, aColor.a);', - '}' - ].join('\n'); - - /** - * The fragment shader. - * @member {Array} - */ - this.fragmentSrc = fragmentSrc || [ - 'precision lowp float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', - '}' - ].join('\n'); - - this.init(); -} - -Shader.prototype.constructor = Shader; -module.exports = Shader; - -Shader.prototype.init = function () { - this.compile(); - - this.gl.useProgram(this.program); - - this.cacheUniformLocations(Object.keys(this.uniforms)); - this.cacheAttributeLocations(Object.keys(this.attributes)); -}; - -Shader.prototype.cacheUniformLocations = function (keys) { - for (var i = 0; i < keys.length; ++i) { - this.uniforms[keys[i]]._location = this.gl.getUniformLocation(this.program, keys[i]); - } -}; - -Shader.prototype.cacheAttributeLocations = function (keys) { - for (var i = 0; i < keys.length; ++i) { - this.attributes[keys[i]] = this.gl.getAttribLocation(this.program, keys[i]); - } - - // TODO: Check if this is needed anymore... - - // Begin worst hack eva // - - // WHY??? ONLY on my chrome pixel the line above returns -1 when using filters? - // maybe its something to do with the current state of the gl context. - // I'm convinced this is a bug in the chrome browser as there is NO reason why this should be returning -1 especially as it only manifests on my chrome pixel - // If theres any webGL people that know why could happen please help :) - // if (this.attributes.aColor === -1) { - // this.attributes.aColor = 2; - // } - - // End worst hack eva // -}; - -Shader.prototype.compile = function () { - var gl = this.gl; - - var glVertShader = this._glCompile(gl.VERTEX_SHADER, this.vertexSrc); - var glFragShader = this._glCompile(gl.FRAGMENT_SHADER, this.fragmentSrc); - - var program = gl.createProgram(); - - gl.attachShader(program, glVertShader); - gl.attachShader(program, glFragShader); - gl.linkProgram(program); - - // if linking fails, then log and cleanup - if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { - window.console.error('Pixi.js Error: Could not initialize shader.'); - window.console.error('gl.VALIDATE_STATUS', gl.getProgramParameter(program, gl.VALIDATE_STATUS)); - window.console.error('gl.getError()', gl.getError()); - - // if there is a program info log, log it - if (gl.getProgramInfoLog(program) !== '') { - window.console.warn('Pixi.js Warning: gl.getProgramInfoLog()', gl.getProgramInfoLog(program)); - } - - gl.deleteProgram(program); - program = null; - } - - // clean up some shaders - gl.deleteShader(glVertShader); - gl.deleteShader(glFragShader); - - return (this.program = program); -}; - -Shader.prototype.syncUniforms = function () { - var gl = this.gl; - - this.textureCount = 1; - - for (var key in this.uniforms) { - var uniform = this.uniforms[key], - location = uniform._location, - value = uniform.value, - i, il; - - switch (uniform.type) { - case 'i': - case '1i': - gl.uniform1i(location, value); - break; - - case 'f': - case '1f': - gl.uniform1f(location, value); - break; - - case '2f': - gl.uniform2f(location, value[0], value[1]); - break; - - case '3f': - gl.uniform3f(location, value[0], value[1], value[2]); - break; - - case '4f': - gl.uniform4f(location, value[0], value[1], value[2], value[3]); - break; - - // a 2D Point object - case 'v2': - gl.uniform2f(location, value.x, value.y); - break; - - // a 3D Point object - case 'v3': - gl.uniform3f(location, value.x, value.y, value.z); - break; - - // a 4D Point object - case 'v4': - gl.uniform4f(location, value.x, value.y, value.z, value.w); - break; - - case '1iv': - gl.uniform1iv(location, value); - break; - - case '3iv': - gl.uniform3iv(location, value); - break; - - case '1fv': - gl.uniform1fv(location, value); - break; - - case '2fv': - gl.uniform2fv(location, value); - break; - - case '3fv': - gl.uniform3fv(location, value); - break; - - case '4fv': - gl.uniform4fv(location, value); - break; - - case 'm2': - case 'mat2': - case 'Matrix2fv': - gl.uniformMatrix2fv(location, uniform.transpose, value); - break; - - case 'm3': - case 'mat3': - case 'Matrix3fv': - gl.uniformMatrix3fv(location, uniform.transpose, value); - break; - - case 'm4': - case 'mat4': - case 'Matrix4fv': - gl.uniformMatrix4fv(location, uniform.transpose, value); - break; - - // a Color Value - case 'c': - if (typeof value === 'number') { - value = utils.hex2rgb(value); - } - - gl.uniform3f(location, value[0], value[1], value[2]); - break; - - // flat array of integers (JS or typed array) - case 'iv1': - gl.uniform1iv(location, value); - break; - - // flat array of integers with 3 x N size (JS or typed array) - case 'iv': - gl.uniform3iv(location, value); - break; - - // flat array of floats (JS or typed array) - case 'fv1': - gl.uniform1fv(location, value); - break; - - // flat array of floats with 3 x N size (JS or typed array) - case 'fv': - gl.uniform3fv(location, value); - break; - - // array of 2D Point objects - case 'v2v': - if (!uniform._array) { - uniform._array = new Float32Array(2 * value.length); - } - - for (i = 0, il = value.length; i < il; ++i) { - uniform._array[i * 2] = value[i].x; - uniform._array[i * 2 + 1] = value[i].y; - } - - gl.uniform2fv(location, uniform._array); - break; - - // array of 3D Point objects - case 'v3v': - if (!uniform._array) { - uniform._array = new Float32Array(3 * value.length); - } - - for (i = 0, il = value.length; i < il; ++i) { - uniform._array[i * 3] = value[i].x; - uniform._array[i * 3 + 1] = value[i].y; - uniform._array[i * 3 + 2] = value[i].z; - - } - - gl.uniform3fv(location, uniform._array); - break; - - // array of 4D Point objects - case 'v4v': - if (!uniform._array) { - uniform._array = new Float32Array(4 * value.length); - } - - for (i = 0, il = value.length; i < il; ++i) { - uniform._array[i * 4] = value[i].x; - uniform._array[i * 4 + 1] = value[i].y; - uniform._array[i * 4 + 2] = value[i].z; - uniform._array[i * 4 + 3] = value[i].w; - - } - - gl.uniform4fv(location, uniform._array); - break; - - case 't': - case 'sampler2D': - if (!uniform.value || !uniform.value.baseTexture || !uniform.value.baseTexture.hasLoaded) { - break; - } - - // activate this texture - gl.activeTexture(gl['TEXTURE' + this.textureCount]); - - // bind the texture - gl.bindTexture(gl.TEXTURE_2D, uniform.value.baseTexture._glTextures[gl.id]); - - // set uniform to texture index - gl.uniform1i(uniform._location, this.textureCount); - - // increment next texture id - this.textureCount++; - - // initialize the texture if we haven't yet - if (!uniform._init) { - this.initSampler2D(uniform); - - uniform._init = true; - } - break; - - default: - window.console.warn('Pixi.js Shader Warning: Unknown uniform type: ' + uniform.type); - } - } -}; - - -/** - * Initialises a Sampler2D uniform (which may only be available later on after initUniforms once the texture has loaded) - * - */ -Shader.prototype.initSampler2D = function (uniform) { - var gl = this.gl; - - // Extended texture data - if (uniform.textureData) { - var data = uniform.textureData; - - // GLTexture = mag linear, min linear_mipmap_linear, wrap repeat + gl.generateMipmap(gl.TEXTURE_2D); - // GLTextureLinear = mag/min linear, wrap clamp - // GLTextureNearestRepeat = mag/min NEAREST, wrap repeat - // GLTextureNearest = mag/min nearest, wrap clamp - // AudioTexture = whatever + luminance + width 512, height 2, border 0 - // KeyTexture = whatever + luminance + width 256, height 2, border 0 - - // magFilter can be: gl.LINEAR, gl.LINEAR_MIPMAP_LINEAR or gl.NEAREST - // wrapS/T can be: gl.CLAMP_TO_EDGE or gl.REPEAT - - var magFilter = (data.magFilter) ? data.magFilter : gl.LINEAR; - var minFilter = (data.minFilter) ? data.minFilter : gl.LINEAR; - var wrapS = (data.wrapS) ? data.wrapS : gl.CLAMP_TO_EDGE; - var wrapT = (data.wrapT) ? data.wrapT : gl.CLAMP_TO_EDGE; - var format = (data.luminance) ? gl.LUMINANCE : gl.RGBA; - - if (data.repeat) { - wrapS = gl.REPEAT; - wrapT = gl.REPEAT; - } - - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, !!data.flipY); - - if (data.width) { - var width = (data.width) ? data.width : 512; - var height = (data.height) ? data.height : 2; - var border = (data.border) ? data.border : 0; - - // void texImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, ArrayBufferView? pixels); - gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, border, format, gl.UNSIGNED_BYTE, null); - } - else { - // void texImage2D(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, ImageData? pixels); - gl.texImage2D(gl.TEXTURE_2D, 0, format, gl.RGBA, gl.UNSIGNED_BYTE, uniform.value.baseTexture.source); - } - - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT); - } -}; - -/** - * Destroys the shader. - * - */ -Shader.prototype.destroy = function () { - this.gl.deleteProgram(this.program); - - this.gl = null; - this.uniforms = null; - this.attributes = null; - - this.vertexSrc = null; - this.fragmentSrc = null; -}; - -Shader.prototype._glCompile = function (type, src) { - var shader = this.gl.createShader(type); - - if (Array.isArray(src)) { - debugger; - } - - this.gl.shaderSource(shader, src); - this.gl.compileShader(shader); - - if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) { - window.console.log(this.gl.getShaderInfoLog(shader)); - return null; - } - - return shader; -}; - -},{"../../../utils":50}],36:[function(require,module,exports){ -var Shader = require('./Shader'); - -/** - * @class - * @namespace PIXI - * @param gl {WebGLContext} the current WebGL drawing context - */ -function StripShader(gl) { - Shader.call(this, - gl, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - // 'attribute vec4 aColor;', - - 'uniform mat3 translationMatrix;', - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - - 'varying vec2 vTextureCoord;', - - 'void main(void) {', - ' vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);', - ' v -= offsetVector.xyx;', - ' gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - '}' - ].join('\n'), - // fragment shader - [ - 'precision mediump float;', - - 'uniform float alpha;', - 'uniform sampler2D uSampler;', - - 'varying vec2 vTextureCoord;', - - 'void main(void) {', - ' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y)) * alpha;', - '}' - ].join('\n'), - // custom uniforms - { - alpha: { type: '1f', value: 0 }, - translationMatrix: { type: 'mat3', value: new Float32Array(9) } - } - ); -} - -StripShader.prototype = Object.create(Shader.prototype); -StripShader.prototype.constructor = StripShader; -module.exports = StripShader; - -},{"./Shader":35}],37:[function(require,module,exports){ -var CONST = require('../../../const'); - -/** - * @class - * @namespace PIXI - * @param gl {WebGLContext} the current WebGL drawing context - * @param width {number} the horizontal range of the filter - * @param height {number} the vertical range of the filter - * @param scaleMode {number} See {{#crossLink "PIXI/scaleModes:property"}}scaleModes{{/crossLink}} for possible values - */ -function FilterTexture(gl, width, height, scaleMode) { - /** - * @member {WebGLContext} - */ - this.gl = gl; - - // next time to create a frame buffer and texture - - /** - * @member {Any} - */ - this.frameBuffer = gl.createFramebuffer(); - - /** - * @member {Any} - */ - this.texture = gl.createTexture(); - - /** - * @member {number} - */ - scaleMode = scaleMode || CONST.scaleModes.DEFAULT; - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); - - // required for masking a mask?? - this.renderBuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.renderBuffer); - - // reset render buffer - gl.bindRenderbuffer(gl.RENDERBUFFER, null); - - this.resize(width, height); -} - -FilterTexture.prototype.constructor = FilterTexture; -module.exports = FilterTexture; - -/** - * Clears the filter texture. - * - */ -FilterTexture.prototype.clear = function () { - var gl = this.gl; - - gl.clearColor(0,0,0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); -}; - -/** - * Resizes the texture to the specified width and height - * - * @param width {number} the new width of the texture - * @param height {number} the new height of the texture - */ -FilterTexture.prototype.resize = function (width, height) { - if (this.width === width && this.height === height) { - return; - } - - this.width = width; - this.height = height; - - var gl = this.gl; - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width , height , 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - // update the stencil buffer width and height - gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width , height); - - // reset render buffer - gl.bindRenderbuffer(gl.RENDERBUFFER, null); -}; - -/** - * Destroys the filter texture. - * - */ -FilterTexture.prototype.destroy = function () { - var gl = this.gl; - gl.deleteFramebuffer( this.frameBuffer ); - gl.deleteTexture( this.texture ); - - this.frameBuffer = null; - this.texture = null; -}; - -},{"../../../const":4}],38:[function(require,module,exports){ -/** - * @author Mat Groves - * - * Big thanks to the very clever Matt DesLauriers https://github.com/mattdesl/ - * for creating the original pixi version! - * - * Heavily inspired by LibGDX's WebGLSpriteBatch: - * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java - */ - -/** - * @class - * @private - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this sprite batch works for. - */ -function WebGLFastSpriteBatch(renderer) { - /** - * The renderer instance this sprite batch operates on. - * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * - * @member {number} - */ - this.vertSize = 10; - - /** - * - * - * @member {number} - */ - this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; - - /** - * - * - * @member {number} - */ - this.size = this.maxSize; - - //the total number of floats in our batch - var numVerts = this.size * 4 * this.vertSize; - - //the total number of indices in our batch - var numIndices = this.maxSize * 6; - - /** - * Vertex data - * - * @member {Float32Array} - */ - this.vertices = new Float32Array(numVerts); - - /** - * Index data - * - * @member {Uint16Array} - */ - this.indices = new Uint16Array(numIndices); - - /** - * - * - * @member {object} - */ - this.vertexBuffer = null; - - /** - * - * - * @member {object} - */ - this.indexBuffer = null; - - /** - * - * - * @member {number} - */ - this.lastIndexCount = 0; - - for (var i=0, j=0; i < numIndices; i += 6, j += 4) { - this.indices[i + 0] = j + 0; - this.indices[i + 1] = j + 1; - this.indices[i + 2] = j + 2; - this.indices[i + 3] = j + 0; - this.indices[i + 4] = j + 2; - this.indices[i + 5] = j + 3; - } - - /** - * - * - * @member {boolean} - */ - this.drawing = false; - - /** - * - * - * @member {number} - */ - this.currentBatchSize = 0; - - /** - * - * - * @member {BaseTexture} - */ - this.currentBaseTexture = null; - - /** - * - * - * @member {number} - */ - this.currentBlendMode = 0; - - /** - * - * - * @member {object} - */ - this.shader = null; - - /** - * - * - * @member {Matrix} - */ - this.matrix = null; - - // listen for context and update necessary buffers - var self = this; - this.renderer.on('context', function () { - self.setupContext(); - }); -} - -WebGLFastSpriteBatch.prototype.constructor = WebGLFastSpriteBatch; -module.exports = WebGLFastSpriteBatch; - -/** - * Sets the WebGL Context. - * - * @param gl {WebGLContext} the current WebGL drawing context - */ -WebGLFastSpriteBatch.prototype.setupContext = function () { - var gl = this.renderer.gl; - - // create a couple of buffers - this.vertexBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - - // 65535 is max index, so 65535 / 6 = 10922. - - //upload the index data - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to prepare for. - */ -WebGLFastSpriteBatch.prototype.begin = function (spriteBatch) { - this.shader = this.renderer.shaderManager.fastShader; - - this.matrix = spriteBatch.worldTransform.toArray(true); - - this.start(); -}; - -/** - */ -WebGLFastSpriteBatch.prototype.end = function () { - this.flush(); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. - */ -WebGLFastSpriteBatch.prototype.render = function (spriteBatch) { - var children = spriteBatch.children; - var sprite = children[0]; - - // if the uvs have not updated then no point rendering just yet! - - // check texture. - if (!sprite.texture._uvs) { - return; - } - - this.currentBaseTexture = sprite.texture.baseTexture; - - // check blend mode - if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) { - this.flush(); - this.renderer.blendModeManager.setBlendMode(sprite.blendMode); - } - - for (var i=0,j= children.length; i= this.size) { - this.flush(); - } -}; - -/** - * - */ -WebGLFastSpriteBatch.prototype.flush = function () { - // If the batch is length 0 then return as there is nothing to draw - if (this.currentBatchSize === 0) { - return; - } - - var gl = this.renderer.gl; - - // bind the current texture - if (!this.currentBaseTexture._glTextures[gl.id]) { - this.renderer.updateTexture(this.currentBaseTexture, gl); - } - //TODO-SHOUD THIS BE ELSE??!?!?! - else { - gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); - } - - // upload the verts to the buffer - - if (this.currentBatchSize > ( this.size * 0.5 ) ) { - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); - } - else { - var view = this.vertices.subarray(0, this.currentBatchSize * 4 * this.vertSize); - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, view); - } - - // now draw those suckas! - gl.drawElements(gl.TRIANGLES, this.currentBatchSize * 6, gl.UNSIGNED_SHORT, 0); - - // then reset the batch! - this.currentBatchSize = 0; - - // increment the draw count - this.renderer.drawCount++; -}; - - -/** - * Ends the batch and flushes - * - */ -WebGLFastSpriteBatch.prototype.stop = function () { - this.flush(); -}; - -/** - * - */ -WebGLFastSpriteBatch.prototype.start = function () { - var gl = this.renderer.gl; - - // bind the main texture - gl.activeTexture(gl.TEXTURE0); - - // bind the buffers - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - // set the projection - var projection = this.renderer.projection; - gl.uniform2f(this.shader.projectionVector, projection.x, projection.y); - - // set the matrix - gl.uniformMatrix3fv(this.shader.uMatrix, false, this.matrix); - - // set the pointers - var stride = this.vertSize * 4; - - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 2 * 4); - gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 4 * 4); - gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 6 * 4); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 7 * 4); - gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 9 * 4); -}; - -},{}],39:[function(require,module,exports){ -var utils = require('../../../utils'), - math = require('../../../math'), - CONST = require('../../../const'), - WebGLGraphicsData = require('./WebGLGraphicsData'); - -/** - * A set of functions used by the webGL renderer to draw the primitive graphics data - * - * @namespace PIXI - * @private - */ -var WebGLGraphics = module.exports = {}; - -/** - * Renders the graphics object - * - * @static - * @private - * @param graphics {Graphics} - * @param renderer {WebGLRenderer} - */ -WebGLGraphics.renderGraphics = function (graphics, renderer) {//projection, offset) { - var gl = renderer.gl; - - var projection = renderer.projection, - offset = renderer.offset, - shader = renderer.shaderManager.primitiveShader, - webGLData; - - if (graphics.dirty) { - WebGLGraphics.updateGraphics(graphics, gl); - } - - var webGL = graphics._webGL[gl.id]; - - // This could be speeded up for sure! - - for (var i = 0; i < webGL.data.length; i++) { - if (webGL.data[i].mode === 1) { - webGLData = webGL.data[i]; - - renderer.stencilManager.pushStencil(graphics, webGLData, renderer); - - // render quad.. - gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_SHORT, ( webGLData.indices.length - 4 ) * 2 ); - - renderer.stencilManager.popStencil(graphics, webGLData, renderer); - } - else { - webGLData = webGL.data[i]; - - - renderer.shaderManager.setShader( shader );//activatePrimitiveShader(); - shader = renderer.shaderManager.primitiveShader; - gl.uniformMatrix3fv(shader.translationMatrix, false, graphics.worldTransform.toArray(true)); - - gl.uniform1f(shader.flipY, 1); - - gl.uniform2f(shader.projectionVector, projection.x, -projection.y); - gl.uniform2f(shader.offsetVector, -offset.x, -offset.y); - - gl.uniform3fv(shader.tintColor, utils.hex2rgb(graphics.tint)); - - gl.uniform1f(shader.alpha, graphics.worldAlpha); - - - gl.bindBuffer(gl.ARRAY_BUFFER, webGLData.buffer); - - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 4 * 6, 0); - gl.vertexAttribPointer(shader.aColor, 4, gl.FLOAT, false,4 * 6, 2 * 4); - - // set the index buffer! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webGLData.indexBuffer); - gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - } - } -}; - -/** - * Updates the graphics object - * - * @static - * @private - * @param graphicsData {Graphics} The graphics object to update - * @param gl {WebGLContext} the current WebGL drawing context - */ -WebGLGraphics.updateGraphics = function (graphics, gl) { - // get the contexts graphics object - var webGL = graphics._webGL[gl.id]; - - // if the graphics object does not exist in the webGL context time to create it! - if (!webGL) { - webGL = graphics._webGL[gl.id] = {lastIndex:0, data:[], gl:gl}; - } - - // flag the graphics as not dirty as we are about to update it... - graphics.dirty = false; - - var i; - - // if the user cleared the graphics object we will need to clear every object - if (graphics.clearDirty) { - graphics.clearDirty = false; - - // lop through and return all the webGLDatas to the object pool so than can be reused later on - for (i = 0; i < webGL.data.length; i++) { - var graphicsData = webGL.data[i]; - graphicsData.reset(); - WebGLGraphics.graphicsDataPool.push( graphicsData ); - } - - // clear the array and reset the index.. - webGL.data = []; - webGL.lastIndex = 0; - } - - var webGLData; - - // loop through the graphics datas and construct each one.. - // if the object is a complex fill then the new stencil buffer technique will be used - // other wise graphics objects will be pushed into a batch.. - for (i = webGL.lastIndex; i < graphics.graphicsData.length; i++) { - var data = graphics.graphicsData[i]; - - if (data.type === CONST.SHAPES.POLY) { - // need to add the points the the graphics object.. - data.points = data.shape.points.slice(); - if (data.shape.closed) { - // close the poly if the value is true! - if (data.points[0] !== data.points[data.points.length-2] || data.points[1] !== data.points[data.points.length-1]) { - data.points.push(data.points[0], data.points[1]); - } - } - - // MAKE SURE WE HAVE THE CORRECT TYPE.. - if (data.fill) { - if (data.points.length >= 6) { - if (data.points.length < 6 * 2) { - webGLData = WebGLGraphics.switchMode(webGL, 0); - - var canDrawUsingSimple = WebGLGraphics.buildPoly(data, webGLData); - // console.log(canDrawUsingSimple); - - if (!canDrawUsingSimple) { - // console.log("<>>>") - webGLData = WebGLGraphics.switchMode(webGL, 1); - WebGLGraphics.buildComplexPoly(data, webGLData); - } - - } - else { - webGLData = WebGLGraphics.switchMode(webGL, 1); - WebGLGraphics.buildComplexPoly(data, webGLData); - } - } - } - - if (data.lineWidth > 0) { - webGLData = WebGLGraphics.switchMode(webGL, 0); - WebGLGraphics.buildLine(data, webGLData); - - } - } - else { - webGLData = WebGLGraphics.switchMode(webGL, 0); - - if (data.type === CONST.SHAPES.RECT) { - WebGLGraphics.buildRectangle(data, webGLData); - } - else if (data.type === CONST.SHAPES.CIRC || data.type === CONST.SHAPES.ELIP) { - WebGLGraphics.buildCircle(data, webGLData); - } - else if (data.type === CONST.SHAPES.RREC) { - WebGLGraphics.buildRoundedRectangle(data, webGLData); - } - } - - webGL.lastIndex++; - } - - // upload all the dirty data... - for (i = 0; i < webGL.data.length; i++) { - webGLData = webGL.data[i]; - - if (webGLData.dirty) { - webGLData.upload(); - } - } -}; - -/** - * @static - * @private - * @param webGL {WebGLContext} - * @param type {number} - */ -WebGLGraphics.switchMode = function (webGL, type) { - var webGLData; - - if (!webGL.data.length) { - webGLData = WebGLGraphics.graphicsDataPool.pop() || new WebGLGraphicsData(webGL.gl); - webGLData.mode = type; - webGL.data.push(webGLData); - } - else { - webGLData = webGL.data[webGL.data.length-1]; - - if (webGLData.mode !== type || type === 1) { - webGLData = WebGLGraphics.graphicsDataPool.pop() || new WebGLGraphicsData(webGL.gl); - webGLData.mode = type; - webGL.data.push(webGLData); - } - } - - webGLData.dirty = true; - - return webGLData; -}; - -/** - * Builds a rectangle to draw - * - * @static - * @private - * @param graphicsData {Graphics} The graphics object containing all the necessary properties - * @param webGLData {object} - */ -WebGLGraphics.buildRectangle = function (graphicsData, webGLData) { - // --- // - // need to convert points to a nice regular data - // - var rectData = graphicsData.shape; - var x = rectData.x; - var y = rectData.y; - var width = rectData.width; - var height = rectData.height; - - if (graphicsData.fill) { - var color = utils.hex2rgb(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var verts = webGLData.points; - var indices = webGLData.indices; - - var vertPos = verts.length/6; - - // start - verts.push(x, y); - verts.push(r, g, b, alpha); - - verts.push(x + width, y); - verts.push(r, g, b, alpha); - - verts.push(x , y + height); - verts.push(r, g, b, alpha); - - verts.push(x + width, y + height); - verts.push(r, g, b, alpha); - - // insert 2 dead triangles.. - indices.push(vertPos, vertPos, vertPos+1, vertPos+2, vertPos+3, vertPos+3); - } - - if (graphicsData.lineWidth) { - var tempPoints = graphicsData.points; - - graphicsData.points = [x, y, - x + width, y, - x + width, y + height, - x, y + height, - x, y]; - - - WebGLGraphics.buildLine(graphicsData, webGLData); - - graphicsData.points = tempPoints; - } -}; - -/** - * Builds a rounded rectangle to draw - * - * @static - * @private - * @param graphicsData {Graphics} The graphics object containing all the necessary properties - * @param webGLData {object} - */ -WebGLGraphics.buildRoundedRectangle = function (graphicsData, webGLData) { - var rrectData = graphicsData.shape; - var x = rrectData.x; - var y = rrectData.y; - var width = rrectData.width; - var height = rrectData.height; - - var radius = rrectData.radius; - - var recPoints = []; - recPoints.push(x, y + radius); - recPoints = recPoints.concat(WebGLGraphics.quadraticBezierCurve(x, y + height - radius, x, y + height, x + radius, y + height)); - recPoints = recPoints.concat(WebGLGraphics.quadraticBezierCurve(x + width - radius, y + height, x + width, y + height, x + width, y + height - radius)); - recPoints = recPoints.concat(WebGLGraphics.quadraticBezierCurve(x + width, y + radius, x + width, y, x + width - radius, y)); - recPoints = recPoints.concat(WebGLGraphics.quadraticBezierCurve(x + radius, y, x, y, x, y + radius)); - - if (graphicsData.fill) { - var color = utils.hex2rgb(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var verts = webGLData.points; - var indices = webGLData.indices; - - var vecPos = verts.length/6; - - var triangles = utils.PolyK.Triangulate(recPoints); - - // - - var i = 0; - for (i = 0; i < triangles.length; i+=3) { - indices.push(triangles[i] + vecPos); - indices.push(triangles[i] + vecPos); - indices.push(triangles[i+1] + vecPos); - indices.push(triangles[i+2] + vecPos); - indices.push(triangles[i+2] + vecPos); - } - - - for (i = 0; i < recPoints.length; i++) { - verts.push(recPoints[i], recPoints[++i], r, g, b, alpha); - } - } - - if (graphicsData.lineWidth) { - var tempPoints = graphicsData.points; - - graphicsData.points = recPoints; - - WebGLGraphics.buildLine(graphicsData, webGLData); - - graphicsData.points = tempPoints; - } -}; - -/** - * Calculate the points for a quadratic bezier curve. (helper function..) - * Based on: https://stackoverflow.com/questions/785097/how-do-i-implement-a-bezier-curve-in-c - * - * @static - * @private - * @param fromX {number} Origin point x - * @param fromY {number} Origin point x - * @param cpX {number} Control point x - * @param cpY {number} Control point y - * @param toX {number} Destination point x - * @param toY {number} Destination point y - * @return {number[]} - */ -WebGLGraphics.quadraticBezierCurve = function (fromX, fromY, cpX, cpY, toX, toY) { - - var xa, - ya, - xb, - yb, - x, - y, - n = 20, - points = []; - - function getPt(n1 , n2, perc) { - var diff = n2 - n1; - - return n1 + ( diff * perc ); - } - - var j = 0; - for (var i = 0; i <= n; i++ ) { - j = i / n; - - // The Green Line - xa = getPt( fromX , cpX , j ); - ya = getPt( fromY , cpY , j ); - xb = getPt( cpX , toX , j ); - yb = getPt( cpY , toY , j ); - - // The Black Dot - x = getPt( xa , xb , j ); - y = getPt( ya , yb , j ); - - points.push(x, y); - } - return points; -}; - -/** - * Builds a circle to draw - * - * @static - * @private - * @param graphicsData {Graphics} The graphics object to draw - * @param webGLData {object} - */ -WebGLGraphics.buildCircle = function (graphicsData, webGLData) { - // need to convert points to a nice regular data - var circleData = graphicsData.shape; - var x = circleData.x; - var y = circleData.y; - var width; - var height; - - // TODO - bit hacky?? - if (graphicsData.type === CONST.SHAPES.CIRC) { - width = circleData.radius; - height = circleData.radius; - } - else { - width = circleData.width; - height = circleData.height; - } - - var totalSegs = 40; - var seg = (Math.PI * 2) / totalSegs ; - - var i = 0; - - if (graphicsData.fill) { - var color = utils.hex2rgb(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var verts = webGLData.points; - var indices = webGLData.indices; - - var vecPos = verts.length/6; - - indices.push(vecPos); - - for (i = 0; i < totalSegs + 1 ; i++) { - verts.push(x,y, r, g, b, alpha); - - verts.push(x + Math.sin(seg * i) * width, - y + Math.cos(seg * i) * height, - r, g, b, alpha); - - indices.push(vecPos++, vecPos++); - } - - indices.push(vecPos-1); - } - - if (graphicsData.lineWidth) { - var tempPoints = graphicsData.points; - - graphicsData.points = []; - - for (i = 0; i < totalSegs + 1; i++) { - graphicsData.points.push(x + Math.sin(seg * i) * width, - y + Math.cos(seg * i) * height); - } - - WebGLGraphics.buildLine(graphicsData, webGLData); - - graphicsData.points = tempPoints; - } -}; - -/** - * Builds a line to draw - * - * @static - * @private - * @param graphicsData {Graphics} The graphics object containing all the necessary properties - * @param webGLData {object} - */ -WebGLGraphics.buildLine = function (graphicsData, webGLData) { - // TODO OPTIMISE! - var i = 0; - var points = graphicsData.points; - - if (points.length === 0) { - return; - } - - // if the line width is an odd number add 0.5 to align to a whole pixel - if (graphicsData.lineWidth%2) { - for (i = 0; i < points.length; i++) { - points[i] += 0.5; - } - } - - // get first and last point.. figure out the middle! - var firstPoint = new math.Point(points[0], points[1]); - var lastPoint = new math.Point(points[points.length - 2], points[points.length - 1]); - - // if the first point is the last point - gonna have issues :) - if (firstPoint.x === lastPoint.x && firstPoint.y === lastPoint.y) { - // need to clone as we are going to slightly modify the shape.. - points = points.slice(); - - points.pop(); - points.pop(); - - lastPoint = new math.Point(points[points.length - 2], points[points.length - 1]); - - var midPointX = lastPoint.x + (firstPoint.x - lastPoint.x) *0.5; - var midPointY = lastPoint.y + (firstPoint.y - lastPoint.y) *0.5; - - points.unshift(midPointX, midPointY); - points.push(midPointX, midPointY); - } - - var verts = webGLData.points; - var indices = webGLData.indices; - var length = points.length / 2; - var indexCount = points.length; - var indexStart = verts.length/6; - - // DRAW the Line - var width = graphicsData.lineWidth / 2; - - // sort color - var color = utils.hex2rgb(graphicsData.lineColor); - var alpha = graphicsData.lineAlpha; - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var px, py, p1x, p1y, p2x, p2y, p3x, p3y; - var perpx, perpy, perp2x, perp2y, perp3x, perp3y; - var a1, b1, c1, a2, b2, c2; - var denom, pdist, dist; - - p1x = points[0]; - p1y = points[1]; - - p2x = points[2]; - p2y = points[3]; - - perpx = -(p1y - p2y); - perpy = p1x - p2x; - - dist = Math.sqrt(perpx*perpx + perpy*perpy); - - perpx /= dist; - perpy /= dist; - perpx *= width; - perpy *= width; - - // start - verts.push(p1x - perpx , p1y - perpy, - r, g, b, alpha); - - verts.push(p1x + perpx , p1y + perpy, - r, g, b, alpha); - - for (i = 1; i < length-1; i++) { - p1x = points[(i-1)*2]; - p1y = points[(i-1)*2 + 1]; - - p2x = points[(i)*2]; - p2y = points[(i)*2 + 1]; - - p3x = points[(i+1)*2]; - p3y = points[(i+1)*2 + 1]; - - perpx = -(p1y - p2y); - perpy = p1x - p2x; - - dist = Math.sqrt(perpx*perpx + perpy*perpy); - perpx /= dist; - perpy /= dist; - perpx *= width; - perpy *= width; - - perp2x = -(p2y - p3y); - perp2y = p2x - p3x; - - dist = Math.sqrt(perp2x*perp2x + perp2y*perp2y); - perp2x /= dist; - perp2y /= dist; - perp2x *= width; - perp2y *= width; - - a1 = (-perpy + p1y) - (-perpy + p2y); - b1 = (-perpx + p2x) - (-perpx + p1x); - c1 = (-perpx + p1x) * (-perpy + p2y) - (-perpx + p2x) * (-perpy + p1y); - a2 = (-perp2y + p3y) - (-perp2y + p2y); - b2 = (-perp2x + p2x) - (-perp2x + p3x); - c2 = (-perp2x + p3x) * (-perp2y + p2y) - (-perp2x + p2x) * (-perp2y + p3y); - - denom = a1*b2 - a2*b1; - - if (Math.abs(denom) < 0.1 ) { - - denom+=10.1; - verts.push(p2x - perpx , p2y - perpy, - r, g, b, alpha); - - verts.push(p2x + perpx , p2y + perpy, - r, g, b, alpha); - - continue; - } - - px = (b1*c2 - b2*c1)/denom; - py = (a2*c1 - a1*c2)/denom; - - - pdist = (px -p2x) * (px -p2x) + (py -p2y) + (py -p2y); - - - if (pdist > 140 * 140) { - perp3x = perpx - perp2x; - perp3y = perpy - perp2y; - - dist = Math.sqrt(perp3x*perp3x + perp3y*perp3y); - perp3x /= dist; - perp3y /= dist; - perp3x *= width; - perp3y *= width; - - verts.push(p2x - perp3x, p2y -perp3y); - verts.push(r, g, b, alpha); - - verts.push(p2x + perp3x, p2y +perp3y); - verts.push(r, g, b, alpha); - - verts.push(p2x - perp3x, p2y -perp3y); - verts.push(r, g, b, alpha); - - indexCount++; - } - else { - - verts.push(px , py); - verts.push(r, g, b, alpha); - - verts.push(p2x - (px-p2x), p2y - (py - p2y)); - verts.push(r, g, b, alpha); - } - } - - p1x = points[(length-2)*2]; - p1y = points[(length-2)*2 + 1]; - - p2x = points[(length-1)*2]; - p2y = points[(length-1)*2 + 1]; - - perpx = -(p1y - p2y); - perpy = p1x - p2x; - - dist = Math.sqrt(perpx*perpx + perpy*perpy); - perpx /= dist; - perpy /= dist; - perpx *= width; - perpy *= width; - - verts.push(p2x - perpx , p2y - perpy); - verts.push(r, g, b, alpha); - - verts.push(p2x + perpx , p2y + perpy); - verts.push(r, g, b, alpha); - - indices.push(indexStart); - - for (i = 0; i < indexCount; i++) { - indices.push(indexStart++); - } - - indices.push(indexStart-1); -}; - -/** - * Builds a complex polygon to draw - * - * @static - * @private - * @param graphicsData {Graphics} The graphics object containing all the necessary properties - * @param webGLData {object} - */ -WebGLGraphics.buildComplexPoly = function (graphicsData, webGLData) { - //TODO - no need to copy this as it gets turned into a FLoat32Array anyways.. - var points = graphicsData.points.slice(); - - if (points.length < 6) { - return; - } - - // get first and last point.. figure out the middle! - var indices = webGLData.indices; - webGLData.points = points; - webGLData.alpha = graphicsData.fillAlpha; - webGLData.color = utils.hex2rgb(graphicsData.fillColor); - - // calclate the bounds.. - var minX = Infinity; - var maxX = -Infinity; - - var minY = Infinity; - var maxY = -Infinity; - - var x,y; - - // get size.. - for (var i = 0; i < points.length; i+=2) { - x = points[i]; - y = points[i+1]; - - minX = x < minX ? x : minX; - maxX = x > maxX ? x : maxX; - - minY = y < minY ? y : minY; - maxY = y > maxY ? y : maxY; - } - - // add a quad to the end cos there is no point making another buffer! - points.push(minX, minY, - maxX, minY, - maxX, maxY, - minX, maxY); - - // push a quad onto the end.. - - //TODO - this aint needed! - var length = points.length / 2; - for (i = 0; i < length; i++) { - indices.push( i ); - } - -}; - -/** - * Builds a polygon to draw - * - * @static - * @private - * @param graphicsData {Graphics} The graphics object containing all the necessary properties - * @param webGLData {object} - */ -WebGLGraphics.buildPoly = function (graphicsData, webGLData) { - var points = graphicsData.points; - - if (points.length < 6) { - return; - } - // get first and last point.. figure out the middle! - var verts = webGLData.points; - var indices = webGLData.indices; - - var length = points.length / 2; - - // sort color - var color = utils.hex2rgb(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var triangles = utils.PolyK.Triangulate(points); - - if (!triangles) { - return false; - } - - var vertPos = verts.length / 6; - - var i = 0; - - for (i = 0; i < triangles.length; i+=3) { - indices.push(triangles[i] + vertPos); - indices.push(triangles[i] + vertPos); - indices.push(triangles[i+1] + vertPos); - indices.push(triangles[i+2] +vertPos); - indices.push(triangles[i+2] + vertPos); - } - - for (i = 0; i < length; i++) { - verts.push(points[i * 2], points[i * 2 + 1], - r, g, b, alpha); - } - - return true; -}; - -WebGLGraphics.graphicsDataPool = []; - -},{"../../../const":4,"../../../math":12,"../../../utils":50,"./WebGLGraphicsData":40}],40:[function(require,module,exports){ -/** - * @class - * @private - */ -function WebGLGraphicsData(gl) { - this.gl = gl; - - //TODO does this need to be split before uploding?? - this.color = [0, 0, 0]; // color split! - this.points = []; - this.indices = []; - this.buffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - this.mode = 1; - this.alpha = 1; - this.dirty = true; -} - -WebGLGraphicsData.prototype.constructor = WebGLGraphicsData; -module.exports = WebGLGraphicsData; - -/** - * - */ -WebGLGraphicsData.prototype.reset = function () { - this.points.length = 0; - this.indices.length = 0; -}; - -/** - * - */ -WebGLGraphicsData.prototype.upload = function () { - var gl = this.gl; - -// this.lastIndex = graphics.graphicsData.length; - this.glPoints = new Float32Array(this.points); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer); - gl.bufferData(gl.ARRAY_BUFFER, this.glPoints, gl.STATIC_DRAW); - - this.glIndicies = new Uint16Array(this.indices); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.glIndicies, gl.STATIC_DRAW); - - this.dirty = false; -}; - -},{}],41:[function(require,module,exports){ -var TextureUvs = require('../../../textures/TextureUvs'), - Shader = require('../shaders/Shader'); - -/** - * @author Mat Groves - * - * Big thanks to the very clever Matt DesLauriers https://github.com/mattdesl/ - * for creating the original pixi version! - * Also a thanks to https://github.com/bchevalier for tweaking the tint and alpha so that they now share 4 bytes on the vertex buffer - * - * Heavily inspired by LibGDX's WebGLSpriteBatch: - * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java - */ - -/** - * - * @class - * @private - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this sprite batch works for. - */ -function WebGLSpriteBatch(renderer) { - /** - * - * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * - * @member {number} - */ - this.vertSize = 5; - - /** - * The number of images in the SpriteBatch before it flushes. - * - * @member {number} - */ - this.size = 2000;//Math.pow(2, 16) / this.vertSize; - - // the total number of bytes in our batch - var numVerts = this.size * 4 * 4 * this.vertSize; - // the total number of indices in our batch - var numIndices = this.size * 6; - - /** - * Holds the vertices - * - * @member {ArrayBuffer} - */ - this.vertices = new ArrayBuffer(numVerts); - - /** - * View on the vertices as a Float32Array - * - * @member {Float32Array} - */ - this.positions = new Float32Array(this.vertices); - - /** - * View on the vertices as a Uint32Array - * - * @member {Uint32Array} - */ - this.colors = new Uint32Array(this.vertices); - - /** - * Holds the indices - * - * @member {Uint16Array} - */ - this.indices = new Uint16Array(numIndices); - - /** - * - * - * @member {number} - */ - this.lastIndexCount = 0; - - for (var i=0, j=0; i < numIndices; i += 6, j += 4) { - this.indices[i + 0] = j + 0; - this.indices[i + 1] = j + 1; - this.indices[i + 2] = j + 2; - this.indices[i + 3] = j + 0; - this.indices[i + 4] = j + 2; - this.indices[i + 5] = j + 3; - } - - /** - * - * - * @member {boolean} - */ - this.drawing = false; - - /** - * - * - * @member {number} - */ - this.currentBatchSize = 0; - - /** - * - * - * @member {BaseTexture} - */ - this.currentBaseTexture = null; - - /** - * - * - * @member {boolean} - */ - this.dirty = true; - - /** - * - * - * @member {Array} - */ - this.textures = []; - - /** - * - * - * @member {Array} - */ - this.blendModes = []; - - /** - * - * - * @member {Array} - */ - this.shaders = []; - - /** - * - * - * @member {Array} - */ - this.sprites = []; - - /** - * The default shader that is used if a sprite doesn't have a more specific one. - * - * @member {Shader} - */ - this.shader = null; - - // listen for context and update necessary buffers - var self = this; - this.renderer.on('context', function () { - self.setupContext(); - }); -} - -WebGLSpriteBatch.prototype.constructor = WebGLSpriteBatch; -module.exports = WebGLSpriteBatch; - -/** - * @param gl {WebGLContext} the current WebGL drawing context - */ -WebGLSpriteBatch.prototype.setupContext = function () { - var gl = this.renderer.gl; - - // setup default shader - this.shader = new Shader(gl); - - // create a couple of buffers - this.vertexBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - - // 65535 is max index, so 65535 / 6 = 10922. - - //upload the index data - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW); - - this.currentBlendMode = 99999; -}; - -/** - * - */ -WebGLSpriteBatch.prototype.begin = function () { - // this.shader = this.renderer.shaderManager.defaultShader; - - this.start(); -}; - -/** - */ -WebGLSpriteBatch.prototype.end = function () { - this.flush(); -}; - -/** - * @param sprite {Sprite} the sprite to render when using this spritebatch - */ -WebGLSpriteBatch.prototype.render = function (sprite) { - var texture = sprite.texture; - - //TODO set blend modes.. - // check texture.. - if (this.currentBatchSize >= this.size) { - this.flush(); - this.currentBaseTexture = texture.baseTexture; - } - - // get the uvs for the texture - var uvs = texture._uvs; - - // if the uvs have not updated then no point rendering just yet! - if (!uvs) { - return; - } - - // TODO trim?? - var aX = sprite.anchor.x; - var aY = sprite.anchor.y; - - var w0, w1, h0, h1; - - if (texture.trim) { - // if the sprite is trimmed then we need to add the extra space before transforming the sprite coords.. - var trim = texture.trim; - - w1 = trim.x - aX * trim.width; - w0 = w1 + texture.crop.width; - - h1 = trim.y - aY * trim.height; - h0 = h1 + texture.crop.height; - - } - else { - w0 = (texture.frame.width ) * (1-aX); - w1 = (texture.frame.width ) * -aX; - - h0 = texture.frame.height * (1-aY); - h1 = texture.frame.height * -aY; - } - - var index = this.currentBatchSize * 4 * this.vertSize; - - var resolution = texture.baseTexture.resolution; - - var worldTransform = sprite.worldTransform; - - var a = worldTransform.a / resolution; - var b = worldTransform.b / resolution; - var c = worldTransform.c / resolution; - var d = worldTransform.d / resolution; - var tx = worldTransform.tx; - var ty = worldTransform.ty; - - var colors = this.colors; - var positions = this.positions; - - if (this.renderer.roundPixels) { - // xy - positions[index] = a * w1 + c * h1 + tx | 0; - positions[index+1] = d * h1 + b * w1 + ty | 0; - - // xy - positions[index+5] = a * w0 + c * h1 + tx | 0; - positions[index+6] = d * h1 + b * w0 + ty | 0; - - // xy - positions[index+10] = a * w0 + c * h0 + tx | 0; - positions[index+11] = d * h0 + b * w0 + ty | 0; - - // xy - positions[index+15] = a * w1 + c * h0 + tx | 0; - positions[index+16] = d * h0 + b * w1 + ty | 0; - } - else { - // xy - positions[index] = a * w1 + c * h1 + tx; - positions[index+1] = d * h1 + b * w1 + ty; - - // xy - positions[index+5] = a * w0 + c * h1 + tx; - positions[index+6] = d * h1 + b * w0 + ty; - - // xy - positions[index+10] = a * w0 + c * h0 + tx; - positions[index+11] = d * h0 + b * w0 + ty; - - // xy - positions[index+15] = a * w1 + c * h0 + tx; - positions[index+16] = d * h0 + b * w1 + ty; - } - - // uv - positions[index+2] = uvs.x0; - positions[index+3] = uvs.y0; - - // uv - positions[index+7] = uvs.x1; - positions[index+8] = uvs.y1; - - // uv - positions[index+12] = uvs.x2; - positions[index+13] = uvs.y2; - - // uv - positions[index+17] = uvs.x3; - positions[index+18] = uvs.y3; - - // color and alpha - var tint = sprite.tint; - colors[index+4] = colors[index+9] = colors[index+14] = colors[index+19] = (tint >> 16) + (tint & 0xff00) + ((tint & 0xff) << 16) + (sprite.worldAlpha * 255 << 24); - - // increment the batchsize - this.sprites[this.currentBatchSize++] = sprite; - - -}; - -/** - * Renders a TilingSprite using the spriteBatch. - * - * @param sprite {TilingSprite} the tilingSprite to render - */ -WebGLSpriteBatch.prototype.renderTilingSprite = function (tilingSprite) { - var texture = tilingSprite.tilingTexture; - - // check texture.. - if (this.currentBatchSize >= this.size) { - //return; - this.flush(); - this.currentBaseTexture = texture.baseTexture; - } - - // set the textures uvs temporarily - // TODO create a separate texture so that we can tile part of a texture - - if (!tilingSprite._uvs) { - tilingSprite._uvs = new TextureUvs(); - } - - var uvs = tilingSprite._uvs; - - tilingSprite.tilePosition.x %= texture.baseTexture.width * tilingSprite.tileScaleOffset.x; - tilingSprite.tilePosition.y %= texture.baseTexture.height * tilingSprite.tileScaleOffset.y; - - var offsetX = tilingSprite.tilePosition.x/(texture.baseTexture.width*tilingSprite.tileScaleOffset.x); - var offsetY = tilingSprite.tilePosition.y/(texture.baseTexture.height*tilingSprite.tileScaleOffset.y); - - var scaleX = (tilingSprite.width / texture.baseTexture.width) / (tilingSprite.tileScale.x * tilingSprite.tileScaleOffset.x); - var scaleY = (tilingSprite.height / texture.baseTexture.height) / (tilingSprite.tileScale.y * tilingSprite.tileScaleOffset.y); - - uvs.x0 = 0 - offsetX; - uvs.y0 = 0 - offsetY; - - uvs.x1 = (1 * scaleX) - offsetX; - uvs.y1 = 0 - offsetY; - - uvs.x2 = (1 * scaleX) - offsetX; - uvs.y2 = (1 * scaleY) - offsetY; - - uvs.x3 = 0 - offsetX; - uvs.y3 = (1 * scaleY) - offsetY; - - // get the tilingSprites current alpha and tint and combining them into a single color - var tint = tilingSprite.tint; - var color = (tint >> 16) + (tint & 0xff00) + ((tint & 0xff) << 16) + (tilingSprite.alpha * 255 << 24); - - var positions = this.positions; - var colors = this.colors; - - var width = tilingSprite.width; - var height = tilingSprite.height; - - // TODO trim?? - var aX = tilingSprite.anchor.x; - var aY = tilingSprite.anchor.y; - var w0 = width * (1-aX); - var w1 = width * -aX; - - var h0 = height * (1-aY); - var h1 = height * -aY; - - var index = this.currentBatchSize * 4 * this.vertSize; - - var resolution = texture.baseTexture.resolution; - - var worldTransform = tilingSprite.worldTransform; - - var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.b / resolution;//[3]; - var c = worldTransform.c / resolution;//[1]; - var d = worldTransform.d / resolution;//[4]; - var tx = worldTransform.tx;//[2]; - var ty = worldTransform.ty;//[5]; - - // xy - positions[index++] = a * w1 + c * h1 + tx; - positions[index++] = d * h1 + b * w1 + ty; - // uv - positions[index++] = uvs.x0; - positions[index++] = uvs.y0; - // color - colors[index++] = color; - - // xy - positions[index++] = (a * w0 + c * h1 + tx); - positions[index++] = d * h1 + b * w0 + ty; - // uv - positions[index++] = uvs.x1; - positions[index++] = uvs.y1; - // color - colors[index++] = color; - - // xy - positions[index++] = a * w0 + c * h0 + tx; - positions[index++] = d * h0 + b * w0 + ty; - // uv - positions[index++] = uvs.x2; - positions[index++] = uvs.y2; - // color - colors[index++] = color; - - // xy - positions[index++] = a * w1 + c * h0 + tx; - positions[index++] = d * h0 + b * w1 + ty; - // uv - positions[index++] = uvs.x3; - positions[index++] = uvs.y3; - // color - colors[index++] = color; - - // increment the batchsize - this.sprites[this.currentBatchSize++] = tilingSprite; -}; - -/** - * Renders the content and empties the current batch. - * - */ -WebGLSpriteBatch.prototype.flush = function () { - // If the batch is length 0 then return as there is nothing to draw - if (this.currentBatchSize === 0) { - return; - } - - var gl = this.renderer.gl; - var shader; - - if (this.dirty) { - this.dirty = false; - // bind the main texture - gl.activeTexture(gl.TEXTURE0); - - // bind the buffers - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - // this is the same for each shader? - var stride = this.vertSize * 4; - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); - - // color attributes will be interpreted as unsigned bytes and normalized - gl.vertexAttribPointer(this.shader.attributes.aColor, 4, gl.UNSIGNED_BYTE, true, stride, 4 * 4); - } - - // upload the verts to the buffer - if (this.currentBatchSize > ( this.size * 0.5 ) ) { - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); - } - else { - var view = this.positions.subarray(0, this.currentBatchSize * 4 * this.vertSize); - gl.bufferSubData(gl.ARRAY_BUFFER, 0, view); - } - - var nextTexture, nextBlendMode, nextShader; - var batchSize = 0; - var start = 0; - - var currentBaseTexture = null; - var currentBlendMode = this.renderer.blendModeManager.currentBlendMode; - var currentShader = null; - - var blendSwap = false; - var shaderSwap = false; - var sprite; - - for (var i = 0, j = this.currentBatchSize; i < j; i++) { - - sprite = this.sprites[i]; - - nextTexture = sprite.texture.baseTexture; - nextBlendMode = sprite.blendMode; - nextShader = sprite.shader || this.shader; - - blendSwap = currentBlendMode !== nextBlendMode; - shaderSwap = currentShader !== nextShader; // should I use uuidS??? - - if (currentBaseTexture !== nextTexture || blendSwap || shaderSwap) { - this.renderBatch(currentBaseTexture, batchSize, start); - - start = i; - batchSize = 0; - currentBaseTexture = nextTexture; - - if (blendSwap) { - currentBlendMode = nextBlendMode; - this.renderer.blendModeManager.setBlendMode( currentBlendMode ); - } - - if (shaderSwap) { - currentShader = nextShader; - - shader = currentShader.shaders ? currentShader.shaders[gl.id] : currentShader; - - if (!shader) { - shader = new Shader(gl, null, currentShader.fragmentSrc, currentShader.uniforms); - currentShader.shaders[gl.id] = shader; - } - - // set shader function??? - this.renderer.shaderManager.setShader(shader); - - if (shader.dirty) { - shader.syncUniforms(); - } - - // both thease only need to be set if they are changing.. - // set the projection - var projection = this.renderer.projection; - gl.uniform2f(shader.uniforms.projectionVector._location, projection.x, projection.y); - - // TODO - this is temprorary! - var offsetVector = this.renderer.offset; - gl.uniform2f(shader.uniforms.offsetVector._location, offsetVector.x, offsetVector.y); - - // set the pointers - } - } - - batchSize++; - } - - this.renderBatch(currentBaseTexture, batchSize, start); - - // then reset the batch! - this.currentBatchSize = 0; -}; - -/** - * @param texture {Texture} - * @param size {number} - * @param startIndex {number} - */ -WebGLSpriteBatch.prototype.renderBatch = function (texture, size, startIndex) { - if (size === 0) { - return; - } - - var gl = this.renderer.gl; - - if (!texture._glTextures[gl.id]) { - this.renderer.updateTexture(texture); - } - else { - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - } - - // now draw those suckas! - gl.drawElements(gl.TRIANGLES, size * 6, gl.UNSIGNED_SHORT, startIndex * 6 * 2); - - // increment the draw count - this.renderer.drawCount++; -}; - -/** - * - */ -WebGLSpriteBatch.prototype.stop = function () { - this.flush(); - this.dirty = true; -}; - -/** - * - */ -WebGLSpriteBatch.prototype.start = function () { - this.dirty = true; -}; - -/** - * Destroys the SpriteBatch. - * - */ -WebGLSpriteBatch.prototype.destroy = function () { - this.renderer.gl.deleteBuffer(this.vertexBuffer); - this.renderer.gl.deleteBuffer(this.indexBuffer); - - this.vertices = null; - this.indices = null; - - this.vertexBuffer = null; - this.indexBuffer = null; - - this.currentBaseTexture = null; - - this.renderer = null; -}; - -},{"../../../textures/TextureUvs":45,"../shaders/Shader":35}],42:[function(require,module,exports){ -var utils = require('../utils'), - CONST = require('../const'); - -/** - * A texture stores the information that represents an image. All textures have a base texture. - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param source {Image|Canvas} the source object of the texture. - * @param [scaleMode=scaleModes.DEFAULT] {number} See {@link scaleModes} for possible values - */ -function BaseTexture(source, scaleMode) { - this.uuid = utils.uuid(); - - /** - * The Resolution of the texture. - * - * @member {number} - */ - this.resolution = 1; - - /** - * The width of the base texture set when the image has loaded - * - * @member {number} - * @readOnly - */ - this.width = 100; - - /** - * The height of the base texture set when the image has loaded - * - * @member {number} - * @readOnly - */ - this.height = 100; - - /** - * The scale mode to apply when scaling this texture - * - * @member {{number}} - * @default scaleModes.LINEAR - */ - this.scaleMode = scaleMode || CONST.scaleModes.DEFAULT; - - /** - * Set to true once the base texture has successfully loaded. - * - * This is never true if the underlying source fails to load or has no texture data. - * - * @member {boolean} - * @readOnly - */ - this.hasLoaded = false; - - /** - * Set to true if the source is currently loading. - * - * If an Image source is loading the 'loaded' or 'error' event will be - * dispatched when the operation ends. An underyling source that is - * immediately-available bypasses loading entirely. - * - * @member {boolean} - * @readonly - */ - this.isLoading = false; - - /** - * The image source that is used to create the texture. - * - * TODO: Make this a setter that calls loadSource(); - * - * @member {Image|Canvas} - * @readonly - */ - this.source = null; // set in loadSource, if at all - - /** - * Controls if RGB channels should be pre-multiplied by Alpha (WebGL only) - * - * @member {boolean} - * @default true - */ - this.premultipliedAlpha = true; - - /** - * @member {string} - */ - this.imageUrl = null; - - /** - * @member {boolean} - * @private - */ - this._powerOf2 = false; - - // used for webGL - - /** - * - * Set this to true if a mipmap of this texture needs to be generated. This value needs to be set before the texture is used - * Also the texture must be a power of two size to work - * - * @member {boolean} - */ - this.mipmap = false; - - /** - * A map of renderer IDs to webgl textures - * - * @member {object} - * @private - */ - this._glTextures = {}; - - /** - * Does the texture on the GPU need to be updated? - * - * @member {boolean} - * @private - */ - this._needsUpdate = false; - - // if no source passed don't try to load - if (source) { - this.loadSource(source); - } - - /** - * Fired when a not-immediately-available source finishes loading. - * - * @event loaded - * @protected - */ - - /** - * Fired when a not-immediately-available source fails to load. - * - * @event error - * @protected - */ -} - -BaseTexture.prototype.constructor = BaseTexture; -module.exports = BaseTexture; - -utils.eventTarget.mixin(BaseTexture.prototype); - -Object.defineProperties(BaseTexture.prototype, { - needsUpdate: { - get: function () { - return this._needsUpdate; - }, - set: function (val) { - this._needsUpdate = val; - - if (val) { - this.emit('update', this); - } - } - } -}); - -/** - * Load a source. - * - * If the source is not-immediately-available, such as an image that needs to be - * downloaded, then the 'loaded' or 'error' event will be dispatched in the future - * and `hasLoaded` will remain false after this call. - * - * The logic state after calling `loadSource` directly or indirectly (eg. `fromImage`, `new BaseTexture`) is: - * - * if (texture.hasLoaded) { - * // texture ready for use - * } else if (texture.isLoading) { - * // listen to 'loaded' and/or 'error' events on texture - * } else { - * // not loading, not going to load UNLESS the source is reloaded - * // (it may still make sense to listen to the events) - * } - * - * @protected - * @param source {Image|Canvas} the source object of the texture. - */ -BaseTexture.prototype.loadSource = function (source) { - var wasLoading = this.isLoading; - this.hasLoaded = false; - this.isLoading = false; - - if (wasLoading && this.source) { - this.source.onload = null; - this.source.onerror = null; - } - - this.source = source; - - // Apply source if loaded. Otherwise setup appropriate loading monitors. - if ((this.source.complete || this.source.getContext) && this.source.width && this.source.height) { - this._sourceLoaded(); - } - else if(!source.getContext) { - // Image fail / not ready - this.isLoading = true; - - var scope = this; - - source.onload = function () { - source.onload = null; - source.onerror = null; - - if(!scope.isLoading) { - return; - } - - scope.isLoading = false; - scope._sourceLoaded(); - - scope.emit('loaded', scope); - }; - - source.onerror = function () { - source.onload = null; - source.onerror = null; - - if(!scope.isLoading) { - return; - } - - scope.isLoading = false; - scope.emit('error', scope); - }; - - // Per http://www.w3.org/TR/html5/embedded-content-0.html#the-img-element - // "The value of `complete` can thus change while a script is executing." - // So complete needs to be re-checked after the callbacks have been added.. - if (source.complete) { - this.isLoading = false; - - // ..and if we're complete now, no need for callbacks - source.onload = null; - source.onerror = null; - - if (source.width && source.height) { - this._sourceLoaded(); - - // If any previous subscribers possible - if (wasLoading) { - this.emit('loaded', this); - } - } - else { - // If any previous subscribers possible - if (wasLoading) { - this.emit('error', this); - } - } - } - } -}; - -/** - * Used internally to update the width, height, and some other tracking vars once - * a source has successfully loaded. - * - * @private - */ -BaseTexture.prototype._sourceLoaded = function () { - this.hasLoaded = true; - - this.width = this.source.naturalWidth || this.source.width; - this.height = this.source.naturalHeight || this.source.height; - - this.needsUpdate = true; -}; - -/** - * Destroys this base texture - * - */ -BaseTexture.prototype.destroy = function () { - if (this.imageUrl) { - delete utils.BaseTextureCache[this.imageUrl]; - delete utils.TextureCache[this.imageUrl]; - this.imageUrl = null; - if (!navigator.isCocoonJS) { - this.source.src = ''; - } - } - else if (this.source && this.source._pixiId) { - delete utils.BaseTextureCache[this.source._pixiId]; - } - this.source = null; - - this.dispose(); -}; - -/** - * Frees the texture from WebGL memory without destroying this texture object. - * This means you can still use the texture later which will upload it to GPU - * memory again. - * - */ -BaseTexture.prototype.dispose = function () { - this.emit('dispose', this); -}; - -/** - * Changes the source image of the texture. - * The original source must be an Image element. - * - * @param newSrc {string} the path of the image - */ -BaseTexture.prototype.updateSourceImage = function (newSrc) { - this.source.src = newSrc; - this.loadSource(this.source); -}; - -/** - * Helper function that creates a base texture from the given image url. - * If the image is not in the base texture cache it will be created and loaded. - * - * @static - * @param imageUrl {string} The image url of the texture - * @param [crossorigin=(auto)] {boolean} Should use anonymouse CORS? Defaults to true if the URL is not a data-URI. - * @param [scaleMode=scaleModes.DEFAULT] {number} See {@link scaleModes} for possible values - * @return BaseTexture - */ -BaseTexture.fromImage = function (imageUrl, crossorigin, scaleMode) { - var baseTexture = utils.BaseTextureCache[imageUrl]; - - if (crossorigin === undefined && imageUrl.indexOf('data:') !== 0) { - crossorigin = true; - } - - if (!baseTexture) { - // new Image() breaks tex loading in some versions of Chrome. - // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); - if (crossorigin) { - image.crossOrigin = ''; - } - - image.src = imageUrl; - baseTexture = new BaseTexture(image, scaleMode); - baseTexture.imageUrl = imageUrl; - utils.BaseTextureCache[imageUrl] = baseTexture; - - // if there is an @2x at the end of the url we are going to assume its a highres image - if ( imageUrl.indexOf(CONST.RETINA_PREFIX + '.') !== -1) { - baseTexture.resolution = 2; - } - } - - return baseTexture; -}; - -/** - * Helper function that creates a base texture from the given canvas element. - * - * @static - * @param canvas {Canvas} The canvas element source of the texture - * @param scaleMode {number} See {{#crossLink "PIXI/scaleModes:property"}}scaleModes{{/crossLink}} for possible values - * @return BaseTexture - */ -BaseTexture.fromCanvas = function (canvas, scaleMode) { - if (!canvas._pixiId) { - canvas._pixiId = 'canvas_' + utils.uuid(); - } - - var baseTexture = utils.BaseTextureCache[canvas._pixiId]; - - if (!baseTexture) { - baseTexture = new BaseTexture(canvas, scaleMode); - utils.BaseTextureCache[canvas._pixiId] = baseTexture; - } - - return baseTexture; -}; - -},{"../const":4,"../utils":50}],43:[function(require,module,exports){ -var BaseTexture = require('./BaseTexture'), - Texture = require('./Texture'), - FilterTexture = require('../renderers/webgl/utils/FilterTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), - math = require('../math'), - CONST = require('../const'); - -/** - * A RenderTexture is a special texture that allows any Pixi display object to be rendered to it. - * - * __Hint__: All DisplayObjects (i.e. Sprites) that render to a RenderTexture should be preloaded - * otherwise black rectangles will be drawn instead. - * - * A RenderTexture takes a snapshot of any Display Object given to its render method. The position - * and rotation of the given Display Objects is ignored. For example: - * - * ```js - * var renderTexture = new PIXI.RenderTexture(800, 600); - * var sprite = PIXI.Sprite.fromImage("spinObj_01.png"); - * - * sprite.position.x = 800/2; - * sprite.position.y = 600/2; - * sprite.anchor.x = 0.5; - * sprite.anchor.y = 0.5; - * - * renderTexture.render(sprite); - * ``` - * - * The Sprite in this case will be rendered to a position of 0,0. To render this sprite at its actual - * position a DisplayObjectContainer should be used: - * - * ```js - * var doc = new DisplayObjectContainer(); - * - * doc.addChild(sprite); - * - * renderTexture.render(doc); // Renders to center of renderTexture - * ``` - * - * @class - * @extends Texture - * @namespace PIXI - * @param renderer {CanvasRenderer|WebGLRenderer} The renderer used for this RenderTexture - * @param [width=100] {number} The width of the render texture - * @param [height=100] {number} The height of the render texture - * @param [scaleMode] {number} See {@link scaleModes} for possible values - * @param [resolution=1] {number} The resolution of the texture being generated - */ -function RenderTexture(renderer, width, height, scaleMode, resolution) { - if (!renderer) { - throw new Error('Unable to create RenderTexture, you must pass a renderer into the constructor.'); - } - - /** - * The with of the render texture - * - * @member {number} - */ - this.width = width || 100; - - /** - * The height of the render texture - * - * @member {number} - */ - this.height = height || 100; - - /** - * The Resolution of the texture. - * - * @member {number} - */ - this.resolution = resolution || 1; - - /** - * The framing rectangle of the render texture - * - * @member {Rectangle} - */ - this.frame = new math.Rectangle(0, 0, this.width * this.resolution, this.height * this.resolution); - - /** - * This is the area of the BaseTexture image to actually copy to the Canvas / WebGL when rendering, - * irrespective of the actual frame size or placement (which can be influenced by trimmed texture atlases) - * - * @member {Rectangle} - */ - this.crop = new math.Rectangle(0, 0, this.width * this.resolution, this.height * this.resolution); - - /** - * Draw/render the given DisplayObject onto the texture. - * - * The displayObject and descendents are transformed during this operation. - * If `restoreWorldTransform` is true then the transformations will be restored before the - * method returns. Otherwise it is up to the calling code to correctly use or reset - * the transformed display objects. - * - * The display object is always rendered with a worldAlpha value of 1. - * - * @method - * @param displayObject {DisplayObject} The display object to render this texture on - * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering. - * @param [clear=false] {boolean} If true the texture will be cleared before the displayObject is drawn - * @param [restoreWorldTransform=true] {boolean} If true the displayObject's worldTransform/worldAlpha and all children - * transformations will be restored. Not restoring this information will be a little faster. - */ - this.render = null; - - /** - * The base texture object that this texture uses - * - * @member {BaseTexture} - */ - this.baseTexture = new BaseTexture(); - this.baseTexture.width = this.width * this.resolution; - this.baseTexture.height = this.height * this.resolution; - this.baseTexture._glTextures = []; - this.baseTexture.resolution = this.resolution; - - this.baseTexture.scaleMode = scaleMode || CONST.scaleModes.DEFAULT; - - this.baseTexture.hasLoaded = true; - - Texture.call(this, - this.baseTexture, - new math.Rectangle(0, 0, this.width, this.height) - ); - - /** - * The renderer this RenderTexture uses. A RenderTexture can only belong to one renderer at the moment if its webGL. - * - * @member {CanvasRenderer|WebGLRenderer} - */ - this.renderer = renderer; - - if (this.renderer.type === CONST.WEBGL_RENDERER) { - var gl = this.renderer.gl; - - this.textureBuffer = new FilterTexture(gl, this.width * this.resolution, this.height * this.resolution, this.baseTexture.scaleMode); - this.baseTexture._glTextures[gl.id] = this.textureBuffer.texture; - - this.render = this.renderWebGL; - this.projection = new math.Point(this.width*0.5, -this.height*0.5); - } - else { - this.render = this.renderCanvas; - this.textureBuffer = new CanvasBuffer(this.width* this.resolution, this.height* this.resolution); - this.baseTexture.source = this.textureBuffer.canvas; - } - - /** - * @member {boolean} - */ - this.valid = true; - - this._updateUvs(); -} - -RenderTexture.prototype = Object.create(Texture.prototype); -RenderTexture.prototype.constructor = RenderTexture; -module.exports = RenderTexture; - -/** - * Resizes the RenderTexture. - * - * @param width {number} The width to resize to. - * @param height {number} The height to resize to. - * @param updateBase {boolean} Should the baseTexture.width and height values be resized as well? - */ -RenderTexture.prototype.resize = function (width, height, updateBase) { - if (width === this.width && height === this.height) { - return; - } - - this.valid = (width > 0 && height > 0); - - this.width = this.frame.width = this.crop.width = width; - this.height = this.frame.height = this.crop.height = height; - - if (updateBase) { - this.baseTexture.width = this.width; - this.baseTexture.height = this.height; - } - - if (this.renderer.type === CONST.WEBGL_RENDERER) { - this.projection.x = this.width / 2; - this.projection.y = -this.height / 2; - } - - if (!this.valid) { - return; - } - - this.textureBuffer.resize(this.width * this.resolution, this.height * this.resolution); -}; - -/** - * Clears the RenderTexture. - * - */ -RenderTexture.prototype.clear = function () { - if (!this.valid) { - return; - } - - if (this.renderer.type === CONST.WEBGL_RENDERER) { - this.renderer.gl.bindFramebuffer(this.renderer.gl.FRAMEBUFFER, this.textureBuffer.frameBuffer); - } - - this.textureBuffer.clear(); -}; - -/** - * Internal method assigned to the `render` property if using a CanvasRenderer. - * - * @private - * @param displayObject {DisplayObject} The display object to render this texture on - * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering. - * @param [clear=false] {boolean} If true the texture will be cleared before the displayObject is drawn - * @param [restoreWorldTransform=true] {boolean} If true the displayObject's worldTransform/worldAlpha and all children - * transformations will be restored. Not restoring this information will be a little faster. - */ -RenderTexture.prototype.renderWebGL = function (displayObject, matrix, clear, restoreWorldTransform) { - if (!this.valid) { - return; - } - - if (typeof restoreWorldTransform === 'undefined') { - restoreWorldTransform = true; - } - - var tempAlpha, - tempTransform; - - if (restoreWorldTransform) { - tempAlpha = displayObject.worldAlpha; - tempTransform = displayObject.worldTransform.toArray(); - } - - //TOOD replace position with matrix.. - - //Lets create a nice matrix to apply to our display object. Frame buffers come in upside down so we need to flip the matrix - var wt = displayObject.worldTransform; - - wt.identity(); - wt.translate(0, this.projection.y * 2); - - if (matrix) { - wt.append(matrix); - } - - wt.scale(1,-1); - - // setWorld Alpha to ensure that the object is renderer at full opacity - displayObject.worldAlpha = 1; - - // Time to update all the children of the displayObject with the new matrix.. - var children = displayObject.children; - var i, j; - - for (i = 0, j = children.length; i < j; ++i) { - children[i].updateTransform(); - } - - // time for the webGL fun stuff! - var gl = this.renderer.gl; - - gl.viewport(0, 0, this.width * this.resolution, this.height * this.resolution); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.textureBuffer.frameBuffer ); - - if (clear) { - this.textureBuffer.clear(); - } - - this.renderer.spriteBatch.dirty = true; - - this.renderer.renderDisplayObject(displayObject, this.projection, this.textureBuffer.frameBuffer); - - this.renderer.spriteBatch.dirty = true; - - if (restoreWorldTransform) { - displayObject.worldAlpha = tempAlpha; - displayObject.worldTransform.fromArray(tempTransform); - - for (i = 0, j = children.length; i < j; ++i) { - children[i].updateTransform(); - } - } -}; - - -/** - * Internal method assigned to the `render` property if using a CanvasRenderer. - * - * @private - * @param displayObject {DisplayObject} The display object to render this texture on - * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering. - * @param [clear] {boolean} If true the texture will be cleared before the displayObject is drawn - * @param [restoreWorldTransform=true] {boolean} If true the displayObject's worldTransform/worldAlpha and all children - * transformations will be restored. Not restoring this information will be a little faster. - */ -RenderTexture.prototype.renderCanvas = function (displayObject, matrix, clear, restoreWorldTransform) { - if (!this.valid) { - return; - } - - if (typeof restoreWorldTransform === 'undefined') { - restoreWorldTransform = true; - } - - var tempAlpha, - tempTransform; - - if (restoreWorldTransform) { - tempAlpha = displayObject.worldAlpha; - tempTransform = displayObject.worldTransform.toArray(); - } - - var wt = displayObject.worldTransform; - wt.identity(); - if (matrix) { - wt.append(matrix); - } - - // setWorld Alpha to ensure that the object is renderer at full opacity - displayObject.worldAlpha = 1; - - // Time to update all the children of the displayObject with the new matrix.. - var children = displayObject.children; - var i, j; - - for (i = 0, j = children.length; i < j; ++i) { - children[i].updateTransform(); - } - - if (clear) { - this.textureBuffer.clear(); - } - - var context = this.textureBuffer.context; - - var realResolution = this.renderer.resolution; - - this.renderer.resolution = this.resolution; - - this.renderer.renderDisplayObject(displayObject, context); - - this.renderer.resolution = realResolution; - - if (restoreWorldTransform) { - displayObject.worldAlpha = tempAlpha; - displayObject.worldTransform.fromArray(tempTransform); - - for (i = 0, j = children.length; i < j; ++i) { - children[i].updateTransform(); - } - } -}; - -/** - * Will return a HTML Image of the texture - * - * @return {Image} - */ -RenderTexture.prototype.getImage = function () { - var image = new Image(); - image.src = this.getBase64(); - return image; -}; - -/** - * Will return a a base64 encoded string of this texture. It works by calling RenderTexture.getCanvas and then running toDataURL on that. - * - * @return {string} A base64 encoded string of the texture. - */ -RenderTexture.prototype.getBase64 = function () { - return this.getCanvas().toDataURL(); -}; - -/** - * Creates a Canvas element, renders this RenderTexture to it and then returns it. - * - * @return {HTMLCanvasElement} A Canvas element with the texture rendered on. - */ -RenderTexture.prototype.getCanvas = function () { - if (this.renderer.type === CONST.WEBGL_RENDERER) { - var gl = this.renderer.gl; - var width = this.textureBuffer.width; - var height = this.textureBuffer.height; - - var webGLPixels = new Uint8Array(4 * width * height); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.textureBuffer.frameBuffer); - gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, webGLPixels); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - var tempCanvas = new CanvasBuffer(width, height); - var canvasData = tempCanvas.context.getImageData(0, 0, width, height); - canvasData.data.set(webGLPixels); - - tempCanvas.context.putImageData(canvasData, 0, 0); - - return tempCanvas.canvas; - } - else { - return this.textureBuffer.canvas; - } -}; - -},{"../const":4,"../math":12,"../renderers/canvas/utils/CanvasBuffer":21,"../renderers/webgl/utils/FilterTexture":37,"./BaseTexture":42,"./Texture":44}],44:[function(require,module,exports){ -var BaseTexture = require('./BaseTexture'), - VideoBaseTexture = require('./VideoBaseTexture'), - TextureUvs = require('./TextureUvs'), - eventTarget = require('../utils/eventTarget'), - math = require('../math'), - utils = require('../utils'); - -/** - * A texture stores the information that represents an image or part of an image. It cannot be added - * to the display list directly. Instead use it as the texture for a Sprite. If no frame is provided then the whole image is used. - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param [frame] {Rectangle} The rectangle frame of the texture to show - * @param [crop] {Rectangle} The area of original texture - * @param [trim] {Rectangle} Trimmed texture rectangle - */ -function Texture(baseTexture, frame, crop, trim) { - /** - * Does this Texture have any frame data assigned to it? - * - * @member {boolean} - */ - this.noFrame = false; - - if (!frame) { - this.noFrame = true; - frame = new math.Rectangle(0, 0, 1, 1); - } - - if (baseTexture instanceof Texture) { - baseTexture = baseTexture.baseTexture; - } - - /** - * The base texture that this texture uses. - * - * @member {BaseTexture} - */ - this.baseTexture = baseTexture; - - /** - * The frame specifies the region of the base texture that this texture uses - * - * @member {Rectangle} - * @private - */ - this._frame = frame; - - /** - * The texture trim data. - * - * @member {Rectangle} - */ - this.trim = trim; - - /** - * This will let the renderer know if the texture is valid. If it's not then it cannot be rendered. - * - * @member {boolean} - */ - this.valid = false; - - /** - * This will let a renderer know that a texture has been updated (used mainly for webGL uv updates) - * - * @member {boolean} - */ - this.requiresUpdate = false; - - /** - * The WebGL UV data cache. - * - * @member {object} - * @private - */ - this._uvs = null; - - /** - * The width of the Texture in pixels. - * - * @member {number} - */ - this.width = 0; - - /** - * The height of the Texture in pixels. - * - * @member {number} - */ - this.height = 0; - - /** - * This is the area of the BaseTexture image to actually copy to the Canvas / WebGL when rendering, - * irrespective of the actual frame size or placement (which can be influenced by trimmed texture atlases) - * - * @member {Rectangle} - */ - this.crop = crop || new math.Rectangle(0, 0, 1, 1); - - if (baseTexture.hasLoaded) { - if (this.noFrame) { - frame = new math.Rectangle(0, 0, baseTexture.width, baseTexture.height); - } - this.frame = frame; - } - else { - baseTexture.addEventListener('loaded', this.onBaseTextureLoaded.bind(this)); - } -} - -Texture.prototype.constructor = Texture; -module.exports = Texture; - -eventTarget.mixin(Texture.prototype); - -Object.defineProperties(Texture.prototype, { - needsUpdate: { - get: function () { - return this.baseTexture.needsUpdate; - }, - set: function (val) { - this.baseTexture.needsUpdate = val; - } - }, - - frame: { - get: function () { - return this._frame; - }, - set: function (frame) { - this._frame = frame; - - this.noFrame = false; - - this.width = frame.width; - this.height = frame.height; - - this.crop.x = frame.x; - this.crop.y = frame.y; - this.crop.width = frame.width; - this.crop.height = frame.height; - - if (!this.trim && (frame.x + frame.width > this.baseTexture.width || frame.y + frame.height > this.baseTexture.height)) { - throw new Error('Texture Error: frame does not fit inside the base Texture dimensions ' + this); - } - - this.valid = frame && frame.width && frame.height && this.baseTexture.source && this.baseTexture.hasLoaded; - - if (this.trim) { - this.width = this.trim.width; - this.height = this.trim.height; - this._frame.width = this.trim.width; - this._frame.height = this.trim.height; - } - - if (this.valid) { - this._updateUvs(); - } - } - } -}); - -/** - * Called when the base texture is loaded - * - * @private - */ -Texture.prototype.onBaseTextureLoaded = function () { - var baseTexture = this.baseTexture; - baseTexture.removeEventListener('loaded', this.onLoaded); - - if (this.noFrame) { - this.frame = new math.Rectangle(0, 0, baseTexture.width, baseTexture.height); - } - - this.dispatchEvent( { type: 'update', content: this } ); -}; - -/** - * Destroys this texture - * - * @param destroyBase {boolean} Whether to destroy the base texture as well - */ -Texture.prototype.destroy = function (destroyBase) { - if (destroyBase) { - this.baseTexture.destroy(); - } - - this.valid = false; -}; - -/** - * Updates the internal WebGL UV cache. - * - * @private - */ -Texture.prototype._updateUvs = function () { - if (!this._uvs) { - this._uvs = new TextureUvs(); - } - - var frame = this.crop; - var tw = this.baseTexture.width; - var th = this.baseTexture.height; - - this._uvs.x0 = frame.x / tw; - this._uvs.y0 = frame.y / th; - - this._uvs.x1 = (frame.x + frame.width) / tw; - this._uvs.y1 = frame.y / th; - - this._uvs.x2 = (frame.x + frame.width) / tw; - this._uvs.y2 = (frame.y + frame.height) / th; - - this._uvs.x3 = frame.x / tw; - this._uvs.y3 = (frame.y + frame.height) / th; -}; - -/** - * Helper function that creates a Texture object from the given image url. - * If the image is not in the texture cache it will be created and loaded. - * - * @static - * @param imageUrl {string} The image url of the texture - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - * @param scaleMode {number} See {{#crossLink "PIXI/scaleModes:property"}}scaleModes{{/crossLink}} for possible values - * @return Texture - */ -Texture.fromImage = function (imageUrl, crossorigin, scaleMode) { - var texture = utils.TextureCache[imageUrl]; - - if (!texture) { - texture = new Texture(BaseTexture.fromImage(imageUrl, crossorigin, scaleMode)); - utils.TextureCache[imageUrl] = texture; - } - - return texture; -}; - -/** - * Helper function that returns a Texture objected based on the given frame id. - * If the frame id is not in the texture cache an error will be thrown. - * - * @static - * @param frameId {string} The frame id of the texture - * @return Texture - */ -Texture.fromFrame = function (frameId) { - var texture = utils.TextureCache[frameId]; - if (!texture) { - throw new Error('The frameId "' + frameId + '" does not exist in the texture cache '); - } - return texture; -}; - -/** - * Helper function that creates a new Texture based on the given canvas element. - * - * @static - * @param canvas {Canvas} The canvas element source of the texture - * @param scaleMode {number} See {{#crossLink "PIXI/scaleModes:property"}}scaleModes{{/crossLink}} for possible values - * @return {Texture} - */ -Texture.fromCanvas = function (canvas, scaleMode) { - return new Texture(BaseTexture.fromCanvas(canvas, scaleMode)); -}; - -/** - * Helper function that creates a new Texture based on the given video element. - * - * @static - * @param video {HTMLVideoElement} - * @param scaleMode {number} See {{#crossLink "PIXI/scaleModes:property"}}scaleModes{{/crossLink}} for possible values - * @return {Texture} A Texture - */ -Texture.fromVideo = function (video, scaleMode) { - return new Texture(VideoBaseTexture.baseTextureFromVideo(video, scaleMode)); -}; - -/** - * Adds a texture to the global utils.TextureCache. This cache is shared across the whole PIXI object. - * - * @static - * @param texture {Texture} The Texture to add to the cache. - * @param id {string} The id that the texture will be stored against. - */ -Texture.addTextureToCache = function (texture, id) { - utils.TextureCache[id] = texture; -}; - -/** - * Remove a texture from the global utils.TextureCache. - * - * @static - * @param id {string} The id of the texture to be removed - * @return {Texture} The texture that was removed - */ -Texture.removeTextureFromCache = function (id) { - var texture = utils.TextureCache[id]; - - delete utils.TextureCache[id]; - delete utils.BaseTextureCache[id]; - - return texture; -}; - -Texture.emptyTexture = new Texture(new BaseTexture()); - -},{"../math":12,"../utils":50,"../utils/eventTarget":49,"./BaseTexture":42,"./TextureUvs":45,"./VideoBaseTexture":46}],45:[function(require,module,exports){ -function TextureUvs() { - this.x0 = 0; - this.y0 = 0; - - this.x1 = 0; - this.y1 = 0; - - this.x2 = 0; - this.y2 = 0; - - this.x3 = 0; - this.y3 = 0; -} - -module.exports = TextureUvs; - -},{}],46:[function(require,module,exports){ -var BaseTexture = require('./BaseTexture'), - utils = require('../utils'); - -/** - * A texture of a [playing] Video. - * - * See the ["deus" demo](http://www.goodboydigital.com/pixijs/examples/deus/). - * - * @class - * @extends BaseTexture - * @namespace PIXI - * @param source {HTMLVideoElement} - * @param [scaleMode] {number} See {@link scaleModes} for possible values - */ -function VideoBaseTexture(source, scaleMode) { - if (!source){ - throw new Error('No video source element specified.'); - } - - // hook in here to check if video is already available. - // BaseTexture looks for a source.complete boolean, plus width & height. - - if ((source.readyState === source.HAVE_ENOUGH_DATA || source.readyState === source.HAVE_FUTURE_DATA) && source.width && source.height) { - source.complete = true; - } - - BaseTexture.call(this, source, scaleMode); - - this.autoUpdate = false; - - this._boundOnUpdate = this._onUpdate.bind(this); - this._boundOnCanPlay = this._onCanPlay.bind(this); - - if (!source.complete) { - source.addEventListener('canplay', this._boundOnCanPlay); - source.addEventListener('canplaythrough', this._boundOnCanPlay); - - // started playing.. - source.addEventListener('play', this._onPlayStart.bind(this)); - source.addEventListener('pause', this._onPlayStop.bind(this)); - } - - this.__loaded = false; -} - -VideoBaseTexture.prototype = Object.create(BaseTexture.prototype); -VideoBaseTexture.prototype.constructor = VideoBaseTexture; -module.exports = VideoBaseTexture; - -VideoBaseTexture.prototype._onUpdate = function () { - if (this.autoUpdate) { - window.requestAnimationFrame(this._boundOnUpdate); - this.needsUpdate = true; - } -}; - -VideoBaseTexture.prototype._onPlayStart = function () { - if (!this.autoUpdate) { - window.requestAnimationFrame(this._boundOnUpdate); - this.autoUpdate = true; - } -}; - -VideoBaseTexture.prototype._onPlayStop = function () { - this.autoUpdate = false; -}; - -VideoBaseTexture.prototype._onCanPlay = function () { - this.hasLoaded = true; - - if (this.source) { - this.source.removeEventListener('canplay', this._boundOnCanPlay); - this.source.removeEventListener('canplaythrough', this._boundOnCanPlay); - - this.width = this.source.videoWidth; - this.height = this.source.videoHeight; - - this.source.play(); - - // prevent multiple loaded dispatches.. - if(!this.__loaded){ - this.__loaded = true; - this.emit('loaded', this); - } - } -}; - -VideoBaseTexture.prototype.destroy = function () { - if (this.source && this.source._pixiId) { - utils.BaseTextureCache[ this.source._pixiId ] = null; - delete utils.BaseTextureCache[ this.source._pixiId ]; - - this.source._pixiId = null; - delete this.source._pixiId; - } - - BaseTexture.prototype.destroy.call(this); -}; - -/** - * Mimic Pixi BaseTexture.from.... method. - * - * @static - * @param video {HTMLVideoElement} - * @param scaleMode {number} See {@link scaleModes} for possible values - * @return {VideoBaseTexture} - */ -VideoBaseTexture.fromVideo = function (video, scaleMode) { - if (!video._pixiId) { - video._pixiId = 'video_' + utils.uuid(); - } - - var baseTexture = utils.BaseTextureCache[video._pixiId]; - - if (!baseTexture) { - baseTexture = new VideoBaseTexture(video, scaleMode); - utils.BaseTextureCache[ video._pixiId ] = baseTexture; - } - - return baseTexture; -}; - -/** - * Mimic Pixi BaseTexture.from.... method. - * - * This can be used in a couple ways, such as: - * - * ```js - * var texture = PIXI.VideoBaseTexture.fromUrl('http://mydomain.com/video.mp4'); - * - * var texture = PIXI.VideoBaseTexture.fromUrl({ src: 'http://mydomain.com/video.mp4', mime: 'video/mp4' }); - * - * var texture = PIXI.VideoBaseTexture.fromUrls(['/video.webm', '/video.mp4']); - * - * var texture = PIXI.VideoBaseTexture.fromUrls([ - * { src: '/video.webm', mime: 'video/webm' }, - * { src: '/video.mp4', mime: 'video/mp4' } - * ]); - * ``` - * - * @alias fromUrls - * @static - * @param videoSrc {string|object|string[]|object[]} The URL(s) for the video. - * @param [videoSrc.src] {string} One of the source urls for the video - * @param [videoSrc.mime] {string} The mimetype of the video (e.g. 'video/mp4'). If not specified - * the url's extension will be used as the second part of the mime type. - * @param scaleMode {number} See {@link scaleModes} for possible values - * @return {VideoBaseTexture} - */ -VideoBaseTexture.fromUrl = function (videoSrc, scaleMode) { - var video = document.createElement('video'); - - // array of objects or strings - if (Array.isArray(videoSrc)) { - for (var i = 0; i < videoSrc.length; ++i) { - video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime)); - } - } - // single object or string - else { - video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime)); - } - - video.load(); - video.play(); - - return VideoBaseTexture.textureFromVideo(video, scaleMode); -}; - -VideoBaseTexture.fromUrls = VideoBaseTexture.fromUrl; - -function createSource(path, type) { - if (!type) { - type = 'video/' + path.substr(path.lastIndexOf('.') + 1); - } - - var source = document.createElement('source'); - - source.src = path; - source.type = type; - - return source; -} - -},{"../utils":50,"./BaseTexture":42}],47:[function(require,module,exports){ -/** - * Creates an homogenous object for tracking events so users can know what to expect. - * - * @class - * @namespace PIXI - * @param target {object} The target object that the event is called on - * @param name {string} The string name of the event that was triggered - * @param data {object} Arbitrary event data to pass along - */ -function EventData(target, name, data) { - // for duck typing in the ".on()" function - this.__isEventObject = true; - - /** - * Tracks the state of bubbling propagation. Do not - * set this directly, instead use `event.stopPropagation()` - * - * @member {boolean} - * @private - * @readonly - */ - this.stopped = false; - - /** - * Tracks the state of sibling listener propagation. Do not - * set this directly, instead use `event.stopImmediatePropagation()` - * - * @member {boolean} - * @private - * @readonly - */ - this.stoppedImmediate = false; - - /** - * The original target the event triggered on. - * - * @member {object} - * @readonly - */ - this.target = target; - - /** - * The string name of the event that this represents. - * - * @member {string} - * @readonly - */ - this.type = name; - - /** - * The data that was passed in with this event. - * - * @member {object} - * @readonly - */ - this.data = data; - - /** - * The timestamp when the event occurred. - * - * @member {number} - * @readonly - */ - this.timeStamp = Date.now(); -} - -EventData.prototype.constructor = EventData; -module.exports = EventData; - -/** - * Stops the propagation of events up the scene graph (prevents bubbling). - * - */ -EventData.prototype.stopPropagation = function stopPropagation() { - this.stopped = true; -}; - -/** - * Stops the propagation of events to sibling listeners (no longer calls any listeners). - * - */ -EventData.prototype.stopImmediatePropagation = function stopImmediatePropagation() { - this.stoppedImmediate = true; -}; - -},{}],48:[function(require,module,exports){ -//TODO: Have Graphics use https://github.com/mattdesl/shape2d -// and https://github.com/mattdesl/shape2d-triangulate instead of custom code. - -/* - PolyK library - url: http://polyk.ivank.net - Released under MIT licence. - - Copyright (c) 2012 Ivan Kuckir - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - This is an amazing lib! - - Slightly modified by Mat Groves (matgroves.com); -*/ - -/** - * Based on the Polyk library http://polyk.ivank.net released under MIT licence. - * This is an amazing lib! - * Slightly modified by Mat Groves (matgroves.com); - * - * @namespace PIXI - */ -var PolyK = module.exports = {}; - -/** - * Triangulates shapes for webGL graphic fills. - * - */ -PolyK.Triangulate = function (p) { - var sign = true; - - var n = p.length >> 1; - if (n < 3) return []; - - var tgs = []; - var avl = []; - for (var i = 0; i < n; i++) avl.push(i); - - i = 0; - var al = n; - while(al > 3) { - var i0 = avl[(i+0)%al]; - var i1 = avl[(i+1)%al]; - var i2 = avl[(i+2)%al]; - - var ax = p[2*i0], ay = p[2*i0+1]; - var bx = p[2*i1], by = p[2*i1+1]; - var cx = p[2*i2], cy = p[2*i2+1]; - - var earFound = false; - if (PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { - earFound = true; - for (var j = 0; j < al; j++) { - var vi = avl[j]; - if (vi === i0 || vi === i1 || vi === i2) continue; - - if (PolyK._PointInTriangle(p[2*vi], p[2*vi+1], ax, ay, bx, by, cx, cy)) { - earFound = false; - break; - } - } - } - - if (earFound) { - tgs.push(i0, i1, i2); - avl.splice((i+1)%al, 1); - al--; - i = 0; - } - else if (i++ > 3*al) { - // need to flip flip reverse it! - // reset! - if (sign) { - tgs = []; - avl = []; - for (i = 0; i < n; i++) avl.push(i); - - i = 0; - al = n; - - sign = false; - } - else { - // window.console.log("PIXI Warning: shape too complex to fill"); - return null; - } - } - } - - tgs.push(avl[0], avl[1], avl[2]); - return tgs; -}; - -/** - * Checks whether a point is within a triangle - * - * @param px {number} x coordinate of the point to test - * @param py {number} y coordinate of the point to test - * @param ax {number} x coordinate of the a point of the triangle - * @param ay {number} y coordinate of the a point of the triangle - * @param bx {number} x coordinate of the b point of the triangle - * @param by {number} y coordinate of the b point of the triangle - * @param cx {number} x coordinate of the c point of the triangle - * @param cy {number} y coordinate of the c point of the triangle - * @private - * @return {boolean} - */ -PolyK._PointInTriangle = function (px, py, ax, ay, bx, by, cx, cy) { - var v0x = cx-ax; - var v0y = cy-ay; - var v1x = bx-ax; - var v1y = by-ay; - var v2x = px-ax; - var v2y = py-ay; - - var dot00 = v0x*v0x+v0y*v0y; - var dot01 = v0x*v1x+v0y*v1y; - var dot02 = v0x*v2x+v0y*v2y; - var dot11 = v1x*v1x+v1y*v1y; - var dot12 = v1x*v2x+v1y*v2y; - - var invDenom = 1 / (dot00 * dot11 - dot01 * dot01); - var u = (dot11 * dot02 - dot01 * dot12) * invDenom; - var v = (dot00 * dot12 - dot01 * dot02) * invDenom; - - // Check if point is in triangle - return (u >= 0) && (v >= 0) && (u + v < 1); -}; - -/** - * Checks whether a shape is convex - * - * @private - * @return {boolean} - */ -PolyK._convex = function (ax, ay, bx, by, cx, cy, sign) { - return ((ay-by)*(cx-bx) + (bx-ax)*(cy-by) >= 0) === sign; -}; - -},{}],49:[function(require,module,exports){ -var EventData = require('./EventData'); - -/** - * Mixins event emitter functionality to an object. - * - * @mixin - * @namespace PIXI - * @example - * function MyEmitter() {} - * - * eventTarget.mixin(MyEmitter.prototype); - * - * var em = new MyEmitter(); - * em.emit('eventName', 'some data', 'some more data', {}, null, ...); - */ -function eventTarget(obj) { - /** - * Return a list of assigned event listeners. - * - * @param eventName {string} The events that should be listed. - * @return {Array} An array of listener functions - */ - obj.listeners = function listeners(eventName) { - this._listeners = this._listeners || {}; - - return this._listeners[eventName] ? this._listeners[eventName].slice() : []; - }; - - /** - * Emit an event to all registered event listeners. - * - * @alias dispatchEvent - * @param eventName {string} The name of the event. - * @return {boolean} Indication if we've emitted an event. - */ - obj.emit = obj.dispatchEvent = function emit(eventName, data) { - this._listeners = this._listeners || {}; - - // fast return when there are no listeners - if (!this._listeners[eventName]) { - return; - } - - //backwards compat with old method ".emit({ type: 'something' })" - if (typeof eventName === 'object') { - data = eventName; - eventName = eventName.type; - } - - //ensure we are using a real pixi event - if (!data || data.__isEventObject !== true) { - data = new EventData(this, eventName, data); - } - - //iterate the listeners - var listeners = this._listeners[eventName].slice(0), - length = listeners.length, - fn = listeners[0], - i; - - for (i = 0; i < length; fn = listeners[++i]) { - //call the event listener - fn.call(this, data); - - //if "stopImmediatePropagation" is called, stop calling sibling events - if (data.stoppedImmediate) { - return this; - } - } - - //if "stopPropagation" is called then don't bubble the event - if (data.stopped) { - return this; - } - - //bubble this event up the scene graph - if (this.parent && this.parent.emit) { - this.parent.emit.call(this.parent, eventName, data); - } - - return this; - }; - - /** - * Register a new EventListener for the given event. - * - * @alias addEventListener - * @param eventName {string} Name of the event. - * @param callback {Functon} fn Callback function. - */ - obj.on = obj.addEventListener = function on(eventName, fn) { - this._listeners = this._listeners || {}; - - (this._listeners[eventName] = this._listeners[eventName] || []) - .push(fn); - - return this; - }; - - /** - * Add an EventListener that's only called once. - * - * @param eventName {string} Name of the event. - * @param callback {Function} Callback function. - */ - obj.once = function once(eventName, fn) { - this._listeners = this._listeners || {}; - - var self = this; - function onceHandlerWrapper() { - fn.apply(self.off(eventName, onceHandlerWrapper), arguments); - } - onceHandlerWrapper._originalHandler = fn; - - return this.on(eventName, onceHandlerWrapper); - }; - - /** - * Remove event listeners. - * - * @alias removeEventListener - * @param eventName {string} The event we want to remove. - * @param callback {Function} The listener that we need to find. - */ - obj.off = obj.removeEventListener = function off(eventName, fn) { - this._listeners = this._listeners || {}; - - if (!this._listeners[eventName]) { - return this; - } - - var list = this._listeners[eventName], - i = fn ? list.length : 0; - - while(i-- > 0) { - if (list[i] === fn || list[i]._originalHandler === fn) { - list.splice(i, 1); - } - } - - if (list.length === 0) { - delete this._listeners[eventName]; - } - - return this; - }; - - /** - * Remove all listeners or only the listeners for the specified event. - * - * @param eventName {string} The event you want to remove all listeners for. - */ - obj.removeAllListeners = function removeAllListeners(eventName) { - this._listeners = this._listeners || {}; - - if (!this._listeners[eventName]) { - return this; - } - - delete this._listeners[eventName]; - - return this; - }; -} - -module.exports = { - /** - * Mixes in the properties of the eventTarget prototype onto another object - * - * @param object {object} The obj to mix into - */ - mixin: function mixin(obj) { - eventTarget(obj); - } -}; - -},{"./EventData":47}],50:[function(require,module,exports){ -var CONST = require('../const'); - -/** - * @namespace PIXI - */ -var utils = module.exports = { - _uid: 0, - _saidHello: false, - - PolyK: require('./PolyK'), - EventData: require('./EventData'), - eventTarget: require('./eventTarget'), - - /** - * Gets the next uuid - * - * @return {number} The next uuid to use. - */ - uuid: function () { - return ++utils._uid; - }, - - /** - * Converts a hex color number to an [R, G, B] array - * - * @param hex {number} - * @return {number[]} An array representing the [R, G, B] of the color. - */ - hex2rgb: function (hex, out) { - out = out || []; - - out[0] = (hex >> 16 & 0xFF) / 255; - out[1] = (hex >> 8 & 0xFF) / 255; - out[2] = (hex & 0xFF) / 255; - - return out; - }, - - /** - * Converts a hex color number to a string. - * - * @param hex {number} - * @return {string} The string color. - */ - hex2string: function (hex) { - hex = hex.toString(16); - hex = '000000'.substr(0, 6 - hex.length) + hex; - - return '#' + hex; - }, - - /** - * Converts a color as an [R, G, B] array to a hex number - * - * @param rgb {number[]} - * @return {number} The color number - */ - rgb2hex: function (rgb) { - return ((rgb[0]*255 << 16) + (rgb[1]*255 << 8) + rgb[2]*255); - }, - - /** - * Checks whether the Canvas BlendModes are supported by the current browser - * - * @return {boolean} whether they are supported - */ - canUseNewCanvasBlendModes: function () { - if (typeof document === 'undefined') { - return false; - } - - var canvas = document.createElement('canvas'), - context = canvas.getContext('2d'); - - canvas.width = 1; - canvas.height = 1; - - context.fillStyle = '#000'; - context.fillRect(0, 0, 1, 1); - - context.globalCompositeOperation = 'multiply'; - - context.fillStyle = '#fff'; - context.fillRect(0, 0, 1, 1); - - return context.getImageData(0,0,1,1).data[0] === 0; - }, - - /** - * Given a number, this function returns the closest number that is a power of two - * this function is taken from Starling Framework as its pretty neat ;) - * - * @param number {number} - * @return {number} the closest number that is a power of two - */ - getNextPowerOfTwo: function (number) { - // see: http://en.wikipedia.org/wiki/Power_of_two#Fast_algorithm_to_check_if_a_positive_number_is_a_power_of_two - if (number > 0 && (number & (number - 1)) === 0) { - return number; - } - else { - var result = 1; - - while (result < number) { - result <<= 1; - } - - return result; - } - }, - - /** - * checks if the given width and height make a power of two rectangle - * - * @param width {number} - * @param height {number} - * @return {boolean} - */ - isPowerOfTwo: function (width, height) { - return (width > 0 && (width & (width - 1)) === 0 && height > 0 && (height & (height - 1)) === 0); - }, - - /** - * Logs out the version and renderer information for this running instance of PIXI. - * If you don't want to see this message you can set `PIXI.utils._saidHello = true;` - * so the library thinks it already said it. Keep in mind that doing that will forever - * makes you a jerk face. - * - * @param {string} type - The string renderer type to log. - * @constant - * @static - */ - sayHello: function (type) { - if (utils._saidHello) { - return; - } - - if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) { - var args = [ - '%c %c %c Pixi.js ' + CONST.VERSION + ' - ' + type + ' %c ' + ' %c ' + ' http://www.pixijs.com/ %c %c ♥%c♥%c♥ ', - 'background: #ff66a5', - 'background: #ff66a5', - 'color: #ff66a5; background: #030307;', - 'background: #ff66a5', - 'background: #ffc3dc', - 'background: #ff66a5', - 'color: #ff2424; background: #fff', - 'color: #ff2424; background: #fff', - 'color: #ff2424; background: #fff' - ]; - - console.log.apply(console, args); //jshint ignore:line - } - else if (window.console) { - console.log('Pixi.js ' + CONST.VERSION + ' - ' + type + ' - http://www.pixijs.com/'); //jshint ignore:line - } - - utils._saidHello = true; - }, - - /** - * A wrapper for ajax requests to be handled cross browser - * - * TODO: Replace this wil superagent - * - * @class - * @namespace PIXI - */ - AjaxRequest: function () { - var activexmodes = ['Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.3.0', 'Microsoft.XMLHTTP']; //activeX versions to check for in IE - - if (window.ActiveXObject) { //Test for support for ActiveXObject in IE first (as XMLHttpRequest in IE7 is broken) - for (var i=0; i= this.textures.length) { - this.gotoAndStop(this.textures.length - 1); - - if (this.onComplete) { - this.onComplete(); - } - } -}; - -/** - * A short hand way of creating a movieclip from an array of frame ids - * - * @static - * @param frames {string[]} the array of frames ids the movieclip will use as its texture frames - */ -MovieClip.fromFrames = function (frames) { - var textures = []; - - for (var i = 0; i < frames.length; ++i) { - textures.push(new core.Texture.fromFrame(frames[i])); - } - - return new MovieClip(textures); -}; - -/** - * A short hand way of creating a movieclip from an array of image ids - * - * @static - * @param images {string[]} the array of image urls the movieclip will use as its texture frames - */ -MovieClip.fromImages = function (images) { - var textures = []; - - for (var i = 0; i < images.length; ++i) { - textures.push(new core.Texture.fromImage(images[i])); - } - - return new MovieClip(textures); -}; - -},{"../core":9}],52:[function(require,module,exports){ -var Strip = require('./Strip'); - -/** - * - * @class - * @namespace PIXI - * @extends Strip - * @param {Texture} texture - The texture to use on the rope. - * @param {Array} points - An array of {Point}. - * - */ -function Rope(texture, points) { - Strip.call(this, texture); - this.points = points; - - this.vertices = new Float32Array(points.length * 4); - this.uvs = new Float32Array(points.length * 4); - this.colors = new Float32Array(points.length * 2); - this.indices = new Uint16Array(points.length * 2); - - this.refresh(); -} - - -// constructor -Rope.prototype = Object.create(Strip.prototype); -Rope.prototype.constructor = Rope; -module.exports = Rope; - -/** - * Refreshes - * - */ -Rope.prototype.refresh = function () { - var points = this.points; - - if (points.length < 1) { - return; - } - - var uvs = this.uvs; - - var indices = this.indices; - var colors = this.colors; - - // this.count -= 0.2; - - uvs[0] = 0; - uvs[1] = 0; - uvs[2] = 0; - uvs[3] = 1; - - colors[0] = 1; - colors[1] = 1; - - indices[0] = 0; - indices[1] = 1; - - var total = points.length, - point, index, amount; - - for (var i = 1; i < total; i++) { - point = points[i]; - index = i * 4; - // time to do some smart drawing! - amount = i / (total-1); - - if (i%2) { - uvs[index] = amount; - uvs[index+1] = 0; - - uvs[index+2] = amount; - uvs[index+3] = 1; - } - else { - uvs[index] = amount; - uvs[index+1] = 0; - - uvs[index+2] = amount; - uvs[index+3] = 1; - } - - index = i * 2; - colors[index] = 1; - colors[index+1] = 1; - - index = i * 2; - indices[index] = index; - indices[index + 1] = index + 1; - } -}; - -/* - * Updates the object transform for rendering - * - * @private - */ -Rope.prototype.updateTransform = function () { - var points = this.points; - - if (points.length < 1) { - return; - } - - var lastPoint = points[0]; - var nextPoint; - var perpX = 0; - var perpY = 0; - - // this.count -= 0.2; - - var vertices = this.vertices; - var total = points.length, - point, index, ratio, perpLength, num; - - for (var i = 0; i < total; i++) { - point = points[i]; - index = i * 4; - - if (i < points.length-1) { - nextPoint = points[i+1]; - } - else { - nextPoint = point; - } - - perpY = -(nextPoint.x - lastPoint.x); - perpX = nextPoint.y - lastPoint.y; - - ratio = (1 - (i / (total-1))) * 10; - - if (ratio > 1) { - ratio = 1; - } - - perpLength = Math.sqrt(perpX * perpX + perpY * perpY); - num = this.texture.height / 2; //(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; - perpX /= perpLength; - perpY /= perpLength; - - perpX *= num; - perpY *= num; - - vertices[index] = point.x + perpX; - vertices[index+1] = point.y + perpY; - vertices[index+2] = point.x - perpX; - vertices[index+3] = point.y - perpY; - - lastPoint = point; - } - - this.displayObjectContainerUpdateTransform(); -}; - -/** - * Sets the texture that the Rope will use - * - * @param texture {Texture} the texture that will be used - */ -Rope.prototype.setTexture = function (texture) { - // stop current texture - this.texture = texture; - //this.updateFrame = true; -}; - -},{"./Strip":53}],53:[function(require,module,exports){ -var core = require('../core'); - -/** - * - * @class - * @extends DisplayObjectContainer - * @namespace PIXI - * @param texture {Texture} The texture to use - * @param width {number} the width - * @param height {number} the height - * - */ -function Strip(texture) { - core.DisplayObjectContainer.call(this); - - /** - * The texture of the strip - * - * @member {Texture} - */ - this.texture = texture; - - // set up the main bits.. - this.uvs = new Float32Array([0, 1, - 1, 1, - 1, 0, - 0, 1]); - - this.vertices = new Float32Array([0, 0, - 100, 0, - 100, 100, - 0, 100]); - - this.colors = new Float32Array([1, 1, 1, 1]); - - this.indices = new Uint16Array([0, 1, 2, 3]); - - /** - * Whether the strip is dirty or not - * - * @member {boolean} - */ - this.dirty = true; - - /** - * The blend mode to be applied to the sprite. Set to blendModes.NORMAL to remove any blend mode. - * - * @member {number} - * @default CONST.blendModes.NORMAL; - */ - this.blendMode = core.CONST.blendModes.NORMAL; - - /** - * Triangles in canvas mode are automatically antialiased, use this value to force triangles to overlap a bit with each other. - * - * @member {number} - */ - this.canvasPadding = 0; - - this.drawMode = Strip.DrawModes.TRIANGLE_STRIP; -} - -// constructor -Strip.prototype = Object.create(core.DisplayObjectContainer.prototype); -Strip.prototype.constructor = Strip; -module.exports = Strip; - -/** - * Renders the object using the WebGL renderer - * - * @param renderer {WebGLRenderer} - */ -Strip.prototype.renderWebGL = function (renderer) { - // if the sprite is not visible or the alpha is 0 then no need to render this element - if (!this.visible || this.alpha <= 0) { - return; - } - - // render triangle strip.. - - renderer.spriteBatch.stop(); - - // init! init! - if (!this._vertexBuffer) { - this._initWebGL(renderer); - } - - renderer.shaderManager.setShader(renderer.shaderManager.stripShader); - - this._renderStrip(renderer); - - ///renderer.shaderManager.activateDefaultShader(); - - renderer.spriteBatch.start(); - - //TODO check culling -}; - -Strip.prototype._initWebGL = function (renderer) { - // build the strip! - var gl = renderer.gl; - - this._vertexBuffer = gl.createBuffer(); - this._indexBuffer = gl.createBuffer(); - this._uvBuffer = gl.createBuffer(); - this._colorBuffer = gl.createBuffer(); - - gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, this._uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.uvs, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, this._colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.colors, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); -}; - -Strip.prototype._renderStrip = function (renderer) { - var gl = renderer.gl; - var projection = renderer.projection, - offset = renderer.offset, - shader = renderer.shaderManager.stripShader; - - var drawMode = this.drawMode === Strip.DrawModes.TRIANGLE_STRIP ? gl.TRIANGLE_STRIP : gl.TRIANGLES; - - // gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mat4Real); - - renderer.blendModeManager.setBlendMode(this.blendMode); - - - // set uniforms - gl.uniformMatrix3fv(shader.translationMatrix, false, this.worldTransform.toArray(true)); - gl.uniform2f(shader.projectionVector, projection.x, -projection.y); - gl.uniform2f(shader.offsetVector, -offset.x, -offset.y); - gl.uniform1f(shader.alpha, this.worldAlpha); - - if (!this.dirty) { - - gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer); - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - - // update the uvs - gl.bindBuffer(gl.ARRAY_BUFFER, this._uvBuffer); - gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.activeTexture(gl.TEXTURE0); - - // check if a texture is dirty.. - if (this.texture.baseTexture._dirty[gl.id]) { - renderer.updateTexture(this.texture.baseTexture); - } - else { - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); - } - - // dont need to upload! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); - - - } - else { - - this.dirty = false; - gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.STATIC_DRAW); - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - - // update the uvs - gl.bindBuffer(gl.ARRAY_BUFFER, this._uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.uvs, gl.STATIC_DRAW); - gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.activeTexture(gl.TEXTURE0); - - // check if a texture is dirty.. - if (this.texture.baseTexture._dirty[gl.id]) { - renderer.updateTexture(this.texture.baseTexture); - } - else { - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); - } - - // dont need to upload! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); - - } - //console.log(gl.TRIANGLE_STRIP) - // - // - gl.drawElements(drawMode, this.indices.length, gl.UNSIGNED_SHORT, 0); - - -}; - -/** - * Renders the object using the Canvas renderer - * - * @param renderer {CanvasRenderer} - */ -Strip.prototype.renderCanvas = function (renderer) { - var context = renderer.context; - - var transform = this.worldTransform; - - if (renderer.roundPixels) { - context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); - } - else { - context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); - } - - if (this.drawMode === Strip.DrawModes.TRIANGLE_STRIP) { - this._renderCanvasTriangleStrip(context); - } - else { - this._renderCanvasTriangles(context); - } -}; - -Strip.prototype._renderCanvasTriangleStrip = function (context) { - // draw triangles!! - var vertices = this.vertices; - var uvs = this.uvs; - - var length = vertices.length / 2; - // this.count++; - - for (var i = 0; i < length - 2; i++) { - // draw some triangles! - var index = i * 2; - this._renderCanvasDrawTriangle(context, vertices, uvs, index, (index + 2), (index + 4)); - } -}; - -Strip.prototype._renderCanvasTriangles = function (context) { - // draw triangles!! - var vertices = this.vertices; - var uvs = this.uvs; - var indices = this.indices; - - var length = indices.length; - // this.count++; - - for (var i = 0; i < length; i += 3) { - // draw some triangles! - var index0 = indices[i] * 2, index1 = indices[i + 1] * 2, index2 = indices[i + 2] * 2; - this._renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2); - } -}; - -Strip.prototype._renderCanvasDrawTriangle = function (context, vertices, uvs, index0, index1, index2) { - var textureSource = this.texture.baseTexture.source; - var textureWidth = this.texture.width; - var textureHeight = this.texture.height; - - var x0 = vertices[index0], x1 = vertices[index1], x2 = vertices[index2]; - var y0 = vertices[index0 + 1], y1 = vertices[index1 + 1], y2 = vertices[index2 + 1]; - - var u0 = uvs[index0] * textureWidth, u1 = uvs[index1] * textureWidth, u2 = uvs[index2] * textureWidth; - var v0 = uvs[index0 + 1] * textureHeight, v1 = uvs[index1 + 1] * textureHeight, v2 = uvs[index2 + 1] * textureHeight; - - if (this.canvasPadding > 0) { - var paddingX = this.canvasPadding / this.worldTransform.a; - var paddingY = this.canvasPadding / this.worldTransform.d; - var centerX = (x0 + x1 + x2) / 3; - var centerY = (y0 + y1 + y2) / 3; - - var normX = x0 - centerX; - var normY = y0 - centerY; - - var dist = Math.sqrt(normX * normX + normY * normY); - x0 = centerX + (normX / dist) * (dist + paddingX); - y0 = centerY + (normY / dist) * (dist + paddingY); - - // - - normX = x1 - centerX; - normY = y1 - centerY; - - dist = Math.sqrt(normX * normX + normY * normY); - x1 = centerX + (normX / dist) * (dist + paddingX); - y1 = centerY + (normY / dist) * (dist + paddingY); - - normX = x2 - centerX; - normY = y2 - centerY; - - dist = Math.sqrt(normX * normX + normY * normY); - x2 = centerX + (normX / dist) * (dist + paddingX); - y2 = centerY + (normY / dist) * (dist + paddingY); - } - - context.save(); - context.beginPath(); - - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - - context.closePath(); - - context.clip(); - - // Compute matrix transform - var delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); - var deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); - var deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); - var deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); - var deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); - var deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); - var deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); - - context.transform(deltaA / delta, deltaD / delta, - deltaB / delta, deltaE / delta, - deltaC / delta, deltaF / delta); - - context.drawImage(textureSource, 0, 0); - context.restore(); -}; - - - -/** - * Renders a flat strip - * - * @param strip {Strip} The Strip to render - * @private - */ -Strip.prototype.renderStripFlat = function (strip) { - var context = this.context; - var vertices = strip.vertices; - - var length = vertices.length/2; - // this.count++; - - context.beginPath(); - for (var i=1; i < length-2; i++) { - // draw some triangles! - var index = i*2; - - var x0 = vertices[index], x1 = vertices[index+2], x2 = vertices[index+4]; - var y0 = vertices[index+1], y1 = vertices[index+3], y2 = vertices[index+5]; - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - } - - context.fillStyle = '#FF0000'; - context.fill(); - context.closePath(); -}; - -/* -Strip.prototype.setTexture = function (texture) { - //TODO SET THE TEXTURES - //TODO VISIBILITY - - // stop current texture - this.texture = texture; - this.width = texture.frame.width; - this.height = texture.frame.height; - this.updateFrame = true; -}; - */ - -/** - * When the texture is updated, this event will fire to update the scale and frame - * - * @param event - * @private - */ - -Strip.prototype.onTextureUpdate = function () { - this.updateFrame = true; -}; - -/** - * Returns the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. - * - * @param matrix {Matrix} the transformation matrix of the sprite - * @return {Rectangle} the framing rectangle - */ -Strip.prototype.getBounds = function (matrix) { - var worldTransform = matrix || this.worldTransform; - - var a = worldTransform.a; - var b = worldTransform.b; - var c = worldTransform.c; - var d = worldTransform.d; - var tx = worldTransform.tx; - var ty = worldTransform.ty; - - var maxX = -Infinity; - var maxY = -Infinity; - - var minX = Infinity; - var minY = Infinity; - - var vertices = this.vertices; - for (var i = 0, n = vertices.length; i < n; i += 2) { - var rawX = vertices[i], rawY = vertices[i + 1]; - var x = (a * rawX) + (c * rawY) + tx; - var y = (d * rawY) + (b * rawX) + ty; - - minX = x < minX ? x : minX; - minY = y < minY ? y : minY; - - maxX = x > maxX ? x : maxX; - maxY = y > maxY ? y : maxY; - } - - if (minX === -Infinity || maxY === Infinity) { - return core.math.Rectangle.EMPTY; - } - - var bounds = this._bounds; - - bounds.x = minX; - bounds.width = maxX - minX; - - bounds.y = minY; - bounds.height = maxY - minY; - - // store a reference so that if this function gets called again in the render cycle we do not have to recalculate - this._currentBounds = bounds; - - return bounds; -}; - -/** - * Different drawing buffer modes supported - * - * @static - * @constant - * @property {object} DrawModes - * @property {number} DrawModes.TRIANGLE_STRIP - * @property {number} DrawModes.TRIANGLES - */ -Strip.DrawModes = { - TRIANGLE_STRIP: 0, - TRIANGLES: 1 -}; - -},{"../core":9}],54:[function(require,module,exports){ -var core = require('../core'); - -/** - * A tiling sprite is a fast way of rendering a tiling image - * - * @class - * @extends Sprite - * @namespace PIXI - * @param texture {Texture} the texture of the tiling sprite - * @param width {number} the width of the tiling sprite - * @param height {number} the height of the tiling sprite - */ -function TilingSprite(texture, width, height) { - core.Sprite.call( this, texture); - - /** - * The with of the tiling sprite - * - * @member {number} - */ - this._width = width || 100; - - /** - * The height of the tiling sprite - * - * @member {number} - */ - this._height = height || 100; - - /** - * The scaling of the image that is being tiled - * - * @member {Point} - */ - this.tileScale = new core.math.Point(1,1); - - /** - * A point that represents the scale of the texture object - * - * @member {Point} - */ - this.tileScaleOffset = new core.math.Point(1,1); - - /** - * The offset position of the image that is being tiled - * - * @member {Point} - */ - this.tilePosition = new core.math.Point(0,0); - - /** - * Whether this sprite is renderable or not - * - * @member {boolean} - * @default true - */ - this.renderable = true; - - /** - * The tint applied to the sprite. This is a hex value - * - * @member {number} - * @default 0xFFFFFF - */ - this.tint = 0xFFFFFF; - - /** - * The blend mode to be applied to the sprite - * - * @member {number} - * @default blendModes.NORMAL; - */ - this.blendMode = core.CONST.blendModes.NORMAL; -} - -TilingSprite.prototype = Object.create(core.Sprite.prototype); -TilingSprite.prototype.constructor = TilingSprite; -module.exports = TilingSprite; - - -Object.defineProperties(TilingSprite.prototype, { - /** - * The width of the sprite, setting this will actually modify the scale to achieve the value set - * - * @member {number} - * @memberof TilingSprite# - */ - width: { - get: function () { - return this._width; - }, - set: function (value) { - this._width = value; - } - }, - - /** - * The height of the TilingSprite, setting this will actually modify the scale to achieve the value set - * - * @member {number} - * @memberof TilingSprite# - */ - height: { - get: function () { - return this._height; - }, - set: function (value) { - this._height = value; - } - }, - - texture: { - get: function () { - return this._texture; - }, - set: function (value) { - if (this._texture === value) { - return; - } - - this._texture = value; - this.refreshTexture = true; - this.cachedTint = 0xFFFFFF; - } - } -}); - -/** - * Renders the object using the WebGL renderer - * - * @param renderer {WebGLRenderer} - */ -TilingSprite.prototype.renderWebGL = function (renderer) { - if (!this.visible || this.alpha <= 0) { - return; - } - - var i, j; - - if (this._mask) { - renderer.spriteBatch.stop(); - renderer.maskManager.pushMask(this.mask, renderer); - renderer.spriteBatch.start(); - } - - if (this._filters) { - renderer.spriteBatch.flush(); - renderer.filterManager.pushFilter(this._filterBlock); - } - - - - if (!this.tilingTexture || this.refreshTexture) { - this.generateTilingTexture(true); - - if (this.tilingTexture && this.tilingTexture.needsUpdate) { - //TODO - tweaking - renderer.updateTexture(this.tilingTexture.baseTexture); - this.tilingTexture.needsUpdate = false; - // this.tilingTexture._uvs = null; - } - } - else { - renderer.spriteBatch.renderTilingSprite(this); - } - // simple render children! - for (i=0,j=this.children.length; i maxX ? x2 : maxX; - maxX = x3 > maxX ? x3 : maxX; - maxX = x4 > maxX ? x4 : maxX; - - maxY = y1; - maxY = y2 > maxY ? y2 : maxY; - maxY = y3 > maxY ? y3 : maxY; - maxY = y4 > maxY ? y4 : maxY; - - var bounds = this._bounds; - - bounds.x = minX; - bounds.width = maxX - minX; - - bounds.y = minY; - bounds.height = maxY - minY; - - // store a reference so that if this function gets called again in the render cycle we do not have to recalculate - this._currentBounds = bounds; - - return bounds; -}; - -/** - * When the texture is updated, this event will fire to update the scale and frame - * - * @param event - * @private - */ -TilingSprite.prototype.onTextureUpdate = function () { - // overriding the sprite version of this! -}; - -/** - * - * @param forcePowerOfTwo {boolean} Whether we want to force the texture to be a power of two - */ -TilingSprite.prototype.generateTilingTexture = function (forcePowerOfTwo) { - if (!this.texture.baseTexture.hasLoaded) { - return; - } - - var texture = this.originalTexture || this.texture; - var frame = texture.frame; - var targetWidth, targetHeight; - - // Check that the frame is the same size as the base texture. - var isFrame = frame.width !== texture.baseTexture.width || frame.height !== texture.baseTexture.height; - - var newTextureRequired = false; - - if (!forcePowerOfTwo) { - if (isFrame) { - targetWidth = frame.width; - targetHeight = frame.height; - - newTextureRequired = true; - } - } - else { - targetWidth = core.utils.getNextPowerOfTwo(frame.width); - targetHeight = core.utils.getNextPowerOfTwo(frame.height); - - // If the BaseTexture dimensions don't match the texture frame then we need a new texture anyway because it's part of a texture atlas - if (frame.width !== targetWidth || frame.height !== targetHeight || texture.baseTexture.width !== targetWidth || texture.baseTexture.height || targetHeight) { - newTextureRequired = true; - } - } - - if (newTextureRequired) { - var canvasBuffer; - - if (this.tilingTexture && this.tilingTexture.isTiling) { - canvasBuffer = this.tilingTexture.canvasBuffer; - canvasBuffer.resize(targetWidth, targetHeight); - this.tilingTexture.baseTexture.width = targetWidth; - this.tilingTexture.baseTexture.height = targetHeight; - this.tilingTexture.needsUpdate = true; - } - else { - canvasBuffer = new core.CanvasBuffer(targetWidth, targetHeight); - - this.tilingTexture = core.Texture.fromCanvas(canvasBuffer.canvas); - this.tilingTexture.canvasBuffer = canvasBuffer; - this.tilingTexture.isTiling = true; - } - - canvasBuffer.context.drawImage(texture.baseTexture.source, - texture.crop.x, - texture.crop.y, - texture.crop.width, - texture.crop.height, - 0, - 0, - targetWidth, - targetHeight); - - this.tileScaleOffset.x = frame.width / targetWidth; - this.tileScaleOffset.y = frame.height / targetHeight; - } - else { - // TODO - switching? - if (this.tilingTexture && this.tilingTexture.isTiling) { - // destroy the tiling texture! - // TODO could store this somewhere? - this.tilingTexture.destroy(true); - } - - this.tileScaleOffset.x = 1; - this.tileScaleOffset.y = 1; - this.tilingTexture = texture; - } - - this.refreshTexture = false; - - this.originalTexture = this.texture; - this.texture = this.tilingTexture; - - this.tilingTexture.baseTexture._powerOf2 = true; -}; - -},{"../core":9}],55:[function(require,module,exports){ -/** - * @file Main export of the PIXI extras library - * @author Mat Groves - * @copyright 2013-2015 GoodBoyDigital - * @license {@link https://github.com/GoodBoyDigital/pixi.js/blob/master/LICENSE|MIT License} - */ - -/** - * @namespace PIXI - */ -module.exports = { - MovieClip: require('./MovieClip'), - Rope: require('./Rope'), - Strip: require('./Strip'), - TilingSprite: require('./TilingSprite') -}; - -},{"./MovieClip":51,"./Rope":52,"./Strip":53,"./TilingSprite":54}],56:[function(require,module,exports){ -/** - * This is the base class for creating a PIXI filter. Currently only WebGL supports filters. - * If you want to make a custom filter this should be your base class. - * - * @class - * @namespace PIXI - * @param fragmentSrc {string|string[]} The fragment source in an array of strings. - * @param uniforms {object} An object containing the uniforms for this filter. - */ -function AbstractFilter(fragmentSrc, uniforms) { - /** - * An array of passes - some filters contain a few steps this array simply stores the steps in a liniear fashion. - * For example the blur filter has two passes blurX and blurY. - * - * @member {AbstractFilter[]} - * @private - */ - this.passes = [this]; - - /** - * @member {Shader[]} - * @private - */ - this.shaders = []; - - /** - * @member {number} - */ - this.padding = 0; - - /** - * @member {object} - * @private - */ - this.uniforms = uniforms || {}; - - /** - * @member {string[]} - * @private - */ - this.fragmentSrc = typeof fragmentSrc === 'string' ? fragmentSrc.split('') : (fragmentSrc || []); -} - -AbstractFilter.prototype.constructor = AbstractFilter; -module.exports = AbstractFilter; - -/** - * Syncs the uniforms between the class object and the shaders. - * - */ -AbstractFilter.prototype.syncUniforms = function () { - for (var i = 0, j = this.shaders.length; i < j; ++i) { - this.shaders[i].dirty = true; - } -}; - -/* -AbstractFilter.prototype.apply = function (frameBuffer) { - // TODO :) -}; -*/ - -},{}],57:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * The AlphaMaskFilter class uses the pixel values from the specified texture (called the displacement map) to perform a displacement of an object. - * You can use this filter to apply all manor of crazy warping effects - * Currently the r property of the texture is used to offset the x and the g property of the texture is used to offset the y. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - * @param texture {Texture} The texture used for the displacement map * must be power of 2 texture at the moment - */ -function AlphaMaskFilter(texture) { - AbstractFilter.call(this); - - texture.baseTexture._powerOf2 = true; - - // set the uniforms - this.uniforms = { - mask: { type: 'sampler2D', value: texture }, - mapDimensions: { type: '2f', value: { x: 1, y: 5112 } }, - dimensions: { type: '4fv', value: [0, 0, 0, 0] }, - offset: { type: '2f', value: { x: 0, y: 0 } } - }; - - if (texture.baseTexture.hasLoaded) { - this.uniforms.mask.value.x = texture.width; - this.uniforms.mask.value.y = texture.height; - } - else { - this.boundLoadedFunction = this.onTextureLoaded.bind(this); - - texture.baseTexture.on('loaded', this.boundLoadedFunction); - } - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform sampler2D uSampler;', - 'uniform sampler2D mask;', - 'uniform vec2 mapDimensions;', - 'uniform vec4 dimensions;', - 'uniform vec2 offset;', - - 'void main() {', - ' vec2 mapCords = vTextureCoord.xy;', - ' mapCords += (dimensions.zw + offset)/ dimensions.xy ;', - ' mapCords.y *= -1.0;', - ' mapCords.y += 1.0;', - ' mapCords *= dimensions.xy / mapDimensions;', - - ' vec4 original = texture2D(uSampler, vTextureCoord);', - ' float maskAlpha = texture2D(mask, mapCords).r;', - ' original *= maskAlpha;', - //' original.rgb *= maskAlpha;', - ' gl_FragColor = original;', - //' gl_FragColor = gl_FragColor;', - '}' - ]; -} - -AlphaMaskFilter.prototype = Object.create(AbstractFilter.prototype); -AlphaMaskFilter.prototype.constructor = AlphaMaskFilter; -module.exports = AlphaMaskFilter; - -/** - * Sets the map dimensions uniforms when the texture becomes available. - * - */ -AlphaMaskFilter.prototype.onTextureLoaded = function () { - this.uniforms.mapDimensions.value.x = this.uniforms.mask.value.width; - this.uniforms.mapDimensions.value.y = this.uniforms.mask.value.height; - - this.uniforms.mask.value.baseTexture.off('loaded', this.boundLoadedFunction); -}; - -Object.defineProperties(AlphaMaskFilter.prototype, { - /** - * The texture used for the displacement map. Must be power of 2 sized texture. - * - * @member {Texture} - * @memberof AlphaMaskFilter# - */ - map: { - get: function () { - return this.uniforms.mask.value; - }, - set: function (value) { - this.uniforms.mask.value = value; - } - }, - - /** - * The offset used to move the displacement map. - * - * @member {Point} - * @memberof AlphaMaskFilter# - */ - offset: { - get: function() { - return this.uniforms.offset.value; - }, - set: function(value) { - this.uniforms.offset.value = value; - } - } -}); - -},{"./AbstractFilter":56}],58:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * @author Vico @vicocotea - * original shader : https://www.shadertoy.com/view/lssGDj by @movAX13h - */ - -/** - * An ASCII filter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function AsciiFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - dimensions: { type: '4fv', value: new Float32Array([10000, 100, 10, 10]) }, - pixelSize: { type: '1f', value: 8} - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'uniform vec4 dimensions;', - 'uniform float pixelSize;', - 'uniform sampler2D uSampler;', - - 'float character(float n, vec2 p)', - '{', - ' p = floor(p*vec2(4.0, -4.0) + 2.5);', - ' if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y)', - ' {', - ' if (int(mod(n/exp2(p.x + 5.0*p.y), 2.0)) == 1) return 1.0;', - ' }', - ' return 0.0;', - '}', - - 'void main()', - '{', - ' vec2 uv = gl_FragCoord.xy;', - ' vec3 col = texture2D(uSampler, floor( uv / pixelSize ) * pixelSize / dimensions.xy).rgb;', - - ' #ifdef HAS_GREENSCREEN', - ' float gray = (col.r + col.b)/2.0;', - ' #else', - ' float gray = (col.r + col.g + col.b)/3.0;', - ' #endif', - - ' float n = 65536.0; // .', - ' if (gray > 0.2) n = 65600.0; // :', - ' if (gray > 0.3) n = 332772.0; // *', - ' if (gray > 0.4) n = 15255086.0; // o', - ' if (gray > 0.5) n = 23385164.0; // &', - ' if (gray > 0.6) n = 15252014.0; // 8', - ' if (gray > 0.7) n = 13199452.0; // @', - ' if (gray > 0.8) n = 11512810.0; // #', - - ' vec2 p = mod( uv / ( pixelSize * 0.5 ), 2.0) - vec2(1.0);', - ' col = col * character(n, p);', - - ' gl_FragColor = vec4(col, 1.0);', - '}' - ]; -} - -AsciiFilter.prototype = Object.create(AbstractFilter.prototype); -AsciiFilter.prototype.constructor = AsciiFilter; -module.exports = AsciiFilter; - -Object.defineProperties(AsciiFilter.prototype, { - /** - * The pixel size used by the filter. - * - * @member {number} - * @memberof AsciiFilter# - */ - size: { - get: function () { - return this.uniforms.pixelSize.value; - }, - set: function (value) { - this.uniforms.pixelSize.value = value; - } - } -}); - -},{"./AbstractFilter":56}],59:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'), - BlurXFilter = require('./BlurXFilter'), - BlurYFilter = require('./BlurYFilter'); - -/** - * The BlurFilter applies a Gaussian blur to an object. - * The strength of the blur can be set for x- and y-axis separately. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function BlurFilter() { - AbstractFilter.call(this); - - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); - - this.passes = [this.blurXFilter, this.blurYFilter]; -} - -BlurFilter.prototype = Object.create(AbstractFilter.prototype); -BlurFilter.prototype.constructor = BlurFilter; -module.exports = BlurFilter; - -Object.defineProperties(BlurFilter.prototype, { - /** - * Sets the strength of both the blurX and blurY properties simultaneously - * - * @member {number} - * @memberOf BlurFilter# - * @default 2 - */ - blur: { - get: function () { - return this.blurXFilter.blur; - }, - set: function (value) { - this.blurXFilter.blur = this.blurYFilter.blur = value; - } - }, - - /** - * Sets the strength of the blurX property - * - * @member {number} - * @memberOf BlurFilter# - * @default 2 - */ - blurX: { - get: function () { - return this.blurXFilter.blur; - }, - set: function (value) { - this.blurXFilter.blur = value; - } - }, - - /** - * Sets the strength of the blurY property - * - * @member {number} - * @memberOf BlurFilter# - * @default 2 - */ - blurY: { - get: function () { - return this.blurYFilter.blur; - }, - set: function (value) { - this.blurYFilter.blur = value; - } - } -}); - -},{"./AbstractFilter":56,"./BlurXFilter":60,"./BlurYFilter":61}],60:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'), - blurFactor = 1 / 7000; - -/** - * The BlurXFilter applies a horizontal Gaussian blur to an object. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function BlurXFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - blur: { type: '1f', value: 1 / 512 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float blur;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' vec4 sum = vec4(0.0);', - - ' sum += texture2D(uSampler, vec2(vTextureCoord.x - 4.0*blur, vTextureCoord.y)) * 0.05;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x - 3.0*blur, vTextureCoord.y)) * 0.09;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x - 2.0*blur, vTextureCoord.y)) * 0.12;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x - blur, vTextureCoord.y)) * 0.15;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y)) * 0.16;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x + blur, vTextureCoord.y)) * 0.15;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x + 2.0*blur, vTextureCoord.y)) * 0.12;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x + 3.0*blur, vTextureCoord.y)) * 0.09;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x + 4.0*blur, vTextureCoord.y)) * 0.05;', - - ' gl_FragColor = sum;', - '}' - ]; -} - -BlurXFilter.prototype = Object.create(AbstractFilter.prototype); -BlurXFilter.prototype.constructor = BlurXFilter; -module.exports = BlurXFilter; - -Object.defineProperties(BlurXFilter.prototype, { - /** - * Sets the strength of both the blur. - * - * @member {number} - * @memberof BlurXFilter# - * @default 2 - */ - blur: { - get: function () { - return this.uniforms.blur.value / blurFactor; - }, - set: function (value) { - this.uniforms.blur.value = blurFactor * value; - } - } -}); - -},{"./AbstractFilter":56}],61:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'), - blurFactor = 1 / 7000; - -/** - * The BlurYFilter applies a vertical Gaussian blur to an object. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function BlurYFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - blur: { type: '1f', value: 1 / 512 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float blur;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' vec4 sum = vec4(0.0);', - - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - 4.0*blur)) * 0.05;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - 3.0*blur)) * 0.09;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - 2.0*blur)) * 0.12;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - blur)) * 0.15;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y)) * 0.16;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + blur)) * 0.15;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + 2.0*blur)) * 0.12;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + 3.0*blur)) * 0.09;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + 4.0*blur)) * 0.05;', - - ' gl_FragColor = sum;', - '}' - ]; -} - -BlurYFilter.prototype = Object.create(AbstractFilter.prototype); -BlurYFilter.prototype.constructor = BlurYFilter; -module.exports = BlurYFilter; - -Object.defineProperties(BlurYFilter.prototype, { - /** - * Sets the strength of both the blur. - * - * @member {number} - * @memberof BlurYFilter - * @default 2 - */ - blur: { - get: function () { - return this.uniforms.blur.value / blurFactor; - }, - set: function (value) { - //this.padding = value; - this.uniforms.blur.value = blurFactor * value; - } - } -}); - -},{"./AbstractFilter":56}],62:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * The ColorMatrixFilter class lets you apply a 4x4 matrix transformation on the RGBA - * color and alpha values of every pixel on your displayObject to produce a result - * with a new set of RGBA color and alpha values. It's pretty powerful! - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function ColorMatrixFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - matrix: { type: 'mat4', value: [1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1] } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float invert;', - 'uniform mat4 matrix;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;', - '}' - ]; -} - -ColorMatrixFilter.prototype = Object.create(AbstractFilter.prototype); -ColorMatrixFilter.prototype.constructor = ColorMatrixFilter; -module.exports = ColorMatrixFilter; - -Object.defineProperties(ColorMatrixFilter.prototype, { - /** - * Sets the matrix of the color matrix filter - * - * @member {number[]} - * @memberof ColorMatrixFilter# - * @default [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] - */ - matrix: { - get: function () { - return this.uniforms.matrix.value; - }, - set: function (value) { - this.uniforms.matrix.value = value; - } - } -}); - -},{"./AbstractFilter":56}],63:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * This lowers the color depth of your image by the given amount, producing an image with a smaller palette. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function ColorStepFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - step: { type: '1f', value: 5 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - 'uniform sampler2D uSampler;', - 'uniform float step;', - - 'void main(void) {', - ' vec4 color = texture2D(uSampler, vTextureCoord);', - ' color = floor(color * step) / step;', - ' gl_FragColor = color;', - '}' - ]; -} - -ColorStepFilter.prototype = Object.create(AbstractFilter.prototype); -ColorStepFilter.prototype.constructor = ColorStepFilter; -module.exports = ColorStepFilter; - -Object.defineProperties(ColorStepFilter.prototype, { - /** - * The number of steps to reduce the palette by. - * - * @member {number} - * @memberof ColorStepFilter# - */ - step: { - get: function () { - return this.uniforms.step.value; - }, - set: function (value) { - this.uniforms.step.value = value; - } - } -}); - -},{"./AbstractFilter":56}],64:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * The ConvolutionFilter class applies a matrix convolution filter effect. - * A convolution combines pixels in the input image with neighboring pixels to produce a new image. - * A wide variety of image effects can be achieved through convolutions, including blurring, edge - * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. - * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. - * @param width {number} Width of the object you are transforming - * @param height {number} Height of the object you are transforming - */ -function ConvolutionFilter(matrix, width, height) { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - matrix: { type: '1fv', value: new Float32Array(matrix) }, - texelSizeX: { type: '1f', value: 1 / width }, - texelSizeY: { type: '1f', value: 1 / height } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying mediump vec2 vTextureCoord;', - - 'uniform sampler2D texture;', - 'uniform float texelSizeX;', - 'uniform float texelSizeY;', - 'uniform float matrix[9];', - - 'vec2 px = vec2(texelSizeX, texelSizeY);', - - 'void main(void) {', - ' vec4 c11 = texture2D(texture, vTextureCoord - px);', // top left - ' vec4 c12 = texture2D(texture, vec2(vTextureCoord.x, vTextureCoord.y - px.y));', // top center - ' vec4 c13 = texture2D(texture, vec2(vTextureCoord.x + px.x, vTextureCoord.y - px.y));', // top right - - ' vec4 c21 = texture2D(texture, vec2(vTextureCoord.x - px.x, vTextureCoord.y) );', // mid left - ' vec4 c22 = texture2D(texture, vTextureCoord);', // mid center - ' vec4 c23 = texture2D(texture, vec2(vTextureCoord.x + px.x, vTextureCoord.y) );', // mid right - - ' vec4 c31 = texture2D(texture, vec2(vTextureCoord.x - px.x, vTextureCoord.y + px.y) );', // bottom left - ' vec4 c32 = texture2D(texture, vec2(vTextureCoord.x, vTextureCoord.y + px.y) );', // bottom center - ' vec4 c33 = texture2D(texture, vTextureCoord + px );', // bottom right - - ' gl_FragColor = ', - ' c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] +', - ' c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] +', - ' c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8];', - ' gl_FragColor.a = c22.a;', - '}' - ]; -} - -ConvolutionFilter.prototype = Object.create(AbstractFilter.prototype); -ConvolutionFilter.prototype.constructor = ConvolutionFilter; -module.exports = ConvolutionFilter; - -Object.defineProperties(ConvolutionFilter.prototype, { - /** - * An array of values used for matrix transformation. Specified as a 9 point Array. - * - * @member {number[]} - * @memberof ConvolutionFilter# - */ - matrix: { - get: function () { - return this.uniforms.matrix.value; - }, - set: function (value) { - this.uniforms.matrix.value = new Float32Array(value); - } - }, - - /** - * Width of the object you are transforming - * - * @member {number} - * @memberof ConvolutionFilter# - */ - width: { - get: function () { - return this.uniforms.texelSizeX.value; - }, - set: function (value) { - this.uniforms.texelSizeX.value = 1/value; - } - }, - - /** - * Height of the object you are transforming - * - * @member {number} - * @memberof ConvolutionFilter# - */ - height: { - get: function () { - return this.uniforms.texelSizeY.value; - }, - set: function (value) { - this.uniforms.texelSizeY.value = 1/value; - } - } -}); - -},{"./AbstractFilter":56}],65:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * A Cross Hatch effect filter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function CrossHatchFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - blur: { type: '1f', value: 1 / 512 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float blur;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' float lum = length(texture2D(uSampler, vTextureCoord.xy).rgb);', - - ' gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);', - - ' if (lum < 1.00) {', - ' if (mod(gl_FragCoord.x + gl_FragCoord.y, 10.0) == 0.0) {', - ' gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);', - ' }', - ' }', - - ' if (lum < 0.75) {', - ' if (mod(gl_FragCoord.x - gl_FragCoord.y, 10.0) == 0.0) {', - ' gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);', - ' }', - ' }', - - ' if (lum < 0.50) {', - ' if (mod(gl_FragCoord.x + gl_FragCoord.y - 5.0, 10.0) == 0.0) {', - ' gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);', - ' }', - ' }', - - ' if (lum < 0.3) {', - ' if (mod(gl_FragCoord.x - gl_FragCoord.y - 5.0, 10.0) == 0.0) {', - ' gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);', - ' }', - ' }', - '}' - ]; -} - -CrossHatchFilter.prototype = Object.create(AbstractFilter.prototype); -CrossHatchFilter.prototype.constructor = CrossHatchFilter; -module.exports = CrossHatchFilter; - -Object.defineProperties(CrossHatchFilter.prototype, { - /** - * Sets the strength of both the blur. - * - * @member {number} - * @memberof CrossHatchFilter# - * @default 2 - */ - blur: { - get: function () { - return this.uniforms.blur.value / (1/7000); - }, - set: function (value) { - //this.padding = value; - this.uniforms.blur.value = (1/7000) * value; - } - } -}); - -},{"./AbstractFilter":56}],66:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * The DisplacementFilter class uses the pixel values from the specified texture (called the displacement map) to perform a displacement of an object. - * You can use this filter to apply all manor of crazy warping effects - * Currently the r property of the texture is used offset the x and the g property of the texture is used to offset the y. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - * @param texture {Texture} The texture used for the displacement map * must be power of 2 texture at the moment - */ -function DisplacementFilter(texture) { - AbstractFilter.call(this); - - texture.baseTexture._powerOf2 = true; - - // set the uniforms - this.uniforms = { - displacementMap: { type: 'sampler2D', value: texture }, - scale: { type: '2f', value: { x: 30, y: 30 } }, - offset: { type: '2f', value: { x: 0, y: 0 } }, - mapDimensions: { type: '2f', value: { x: 1, y: 5112 } }, - dimensions: { type: '4fv', value: [0, 0, 0, 0] } - }; - - if (texture.baseTexture.hasLoaded) { - this.onTextureLoaded(); - } - else { - this.boundLoadedFunction = this.onTextureLoaded.bind(this); - - texture.baseTexture.on('loaded', this.boundLoadedFunction); - } - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform sampler2D displacementMap;', - 'uniform sampler2D uSampler;', - 'uniform vec2 scale;', - 'uniform vec2 offset;', - 'uniform vec4 dimensions;', - 'uniform vec2 mapDimensions;',// = vec2(256.0, 256.0);', - // 'const vec2 textureDimensions = vec2(750.0, 750.0);', - - 'void main(void) {', - ' vec2 mapCords = vTextureCoord.xy;', - ' mapCords += (dimensions.zw + offset)/ dimensions.xy ;', - ' mapCords.y *= -1.0;', - ' mapCords.y += 1.0;', - - ' vec2 matSample = texture2D(displacementMap, mapCords).xy;', - ' matSample -= 0.5;', - ' matSample *= scale;', - ' matSample /= mapDimensions;', - - ' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x + matSample.x, vTextureCoord.y + matSample.y));', - - //TODO: Is this needed? - ' gl_FragColor.rgb = mix( gl_FragColor.rgb, gl_FragColor.rgb, 1.0);', - '}' - ]; -} - -DisplacementFilter.prototype = Object.create(AbstractFilter.prototype); -DisplacementFilter.prototype.constructor = DisplacementFilter; -module.exports = DisplacementFilter; - -/** - * Sets the map dimensions uniforms when the texture becomes available. - * - * @private - */ -DisplacementFilter.prototype.onTextureLoaded = function () { - this.uniforms.mapDimensions.value.x = this.uniforms.displacementMap.value.width; - this.uniforms.mapDimensions.value.y = this.uniforms.displacementMap.value.height; - - this.uniforms.displacementMap.value.baseTexture.off('loaded', this.boundLoadedFunction); -}; - -Object.defineProperties(DisplacementFilter.prototype, { - /** - * The texture used for the displacement map. Must be power of 2 texture. - * - * @member {Texture} - * @memberof DisplacementFilter# - */ - map: { - get: function () { - return this.uniforms.displacementMap.value; - }, - set: function (value) { - this.uniforms.displacementMap.value = value; - } - }, - - /** - * The multiplier used to scale the displacement result from the map calculation. - * - * @member {Point} - * @memberof DisplacementFilter# - */ - scale: { - get: function () { - return this.uniforms.scale.value; - }, - set: function (value) { - this.uniforms.scale.value = value; - } - }, - - /** - * The offset used to move the displacement map. - * - * @member {Point} - * @memberof DisplacementFilter# - */ - offset: { - get: function () { - return this.uniforms.offset.value; - }, - set: function (value) { - this.uniforms.offset.value = value; - } - } -}); - -},{"./AbstractFilter":56}],67:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js - */ - -/** - * This filter applies a dotscreen effect making display objects appear to be made out of - * black and white halftone dots like an old printer. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function DotScreenFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - scale: { type: '1f', value: 1 }, - angle: { type: '1f', value: 5 }, - dimensions: { type: '4fv', value: [0, 0, 0, 0] } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform vec4 dimensions;', - 'uniform sampler2D uSampler;', - - 'uniform float angle;', - 'uniform float scale;', - - 'float pattern() {', - ' float s = sin(angle), c = cos(angle);', - ' vec2 tex = vTextureCoord * dimensions.xy;', - ' vec2 point = vec2(', - ' c * tex.x - s * tex.y,', - ' s * tex.x + c * tex.y', - ' ) * scale;', - ' return (sin(point.x) * sin(point.y)) * 4.0;', - '}', - - 'void main() {', - ' vec4 color = texture2D(uSampler, vTextureCoord);', - ' float average = (color.r + color.g + color.b) / 3.0;', - ' gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a);', - '}' - ]; -} - -DotScreenFilter.prototype = Object.create(AbstractFilter.prototype); -DotScreenFilter.prototype.constructor = DotScreenFilter; -module.exports = DotScreenFilter; - -Object.defineProperties(DotScreenFilter.prototype, { - /** - * The scale of the effect. - * @member {number} - * @memberof DotScreenFilter# - */ - scale: { - get: function () { - return this.uniforms.scale.value; - }, - set: function (value) { - this.uniforms.scale.value = value; - } - }, - - /** - * The radius of the effect. - * @member {number} - * @memberof DotScreenFilter# - */ - angle: { - get: function () { - return this.uniforms.angle.value; - }, - set: function (value) { - this.uniforms.angle.value = value; - } - } -}); - -},{"./AbstractFilter":56}],68:[function(require,module,exports){ -/** - * A target and pass info object for filters. - * - * @class - * @namespace PIXI - */ -function FilterBlock() { - /** - * The visible state of this FilterBlock. - * - * @member {boolean} - */ - this.visible = true; - - /** - * The renderable state of this FilterBlock. - * - * @member {boolean} - */ - this.renderable = true; -} - -FilterBlock.prototype.constructor = FilterBlock; -module.exports = FilterBlock; - -},{}],69:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * This greyscales the palette of your Display Objects. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function GrayFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - gray: { type: '1f', value: 1 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform sampler2D uSampler;', - 'uniform float gray;', - - 'void main(void) {', - ' gl_FragColor = texture2D(uSampler, vTextureCoord);', - ' gl_FragColor.rgb = mix(gl_FragColor.rgb, vec3(0.2126*gl_FragColor.r + 0.7152*gl_FragColor.g + 0.0722*gl_FragColor.b), gray);', - // ' gl_FragColor = gl_FragColor;', - '}' - ]; -} - -GrayFilter.prototype = Object.create(AbstractFilter.prototype); -GrayFilter.prototype.constructor = GrayFilter; -module.exports = GrayFilter; - -Object.defineProperties(GrayFilter.prototype, { - /** - * The strength of the gray. 1 will make the object black and white, 0 will make the object its normal color. - * - * @member {number} - * @memberof GrayFilter# - */ - gray: { - get: function () { - return this.uniforms.gray.value; - }, - set: function (value) { - this.uniforms.gray.value = value; - } - } -}); - -},{"./AbstractFilter":56}],70:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * This inverts your Display Objects colors. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function InvertFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - invert: { type: '1f', value: 1 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float invert;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' gl_FragColor = texture2D(uSampler, vTextureCoord);', - ' gl_FragColor.rgb = mix( (vec3(1)-gl_FragColor.rgb) * gl_FragColor.a, gl_FragColor.rgb, 1.0 - invert);', - //' gl_FragColor.rgb = gl_FragColor.rgb * gl_FragColor.a;', - // ' gl_FragColor = gl_FragColor * vColor;', - '}' - ]; -} - -InvertFilter.prototype = Object.create(AbstractFilter.prototype); -InvertFilter.prototype.constructor = InvertFilter; -module.exports = InvertFilter; - -Object.defineProperties(InvertFilter.prototype, { - /** - * The strength of the invert. 1 will fully invert the colors, 0 will make the object its normal color - * - * @member {number} - * @memberof InvertFilter# - */ - invert: { - get: function () { - return this.uniforms.invert.value; - }, - set: function (value) { - this.uniforms.invert.value = value; - } - } -}); - -},{"./AbstractFilter":56}],71:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * @author Vico @vicocotea - * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/noise.js - */ - -/** - * A Noise effect filter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function NoiseFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - noise: { type: '1f', value: 0.5 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float noise;', - 'uniform sampler2D uSampler;', - - 'float rand(vec2 co) {', - ' return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);', - '}', - - 'void main() {', - ' vec4 color = texture2D(uSampler, vTextureCoord);', - - ' float diff = (rand(vTextureCoord) - 0.5) * noise;', - ' color.r += diff;', - ' color.g += diff;', - ' color.b += diff;', - - ' gl_FragColor = color;', - '}' - ]; -} - -NoiseFilter.prototype = Object.create(AbstractFilter.prototype); -NoiseFilter.prototype.constructor = NoiseFilter; -module.exports = NoiseFilter; - -Object.defineProperties(NoiseFilter.prototype, { - /** - * The amount of noise to apply. - * - * @member {number} - * @memberof NoiseFilter# - * @default 0.5 - */ - noise: { - get: function () { - return this.uniforms.noise.value; - }, - set: function (value) { - this.dirty = true; - this.uniforms.noise.value = value; - } - } -}); - -},{"./AbstractFilter":56}],72:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * The NormalMapFilter class uses the pixel values from the specified texture (called the displacement map) to perform a displacement of an object. - * You can use this filter to apply all manor of crazy warping effects - * Currently the r property of the texture is used offset the x and the g property of the texture is used to offset the y. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - * @param texture {Texture} The texture used for the normal map, must be power of 2 texture at the moment - */ -function NormalMapFilter(texture) { - AbstractFilter.call(this); - - texture.baseTexture._powerOf2 = true; - - // set the uniforms - this.uniforms = { - displacementMap: { type: 'sampler2D', value: texture }, - scale: { type: '2f', value: { x: 15, y: 15 } }, - offset: { type: '2f', value: { x: 0, y: 0 } }, - mapDimensions: { type: '2f', value: { x: 1, y: 1 } }, - dimensions: { type: '4f', value: [0, 0, 0, 0] }, - // LightDir: { type: 'f3', value: [0, 1, 0] }, - LightPos: { type: '3f', value: [0, 1, 0] } - }; - - if (texture.baseTexture.hasLoaded) { - this.onTextureLoaded(); - } - else { - this.boundLoadedFunction = this.onTextureLoaded.bind(this); - - texture.baseTexture.on('loaded', this.boundLoadedFunction); - } - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'uniform sampler2D displacementMap;', - 'uniform sampler2D uSampler;', - - 'uniform vec4 dimensions;', - - 'const vec2 Resolution = vec2(1.0,1.0);', //resolution of screen - 'uniform vec3 LightPos;', //light position, normalized - 'const vec4 LightColor = vec4(1.0, 1.0, 1.0, 1.0);', //light RGBA -- alpha is intensity - 'const vec4 AmbientColor = vec4(1.0, 1.0, 1.0, 0.5);', //ambient RGBA -- alpha is intensity - 'const vec3 Falloff = vec3(0.0, 1.0, 0.2);', //attenuation coefficients - - 'uniform vec3 LightDir;',//' = vec3(1.0, 0.0, 1.0);', - - - 'uniform vec2 mapDimensions;',// = vec2(256.0, 256.0);', - - - 'void main(void) {', - ' vec2 mapCords = vTextureCoord.xy;', - - ' vec4 color = texture2D(uSampler, vTextureCoord.st);', - ' vec3 nColor = texture2D(displacementMap, vTextureCoord.st).rgb;', - - - ' mapCords *= vec2(dimensions.x/512.0, dimensions.y/512.0);', - - ' mapCords.y *= -1.0;', - ' mapCords.y += 1.0;', - - //RGBA of our diffuse color - ' vec4 DiffuseColor = texture2D(uSampler, vTextureCoord);', - - //RGB of our normal map - ' vec3 NormalMap = texture2D(displacementMap, mapCords).rgb;', - - //The delta position of light - //'vec3 LightDir = vec3(LightPos.xy - (gl_FragCoord.xy / Resolution.xy), LightPos.z);', - ' vec3 LightDir = vec3(LightPos.xy - (mapCords.xy), LightPos.z);', - //Correct for aspect ratio - // ' LightDir.x *= Resolution.x / Resolution.y;', - - //Determine distance (used for attenuation) BEFORE we normalize our LightDir - ' float D = length(LightDir);', - - //normalize our vectors - ' vec3 N = normalize(NormalMap * 2.0 - 1.0);', - ' vec3 L = normalize(LightDir);', - - //Pre-multiply light color with intensity - //Then perform 'N dot L' to determine our diffuse term - ' vec3 Diffuse = (LightColor.rgb * LightColor.a) * max(dot(N, L), 0.0);', - - //pre-multiply ambient color with intensity - ' vec3 Ambient = AmbientColor.rgb * AmbientColor.a;', - - //calculate attenuation - ' float Attenuation = 1.0 / ( Falloff.x + (Falloff.y*D) + (Falloff.z*D*D) );', - - //the calculation which brings it all together - ' vec3 Intensity = Ambient + Diffuse * Attenuation;', - ' vec3 FinalColor = DiffuseColor.rgb * Intensity;', - ' gl_FragColor = vColor * vec4(FinalColor, DiffuseColor.a);', - // ' gl_FragColor = vec4(1.0, 0.0, 0.0, Attenuation);',//vColor * vec4(FinalColor, DiffuseColor.a);', - - /*// normalise color - ' vec3 normal = normalize(nColor * 2.0 - 1.0);', - - ' vec3 deltaPos = vec3( (light.xy - gl_FragCoord.xy) / resolution.xy, light.z );', - - ' float lambert = clamp(dot(normal, lightDir), 0.0, 1.0);', - - ' float d = sqrt(dot(deltaPos, deltaPos));', - ' float att = 1.0 / ( attenuation.x + (attenuation.y*d) + (attenuation.z*d*d) );', - - ' vec3 result = (ambientColor * ambientIntensity) + (lightColor.rgb * lambert) * att;', - ' result *= color.rgb;', - - ' gl_FragColor = vec4(result, 1.0);',*/ - '}' - ]; -} - -NormalMapFilter.prototype = Object.create(AbstractFilter.prototype); -NormalMapFilter.prototype.constructor = NormalMapFilter; -module.exports = NormalMapFilter; - -/** - * Sets the map dimensions uniforms when the texture becomes available. - * - */ -NormalMapFilter.prototype.onTextureLoaded = function () { - this.uniforms.mapDimensions.value.x = this.uniforms.displacementMap.value.width; - this.uniforms.mapDimensions.value.y = this.uniforms.displacementMap.value.height; - - this.uniforms.displacementMap.value.baseTexture.off('loaded', this.boundLoadedFunction); -}; - -Object.defineProperties(NormalMapFilter.prototype, { - /** - * The texture used for the displacement map. Must be power of 2 texture. - * - * @member {Texture} - * @memberof NormalMapFilter# - */ - map: { - get: function () { - return this.uniforms.displacementMap.value; - }, - set: function (value) { - this.uniforms.displacementMap.value = value; - } - }, - - /** - * The multiplier used to scale the displacement result from the map calculation. - * - * @member {Point} - * @memberof NormalMapFilter# - */ - scale: { - get: function () { - return this.uniforms.scale.value; - }, - set: function (value) { - this.uniforms.scale.value = value; - } - }, - - /** - * The offset used to move the displacement map. - * - * @member {Point} - * @memberof NormalMapFilter# - */ - offset: { - get: function () { - return this.uniforms.offset.value; - }, - set: function (value) { - this.uniforms.offset.value = value; - } - } -}); - -},{"./AbstractFilter":56}],73:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * This filter applies a pixelate effect making display objects appear 'blocky'. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function PixelateFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - invert: { type: '1f', value: 0 }, - dimensions: { type: '4fv', value: new Float32Array([10000, 100, 10, 10]) }, - pixelSize: { type: '2f', value: { x: 10, y: 10 } } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform vec2 testDim;', - 'uniform vec4 dimensions;', - 'uniform vec2 pixelSize;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' vec2 coord = vTextureCoord;', - - ' vec2 size = dimensions.xy/pixelSize;', - - ' vec2 color = floor( ( vTextureCoord * size ) ) / size + pixelSize/dimensions.xy * 0.5;', - ' gl_FragColor = texture2D(uSampler, color);', - '}' - ]; -} - -PixelateFilter.prototype = Object.create(AbstractFilter.prototype); -PixelateFilter.prototype.constructor = PixelateFilter; -module.exports = PixelateFilter; - -Object.defineProperties(PixelateFilter.prototype, { - /** - * This a point that describes the size of the blocks. x is the width of the block and y is the height. - * - * @member {Point} - * @memberof PixelateFilter# - */ - size: { - get: function () { - return this.uniforms.pixelSize.value; - }, - set: function (value) { - this.uniforms.pixelSize.value = value; - } - } -}); - -},{"./AbstractFilter":56}],74:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * An RGB Split Filter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function RGBSplitFilter() { - AbstractFilter.call(this); - - this.passes = [this]; - - // set the uniforms - this.uniforms = { - red: { type: '2f', value: { x: 20, y: 20 } }, - green: { type: '2f', value: { x: -20, y: 20 } }, - blue: { type: '2f', value: { x: 20, y: -20 } }, - dimensions: { type: '4fv', value: [0, 0, 0, 0] } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform vec2 red;', - 'uniform vec2 green;', - 'uniform vec2 blue;', - 'uniform vec4 dimensions;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' gl_FragColor.r = texture2D(uSampler, vTextureCoord + red/dimensions.xy).r;', - ' gl_FragColor.g = texture2D(uSampler, vTextureCoord + green/dimensions.xy).g;', - ' gl_FragColor.b = texture2D(uSampler, vTextureCoord + blue/dimensions.xy).b;', - ' gl_FragColor.a = texture2D(uSampler, vTextureCoord).a;', - '}' - ]; -} - -RGBSplitFilter.prototype = Object.create(AbstractFilter.prototype); -RGBSplitFilter.prototype.constructor = RGBSplitFilter; -module.exports = RGBSplitFilter; - -Object.defineProperties(RGBSplitFilter.prototype, { - /** - * Red channel offset. - * - * @member {Point} - * @memberof RGBSplitFilter# - */ - red: { - get: function () { - return this.uniforms.red.value; - }, - set: function (value) { - this.uniforms.red.value = value; - } - }, - - /** - * Green channel offset. - * - * @member {Point} - * @memberof RGBSplitFilter# - */ - green: { - get: function () { - return this.uniforms.green.value; - }, - set: function (value) { - this.uniforms.green.value = value; - } - }, - - /** - * Blue offset. - * - * @member {Point} - * @memberof RGBSplitFilter# - */ - blue: { - get: function () { - return this.uniforms.blue.value; - }, - set: function (value) { - this.uniforms.blue.value = value; - } - } -}); - -},{"./AbstractFilter":56}],75:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * This applies a sepia effect to your Display Objects. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function SepiaFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - sepia: { type: '1f', value: 1 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float sepia;', - 'uniform sampler2D uSampler;', - - 'const mat3 sepiaMatrix = mat3(0.3588, 0.7044, 0.1368, 0.2990, 0.5870, 0.1140, 0.2392, 0.4696, 0.0912);', - - 'void main(void) {', - ' gl_FragColor = texture2D(uSampler, vTextureCoord);', - ' gl_FragColor.rgb = mix( gl_FragColor.rgb, gl_FragColor.rgb * sepiaMatrix, sepia);', - '}' - ]; -} - -SepiaFilter.prototype = Object.create(AbstractFilter.prototype); -SepiaFilter.prototype.constructor = SepiaFilter; -module.exports = SepiaFilter; - -Object.defineProperties(SepiaFilter.prototype, { - /** - * The strength of the sepia. 1 will apply the full sepia effect, 0 will make the object its normal color. - * - * @member {number} - * @memberof SepiaFilter# - */ - sepia: { - get: function () { - return this.uniforms.sepia.value; - }, - set: function (value) { - this.uniforms.sepia.value = value; - } - } -}); - -},{"./AbstractFilter":56}],76:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * A Smart Blur Filter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function SmartBlurFilter() { - AbstractFilter.call(this); - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - - 'uniform sampler2D uSampler;', - 'const vec2 delta = vec2(1.0/10.0, 0.0);', - - 'float random(vec3 scale, float seed) {', - ' return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);', - '}', - - - 'void main(void) {', - ' vec4 color = vec4(0.0);', - ' float total = 0.0;', - - ' float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);', - - ' for (float t = -30.0; t <= 30.0; t++) {', - ' float percent = (t + offset - 0.5) / 30.0;', - ' float weight = 1.0 - abs(percent);', - ' vec4 sample = texture2D(uSampler, vTextureCoord + delta * percent);', - ' sample.rgb *= sample.a;', - ' color += sample * weight;', - ' total += weight;', - ' }', - - ' gl_FragColor = color / total;', - ' gl_FragColor.rgb /= gl_FragColor.a + 0.00001;', - '}' - ]; -} - -SmartBlurFilter.prototype = Object.create(AbstractFilter.prototype); -SmartBlurFilter.prototype.constructor = SmartBlurFilter; -module.exports = SmartBlurFilter; - -},{"./AbstractFilter":56}],77:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'), - TiltShiftXFilter = require('./TiltShiftXFilter'), - TiltShiftYFilter = require('./TiltShiftYFilter'); - -/** - * @author Vico @vicocotea - * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ - */ - -/** - * A TiltShift Filter. Manages the pass of both a TiltShiftXFilter and TiltShiftYFilter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function TiltShiftFilter() { - AbstractFilter.call(this); - - this.tiltShiftXFilter = new TiltShiftXFilter(); - this.tiltShiftYFilter = new TiltShiftYFilter(); - - this.tiltShiftXFilter.updateDelta(); - this.tiltShiftXFilter.updateDelta(); - - this.passes = [this.tiltShiftXFilter, this.tiltShiftYFilter]; -} - -TiltShiftFilter.prototype = Object.create(AbstractFilter.prototype); -TiltShiftFilter.prototype.constructor = TiltShiftFilter; -module.exports = TiltShiftFilter; - -Object.defineProperties(TiltShiftFilter.prototype, { - /** - * The strength of the blur. - * - * @member {number} - * @memberof TiltShiftFilter# - */ - blur: { - get: function () { - return this.tiltShiftXFilter.blur; - }, - set: function (value) { - this.tiltShiftXFilter.blur = this.tiltShiftYFilter.blur = value; - } - }, - - /** - * The strength of the gradient blur. - * - * @member {number} - * @memberof TiltShiftFilter# - */ - gradientBlur: { - get: function () { - return this.tiltShiftXFilter.gradientBlur; - }, - set: function (value) { - this.tiltShiftXFilter.gradientBlur = this.tiltShiftYFilter.gradientBlur = value; - } - }, - - /** - * The Y value to start the effect at. - * - * @member {number} - * @memberof TiltShiftFilter# - */ - start: { - get: function () { - return this.tiltShiftXFilter.start; - }, - set: function (value) { - this.tiltShiftXFilter.start = this.tiltShiftYFilter.start = value; - } - }, - - /** - * The Y value to end the effect at. - * - * @member {number} - * @memberof TiltShiftFilter# - */ - end: { - get: function () { - return this.tiltShiftXFilter.end; - }, - set: function (value) { - this.tiltShiftXFilter.end = this.tiltShiftYFilter.end = value; - } - }, -}); - -},{"./AbstractFilter":56,"./TiltShiftXFilter":78,"./TiltShiftYFilter":79}],78:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * @author Vico @vicocotea - * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ - */ - -/** - * A TiltShiftXFilter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function TiltShiftXFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - blur: { type: '1f', value: 100 }, - gradientBlur: { type: '1f', value: 600 }, - start: { type: '2f', value: { x: 0, y: window.screenHeight / 2 } }, - end: { type: '2f', value: { x: 600, y: window.screenHeight / 2 } }, - delta: { type: '2f', value: { x: 30, y: 30 } }, - texSize: { type: '2f', value: { x: window.screenWidth, y: window.screenHeight } } - }; - - this.updateDelta(); - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - - 'uniform sampler2D uSampler;', - 'uniform float blur;', - 'uniform float gradientBlur;', - 'uniform vec2 start;', - 'uniform vec2 end;', - 'uniform vec2 delta;', - 'uniform vec2 texSize;', - - 'float random(vec3 scale, float seed) {', - ' return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);', - '}', - - 'void main(void) {', - ' vec4 color = vec4(0.0);', - ' float total = 0.0;', - - ' float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);', - ' vec2 normal = normalize(vec2(start.y - end.y, end.x - start.x));', - ' float radius = smoothstep(0.0, 1.0, abs(dot(vTextureCoord * texSize - start, normal)) / gradientBlur) * blur;', - - ' for (float t = -30.0; t <= 30.0; t++) {', - ' float percent = (t + offset - 0.5) / 30.0;', - ' float weight = 1.0 - abs(percent);', - ' vec4 sample = texture2D(uSampler, vTextureCoord + delta / texSize * percent * radius);', - ' sample.rgb *= sample.a;', - ' color += sample * weight;', - ' total += weight;', - ' }', - - ' gl_FragColor = color / total;', - ' gl_FragColor.rgb /= gl_FragColor.a + 0.00001;', - '}' - ]; -} - -TiltShiftXFilter.prototype = Object.create(AbstractFilter.prototype); -TiltShiftXFilter.prototype.constructor = TiltShiftXFilter; -module.exports = TiltShiftXFilter; - -/** - * Updates the filter delta values. - * - */ -TiltShiftXFilter.prototype.updateDelta = function () { - var dx = this.uniforms.end.value.x - this.uniforms.start.value.x; - var dy = this.uniforms.end.value.y - this.uniforms.start.value.y; - var d = Math.sqrt(dx * dx + dy * dy); - - this.uniforms.delta.value.x = dx / d; - this.uniforms.delta.value.y = dy / d; -}; - - -Object.defineProperties(TiltShiftXFilter.prototype, { - /** - * The strength of the blur. - * - * @member {number} - * @memberof TilttShiftXFilter# - */ - blur: { - get: function () { - return this.uniforms.blur.value; - }, - set: function (value) { - this.uniforms.blur.value = value; - } - }, - - /** - * The strength of the gradient blur. - * - * @member {number} - * @memberof TilttShiftXFilter# - */ - gradientBlur: { - get: function () { - return this.uniforms.gradientBlur.value; - }, - set: function (value) { - this.uniforms.gradientBlur.value = value; - } - }, - - /** - * The X value to start the effect at. - * - * @member {number} - * @memberof TilttShiftXFilter# - */ - start: { - get: function () { - return this.uniforms.start.value; - }, - set: function (value) { - this.uniforms.start.value = value; - this.updateDelta(); - } - }, - - /** - * The X value to end the effect at. - * - * @member {number} - * @memberof TilttShiftXFilter# - */ - end: { - get: function () { - return this.uniforms.end.value; - }, - set: function (value) { - this.uniforms.end.value = value; - this.updateDelta(); - } - } -}); - -},{"./AbstractFilter":56}],79:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * @author Vico @vicocotea - * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ - */ - -/** - * A TiltShiftYFilter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function TiltShiftYFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - blur: { type: '1f', value: 100 }, - gradientBlur: { type: '1f', value: 600 }, - start: { type: '2f', value: { x: 0, y: window.screenHeight / 2 } }, - end: { type: '2f', value: { x: 600, y: window.screenHeight / 2 } }, - delta: { type: '2f', value: { x: 30, y: 30 } }, - texSize: { type: '2f', value: { x: window.screenWidth, y: window.screenHeight } } - }; - - this.updateDelta(); - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - - 'uniform sampler2D uSampler;', - 'uniform float blur;', - 'uniform float gradientBlur;', - 'uniform vec2 start;', - 'uniform vec2 end;', - 'uniform vec2 delta;', - 'uniform vec2 texSize;', - - 'float random(vec3 scale, float seed) {', - ' return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);', - '}', - - 'void main(void) {', - ' vec4 color = vec4(0.0);', - ' float total = 0.0;', - - ' float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);', - ' vec2 normal = normalize(vec2(start.y - end.y, end.x - start.x));', - ' float radius = smoothstep(0.0, 1.0, abs(dot(vTextureCoord * texSize - start, normal)) / gradientBlur) * blur;', - - ' for (float t = -30.0; t <= 30.0; t++) {', - ' float percent = (t + offset - 0.5) / 30.0;', - ' float weight = 1.0 - abs(percent);', - ' vec4 sample = texture2D(uSampler, vTextureCoord + delta / texSize * percent * radius);', - ' sample.rgb *= sample.a;', - ' color += sample * weight;', - ' total += weight;', - ' }', - - ' gl_FragColor = color / total;', - ' gl_FragColor.rgb /= gl_FragColor.a + 0.00001;', - '}' - ]; -} - -TiltShiftYFilter.prototype = Object.create(AbstractFilter.prototype); -TiltShiftYFilter.prototype.constructor = TiltShiftYFilter; -module.exports = TiltShiftYFilter; - -/** - * Updates the filter delta values. - * - */ -TiltShiftYFilter.prototype.updateDelta = function (){ - var dx = this.uniforms.end.value.x - this.uniforms.start.value.x; - var dy = this.uniforms.end.value.y - this.uniforms.start.value.y; - var d = Math.sqrt(dx * dx + dy * dy); - this.uniforms.delta.value.x = -dy / d; - this.uniforms.delta.value.y = dx / d; -}; - -Object.defineProperties(TiltShiftYFilter.prototype, { - /** - * The strength of the blur. - * - * @member {number} - * @memberof TiltShiftYFilter# - */ - blur: { - get: function () { - return this.uniforms.blur.value; - }, - set: function (value) { - this.uniforms.blur.value = value; - } - }, - - /** - * The strength of the gradient blur. - * - * @member {number} - * @memberof TiltShiftYFilter# - */ - gradientBlur: { - get: function () { - return this.uniforms.gradientBlur.value; - }, - set: function (value) { - this.uniforms.gradientBlur.value = value; - } - }, - - /** - * The Y value to start the effect at. - * - * @member {number} - * @memberof TiltShiftYFilter# - */ - start: { - get: function () { - return this.uniforms.start.value; - }, - set: function (value) { - this.uniforms.start.value = value; - this.updateDelta(); - } - }, - - /** - * The Y value to end the effect at. - * - * @member {number} - * @memberof TiltShiftYFilter# - */ - end: { - get: function () { - return this.uniforms.end.value; - }, - set: function (value) { - this.uniforms.end.value = value; - this.updateDelta(); - } - } -}); - -},{"./AbstractFilter":56}],80:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * This filter applies a twist effect making display objects appear twisted in the given direction. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function TwistFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - radius: { type: '1f', value: 0.5}, - angle: { type: '1f', value: 5}, - offset: { type: '2f', value: { x: 0.5, y: 0.5 } } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float radius;', - 'uniform float angle;', - 'uniform vec2 offset;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' vec2 coord = vTextureCoord - offset;', - ' float distance = length(coord);', - - ' if (distance < radius) {', - ' float ratio = (radius - distance) / radius;', - ' float angleMod = ratio * ratio * angle;', - ' float s = sin(angleMod);', - ' float c = cos(angleMod);', - ' coord = vec2(coord.x * c - coord.y * s, coord.x * s + coord.y * c);', - ' }', - - ' gl_FragColor = texture2D(uSampler, coord+offset);', - '}' - ]; -} - -TwistFilter.prototype = Object.create(AbstractFilter.prototype); -TwistFilter.prototype.constructor = TwistFilter; -module.exports = TwistFilter; - -Object.defineProperties(TwistFilter.prototype, { - /** - * This point describes the the offset of the twist. - * - * @member {Point} - * @memberof TwistFilter# - */ - offset: { - get: function () { - return this.uniforms.offset.value; - }, - set: function (value) { - this.uniforms.offset.value = value; - } - }, - - /** - * This radius of the twist. - * - * @member {number} - * @memberof TwistFilter# - */ - radius: { - get: function () { - return this.uniforms.radius.value; - }, - set: function (value) { - this.uniforms.radius.value = value; - } - }, - - /** - * This angle of the twist. - * - * @member {number} - * @memberof TwistFilter# - */ - angle: { - get: function () { - return this.uniforms.angle.value; - }, - set: function (value) { - this.uniforms.angle.value = value; - } - } -}); - -},{"./AbstractFilter":56}],81:[function(require,module,exports){ -/** - * @file Main export of the PIXI filters library - * @author Mat Groves - * @copyright 2013-2015 GoodBoyDigital - * @license {@link https://github.com/GoodBoyDigital/pixi.js/blob/master/LICENSE|MIT License} - */ - -/** - * @namespace PIXI - */ -module.exports = { - AbstractFilter: require('./AbstractFilter'), - AlphaMaskFilter: require('./AlphaMaskFilter'), - AsciiFilter: require('./AsciiFilter'), - BlurFilter: require('./BlurFilter'), - BlurXFilter: require('./BlurXFilter'), - BlurYFilter: require('./BlurYFilter'), - ColorMatrixFilter: require('./ColorMatrixFilter'), - ColorStepFilter: require('./ColorStepFilter'), - ConvolutionFilter: require('./ConvolutionFilter'), - CrossHatchFilter: require('./CrossHatchFilter'), - DisplacementFilter: require('./DisplacementFilter'), - DotScreenFilter: require('./DotScreenFilter'), - FilterBlock: require('./FilterBlock'), - GrayFilter: require('./GrayFilter'), - InvertFilter: require('./InvertFilter'), - NoiseFilter: require('./NoiseFilter'), - NormalMapFilter: require('./NormalMapFilter'), - PixelateFilter: require('./PixelateFilter'), - RGBSplitFilter: require('./RGBSplitFilter'), - SepiaFilter: require('./SepiaFilter'), - SmartBlurFilter: require('./SmartBlurFilter'), - TiltShiftFilter: require('./TiltShiftFilter'), - TiltShiftXFilter: require('./TiltShiftXFilter'), - TiltShiftYFilter: require('./TiltShiftYFilter'), - TwistFilter: require('./TwistFilter') -}; - -},{"./AbstractFilter":56,"./AlphaMaskFilter":57,"./AsciiFilter":58,"./BlurFilter":59,"./BlurXFilter":60,"./BlurYFilter":61,"./ColorMatrixFilter":62,"./ColorStepFilter":63,"./ConvolutionFilter":64,"./CrossHatchFilter":65,"./DisplacementFilter":66,"./DotScreenFilter":67,"./FilterBlock":68,"./GrayFilter":69,"./InvertFilter":70,"./NoiseFilter":71,"./NormalMapFilter":72,"./PixelateFilter":73,"./RGBSplitFilter":74,"./SepiaFilter":75,"./SmartBlurFilter":76,"./TiltShiftFilter":77,"./TiltShiftXFilter":78,"./TiltShiftYFilter":79,"./TwistFilter":80}],82:[function(require,module,exports){ -var core = require('../core'); - -/** - * Holds all information related to an Interaction event - * - * @class - * @namespace PIXI - */ -function InteractionData() { - /** - * This point stores the global coords of where the touch/mouse event happened - * - * @member {Point} - */ - this.global = new core.math.Point(); - - /** - * The target Sprite that was interacted with - * - * @member {Sprite} - */ - this.target = null; - - /** - * When passed to an event handler, this will be the original DOM Event that was captured - * - * @member {Event} - */ - this.originalEvent = null; -} - -InteractionData.prototype.constructor = InteractionData; -module.exports = InteractionData; - -/** - * This will return the local coordinates of the specified displayObject for this InteractionData - * - * @param displayObject {DisplayObject} The DisplayObject that you would like the local coords off - * @param [point] {Point} A Point object in which to store the value, optional (otherwise will create a new point) - * @return {Point} A point containing the coordinates of the InteractionData position relative to the DisplayObject - */ -InteractionData.prototype.getLocalPosition = function (displayObject, point) { - var worldTransform = displayObject.worldTransform; - var global = this.global; - - // do a cheeky transform to get the mouse coords; - var a00 = worldTransform.a, a01 = worldTransform.c, a02 = worldTransform.tx, - a10 = worldTransform.b, a11 = worldTransform.d, a12 = worldTransform.ty, - id = 1 / (a00 * a11 + a01 * -a10); - - point = point || new core.math.Point(); - - point.x = a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id; - point.y = a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id; - - // set the mouse coords... - return point; -}; - -},{"../core":9}],83:[function(require,module,exports){ -var core = require('../core'), - InteractionData = require('./InteractionData'); - -// TODO: Obviously rewrite this... -var INTERACTION_FREQUENCY = 30; -var AUTO_PREVENT_DEFAULT = true; - -/** - * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive - * if its interactive parameter is set to true - * This manager also supports multitouch. - * - * @class - * @namespace PIXI - * @param stage {Stage} The stage to handle interactions - */ -function InteractionManager(stage) { - /** - * A reference to the stage - * - * @member {Stage} - */ - this.stage = stage; - - /** - * The mouse data - * - * @member {InteractionData} - */ - this.mouse = new InteractionData(); - - /** - * An object that stores current touches (InteractionData) by id reference - * - * @member {object} - */ - this.touches = {}; - - /** - * @member {Point} - * @private - */ - this.tempPoint = new core.math.Point(); - - /** - * @member {boolean} - * @default - */ - this.mouseoverEnabled = true; - - /** - * Tiny little interactiveData pool ! - * - * @member {Array} - */ - this.pool = []; - - /** - * An array containing all the iterative items from the our interactive tree - * - * @member {Array} - * @private - */ - this.interactiveItems = []; - - /** - * The DOM element to bind to. - * - * @member {HTMLElement} - * @private - */ - this.interactionDOMElement = null; - - /** - * Have events been attached to the dom element? - * - * @member {boolean} - * @private - */ - this.eventsAdded = false; - - //this will make it so that you don't have to call bind all the time - - /** - * @member {Function} - */ - this.onMouseMove = this.onMouseMove.bind( this ); - - /** - * @member {Function} - */ - this.onMouseDown = this.onMouseDown.bind(this); - - /** - * @member {Function} - */ - this.onMouseOut = this.onMouseOut.bind(this); - - /** - * @member {Function} - */ - this.onMouseUp = this.onMouseUp.bind(this); - - /** - * @member {Function} - */ - this.onTouchStart = this.onTouchStart.bind(this); - - /** - * @member {Function} - */ - this.onTouchEnd = this.onTouchEnd.bind(this); - - /** - * @member {Function} - */ - this.onTouchMove = this.onTouchMove.bind(this); - - /** - * @member {number} - */ - this.last = 0; - - /** - * The css style of the cursor that is being used - * @member {string} - */ - this.currentCursorStyle = 'inherit'; - - /** - * Is set to true when the mouse is moved out of the canvas - * @member {boolean} - */ - this.mouseOut = false; - - /** - * @member {number} - */ - this.resolution = 1; - - // used for hit testing - this._tempPoint = new core.math.Point(); -} - -InteractionManager.prototype.constructor = InteractionManager; -module.exports = InteractionManager; - -/** - * Collects an interactive sprite recursively to have their interactions managed - * - * @param displayObject {DisplayObject} the displayObject to collect - * @param iParent {DisplayObject} the display object's parent - * @private - */ -InteractionManager.prototype.collectInteractiveSprite = function (displayObject, iParent) { - var children = displayObject.children; - var length = children.length; - - // make an interaction tree... {item.__interactiveParent} - for (var i = length - 1; i >= 0; i--) { - var child = children[i]; - - // push all interactive bits - if (child._interactive) { - iParent.interactiveChildren = true; - //child.__iParent = iParent; - this.interactiveItems.push(child); - - if (child.children.length > 0) { - this.collectInteractiveSprite(child, child); - } - } - else { - child.__iParent = null; - if (child.children.length > 0) { - this.collectInteractiveSprite(child, iParent); - } - } - - } -}; - -/** - * Sets the DOM element which will receive mouse/touch events. This is useful for when you have - * other DOM elements on top of the renderers Canvas element. With this you'll be bale to deletegate - * another DOM element to receive those events. - * - * @param element {HTMLElement} the DOM element which will receive mouse and touch events. - * @param [resolution=1] {number} THe resolution of the new element (relative to the canvas). - * @private - */ -InteractionManager.prototype.setTargetElement = function (element, resolution) { - this.removeEvents(); - - this.interactionDOMElement = element; - - this.resolution = resolution || 1; - - this.addEvents(); -}; - -/** - * - * @private - */ -InteractionManager.prototype.addEvents = function () { - if (!this.interactionDOMElement) { - return; - } - - if (window.navigator.msPointerEnabled) { - this.interactionDOMElement.style['-ms-content-zooming'] = 'none'; - this.interactionDOMElement.style['-ms-touch-action'] = 'none'; - } - - this.interactionDOMElement.addEventListener('mousemove', this.onMouseMove, true); - this.interactionDOMElement.addEventListener('mousedown', this.onMouseDown, true); - this.interactionDOMElement.addEventListener('mouseout', this.onMouseOut, true); - - this.interactionDOMElement.addEventListener('touchstart', this.onTouchStart, true); - this.interactionDOMElement.addEventListener('touchend', this.onTouchEnd, true); - this.interactionDOMElement.addEventListener('touchmove', this.onTouchMove, true); - - window.addEventListener('mouseup', this.onMouseUp, true); - - this.eventsAdded = true; -}; - -/** - * - * @private - */ -InteractionManager.prototype.removeEvents = function () { - if (!this.interactionDOMElement) { - return; - } - - if (window.navigator.msPointerEnabled) { - this.interactionDOMElement.style['-ms-content-zooming'] = ''; - this.interactionDOMElement.style['-ms-touch-action'] = ''; - } - - this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); - this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); - this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); - - this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); - this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); - this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); - - this.interactionDOMElement = null; - - window.removeEventListener('mouseup', this.onMouseUp, true); - - this.eventsAdded = false; -}; - -/** - * updates the state of interactive objects - * - * @private - */ -InteractionManager.prototype.update = function () { - if (!this.interactionDOMElement) { - return; - } - - // frequency of 30fps?? - var now = Date.now(); - var diff = now - this.last; - diff = (diff * INTERACTION_FREQUENCY ) / 1000; - if (diff < 1) { - return; - } - - this.last = now; - - var i = 0; - - // ok.. so mouse events?? - // yes for now :) - // OPTIMISE - how often to check?? - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - // loop through interactive objects! - var length = this.interactiveItems.length; - var cursor = 'inherit'; - var over = false; - - for (i = 0; i < length; i++) { - var item = this.interactiveItems[i]; - - // OPTIMISATION - only calculate every time if the mousemove function exists.. - // OK so.. does the object have any other interactive functions? - // hit-test the clip! - // if (item.mouseover || item.mouseout || item.buttonMode) - // { - // ok so there are some functions so lets hit test it.. - item.__hit = this.hitTest(item, this.mouse); - this.mouse.target = item; - // ok so deal with interactions.. - // looks like there was a hit! - if (item.__hit && !over) { - if (item.buttonMode) { - cursor = item.defaultCursor; - } - - if (!item.interactiveChildren) { - over = true; - } - - if (!item.__isOver) { - if (item.mouseover) { - item.mouseover (this.mouse); - } - item.__isOver = true; - } - } - else { - if (item.__isOver) { - // roll out! - if (item.mouseout) { - item.mouseout (this.mouse); - } - item.__isOver = false; - } - } - } - - if (this.currentCursorStyle !== cursor) { - this.currentCursorStyle = cursor; - this.interactionDOMElement.style.cursor = cursor; - } -}; - -/** - * @private - */ -InteractionManager.prototype.rebuildInteractiveGraph = function () { - this.dirty = false; - - var len = this.interactiveItems.length; - - for (var i = 0; i < len; i++) { - this.interactiveItems[i].interactiveChildren = false; - } - - this.interactiveItems.length = 0; - - if (this.stage.interactive) { - this.interactiveItems.push(this.stage); - } - - // Go through and collect all the objects that are interactive.. - this.collectInteractiveSprite(this.stage, this.stage); -}; - -/** - * Is called when the mouse moves across the renderer element - * - * @param event {Event} The DOM event of the mouse moving - * @private - */ -InteractionManager.prototype.onMouseMove = function (event) { - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - this.mouse.originalEvent = event; - - // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.interactionDOMElement.getBoundingClientRect(); - - this.mouse.global.x = (event.clientX - rect.left) * (this.interactionDOMElement.width / rect.width) / this.resolution; - this.mouse.global.y = (event.clientY - rect.top) * ( this.interactionDOMElement.height / rect.height) / this.resolution; - - var length = this.interactiveItems.length; - - for (var i = 0; i < length; i++) { - var item = this.interactiveItems[i]; - - // Call the function! - if (item.mousemove) { - item.mousemove(this.mouse); - } - } -}; - -/** - * Is called when the mouse button is pressed down on the renderer element - * - * @param event {Event} The DOM event of a mouse button being pressed down - * @private - */ -InteractionManager.prototype.onMouseDown = function (event) { - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - this.mouse.originalEvent = event; - - if (AUTO_PREVENT_DEFAULT) { - this.mouse.originalEvent.preventDefault(); - } - - // loop through interaction tree... - // hit test each item! -> - // get interactive items under point?? - //stage.__i - var length = this.interactiveItems.length; - - var e = this.mouse.originalEvent; - var isRightButton = e.button === 2 || e.which === 3; - var downFunction = isRightButton ? 'rightdown' : 'mousedown'; - var clickFunction = isRightButton ? 'rightclick' : 'click'; - var buttonIsDown = isRightButton ? '__rightIsDown' : '__mouseIsDown'; - var isDown = isRightButton ? '__isRightDown' : '__isDown'; - - // while - // hit test - for (var i = 0; i < length; i++) { - var item = this.interactiveItems[i]; - - if (item[downFunction] || item[clickFunction]) { - item[buttonIsDown] = true; - item.__hit = this.hitTest(item, this.mouse); - - if (item.__hit) { - //call the function! - if (item[downFunction]) { - item[downFunction](this.mouse); - } - item[isDown] = true; - - // just the one! - if (!item.interactiveChildren) { - break; - } - } - } - } -}; - -/** - * Is called when the mouse is moved out of the renderer element - * - * @param event {Event} The DOM event of a mouse being moved out - * @private - */ -InteractionManager.prototype.onMouseOut = function (event) { - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - this.mouse.originalEvent = event; - - var length = this.interactiveItems.length; - - this.interactionDOMElement.style.cursor = 'inherit'; - - for (var i = 0; i < length; i++) { - var item = this.interactiveItems[i]; - if (item.__isOver) { - this.mouse.target = item; - if (item.mouseout) { - item.mouseout(this.mouse); - } - item.__isOver = false; - } - } - - this.mouseOut = true; - - // move the mouse to an impossible position - this.mouse.global.x = -10000; - this.mouse.global.y = -10000; -}; - -/** - * Is called when the mouse button is released on the renderer element - * - * @param event {Event} The DOM event of a mouse button being released - * @private - */ -InteractionManager.prototype.onMouseUp = function (event) { - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - this.mouse.originalEvent = event; - - var length = this.interactiveItems.length; - var up = false; - - var e = this.mouse.originalEvent; - var isRightButton = e.button === 2 || e.which === 3; - - var upFunction = isRightButton ? 'rightup' : 'mouseup'; - var clickFunction = isRightButton ? 'rightclick' : 'click'; - var upOutsideFunction = isRightButton ? 'rightupoutside' : 'mouseupoutside'; - var isDown = isRightButton ? '__isRightDown' : '__isDown'; - - for (var i = 0; i < length; i++) { - var item = this.interactiveItems[i]; - - if (item[clickFunction] || item[upFunction] || item[upOutsideFunction]) { - item.__hit = this.hitTest(item, this.mouse); - - if (item.__hit && !up) { - //call the function! - if (item[upFunction]) { - item[upFunction](this.mouse); - } - if (item[isDown]) { - if (item[clickFunction]) { - item[clickFunction](this.mouse); - } - } - - if (!item.interactiveChildren) { - up = true; - } - } - else { - if (item[isDown]) { - if (item[upOutsideFunction]) { - item[upOutsideFunction](this.mouse); - } - } - } - - item[isDown] = false; - } - } -}; - -/** - * Tests if the current mouse coordinates hit a sprite - * - * @param item {DisplayObject} The displayObject to test for a hit - * @param interactionData {InteractionData} The interactionData object to update in the case there is a hit - * @private - */ -InteractionManager.prototype.hitTest = function (item, interactionData) { - var global = interactionData.global; - - if (!item.worldVisible) { - return false; - } - - // map the global point to local space. - item.worldTransform.applyInverse(global, this._tempPoint); - - var x = this._tempPoint.x, - y = this._tempPoint.y, - i; - - interactionData.target = item; - - //a sprite or display object with a hit area defined - if (item.hitArea && item.hitArea.contains) { - return item.hitArea.contains(x, y); - } - // a sprite with no hitarea defined - else if (item instanceof core.Sprite) { - var width = item.texture.frame.width; - var height = item.texture.frame.height; - var x1 = -width * item.anchor.x; - var y1; - - if (x > x1 && x < x1 + width) { - y1 = -height * item.anchor.y; - - if (y > y1 && y < y1 + height) { - // set the target property if a hit is true! - return true; - } - } - } - else if (item instanceof core.Graphics) { - var graphicsData = item.graphicsData; - for (i = 0; i < graphicsData.length; i++) { - var data = graphicsData[i]; - - if (!data.fill) { - continue; - } - - // only deal with fills.. - if (data.shape) { - if (data.shape.contains(x, y)) { - //interactionData.target = item; - return true; - } - } - } - } - - var length = item.children.length; - - for (i = 0; i < length; i++) { - var tempItem = item.children[i]; - var hit = this.hitTest(tempItem, interactionData); - if (hit) { - // hmm.. TODO SET CORRECT TARGET? - interactionData.target = item; - return true; - } - } - return false; -}; - -/** - * Is called when a touch is moved across the renderer element - * - * @param event {Event} The DOM event of a touch moving across the renderer view - * @private - */ -InteractionManager.prototype.onTouchMove = function (event) { - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - var rect = this.interactionDOMElement.getBoundingClientRect(); - var changedTouches = event.changedTouches; - var touchData; - var i = 0; - - for (i = 0; i < changedTouches.length; i++) { - var touchEvent = changedTouches[i]; - touchData = this.touches[touchEvent.identifier]; - touchData.originalEvent = event; - - // update the touch position - touchData.global.x = ( (touchEvent.clientX - rect.left) * (this.interactionDOMElement.width / rect.width) ) / this.resolution; - touchData.global.y = ( (touchEvent.clientY - rect.top) * (this.interactionDOMElement.height / rect.height) ) / this.resolution; - if (navigator.isCocoonJS && !rect.left && !rect.top && !event.target.style.width && !event.target.style.height) { - //Support for CocoonJS fullscreen scale modes - touchData.global.x = touchEvent.clientX; - touchData.global.y = touchEvent.clientY; - } - - for (var j = 0; j < this.interactiveItems.length; j++) { - var item = this.interactiveItems[j]; - if (item.touchmove && item.__touchData && item.__touchData[touchEvent.identifier]) { - item.touchmove(touchData); - } - } - } -}; - -/** - * Is called when a touch is started on the renderer element - * - * @param event {Event} The DOM event of a touch starting on the renderer view - * @private - */ -InteractionManager.prototype.onTouchStart = function (event) { - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - var rect = this.interactionDOMElement.getBoundingClientRect(); - - if (AUTO_PREVENT_DEFAULT) { - event.preventDefault(); - } - - var changedTouches = event.changedTouches; - for (var i=0; i < changedTouches.length; i++) { - var touchEvent = changedTouches[i]; - - var touchData = this.pool.pop(); - if (!touchData) { - touchData = new InteractionData(); - } - - touchData.originalEvent = event; - - this.touches[touchEvent.identifier] = touchData; - touchData.global.x = ( (touchEvent.clientX - rect.left) * (this.interactionDOMElement.width / rect.width) ) / this.resolution; - touchData.global.y = ( (touchEvent.clientY - rect.top) * (this.interactionDOMElement.height / rect.height) ) / this.resolution; - if (navigator.isCocoonJS && !rect.left && !rect.top && !event.target.style.width && !event.target.style.height) { - //Support for CocoonJS fullscreen scale modes - touchData.global.x = touchEvent.clientX; - touchData.global.y = touchEvent.clientY; - } - - var length = this.interactiveItems.length; - - for (var j = 0; j < length; j++) { - var item = this.interactiveItems[j]; - - if (item.touchstart || item.tap) { - item.__hit = this.hitTest(item, touchData); - - if (item.__hit) { - //call the function! - if (item.touchstart) { - item.touchstart(touchData); - } - - item.__isDown = true; - item.__touchData = item.__touchData || {}; - item.__touchData[touchEvent.identifier] = touchData; - - if (!item.interactiveChildren) { - break; - } - } - } - } - } -}; - -/** - * Is called when a touch is ended on the renderer element - * - * @param event {Event} The DOM event of a touch ending on the renderer view - * @private - */ -InteractionManager.prototype.onTouchEnd = function (event) { - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - var rect = this.interactionDOMElement.getBoundingClientRect(); - var changedTouches = event.changedTouches; - - for (var i=0; i < changedTouches.length; i++) { - var touchEvent = changedTouches[i]; - var touchData = this.touches[touchEvent.identifier]; - var up = false; - touchData.global.x = ( (touchEvent.clientX - rect.left) * (this.interactionDOMElement.width / rect.width) ) / this.resolution; - touchData.global.y = ( (touchEvent.clientY - rect.top) * (this.interactionDOMElement.height / rect.height) ) / this.resolution; - if (navigator.isCocoonJS && !rect.left && !rect.top && !event.target.style.width && !event.target.style.height) { - //Support for CocoonJS fullscreen scale modes - touchData.global.x = touchEvent.clientX; - touchData.global.y = touchEvent.clientY; - } - - var length = this.interactiveItems.length; - for (var j = 0; j < length; j++) { - var item = this.interactiveItems[j]; - - if (item.__touchData && item.__touchData[touchEvent.identifier]) { - - item.__hit = this.hitTest(item, item.__touchData[touchEvent.identifier]); - - // so this one WAS down... - touchData.originalEvent = event; - // hitTest?? - - if (item.touchend || item.tap) { - if (item.__hit && !up) { - if (item.touchend) { - item.touchend(touchData); - } - if (item.__isDown && item.tap) { - item.tap(touchData); - } - if (!item.interactiveChildren) { - up = true; - } - } - else { - if (item.__isDown && item.touchendoutside) { - item.touchendoutside(touchData); - } - } - - item.__isDown = false; - } - - item.__touchData[touchEvent.identifier] = null; - } - } - // remove the touch.. - this.pool.push(touchData); - this.touches[touchEvent.identifier] = null; - } -}; - -},{"../core":9,"./InteractionData":82}],84:[function(require,module,exports){ -/** - * @file Main export of the PIXI interactions library - * @author Mat Groves - * @copyright 2013-2015 GoodBoyDigital - * @license {@link https://github.com/GoodBoyDigital/pixi.js/blob/master/LICENSE|MIT License} - */ - -/** - * @namespace PIXI - */ -module.exports = { - InteractionData: require('./InteractionData'), - InteractionManager: require('./InteractionManager') -}; - -},{"./InteractionData":82,"./InteractionManager":83}],85:[function(require,module,exports){ -var core = require('../core'), - ImageLoader = require('./ImageLoader'); - -/** - * The atlas file loader is used to load in Texture Atlas data and parse it. When loaded this class will dispatch a 'loaded' event. If loading fails this class will dispatch an 'error' event. - * - * To generate the data you can use http://www.codeandweb.com/texturepacker and publish in the 'JSON' format. - * - * It is highly recommended to use texture atlases (also know as 'sprite sheets') as it allowed sprites to be batched and drawn together for highly increased rendering speed. - * Once the data has been loaded the frames are stored in the PIXI texture cache and can be accessed though Texture.fromFrameId() and Sprite.fromFrameId() - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param url {String} The url of the JSON file - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - */ -function AtlasLoader(url, crossorigin) { - this.url = url; - this.baseUrl = url.replace(/[^\/]*$/, ''); - this.crossorigin = crossorigin; - this.loaded = false; -} - -AtlasLoader.prototype.constructor = AtlasLoader; -module.exports = AtlasLoader; - -core.utils.eventTarget.mixin(AtlasLoader.prototype); - - /** - * Starts loading the JSON file - * - */ -AtlasLoader.prototype.load = function () { - this.ajaxRequest = new core.utils.AjaxRequest(); - this.ajaxRequest.onreadystatechange = this.onAtlasLoaded.bind(this); - - this.ajaxRequest.open('GET', this.url, true); - - if (this.ajaxRequest.overrideMimeType) { - this.ajaxRequest.overrideMimeType('application/json'); - } - - this.ajaxRequest.send(null); -}; - -/** - * Invoked when the Atlas has fully loaded. Parses the JSON and builds the texture frames. - * - * @private - */ -AtlasLoader.prototype.onAtlasLoaded = function () { - if (this.ajaxRequest.readyState === 4) { - if (this.ajaxRequest.status === 200 || window.location.href.indexOf('http') === -1) { - this.atlas = { - meta : { - image : [] - }, - frames : [] - }; - var result = this.ajaxRequest.responseText.split(/\r?\n/); - var lineCount = -3; - - var currentImageId = 0; - var currentFrame = null; - var nameInNextLine = false; - - var i = 0, - j = 0, - selfOnLoaded = this.onLoaded.bind(this); - - // parser without rotation support yet! - for (i = 0; i < result.length; i++) { - result[i] = result[i].replace(/^\s+|\s+$/g, ''); - - if (result[i] === '') { - nameInNextLine = i+1; - } - - if (result[i].length > 0) { - if (nameInNextLine === i) { - this.atlas.meta.image.push(result[i]); - currentImageId = this.atlas.meta.image.length - 1; - this.atlas.frames.push({}); - lineCount = -3; - } else if (lineCount > 0) { - if (lineCount % 7 === 1) { // frame name - if (currentFrame != null) { //jshint ignore:line - this.atlas.frames[currentImageId][currentFrame.name] = currentFrame; - } - currentFrame = { name: result[i], frame : {} }; - } else { - var text = result[i].split(' '); - if (lineCount % 7 === 3) { // position - currentFrame.frame.x = Number(text[1].replace(',', '')); - currentFrame.frame.y = Number(text[2]); - } else if (lineCount % 7 === 4) { // size - currentFrame.frame.w = Number(text[1].replace(',', '')); - currentFrame.frame.h = Number(text[2]); - } else if (lineCount % 7 === 5) { // real size - var realSize = { - x : 0, - y : 0, - w : Number(text[1].replace(',', '')), - h : Number(text[2]) - }; - - if (realSize.w > currentFrame.frame.w || realSize.h > currentFrame.frame.h) { - currentFrame.trimmed = true; - currentFrame.realSize = realSize; - } else { - currentFrame.trimmed = false; - } - } - } - } - lineCount++; - } - } - - if (currentFrame != null) { //jshint ignore:line - this.atlas.frames[currentImageId][currentFrame.name] = currentFrame; - } - - if (this.atlas.meta.image.length > 0) { - this.images = []; - for (j = 0; j < this.atlas.meta.image.length; j++) { - // sprite sheet - var textureUrl = this.baseUrl + this.atlas.meta.image[j]; - var frameData = this.atlas.frames[j]; - this.images.push(new ImageLoader(textureUrl, this.crossorigin)); - - for (i in frameData) { - var rect = frameData[i].frame; - if (rect) { - core.utils.TextureCache[i] = new core.Texture(this.images[j].texture.baseTexture, { - x: rect.x, - y: rect.y, - width: rect.w, - height: rect.h - }); - if (frameData[i].trimmed) { - core.utils.TextureCache[i].realSize = frameData[i].realSize; - // trim in pixi not supported yet, todo update trim properties if it is done ... - core.utils.TextureCache[i].trim.x = 0; - core.utils.TextureCache[i].trim.y = 0; - } - } - } - } - - this.currentImageId = 0; - for (j = 0; j < this.images.length; j++) { - this.images[j].on('loaded', selfOnLoaded); - } - this.images[this.currentImageId].load(); - - } else { - this.onLoaded(); - } - - } else { - this.onError(); - } - } -}; - -/** - * Invoked when json file has loaded. - * - * @private - */ -AtlasLoader.prototype.onLoaded = function () { - if (this.images.length - 1 > this.currentImageId) { - this.currentImageId++; - this.images[this.currentImageId].load(); - } else { - this.loaded = true; - this.emit('loaded', { content: this }); - } -}; - -/** - * Invoked when an error occurs. - * - * @private - */ -AtlasLoader.prototype.onError = function () { - this.emit('error', { content: this }); -}; - -},{"../core":9,"./ImageLoader":87}],86:[function(require,module,exports){ -var core = require('../core'), - ImageLoader = require('./ImageLoader'); - -/** - * The xml loader is used to load in XML bitmap font data ('xml' or 'fnt') - * To generate the data you can use http://www.angelcode.com/products/bmfont/ - * This loader will also load the image file as the data. - * When loaded this class will dispatch a 'loaded' event - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param url {String} The url of the sprite sheet JSON file - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - */ -function BitmapFontLoader(url, crossorigin) { - /** - * The url of the bitmap font data - * - * @member {String} - */ - this.url = url; - - /** - * Whether the requests should be treated as cross origin - * - * @member {boolean} - */ - this.crossorigin = crossorigin; - - /** - * The base url of the bitmap font data - * - * @member {String} - * @readOnly - */ - this.baseUrl = url.replace(/[^\/]*$/, ''); - - /** - * The texture of the bitmap font - * - * @member {Texture} - */ - this.texture = null; -} - -// constructor -BitmapFontLoader.prototype.constructor = BitmapFontLoader; -module.exports = BitmapFontLoader; - -core.utils.eventTarget.mixin(BitmapFontLoader.prototype); - -/** - * Loads the XML font data - * - */ -BitmapFontLoader.prototype.load = function () { - this.ajaxRequest = new core.utils.AjaxRequest(); - this.ajaxRequest.onreadystatechange = this.onXMLLoaded.bind(this); - - this.ajaxRequest.open('GET', this.url, true); - - if (this.ajaxRequest.overrideMimeType) { - this.ajaxRequest.overrideMimeType('application/xml'); - } - - this.ajaxRequest.send(null); -}; - -/** - * Invoked when the XML file is loaded, parses the data. - * - * @private - */ -BitmapFontLoader.prototype.onXMLLoaded = function () { - if (this.ajaxRequest.readyState === 4) { - if (this.ajaxRequest.status === 200 || window.location.protocol.indexOf('http') === -1) { - var responseXML = this.ajaxRequest.responseXML; - if (!responseXML || /MSIE 9/i.test(navigator.userAgent) || navigator.isCocoonJS) { - if (typeof(window.DOMParser) === 'function') { - var domparser = new DOMParser(); - responseXML = domparser.parseFromString(this.ajaxRequest.responseText, 'text/xml'); - } else { - var div = document.createElement('div'); - div.innerHTML = this.ajaxRequest.responseText; - responseXML = div; - } - } - - var textureUrl = this.baseUrl + responseXML.getElementsByTagName('page')[0].getAttribute('file'); - var image = new ImageLoader(textureUrl, this.crossorigin); - this.texture = image.texture.baseTexture; - - var data = {}; - var info = responseXML.getElementsByTagName('info')[0]; - var common = responseXML.getElementsByTagName('common')[0]; - data.font = info.getAttribute('face'); - data.size = parseInt(info.getAttribute('size'), 10); - data.lineHeight = parseInt(common.getAttribute('lineHeight'), 10); - data.chars = {}; - - //parse letters - var letters = responseXML.getElementsByTagName('char'); - - for (var i = 0; i < letters.length; i++) { - var charCode = parseInt(letters[i].getAttribute('id'), 10); - - var textureRect = new core.math.Rectangle( - parseInt(letters[i].getAttribute('x'), 10), - parseInt(letters[i].getAttribute('y'), 10), - parseInt(letters[i].getAttribute('width'), 10), - parseInt(letters[i].getAttribute('height'), 10) - ); - - data.chars[charCode] = { - xOffset: parseInt(letters[i].getAttribute('xoffset'), 10), - yOffset: parseInt(letters[i].getAttribute('yoffset'), 10), - xAdvance: parseInt(letters[i].getAttribute('xadvance'), 10), - kerning: {}, - texture: core.utils.TextureCache[charCode] = new core.Texture(this.texture, textureRect) - - }; - } - - //parse kernings - var kernings = responseXML.getElementsByTagName('kerning'); - for (i = 0; i < kernings.length; i++) { - var first = parseInt(kernings[i].getAttribute('first'), 10); - var second = parseInt(kernings[i].getAttribute('second'), 10); - var amount = parseInt(kernings[i].getAttribute('amount'), 10); - - data.chars[second].kerning[first] = amount; - - } - - core.BitmapText.fonts[data.font] = data; - - image.addEventListener('loaded', this.onLoaded.bind(this)); - image.load(); - } - } -}; - -/** - * Invoked when all files are loaded (xml/fnt and texture) - * - * @private - */ -BitmapFontLoader.prototype.onLoaded = function () { - this.emit('loaded', { content: this }); -}; - -},{"../core":9,"./ImageLoader":87}],87:[function(require,module,exports){ -var core = require('../core'); - -/** - * The image loader class is responsible for loading images file formats ('jpeg', 'jpg', 'png' and 'gif') - * Once the image has been loaded it is stored in the PIXI texture cache and can be accessed though Texture.fromFrame() and Sprite.fromFrame() - * When loaded this class will dispatch a 'loaded' event - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param url {String} The url of the image - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - */ -function ImageLoader(url, crossorigin) { - /** - * The texture being loaded - * - * @member {Texture} - */ - this.texture = core.Texture.fromImage(url, crossorigin); - - /** - * if the image is loaded with loadFramedSpriteSheet - * frames will contain the sprite sheet frames - * - * @member {Array} - * @readOnly - */ - this.frames = []; -} - -// constructor -ImageLoader.prototype.constructor = ImageLoader; -module.exports = ImageLoader; - -core.utils.eventTarget.mixin(ImageLoader.prototype); - -/** - * Loads image or takes it from cache - * - */ -ImageLoader.prototype.load = function () { - if (!this.texture.baseTexture.hasLoaded) { - this.texture.baseTexture.on('loaded', this.onLoaded.bind(this)); - this.texture.baseTexture.on('error', this.onError.bind(this)); - } - else { - this.onLoaded(); - } -}; - -/** - * Invoked when image file is loaded or it is already cached and ready to use - * - * @private - */ -ImageLoader.prototype.onLoaded = function () { - this.emit('loaded', { content: this }); -}; - -/** - * Invoked when image file failed loading - * - * @method onError - * @private - */ -ImageLoader.prototype.onError = function () { - this.emit('error', { content: this }); -}; - -/** - * Loads image and split it to uniform sized frames - * - * @param frameWidth {number} width of each frame - * @param frameHeight {number} height of each frame - * @param textureName {String} if given, the frames will be cached in - format - */ -ImageLoader.prototype.loadFramedSpriteSheet = function (frameWidth, frameHeight, textureName) { - this.frames = []; - - var cols = Math.floor(this.texture.width / frameWidth); - var rows = Math.floor(this.texture.height / frameHeight); - - var i=0; - for (var y = 0; y < rows; ++y) { - for (var x = 0; x < cols; ++x, ++i) { - var texture = new core.Texture( - this.texture.baseTexture, - new core.math.Rectangle( - x * frameWidth, - y * frameHeight, - frameWidth, - frameHeight - ) - ); - - this.frames.push(texture); - - if (textureName) { - core.utils.TextureCache[textureName + '-' + i] = texture; - } - } - } - - this.load(); -}; - -},{"../core":9}],88:[function(require,module,exports){ -var core = require('../core'), - spine = require('../spine/SpineRuntime'), - ImageLoader = require('./ImageLoader'), - SpineTextureLoader = require('./SpineTextureLoader'); - -/** - * The json file loader is used to load in JSON data and parse it - * When loaded this class will dispatch a 'loaded' event - * If loading fails this class will dispatch an 'error' event - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param url {String} The url of the JSON file - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - */ -function JsonLoader(url, crossorigin) { - /** - * The url of the bitmap font data - * - * @member {String} - */ - this.url = url; - - /** - * Whether the requests should be treated as cross origin - * - * @member {boolean} - */ - this.crossorigin = crossorigin; - - /** - * The base url of the bitmap font data - * - * @member {String} - * @readOnly - */ - this.baseUrl = url.replace(/[^\/]*$/, ''); - - /** - * Whether the data has loaded yet - * - * @member {boolean} - * @readOnly - */ - this.loaded = false; -} - -// constructor -JsonLoader.prototype.constructor = JsonLoader; -module.exports = JsonLoader; - -core.utils.eventTarget.mixin(JsonLoader.prototype); - -/** - * Loads the JSON data - * - */ -JsonLoader.prototype.load = function () { - if (window.XDomainRequest && this.crossorigin) { - this.ajaxRequest = new window.XDomainRequest(); - - // XDomainRequest has a few quirks. Occasionally it will abort requests - // A way to avoid this is to make sure ALL callbacks are set even if not used - // More info here: http://stackoverflow.com/questions/15786966/xdomainrequest-aborts-post-on-ie-9 - this.ajaxRequest.timeout = 3000; - - this.ajaxRequest.onerror = this.onError.bind(this); - this.ajaxRequest.ontimeout = this.onError.bind(this); - - this.ajaxRequest.onprogress = function () {}; - - this.ajaxRequest.onload = this.onJSONLoaded.bind(this); - } - else { - if (window.XMLHttpRequest) { - this.ajaxRequest = new window.XMLHttpRequest(); - } - else { - this.ajaxRequest = new window.ActiveXObject('Microsoft.XMLHTTP'); - } - - this.ajaxRequest.onreadystatechange = this.onReadyStateChanged.bind(this); - } - - this.ajaxRequest.open('GET',this.url,true); - - this.ajaxRequest.send(); -}; - -/** - * Bridge function to be able to use the more reliable onreadystatechange in XMLHttpRequest. - * - * @private - */ -JsonLoader.prototype.onReadyStateChanged = function () { - if (this.ajaxRequest.readyState === 4 && (this.ajaxRequest.status === 200 || window.location.href.indexOf('http') === -1)) { - this.onJSONLoaded(); - } -}; - -/** - * Invoke when JSON file is loaded - * - * @private - */ -JsonLoader.prototype.onJSONLoaded = function () { - if (!this.ajaxRequest.responseText) { - this.onError(); - return; - } - - this.json = JSON.parse(this.ajaxRequest.responseText); - - if (this.json.frames) { - // sprite sheet - var textureUrl = this.baseUrl + this.json.meta.image; - var image = new ImageLoader(textureUrl, this.crossorigin); - var frameData = this.json.frames; - - this.texture = image.texture.baseTexture; - image.addEventListener('loaded', this.onLoaded.bind(this)); - image.addEventListener('error', this.onError.bind(this)); - - for (var i in frameData) { - var rect = frameData[i].frame; - - if (rect) { - var textureSize = new core.math.Rectangle(rect.x, rect.y, rect.w, rect.h); - var crop = textureSize.clone(); - var trim = null; - - // Check to see if the sprite is trimmed - if (frameData[i].trimmed) { - var actualSize = frameData[i].sourceSize; - var realSize = frameData[i].spriteSourceSize; - trim = new core.math.Rectangle(realSize.x, realSize.y, actualSize.w, actualSize.h); - } - core.utils.TextureCache[i] = new core.Texture(this.texture, textureSize, crop, trim); - } - } - - image.load(); - - } - else if (this.json.bones) { - // check if the json was loaded before - if (core.utils.AnimCache[this.url]) { - this.onLoaded(); - } - else { - /** - * use a bit of hackery to load the atlas file, here we assume that the .json, .atlas and .png files - * that correspond to the spine file are in the same base URL and that the .json and .atlas files - * have the same name - */ - var atlasPath = this.url.substr(0, this.url.lastIndexOf('.')) + '.atlas'; - var atlasLoader = new JsonLoader(atlasPath, this.crossorigin); - // save a copy of the current object for future reference // - var originalLoader = this; - // before loading the file, replace the "onJSONLoaded" function for our own // - atlasLoader.onJSONLoaded = function () { - // at this point "this" points at the atlasLoader (JsonLoader) instance // - if (!this.ajaxRequest.responseText) { - this.onError(); // FIXME: hmm, this is funny because we are not responding to errors yet - return; - } - // create a new instance of a spine texture loader for this spine object // - var textureLoader = new SpineTextureLoader(this.url.substring(0, this.url.lastIndexOf('/'))); - // create a spine atlas using the loaded text and a spine texture loader instance // - var spineAtlas = new spine.Atlas(this.ajaxRequest.responseText, textureLoader); - // now we use an atlas attachment loader // - var attachmentLoader = new spine.AtlasAttachmentLoader(spineAtlas); - // spine animation - var spineJsonParser = new spine.SkeletonJson(attachmentLoader); - var skeletonData = spineJsonParser.readSkeletonData(originalLoader.json); - core.utils.AnimCache[originalLoader.url] = skeletonData; - originalLoader.spine = skeletonData; - originalLoader.spineAtlas = spineAtlas; - originalLoader.spineAtlasLoader = atlasLoader; - // wait for textures to finish loading if needed - if (textureLoader.loadingCount > 0) { - textureLoader.addEventListener('loadedBaseTexture', function (evt){ - if (evt.content.content.loadingCount <= 0) { - originalLoader.onLoaded(); - } - }); - } - else { - originalLoader.onLoaded(); - } - }; - // start the loading // - atlasLoader.load(); - } - } - else { - this.onLoaded(); - } -}; - -/** - * Invoke when json file loaded - * - * @private - */ -JsonLoader.prototype.onLoaded = function () { - this.loaded = true; - this.dispatchEvent({ - type: 'loaded', - content: this - }); -}; - -/** - * Invoke when error occured - * - * @private - */ -JsonLoader.prototype.onError = function () { - - this.dispatchEvent({ - type: 'error', - content: this - }); -}; - -},{"../core":9,"../spine/SpineRuntime":94,"./ImageLoader":87,"./SpineTextureLoader":90}],89:[function(require,module,exports){ -var core = require('../core'), - JsonLoader = require('./JsonLoader'); - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * - * Awesome JS run time provided by EsotericSoftware - * https://github.com/EsotericSoftware/spine-runtimes - * - */ - -/** - * The Spine loader is used to load in JSON spine data - * To generate the data you need to use http://esotericsoftware.com/ and export in the "JSON" format - * Due to a clash of names You will need to change the extension of the spine file from *.json to *.anim for it to load - * See example 12 (http://www.goodboydigital.com/pixijs/examples/12/) to see a working example and check out the source - * You will need to generate a sprite sheet to accompany the spine data - * When loaded this class will dispatch a "loaded" event - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param url {String} The url of the JSON file - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - */ -function SpineLoader(url, crossorigin) { - /** - * The url of the bitmap font data - * - * @member {String} - */ - this.url = url; - - /** - * Whether the requests should be treated as cross origin - * - * @member {boolean} - */ - this.crossorigin = crossorigin; - - /** - * Whether the data has loaded yet - * - * @member {boolean} - * @readOnly - */ - this.loaded = false; -} - -SpineLoader.prototype.constructor = SpineLoader; -module.exports = SpineLoader; - -core.utils.eventTarget.mixin(SpineLoader.prototype); - -/** - * Loads the JSON data - * - */ -SpineLoader.prototype.load = function () { - var scope = this; - var jsonLoader = new JsonLoader(this.url, this.crossorigin); - - jsonLoader.on('loaded', function (event) { - scope.json = event.data.content.json; - scope.onLoaded(); - }); - - jsonLoader.load(); -}; - -/** - * Invoked when JSON file is loaded. - * - * @private - */ -SpineLoader.prototype.onLoaded = function () { - this.loaded = true; - this.emit('loaded', { content: this }); -}; - -},{"../core":9,"./JsonLoader":88}],90:[function(require,module,exports){ -var core = require('../core'); - -/** - * Supporting class to load images from spine atlases as per spine spec. - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param basePath {string} Tha base path where to look for the images to be loaded - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - */ -function SpineTextureLoader(basePath, crossorigin) { - this.basePath = basePath; - this.crossorigin = crossorigin; - this.loadingCount = 0; -} - -SpineTextureLoader.prototype.constructor = SpineTextureLoader; -module.exports = SpineTextureLoader; - -core.utils.eventTarget.mixin(SpineTextureLoader.prototype); - -/** - * Starts loading a base texture as per spine specification - * - * @param page {spine.AtlasPage} Atlas page to which texture belongs - * @param file {string} The file to load, this is just the file path relative to the base path configured in the constructor - */ -SpineTextureLoader.prototype.load = function (page, file) { - page.rendererObject = core.BaseTexture.fromImage(this.basePath + '/' + file, this.crossorigin); - if (!page.rendererObject.hasLoaded) { - var scope = this; - ++scope.loadingCount; - page.rendererObject.addEventListener('loaded', function (){ - --scope.loadingCount; - scope.dispatchEvent({ - type: 'loadedBaseTexture', - content: scope - }); - }); - } -}; - -/** - * Unloads a previously loaded texture as per spine specification - * - * @param texture {BaseTexture} Texture object to destroy - */ -SpineTextureLoader.prototype.unload = function (texture) { - texture.destroy(true); -}; - -},{"../core":9}],91:[function(require,module,exports){ -var core = require('../core'), - JsonLoader = require('./JsonLoader'); - -/** - * The sprite sheet loader is used to load in JSON sprite sheet data - * To generate the data you can use http://www.codeandweb.com/texturepacker and publish in the 'JSON' format - * There is a free version so thats nice, although the paid version is great value for money. - * It is highly recommended to use Sprite sheets (also know as a 'texture atlas') as it means sprites can be batched and drawn together for highly increased rendering speed. - * Once the data has been loaded the frames are stored in the PIXI texture cache and can be accessed though Texture.fromFrameId() and Sprite.fromFrameId() - * This loader will load the image file that the Spritesheet points to as well as the data. - * When loaded this class will dispatch a 'loaded' event - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param url {String} The url of the sprite sheet JSON file - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - */ -function SpriteSheetLoader(url, crossorigin) { - - /** - * The url of the atlas data - * - * @member {String} - */ - this.url = url; - - /** - * Whether the requests should be treated as cross origin - * - * @member {boolean} - */ - this.crossorigin = crossorigin; - - /** - * The base url of the bitmap font data - * - * @member {String} - * @readOnly - */ - this.baseUrl = url.replace(/[^\/]*$/, ''); - - /** - * The texture being loaded - * - * @member {Texture} - */ - this.texture = null; - - /** - * The frames of the sprite sheet - * - * @member {object} - */ - this.frames = {}; -} - -// constructor -SpriteSheetLoader.prototype.constructor = SpriteSheetLoader; -module.exports = SpriteSheetLoader; - -core.utils.eventTarget.mixin(SpriteSheetLoader.prototype); - -/** - * This will begin loading the JSON file - * - */ -SpriteSheetLoader.prototype.load = function () { - var scope = this; - var jsonLoader = new JsonLoader(this.url, this.crossorigin); - - jsonLoader.on('loaded', function (event) { - scope.json = event.data.content.json; - scope.onLoaded(); - }); - - jsonLoader.load(); -}; - -/** - * Invoke when all files are loaded (json and texture) - * - * @private - */ -SpriteSheetLoader.prototype.onLoaded = function () { - this.emit('loaded', { - content: this - }); -}; - -},{"../core":9,"./JsonLoader":88}],92:[function(require,module,exports){ -/** - * @file Main export of the PIXI loaders library - * @author Mat Groves - * @copyright 2013-2015 GoodBoyDigital - * @license {@link https://github.com/GoodBoyDigital/pixi.js/blob/master/LICENSE|MIT License} - */ - -/** - * @namespace PIXI - */ -module.exports = { - AtlasLoader: require('./AtlasLoader'), - BitmapFontLoader: require('./BitmapFontLoader'), - ImageLoader: require('./ImageLoader'), - JsonLoader: require('./JsonLoader'), - SpineLoader: require('./SpineLoader'), - SpriteSheetLoader: require('./SpriteSheetLoader') -}; - -},{"./AtlasLoader":85,"./BitmapFontLoader":86,"./ImageLoader":87,"./JsonLoader":88,"./SpineLoader":89,"./SpriteSheetLoader":91}],93:[function(require,module,exports){ -var core = require('../core'), - spine = require('./SpineRuntime'); - -/* Esoteric Software SPINE wrapper for pixi.js */ - -spine.Bone.yDown = true; - -/** - * A class that enables the you to import and run your spine animations in pixi. - * Spine animation data needs to be loaded using the AssetLoader or SpineLoader before it can be used by this class - * See example 12 (http://www.goodboydigital.com/pixijs/examples/12/) to see a working example and check out the source - * - * @class - * @extends DisplayObjectContainer - * @namespace PIXI - * @param url {string} The url of the spine anim file to be used - */ -function Spine(url) { - core.DisplayObjectContainer.call(this); - - this.spineData = core.utils.AnimCache[url]; - - if (!this.spineData) { - throw new Error('Spine data must be preloaded using SpineLoader or AssetLoader: ' + url); - } - - this.skeleton = new spine.Skeleton(this.spineData); - this.skeleton.updateWorldTransform(); - - this.stateData = new spine.AnimationStateData(this.spineData); - this.state = new spine.AnimationState(this.stateData); - - this.slotContainers = []; - - for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { - var slot = this.skeleton.drawOrder[i]; - var attachment = slot.attachment; - var slotContainer = new core.DisplayObjectContainer(); - this.slotContainers.push(slotContainer); - this.addChild(slotContainer); - - if (attachment instanceof spine.RegionAttachment) { - var spriteName = attachment.rendererObject.name; - var sprite = this.createSprite(slot, attachment); - slot.currentSprite = sprite; - slot.currentSpriteName = spriteName; - slotContainer.addChild(sprite); - } - else if (attachment instanceof spine.MeshAttachment) { - var mesh = this.createMesh(slot, attachment); - slot.currentMesh = mesh; - slot.currentMeshName = attachment.name; - slotContainer.addChild(mesh); - } - else { - continue; - } - - } - - this.autoUpdate = true; -} - -Spine.prototype = Object.create(core.DisplayObjectContainer.prototype); -Spine.prototype.constructor = Spine; -module.exports = Spine; - -Object.defineProperties(Spine.prototype, { - /** - * If this flag is set to true, the spine animation will be autoupdated every time - * the object id drawn. The down side of this approach is that the delta time is - * automatically calculated and you could miss out on cool effects like slow motion, - * pause, skip ahead and the sorts. Most of these effects can be achieved even with - * autoupdate enabled but are harder to achieve. - * - * @member {boolean} - * @memberof Spine# - * @default true - */ - autoUpdate: { - get: function () { - return (this.updateTransform === Spine.prototype.autoUpdateTransform); - }, - - set: function (value) { - this.updateTransform = value ? Spine.prototype.autoUpdateTransform : core.DisplayObjectContainer.prototype.updateTransform; - } - } -}); - -/** - * Update the spine skeleton and its animations by delta time (dt) - * - * @param dt {number} Delta time. Time by which the animation should be updated - */ -Spine.prototype.update = function (dt) { - this.state.update(dt); - this.state.apply(this.skeleton); - this.skeleton.updateWorldTransform(); - - var drawOrder = this.skeleton.drawOrder; - for (var i = 0, n = drawOrder.length; i < n; i++) { - var slot = drawOrder[i]; - var attachment = slot.attachment; - var slotContainer = this.slotContainers[i]; - - if (!attachment) { - slotContainer.visible = false; - continue; - } - - var type = attachment.type; - if (type === spine.AttachmentType.region) { - if (attachment.rendererObject) { - if (!slot.currentSpriteName || slot.currentSpriteName !== attachment.rendererObject.name) { - var spriteName = attachment.rendererObject.name; - if (slot.currentSprite !== undefined) { - slot.currentSprite.visible = false; - } - slot.sprites = slot.sprites || {}; - if (slot.sprites[spriteName] !== undefined) { - slot.sprites[spriteName].visible = true; - } - else { - var sprite = this.createSprite(slot, attachment); - slotContainer.addChild(sprite); - } - slot.currentSprite = slot.sprites[spriteName]; - slot.currentSpriteName = spriteName; - } - } - - var bone = slot.bone; - - slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; - slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; - slotContainer.scale.x = bone.worldScaleX; - slotContainer.scale.y = bone.worldScaleY; - - slotContainer.rotation = -(slot.bone.worldRotation * spine.degRad); - - slot.currentSprite.tint = core.utils.rgb2hex([slot.r,slot.g,slot.b]); - } - else if (type === spine.AttachmentType.skinnedmesh) { - if (!slot.currentMeshName || slot.currentMeshName !== attachment.name) { - var meshName = attachment.name; - if (slot.currentMesh !== undefined) { - slot.currentMesh.visible = false; - } - - slot.meshes = slot.meshes || {}; - - if (slot.meshes[meshName] !== undefined) { - slot.meshes[meshName].visible = true; - } - else { - var mesh = this.createMesh(slot, attachment); - slotContainer.addChild(mesh); - } - - slot.currentMesh = slot.meshes[meshName]; - slot.currentMeshName = meshName; - } - - attachment.computeWorldVertices(slot.bone.skeleton.x, slot.bone.skeleton.y, slot, slot.currentMesh.vertices); - - } - else { - slotContainer.visible = false; - continue; - } - slotContainer.visible = true; - - slotContainer.alpha = slot.a; - } -}; - -/** - * When autoupdate is set to yes this function is used as pixi's updateTransform function - * - * @private - */ -Spine.prototype.autoUpdateTransform = function () { - this.lastTime = this.lastTime || Date.now(); - var timeDelta = (Date.now() - this.lastTime) * 0.001; - this.lastTime = Date.now(); - - this.update(timeDelta); - - core.DisplayObjectContainer.prototype.updateTransform.call(this); -}; - -/** - * Create a new sprite to be used with spine.RegionAttachment - * - * @param slot {spine.Slot} The slot to which the attachment is parented - * @param attachment {spine.RegionAttachment} The attachment that the sprite will represent - * @private - */ -Spine.prototype.createSprite = function (slot, attachment) { - var descriptor = attachment.rendererObject; - var baseTexture = descriptor.page.rendererObject; - var spriteRect = new core.math.Rectangle(descriptor.x, - descriptor.y, - descriptor.rotate ? descriptor.height : descriptor.width, - descriptor.rotate ? descriptor.width : descriptor.height); - var spriteTexture = new core.Texture(baseTexture, spriteRect); - var sprite = new core.Sprite(spriteTexture); - - var baseRotation = descriptor.rotate ? Math.PI * 0.5 : 0.0; - sprite.scale.set(descriptor.width / descriptor.originalWidth, descriptor.height / descriptor.originalHeight); - sprite.rotation = baseRotation - (attachment.rotation * spine.degRad); - sprite.anchor.x = sprite.anchor.y = 0.5; - - slot.sprites = slot.sprites || {}; - slot.sprites[descriptor.name] = sprite; - return sprite; -}; - -/** - * - * @param slot {spine.Slot} The slot to which the attachment is parented - * @param attachment {spine.RegionAttachment} The attachment that the sprite will represent - * @private - */ -Spine.prototype.createMesh = function (slot, attachment) { - var descriptor = attachment.rendererObject; - var baseTexture = descriptor.page.rendererObject; - var texture = new core.Texture(baseTexture); - - var strip = new core.Strip(texture); - strip.drawMode = core.Strip.DrawModes.TRIANGLES; - strip.canvasPadding = 1.5; - - strip.vertices = new Float32Array(attachment.uvs.length); - strip.uvs = attachment.uvs; - strip.indices = attachment.triangles; - - slot.meshes = slot.meshes || {}; - slot.meshes[attachment.name] = strip; - - return strip; -}; - -},{"../core":9,"./SpineRuntime":94}],94:[function(require,module,exports){ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.1 - * - * Copyright (c) 2013, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to install, execute and perform the Spine Runtimes - * Software (the "Software") solely for internal use. Without the written - * permission of Esoteric Software (typically granted by licensing Spine), you - * may not (a) modify, translate, adapt or otherwise create derivative works, - * improvements of the Software or develop new applications using the Software - * or (b) remove, delete, alter or obscure any trademarks or any copyright, - * trademark, patent or other intellectual property or proprietary rights - * notices on or in the Software, including any copy thereof. Redistributions - * in binary or source form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -var spine = module.exports = { - radDeg: 180 / Math.PI, - degRad: Math.PI / 180, - temp: [], - Float32Array: (typeof(Float32Array) === 'undefined') ? Array : Float32Array, - Uint16Array: (typeof(Uint16Array) === 'undefined') ? Array : Uint16Array -}; - -spine.BoneData = function (name, parent) { - this.name = name; - this.parent = parent; -}; -spine.BoneData.prototype = { - length: 0, - x: 0, y: 0, - rotation: 0, - scaleX: 1, scaleY: 1, - inheritScale: true, - inheritRotation: true, - flipX: false, flipY: false -}; - -spine.SlotData = function (name, boneData) { - this.name = name; - this.boneData = boneData; -}; -spine.SlotData.prototype = { - r: 1, g: 1, b: 1, a: 1, - attachmentName: null, - additiveBlending: false -}; - -spine.IkConstraintData = function (name) { - this.name = name; - this.bones = []; -}; -spine.IkConstraintData.prototype = { - target: null, - bendDirection: 1, - mix: 1 -}; - -spine.Bone = function (boneData, skeleton, parent) { - this.data = boneData; - this.skeleton = skeleton; - this.parent = parent; - this.setToSetupPose(); -}; -spine.Bone.yDown = false; -spine.Bone.prototype = { - x: 0, y: 0, - rotation: 0, rotationIK: 0, - scaleX: 1, scaleY: 1, - flipX: false, flipY: false, - m00: 0, m01: 0, worldX: 0, // a b x - m10: 0, m11: 0, worldY: 0, // c d y - worldRotation: 0, - worldScaleX: 1, worldScaleY: 1, - worldFlipX: false, worldFlipY: false, - updateWorldTransform: function () { - var parent = this.parent; - if (parent) { - this.worldX = this.x * parent.m00 + this.y * parent.m01 + parent.worldX; - this.worldY = this.x * parent.m10 + this.y * parent.m11 + parent.worldY; - if (this.data.inheritScale) { - this.worldScaleX = parent.worldScaleX * this.scaleX; - this.worldScaleY = parent.worldScaleY * this.scaleY; - } else { - this.worldScaleX = this.scaleX; - this.worldScaleY = this.scaleY; - } - this.worldRotation = this.data.inheritRotation ? (parent.worldRotation + this.rotationIK) : this.rotationIK; - this.worldFlipX = parent.worldFlipX != this.flipX; - this.worldFlipY = parent.worldFlipY != this.flipY; - } else { - var skeletonFlipX = this.skeleton.flipX, skeletonFlipY = this.skeleton.flipY; - this.worldX = skeletonFlipX ? -this.x : this.x; - this.worldY = (skeletonFlipY != spine.Bone.yDown) ? -this.y : this.y; - this.worldScaleX = this.scaleX; - this.worldScaleY = this.scaleY; - this.worldRotation = this.rotationIK; - this.worldFlipX = skeletonFlipX != this.flipX; - this.worldFlipY = skeletonFlipY != this.flipY; - } - var radians = this.worldRotation * spine.degRad; - var cos = Math.cos(radians); - var sin = Math.sin(radians); - if (this.worldFlipX) { - this.m00 = -cos * this.worldScaleX; - this.m01 = sin * this.worldScaleY; - } else { - this.m00 = cos * this.worldScaleX; - this.m01 = -sin * this.worldScaleY; - } - if (this.worldFlipY != spine.Bone.yDown) { - this.m10 = -sin * this.worldScaleX; - this.m11 = -cos * this.worldScaleY; - } else { - this.m10 = sin * this.worldScaleX; - this.m11 = cos * this.worldScaleY; - } - }, - setToSetupPose: function () { - var data = this.data; - this.x = data.x; - this.y = data.y; - this.rotation = data.rotation; - this.rotationIK = this.rotation; - this.scaleX = data.scaleX; - this.scaleY = data.scaleY; - this.flipX = data.flipX; - this.flipY = data.flipY; - }, - worldToLocal: function (world) { - var dx = world[0] - this.worldX, dy = world[1] - this.worldY; - var m00 = this.m00, m10 = this.m10, m01 = this.m01, m11 = this.m11; - if (this.worldFlipX != (this.worldFlipY != spine.Bone.yDown)) { - m00 = -m00; - m11 = -m11; - } - var invDet = 1 / (m00 * m11 - m01 * m10); - world[0] = dx * m00 * invDet - dy * m01 * invDet; - world[1] = dy * m11 * invDet - dx * m10 * invDet; - }, - localToWorld: function (local) { - var localX = local[0], localY = local[1]; - local[0] = localX * this.m00 + localY * this.m01 + this.worldX; - local[1] = localX * this.m10 + localY * this.m11 + this.worldY; - } -}; - -spine.Slot = function (slotData, bone) { - this.data = slotData; - this.bone = bone; - this.setToSetupPose(); -}; -spine.Slot.prototype = { - r: 1, g: 1, b: 1, a: 1, - _attachmentTime: 0, - attachment: null, - attachmentVertices: [], - setAttachment: function (attachment) { - this.attachment = attachment; - this._attachmentTime = this.bone.skeleton.time; - this.attachmentVertices.length = 0; - }, - setAttachmentTime: function (time) { - this._attachmentTime = this.bone.skeleton.time - time; - }, - getAttachmentTime: function () { - return this.bone.skeleton.time - this._attachmentTime; - }, - setToSetupPose: function () { - var data = this.data; - this.r = data.r; - this.g = data.g; - this.b = data.b; - this.a = data.a; - - var slotDatas = this.bone.skeleton.data.slots; - for (var i = 0, n = slotDatas.length; i < n; i++) { - if (slotDatas[i] == data) { - this.setAttachment(!data.attachmentName ? null : this.bone.skeleton.getAttachmentBySlotIndex(i, data.attachmentName)); - break; - } - } - } -}; - -spine.IkConstraint = function (data, skeleton) { - this.data = data; - this.mix = data.mix; - this.bendDirection = data.bendDirection; - - this.bones = []; - for (var i = 0, n = data.bones.length; i < n; i++) - this.bones.push(skeleton.findBone(data.bones[i].name)); - this.target = skeleton.findBone(data.target.name); -}; -spine.IkConstraint.prototype = { - apply: function () { - var target = this.target; - var bones = this.bones; - switch (bones.length) { - case 1: - spine.IkConstraint.apply1(bones[0], target.worldX, target.worldY, this.mix); - break; - case 2: - spine.IkConstraint.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.mix); - break; - } - } -}; -/** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world - * coordinate system. */ -spine.IkConstraint.apply1 = function (bone, targetX, targetY, alpha) { - var parentRotation = (!bone.data.inheritRotation || !bone.parent) ? 0 : bone.parent.worldRotation; - var rotation = bone.rotation; - var rotationIK = Math.atan2(targetY - bone.worldY, targetX - bone.worldX) * spine.radDeg - parentRotation; - bone.rotationIK = rotation + (rotationIK - rotation) * alpha; -}; -/** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The - * target is specified in the world coordinate system. - * @param child Any descendant bone of the parent. */ -spine.IkConstraint.apply2 = function (parent, child, targetX, targetY, bendDirection, alpha) { - var childRotation = child.rotation, parentRotation = parent.rotation; - if (!alpha) { - child.rotationIK = childRotation; - parent.rotationIK = parentRotation; - return; - } - var positionX, positionY, tempPosition = spine.temp; - var parentParent = parent.parent; - if (parentParent) { - tempPosition[0] = targetX; - tempPosition[1] = targetY; - parentParent.worldToLocal(tempPosition); - targetX = (tempPosition[0] - parent.x) * parentParent.worldScaleX; - targetY = (tempPosition[1] - parent.y) * parentParent.worldScaleY; - } else { - targetX -= parent.x; - targetY -= parent.y; - } - if (child.parent == parent) { - positionX = child.x; - positionY = child.y; - } else { - tempPosition[0] = child.x; - tempPosition[1] = child.y; - child.parent.localToWorld(tempPosition); - parent.worldToLocal(tempPosition); - positionX = tempPosition[0]; - positionY = tempPosition[1]; - } - var childX = positionX * parent.worldScaleX, childY = positionY * parent.worldScaleY; - var offset = Math.atan2(childY, childX); - var len1 = Math.sqrt(childX * childX + childY * childY), len2 = child.data.length * child.worldScaleX; - // Based on code by Ryan Juckett with permission: Copyright (c) 2008-2009 Ryan Juckett, http://www.ryanjuckett.com/ - var cosDenom = 2 * len1 * len2; - if (cosDenom < 0.0001) { - child.rotationIK = childRotation + (Math.atan2(targetY, targetX) * spine.radDeg - parentRotation - childRotation) * alpha; - return; - } - var cos = (targetX * targetX + targetY * targetY - len1 * len1 - len2 * len2) / cosDenom; - if (cos < -1) - cos = -1; - else if (cos > 1) - cos = 1; - var childAngle = Math.acos(cos) * bendDirection; - var adjacent = len1 + len2 * cos, opposite = len2 * Math.sin(childAngle); - var parentAngle = Math.atan2(targetY * adjacent - targetX * opposite, targetX * adjacent + targetY * opposite); - var rotation = (parentAngle - offset) * spine.radDeg - parentRotation; - if (rotation > 180) - rotation -= 360; - else if (rotation < -180) // - rotation += 360; - parent.rotationIK = parentRotation + rotation * alpha; - rotation = (childAngle + offset) * spine.radDeg - childRotation; - if (rotation > 180) - rotation -= 360; - else if (rotation < -180) // - rotation += 360; - child.rotationIK = childRotation + (rotation + parent.worldRotation - child.parent.worldRotation) * alpha; -}; - -spine.Skin = function (name) { - this.name = name; - this.attachments = {}; -}; -spine.Skin.prototype = { - addAttachment: function (slotIndex, name, attachment) { - this.attachments[slotIndex + ":" + name] = attachment; - }, - getAttachment: function (slotIndex, name) { - return this.attachments[slotIndex + ":" + name]; - }, - _attachAll: function (skeleton, oldSkin) { - for (var key in oldSkin.attachments) { - var colon = key.indexOf(":"); - var slotIndex = parseInt(key.substring(0, colon)); - var name = key.substring(colon + 1); - var slot = skeleton.slots[slotIndex]; - if (slot.attachment && slot.attachment.name == name) { - var attachment = this.getAttachment(slotIndex, name); - if (attachment) slot.setAttachment(attachment); - } - } - } -}; - -spine.Animation = function (name, timelines, duration) { - this.name = name; - this.timelines = timelines; - this.duration = duration; -}; -spine.Animation.prototype = { - apply: function (skeleton, lastTime, time, loop, events) { - if (loop && this.duration != 0) { - time %= this.duration; - lastTime %= this.duration; - } - var timelines = this.timelines; - for (var i = 0, n = timelines.length; i < n; i++) - timelines[i].apply(skeleton, lastTime, time, events, 1); - }, - mix: function (skeleton, lastTime, time, loop, events, alpha) { - if (loop && this.duration != 0) { - time %= this.duration; - lastTime %= this.duration; - } - var timelines = this.timelines; - for (var i = 0, n = timelines.length; i < n; i++) - timelines[i].apply(skeleton, lastTime, time, events, alpha); - } -}; -spine.Animation.binarySearch = function (values, target, step) { - var low = 0; - var high = Math.floor(values.length / step) - 2; - if (!high) return step; - var current = high >>> 1; - while (true) { - if (values[(current + 1) * step] <= target) - low = current + 1; - else - high = current; - if (low == high) return (low + 1) * step; - current = (low + high) >>> 1; - } -}; -spine.Animation.binarySearch1 = function (values, target) { - var low = 0; - var high = values.length - 2; - if (!high) return 1; - var current = high >>> 1; - while (true) { - if (values[current + 1] <= target) - low = current + 1; - else - high = current; - if (low == high) return low + 1; - current = (low + high) >>> 1; - } -}; -spine.Animation.linearSearch = function (values, target, step) { - for (var i = 0, last = values.length - step; i <= last; i += step) - if (values[i] > target) return i; - return -1; -}; - -spine.Curves = function (frameCount) { - this.curves = []; // type, x, y, ... - //this.curves.length = (frameCount - 1) * 19/*BEZIER_SIZE*/; -}; -spine.Curves.prototype = { - setLinear: function (frameIndex) { - this.curves[frameIndex * 19/*BEZIER_SIZE*/] = 0/*LINEAR*/; - }, - setStepped: function (frameIndex) { - this.curves[frameIndex * 19/*BEZIER_SIZE*/] = 1/*STEPPED*/; - }, - /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. - * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of - * the difference between the keyframe's values. */ - setCurve: function (frameIndex, cx1, cy1, cx2, cy2) { - var subdiv1 = 1 / 10/*BEZIER_SEGMENTS*/, subdiv2 = subdiv1 * subdiv1, subdiv3 = subdiv2 * subdiv1; - var pre1 = 3 * subdiv1, pre2 = 3 * subdiv2, pre4 = 6 * subdiv2, pre5 = 6 * subdiv3; - var tmp1x = -cx1 * 2 + cx2, tmp1y = -cy1 * 2 + cy2, tmp2x = (cx1 - cx2) * 3 + 1, tmp2y = (cy1 - cy2) * 3 + 1; - var dfx = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv3, dfy = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv3; - var ddfx = tmp1x * pre4 + tmp2x * pre5, ddfy = tmp1y * pre4 + tmp2y * pre5; - var dddfx = tmp2x * pre5, dddfy = tmp2y * pre5; - - var i = frameIndex * 19/*BEZIER_SIZE*/; - var curves = this.curves; - curves[i++] = 2/*BEZIER*/; - - var x = dfx, y = dfy; - for (var n = i + 19/*BEZIER_SIZE*/ - 1; i < n; i += 2) { - curves[i] = x; - curves[i + 1] = y; - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - x += dfx; - y += dfy; - } - }, - getCurvePercent: function (frameIndex, percent) { - percent = percent < 0 ? 0 : (percent > 1 ? 1 : percent); - var curves = this.curves; - var i = frameIndex * 19/*BEZIER_SIZE*/; - var type = curves[i]; - if (type === 0/*LINEAR*/) return percent; - if (type == 1/*STEPPED*/) return 0; - i++; - var x = 0; - for (var start = i, n = i + 19/*BEZIER_SIZE*/ - 1; i < n; i += 2) { - x = curves[i]; - if (x >= percent) { - var prevX, prevY; - if (i == start) { - prevX = 0; - prevY = 0; - } else { - prevX = curves[i - 2]; - prevY = curves[i - 1]; - } - return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX); - } - } - var y = curves[i - 1]; - return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. - } -}; - -spine.RotateTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, angle, ... - this.frames.length = frameCount * 2; -}; -spine.RotateTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 2; - }, - setFrame: function (frameIndex, time, angle) { - frameIndex *= 2; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = angle; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - 2]) { // Time is after last frame. - var amount = bone.data.rotation + frames[frames.length - 1] - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - var frameIndex = spine.Animation.binarySearch(frames, time, 2); - var prevFrameValue = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex - 2/*PREV_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 2 - 1, percent); - - var amount = frames[frameIndex + 1/*FRAME_VALUE*/] - prevFrameValue; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - amount = bone.data.rotation + (prevFrameValue + amount * percent) - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - } -}; - -spine.TranslateTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, x, y, ... - this.frames.length = frameCount * 3; -}; -spine.TranslateTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 3; - }, - setFrame: function (frameIndex, time, x, y) { - frameIndex *= 3; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = x; - this.frames[frameIndex + 2] = y; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - 3]) { // Time is after last frame. - bone.x += (bone.data.x + frames[frames.length - 2] - bone.x) * alpha; - bone.y += (bone.data.y + frames[frames.length - 1] - bone.y) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - var frameIndex = spine.Animation.binarySearch(frames, time, 3); - var prevFrameX = frames[frameIndex - 2]; - var prevFrameY = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*PREV_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); - - bone.x += (bone.data.x + prevFrameX + (frames[frameIndex + 1/*FRAME_X*/] - prevFrameX) * percent - bone.x) * alpha; - bone.y += (bone.data.y + prevFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - prevFrameY) * percent - bone.y) * alpha; - } -}; - -spine.ScaleTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, x, y, ... - this.frames.length = frameCount * 3; -}; -spine.ScaleTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 3; - }, - setFrame: function (frameIndex, time, x, y) { - frameIndex *= 3; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = x; - this.frames[frameIndex + 2] = y; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - 3]) { // Time is after last frame. - bone.scaleX += (bone.data.scaleX * frames[frames.length - 2] - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY * frames[frames.length - 1] - bone.scaleY) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - var frameIndex = spine.Animation.binarySearch(frames, time, 3); - var prevFrameX = frames[frameIndex - 2]; - var prevFrameY = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*PREV_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); - - bone.scaleX += (bone.data.scaleX * (prevFrameX + (frames[frameIndex + 1/*FRAME_X*/] - prevFrameX) * percent) - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY * (prevFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - prevFrameY) * percent) - bone.scaleY) * alpha; - } -}; - -spine.ColorTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, r, g, b, a, ... - this.frames.length = frameCount * 5; -}; -spine.ColorTimeline.prototype = { - slotIndex: 0, - getFrameCount: function () { - return this.frames.length / 5; - }, - setFrame: function (frameIndex, time, r, g, b, a) { - frameIndex *= 5; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = r; - this.frames[frameIndex + 2] = g; - this.frames[frameIndex + 3] = b; - this.frames[frameIndex + 4] = a; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var r, g, b, a; - if (time >= frames[frames.length - 5]) { - // Time is after last frame. - var i = frames.length - 1; - r = frames[i - 3]; - g = frames[i - 2]; - b = frames[i - 1]; - a = frames[i]; - } else { - // Interpolate between the previous frame and the current frame. - var frameIndex = spine.Animation.binarySearch(frames, time, 5); - var prevFrameR = frames[frameIndex - 4]; - var prevFrameG = frames[frameIndex - 3]; - var prevFrameB = frames[frameIndex - 2]; - var prevFrameA = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex - 5/*PREV_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 5 - 1, percent); - - r = prevFrameR + (frames[frameIndex + 1/*FRAME_R*/] - prevFrameR) * percent; - g = prevFrameG + (frames[frameIndex + 2/*FRAME_G*/] - prevFrameG) * percent; - b = prevFrameB + (frames[frameIndex + 3/*FRAME_B*/] - prevFrameB) * percent; - a = prevFrameA + (frames[frameIndex + 4/*FRAME_A*/] - prevFrameA) * percent; - } - var slot = skeleton.slots[this.slotIndex]; - if (alpha < 1) { - slot.r += (r - slot.r) * alpha; - slot.g += (g - slot.g) * alpha; - slot.b += (b - slot.b) * alpha; - slot.a += (a - slot.a) * alpha; - } else { - slot.r = r; - slot.g = g; - slot.b = b; - slot.a = a; - } - } -}; - -spine.AttachmentTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, ... - this.frames.length = frameCount; - this.attachmentNames = []; - this.attachmentNames.length = frameCount; -}; -spine.AttachmentTimeline.prototype = { - slotIndex: 0, - getFrameCount: function () { - return this.frames.length; - }, - setFrame: function (frameIndex, time, attachmentName) { - this.frames[frameIndex] = time; - this.attachmentNames[frameIndex] = attachmentName; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) { - if (lastTime > time) this.apply(skeleton, lastTime, Number.MAX_VALUE, null, 0); - return; - } else if (lastTime > time) // - lastTime = -1; - - var frameIndex = time >= frames[frames.length - 1] ? frames.length - 1 : spine.Animation.binarySearch1(frames, time) - 1; - if (frames[frameIndex] < lastTime) return; - - var attachmentName = this.attachmentNames[frameIndex]; - skeleton.slots[this.slotIndex].setAttachment( - !attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); - } -}; - -spine.EventTimeline = function (frameCount) { - this.frames = []; // time, ... - this.frames.length = frameCount; - this.events = []; - this.events.length = frameCount; -}; -spine.EventTimeline.prototype = { - getFrameCount: function () { - return this.frames.length; - }, - setFrame: function (frameIndex, time, event) { - this.frames[frameIndex] = time; - this.events[frameIndex] = event; - }, - /** Fires events for frames > lastTime and <= time. */ - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - if (!firedEvents) return; - - var frames = this.frames; - var frameCount = frames.length; - - if (lastTime > time) { // Fire events after last time for looped animations. - this.apply(skeleton, lastTime, Number.MAX_VALUE, firedEvents, alpha); - lastTime = -1; - } else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame. - return; - if (time < frames[0]) return; // Time is before first frame. - - var frameIndex; - if (lastTime < frames[0]) - frameIndex = 0; - else { - frameIndex = spine.Animation.binarySearch1(frames, lastTime); - var frame = frames[frameIndex]; - while (frameIndex > 0) { // Fire multiple events with the same frame. - if (frames[frameIndex - 1] != frame) break; - frameIndex--; - } - } - var events = this.events; - for (; frameIndex < frameCount && time >= frames[frameIndex]; frameIndex++) - firedEvents.push(events[frameIndex]); - } -}; - -spine.DrawOrderTimeline = function (frameCount) { - this.frames = []; // time, ... - this.frames.length = frameCount; - this.drawOrders = []; - this.drawOrders.length = frameCount; -}; -spine.DrawOrderTimeline.prototype = { - getFrameCount: function () { - return this.frames.length; - }, - setFrame: function (frameIndex, time, drawOrder) { - this.frames[frameIndex] = time; - this.drawOrders[frameIndex] = drawOrder; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var frameIndex; - if (time >= frames[frames.length - 1]) // Time is after last frame. - frameIndex = frames.length - 1; - else - frameIndex = spine.Animation.binarySearch1(frames, time) - 1; - - var drawOrder = skeleton.drawOrder; - var slots = skeleton.slots; - var drawOrderToSetupIndex = this.drawOrders[frameIndex]; - if (!drawOrderToSetupIndex) { - for (var i = 0, n = slots.length; i < n; i++) - drawOrder[i] = slots[i]; - } else { - for (var i = 0, n = drawOrderToSetupIndex.length; i < n; i++) - drawOrder[i] = skeleton.slots[drawOrderToSetupIndex[i]]; - } - - } -}; - -spine.FfdTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; - this.frames.length = frameCount; - this.frameVertices = []; - this.frameVertices.length = frameCount; -}; -spine.FfdTimeline.prototype = { - slotIndex: 0, - attachment: 0, - getFrameCount: function () { - return this.frames.length; - }, - setFrame: function (frameIndex, time, vertices) { - this.frames[frameIndex] = time; - this.frameVertices[frameIndex] = vertices; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var slot = skeleton.slots[this.slotIndex]; - if (slot.attachment != this.attachment) return; - - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var frameVertices = this.frameVertices; - var vertexCount = frameVertices[0].length; - - var vertices = slot.attachmentVertices; - if (vertices.length != vertexCount) alpha = 1; - vertices.length = vertexCount; - - if (time >= frames[frames.length - 1]) { // Time is after last frame. - var lastVertices = frameVertices[frames.length - 1]; - if (alpha < 1) { - for (var i = 0; i < vertexCount; i++) - vertices[i] += (lastVertices[i] - vertices[i]) * alpha; - } else { - for (var i = 0; i < vertexCount; i++) - vertices[i] = lastVertices[i]; - } - return; - } - - // Interpolate between the previous frame and the current frame. - var frameIndex = spine.Animation.binarySearch1(frames, time); - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex - 1] - frameTime); - percent = this.curves.getCurvePercent(frameIndex - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); - - var prevVertices = frameVertices[frameIndex - 1]; - var nextVertices = frameVertices[frameIndex]; - - if (alpha < 1) { - for (var i = 0; i < vertexCount; i++) { - var prev = prevVertices[i]; - vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha; - } - } else { - for (var i = 0; i < vertexCount; i++) { - var prev = prevVertices[i]; - vertices[i] = prev + (nextVertices[i] - prev) * percent; - } - } - } -}; - -spine.IkConstraintTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, mix, bendDirection, ... - this.frames.length = frameCount * 3; -}; -spine.IkConstraintTimeline.prototype = { - ikConstraintIndex: 0, - getFrameCount: function () { - return this.frames.length / 3; - }, - setFrame: function (frameIndex, time, mix, bendDirection) { - frameIndex *= 3; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = mix; - this.frames[frameIndex + 2] = bendDirection; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var ikConstraint = skeleton.ikConstraints[this.ikConstraintIndex]; - - if (time >= frames[frames.length - 3]) { // Time is after last frame. - ikConstraint.mix += (frames[frames.length - 2] - ikConstraint.mix) * alpha; - ikConstraint.bendDirection = frames[frames.length - 1]; - return; - } - - // Interpolate between the previous frame and the current frame. - var frameIndex = spine.Animation.binarySearch(frames, time, 3); - var prevFrameMix = frames[frameIndex + -2/*PREV_FRAME_MIX*/]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*PREV_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); - - var mix = prevFrameMix + (frames[frameIndex + 1/*FRAME_MIX*/] - prevFrameMix) * percent; - ikConstraint.mix += (mix - ikConstraint.mix) * alpha; - ikConstraint.bendDirection = frames[frameIndex + -1/*PREV_FRAME_BEND_DIRECTION*/]; - } -}; - -spine.FlipXTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, flip, ... - this.frames.length = frameCount * 2; -}; -spine.FlipXTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 2; - }, - setFrame: function (frameIndex, time, flip) { - frameIndex *= 2; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = flip ? 1 : 0; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) { - if (lastTime > time) this.apply(skeleton, lastTime, Number.MAX_VALUE, null, 0); - return; - } else if (lastTime > time) // - lastTime = -1; - var frameIndex = (time >= frames[frames.length - 2] ? frames.length : spine.Animation.binarySearch(frames, time, 2)) - 2; - if (frames[frameIndex] < lastTime) return; - skeleton.bones[boneIndex].flipX = frames[frameIndex + 1] != 0; - } -}; - -spine.FlipYTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, flip, ... - this.frames.length = frameCount * 2; -}; -spine.FlipYTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 2; - }, - setFrame: function (frameIndex, time, flip) { - frameIndex *= 2; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = flip ? 1 : 0; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) { - if (lastTime > time) this.apply(skeleton, lastTime, Number.MAX_VALUE, null, 0); - return; - } else if (lastTime > time) // - lastTime = -1; - var frameIndex = (time >= frames[frames.length - 2] ? frames.length : spine.Animation.binarySearch(frames, time, 2)) - 2; - if (frames[frameIndex] < lastTime) return; - skeleton.bones[boneIndex].flipY = frames[frameIndex + 1] != 0; - } -}; - -spine.SkeletonData = function () { - this.bones = []; - this.slots = []; - this.skins = []; - this.events = []; - this.animations = []; - this.ikConstraints = []; -}; -spine.SkeletonData.prototype = { - name: null, - defaultSkin: null, - width: 0, height: 0, - version: null, hash: null, - /** @return May be null. */ - findBone: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].name == boneName) return bones[i]; - return null; - }, - /** @return -1 if the bone was not found. */ - findBoneIndex: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].name == boneName) return i; - return -1; - }, - /** @return May be null. */ - findSlot: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) { - if (slots[i].name == slotName) return slot[i]; - } - return null; - }, - /** @return -1 if the bone was not found. */ - findSlotIndex: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - if (slots[i].name == slotName) return i; - return -1; - }, - /** @return May be null. */ - findSkin: function (skinName) { - var skins = this.skins; - for (var i = 0, n = skins.length; i < n; i++) - if (skins[i].name == skinName) return skins[i]; - return null; - }, - /** @return May be null. */ - findEvent: function (eventName) { - var events = this.events; - for (var i = 0, n = events.length; i < n; i++) - if (events[i].name == eventName) return events[i]; - return null; - }, - /** @return May be null. */ - findAnimation: function (animationName) { - var animations = this.animations; - for (var i = 0, n = animations.length; i < n; i++) - if (animations[i].name == animationName) return animations[i]; - return null; - }, - /** @return May be null. */ - findIkConstraint: function (ikConstraintName) { - var ikConstraints = this.ikConstraints; - for (var i = 0, n = ikConstraints.length; i < n; i++) - if (ikConstraints[i].name == ikConstraintName) return ikConstraints[i]; - return null; - } -}; - -spine.Skeleton = function (skeletonData) { - this.data = skeletonData; - - this.bones = []; - for (var i = 0, n = skeletonData.bones.length; i < n; i++) { - var boneData = skeletonData.bones[i]; - var parent = !boneData.parent ? null : this.bones[skeletonData.bones.indexOf(boneData.parent)]; - this.bones.push(new spine.Bone(boneData, this, parent)); - } - - this.slots = []; - this.drawOrder = []; - for (var i = 0, n = skeletonData.slots.length; i < n; i++) { - var slotData = skeletonData.slots[i]; - var bone = this.bones[skeletonData.bones.indexOf(slotData.boneData)]; - var slot = new spine.Slot(slotData, bone); - this.slots.push(slot); - this.drawOrder.push(slot); - } - - this.ikConstraints = []; - for (var i = 0, n = skeletonData.ikConstraints.length; i < n; i++) - this.ikConstraints.push(new spine.IkConstraint(skeletonData.ikConstraints[i], this)); - - this.boneCache = []; - this.updateCache(); -}; -spine.Skeleton.prototype = { - x: 0, y: 0, - skin: null, - r: 1, g: 1, b: 1, a: 1, - time: 0, - flipX: false, flipY: false, - /** Caches information about bones and IK constraints. Must be called if bones or IK constraints are added or removed. */ - updateCache: function () { - var ikConstraints = this.ikConstraints; - var ikConstraintsCount = ikConstraints.length; - - var arrayCount = ikConstraintsCount + 1; - var boneCache = this.boneCache; - if (boneCache.length > arrayCount) boneCache.length = arrayCount; - for (var i = 0, n = boneCache.length; i < n; i++) - boneCache[i].length = 0; - while (boneCache.length < arrayCount) - boneCache[boneCache.length] = []; - - var nonIkBones = boneCache[0]; - var bones = this.bones; - - outer: - for (var i = 0, n = bones.length; i < n; i++) { - var bone = bones[i]; - var current = bone; - do { - for (var ii = 0; ii < ikConstraintsCount; ii++) { - var ikConstraint = ikConstraints[ii]; - var parent = ikConstraint.bones[0]; - var child= ikConstraint.bones[ikConstraint.bones.length - 1]; - while (true) { - if (current == child) { - boneCache[ii].push(bone); - boneCache[ii + 1].push(bone); - continue outer; - } - if (child == parent) break; - child = child.parent; - } - } - current = current.parent; - } while (current); - nonIkBones[nonIkBones.length] = bone; - } - }, - /** Updates the world transform for each bone. */ - updateWorldTransform: function () { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) { - var bone = bones[i]; - bone.rotationIK = bone.rotation; - } - var i = 0, last = this.boneCache.length - 1; - while (true) { - var cacheBones = this.boneCache[i]; - for (var ii = 0, nn = cacheBones.length; ii < nn; ii++) - cacheBones[ii].updateWorldTransform(); - if (i == last) break; - this.ikConstraints[i].apply(); - i++; - } - }, - /** Sets the bones and slots to their setup pose values. */ - setToSetupPose: function () { - this.setBonesToSetupPose(); - this.setSlotsToSetupPose(); - }, - setBonesToSetupPose: function () { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - bones[i].setToSetupPose(); - - var ikConstraints = this.ikConstraints; - for (var i = 0, n = ikConstraints.length; i < n; i++) { - var ikConstraint = ikConstraints[i]; - ikConstraint.bendDirection = ikConstraint.data.bendDirection; - ikConstraint.mix = ikConstraint.data.mix; - } - }, - setSlotsToSetupPose: function () { - var slots = this.slots; - var drawOrder = this.drawOrder; - for (var i = 0, n = slots.length; i < n; i++) { - drawOrder[i] = slots[i]; - slots[i].setToSetupPose(i); - } - }, - /** @return May return null. */ - getRootBone: function () { - return this.bones.length ? this.bones[0] : null; - }, - /** @return May be null. */ - findBone: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].data.name == boneName) return bones[i]; - return null; - }, - /** @return -1 if the bone was not found. */ - findBoneIndex: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].data.name == boneName) return i; - return -1; - }, - /** @return May be null. */ - findSlot: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - if (slots[i].data.name == slotName) return slots[i]; - return null; - }, - /** @return -1 if the bone was not found. */ - findSlotIndex: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - if (slots[i].data.name == slotName) return i; - return -1; - }, - setSkinByName: function (skinName) { - var skin = this.data.findSkin(skinName); - if (!skin) throw "Skin not found: " + skinName; - this.setSkin(skin); - }, - /** Sets the skin used to look up attachments before looking in the {@link SkeletonData#getDefaultSkin() default skin}. - * Attachments from the new skin are attached if the corresponding attachment from the old skin was attached. If there was - * no old skin, each slot's setup mode attachment is attached from the new skin. - * @param newSkin May be null. */ - setSkin: function (newSkin) { - if (newSkin) { - if (this.skin) - newSkin._attachAll(this, this.skin); - else { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) { - var slot = slots[i]; - var name = slot.data.attachmentName; - if (name) { - var attachment = newSkin.getAttachment(i, name); - if (attachment) slot.setAttachment(attachment); - } - } - } - } - this.skin = newSkin; - }, - /** @return May be null. */ - getAttachmentBySlotName: function (slotName, attachmentName) { - return this.getAttachmentBySlotIndex(this.data.findSlotIndex(slotName), attachmentName); - }, - /** @return May be null. */ - getAttachmentBySlotIndex: function (slotIndex, attachmentName) { - if (this.skin) { - var attachment = this.skin.getAttachment(slotIndex, attachmentName); - if (attachment) return attachment; - } - if (this.data.defaultSkin) return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); - return null; - }, - /** @param attachmentName May be null. */ - setAttachment: function (slotName, attachmentName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) { - var slot = slots[i]; - if (slot.data.name == slotName) { - var attachment = null; - if (attachmentName) { - attachment = this.getAttachmentBySlotIndex(i, attachmentName); - if (!attachment) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; - } - slot.setAttachment(attachment); - return; - } - } - throw "Slot not found: " + slotName; - }, - /** @return May be null. */ - findIkConstraint: function (ikConstraintName) { - var ikConstraints = this.ikConstraints; - for (var i = 0, n = ikConstraints.length; i < n; i++) - if (ikConstraints[i].data.name == ikConstraintName) return ikConstraints[i]; - return null; - }, - update: function (delta) { - this.time += delta; - } -}; - -spine.EventData = function (name) { - this.name = name; -}; -spine.EventData.prototype = { - intValue: 0, - floatValue: 0, - stringValue: null -}; - -spine.Event = function (data) { - this.data = data; -}; -spine.Event.prototype = { - intValue: 0, - floatValue: 0, - stringValue: null -}; - -spine.AttachmentType = { - region: 0, - boundingbox: 1, - mesh: 2, - skinnedmesh: 3 -}; - -spine.RegionAttachment = function (name) { - this.name = name; - this.offset = []; - this.offset.length = 8; - this.uvs = []; - this.uvs.length = 8; -}; -spine.RegionAttachment.prototype = { - type: spine.AttachmentType.region, - x: 0, y: 0, - rotation: 0, - scaleX: 1, scaleY: 1, - width: 0, height: 0, - r: 1, g: 1, b: 1, a: 1, - path: null, - rendererObject: null, - regionOffsetX: 0, regionOffsetY: 0, - regionWidth: 0, regionHeight: 0, - regionOriginalWidth: 0, regionOriginalHeight: 0, - setUVs: function (u, v, u2, v2, rotate) { - var uvs = this.uvs; - if (rotate) { - uvs[2/*X2*/] = u; - uvs[3/*Y2*/] = v2; - uvs[4/*X3*/] = u; - uvs[5/*Y3*/] = v; - uvs[6/*X4*/] = u2; - uvs[7/*Y4*/] = v; - uvs[0/*X1*/] = u2; - uvs[1/*Y1*/] = v2; - } else { - uvs[0/*X1*/] = u; - uvs[1/*Y1*/] = v2; - uvs[2/*X2*/] = u; - uvs[3/*Y2*/] = v; - uvs[4/*X3*/] = u2; - uvs[5/*Y3*/] = v; - uvs[6/*X4*/] = u2; - uvs[7/*Y4*/] = v2; - } - }, - updateOffset: function () { - var regionScaleX = this.width / this.regionOriginalWidth * this.scaleX; - var regionScaleY = this.height / this.regionOriginalHeight * this.scaleY; - var localX = -this.width / 2 * this.scaleX + this.regionOffsetX * regionScaleX; - var localY = -this.height / 2 * this.scaleY + this.regionOffsetY * regionScaleY; - var localX2 = localX + this.regionWidth * regionScaleX; - var localY2 = localY + this.regionHeight * regionScaleY; - var radians = this.rotation * spine.degRad; - var cos = Math.cos(radians); - var sin = Math.sin(radians); - var localXCos = localX * cos + this.x; - var localXSin = localX * sin; - var localYCos = localY * cos + this.y; - var localYSin = localY * sin; - var localX2Cos = localX2 * cos + this.x; - var localX2Sin = localX2 * sin; - var localY2Cos = localY2 * cos + this.y; - var localY2Sin = localY2 * sin; - var offset = this.offset; - offset[0/*X1*/] = localXCos - localYSin; - offset[1/*Y1*/] = localYCos + localXSin; - offset[2/*X2*/] = localXCos - localY2Sin; - offset[3/*Y2*/] = localY2Cos + localXSin; - offset[4/*X3*/] = localX2Cos - localY2Sin; - offset[5/*Y3*/] = localY2Cos + localX2Sin; - offset[6/*X4*/] = localX2Cos - localYSin; - offset[7/*Y4*/] = localYCos + localX2Sin; - }, - computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; - y += bone.worldY; - var m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11; - var offset = this.offset; - vertices[0/*X1*/] = offset[0/*X1*/] * m00 + offset[1/*Y1*/] * m01 + x; - vertices[1/*Y1*/] = offset[0/*X1*/] * m10 + offset[1/*Y1*/] * m11 + y; - vertices[2/*X2*/] = offset[2/*X2*/] * m00 + offset[3/*Y2*/] * m01 + x; - vertices[3/*Y2*/] = offset[2/*X2*/] * m10 + offset[3/*Y2*/] * m11 + y; - vertices[4/*X3*/] = offset[4/*X3*/] * m00 + offset[5/*X3*/] * m01 + x; - vertices[5/*X3*/] = offset[4/*X3*/] * m10 + offset[5/*X3*/] * m11 + y; - vertices[6/*X4*/] = offset[6/*X4*/] * m00 + offset[7/*Y4*/] * m01 + x; - vertices[7/*Y4*/] = offset[6/*X4*/] * m10 + offset[7/*Y4*/] * m11 + y; - } -}; - -spine.MeshAttachment = function (name) { - this.name = name; -}; -spine.MeshAttachment.prototype = { - type: spine.AttachmentType.mesh, - vertices: null, - uvs: null, - regionUVs: null, - triangles: null, - hullLength: 0, - r: 1, g: 1, b: 1, a: 1, - path: null, - rendererObject: null, - regionU: 0, regionV: 0, regionU2: 0, regionV2: 0, regionRotate: false, - regionOffsetX: 0, regionOffsetY: 0, - regionWidth: 0, regionHeight: 0, - regionOriginalWidth: 0, regionOriginalHeight: 0, - edges: null, - width: 0, height: 0, - updateUVs: function () { - var width = this.regionU2 - this.regionU, height = this.regionV2 - this.regionV; - var n = this.regionUVs.length; - if (!this.uvs || this.uvs.length != n) { - this.uvs = new spine.Float32Array(n); - } - if (this.regionRotate) { - for (var i = 0; i < n; i += 2) { - this.uvs[i] = this.regionU + this.regionUVs[i + 1] * width; - this.uvs[i + 1] = this.regionV + height - this.regionUVs[i] * height; - } - } else { - for (var i = 0; i < n; i += 2) { - this.uvs[i] = this.regionU + this.regionUVs[i] * width; - this.uvs[i + 1] = this.regionV + this.regionUVs[i + 1] * height; - } - } - }, - computeWorldVertices: function (x, y, slot, worldVertices) { - var bone = slot.bone; - x += bone.worldX; - y += bone.worldY; - var m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11; - var vertices = this.vertices; - var verticesCount = vertices.length; - if (slot.attachmentVertices.length == verticesCount) vertices = slot.attachmentVertices; - for (var i = 0; i < verticesCount; i += 2) { - var vx = vertices[i]; - var vy = vertices[i + 1]; - worldVertices[i] = vx * m00 + vy * m01 + x; - worldVertices[i + 1] = vx * m10 + vy * m11 + y; - } - } -}; - -spine.SkinnedMeshAttachment = function (name) { - this.name = name; -}; -spine.SkinnedMeshAttachment.prototype = { - type: spine.AttachmentType.skinnedmesh, - bones: null, - weights: null, - uvs: null, - regionUVs: null, - triangles: null, - hullLength: 0, - r: 1, g: 1, b: 1, a: 1, - path: null, - rendererObject: null, - regionU: 0, regionV: 0, regionU2: 0, regionV2: 0, regionRotate: false, - regionOffsetX: 0, regionOffsetY: 0, - regionWidth: 0, regionHeight: 0, - regionOriginalWidth: 0, regionOriginalHeight: 0, - edges: null, - width: 0, height: 0, - updateUVs: function (u, v, u2, v2, rotate) { - var width = this.regionU2 - this.regionU, height = this.regionV2 - this.regionV; - var n = this.regionUVs.length; - if (!this.uvs || this.uvs.length != n) { - this.uvs = new spine.Float32Array(n); - } - if (this.regionRotate) { - for (var i = 0; i < n; i += 2) { - this.uvs[i] = this.regionU + this.regionUVs[i + 1] * width; - this.uvs[i + 1] = this.regionV + height - this.regionUVs[i] * height; - } - } else { - for (var i = 0; i < n; i += 2) { - this.uvs[i] = this.regionU + this.regionUVs[i] * width; - this.uvs[i + 1] = this.regionV + this.regionUVs[i + 1] * height; - } - } - }, - computeWorldVertices: function (x, y, slot, worldVertices) { - var skeletonBones = slot.bone.skeleton.bones; - var weights = this.weights; - var bones = this.bones; - - var w = 0, v = 0, b = 0, f = 0, n = bones.length, nn; - var wx, wy, bone, vx, vy, weight; - if (!slot.attachmentVertices.length) { - for (; v < n; w += 2) { - wx = 0; - wy = 0; - nn = bones[v++] + v; - for (; v < nn; v++, b += 3) { - bone = skeletonBones[bones[v]]; - vx = weights[b]; - vy = weights[b + 1]; - weight = weights[b + 2]; - wx += (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight; - wy += (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight; - } - worldVertices[w] = wx + x; - worldVertices[w + 1] = wy + y; - } - } else { - var ffd = slot.attachmentVertices; - for (; v < n; w += 2) { - wx = 0; - wy = 0; - nn = bones[v++] + v; - for (; v < nn; v++, b += 3, f += 2) { - bone = skeletonBones[bones[v]]; - vx = weights[b] + ffd[f]; - vy = weights[b + 1] + ffd[f + 1]; - weight = weights[b + 2]; - wx += (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight; - wy += (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight; - } - worldVertices[w] = wx + x; - worldVertices[w + 1] = wy + y; - } - } - } -}; - -spine.BoundingBoxAttachment = function (name) { - this.name = name; - this.vertices = []; -}; -spine.BoundingBoxAttachment.prototype = { - type: spine.AttachmentType.boundingbox, - computeWorldVertices: function (x, y, bone, worldVertices) { - x += bone.worldX; - y += bone.worldY; - var m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11; - var vertices = this.vertices; - for (var i = 0, n = vertices.length; i < n; i += 2) { - var px = vertices[i]; - var py = vertices[i + 1]; - worldVertices[i] = px * m00 + py * m01 + x; - worldVertices[i + 1] = px * m10 + py * m11 + y; - } - } -}; - -spine.AnimationStateData = function (skeletonData) { - this.skeletonData = skeletonData; - this.animationToMixTime = {}; -}; -spine.AnimationStateData.prototype = { - defaultMix: 0, - setMixByName: function (fromName, toName, duration) { - var from = this.skeletonData.findAnimation(fromName); - if (!from) throw "Animation not found: " + fromName; - var to = this.skeletonData.findAnimation(toName); - if (!to) throw "Animation not found: " + toName; - this.setMix(from, to, duration); - }, - setMix: function (from, to, duration) { - this.animationToMixTime[from.name + ":" + to.name] = duration; - }, - getMix: function (from, to) { - var key = from.name + ":" + to.name; - return this.animationToMixTime.hasOwnProperty(key) ? this.animationToMixTime[key] : this.defaultMix; - } -}; - -spine.TrackEntry = function () {}; -spine.TrackEntry.prototype = { - next: null, previous: null, - animation: null, - loop: false, - delay: 0, time: 0, lastTime: -1, endTime: 0, - timeScale: 1, - mixTime: 0, mixDuration: 0, mix: 1, - onStart: null, onEnd: null, onComplete: null, onEvent: null -}; - -spine.AnimationState = function (stateData) { - this.data = stateData; - this.tracks = []; - this.events = []; -}; -spine.AnimationState.prototype = { - onStart: null, - onEnd: null, - onComplete: null, - onEvent: null, - timeScale: 1, - update: function (delta) { - delta *= this.timeScale; - for (var i = 0; i < this.tracks.length; i++) { - var current = this.tracks[i]; - if (!current) continue; - - current.time += delta * current.timeScale; - if (current.previous) { - var previousDelta = delta * current.previous.timeScale; - current.previous.time += previousDelta; - current.mixTime += previousDelta; - } - - var next = current.next; - if (next) { - next.time = current.lastTime - next.delay; - if (next.time >= 0) this.setCurrent(i, next); - } else { - // End non-looping animation when it reaches its end time and there is no next entry. - if (!current.loop && current.lastTime >= current.endTime) this.clearTrack(i); - } - } - }, - apply: function (skeleton) { - for (var i = 0; i < this.tracks.length; i++) { - var current = this.tracks[i]; - if (!current) continue; - - this.events.length = 0; - - var time = current.time; - var lastTime = current.lastTime; - var endTime = current.endTime; - var loop = current.loop; - if (!loop && time > endTime) time = endTime; - - var previous = current.previous; - if (!previous) { - if (current.mix == 1) - current.animation.apply(skeleton, current.lastTime, time, loop, this.events); - else - current.animation.mix(skeleton, current.lastTime, time, loop, this.events, current.mix); - } else { - var previousTime = previous.time; - if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; - previous.animation.apply(skeleton, previousTime, previousTime, previous.loop, null); - - var alpha = current.mixTime / current.mixDuration * current.mix; - if (alpha >= 1) { - alpha = 1; - current.previous = null; - } - current.animation.mix(skeleton, current.lastTime, time, loop, this.events, alpha); - } - - for (var ii = 0, nn = this.events.length; ii < nn; ii++) { - var event = this.events[ii]; - if (current.onEvent) current.onEvent(i, event); - if (this.onEvent) this.onEvent(i, event); - } - - // Check if completed the animation or a loop iteration. - if (loop ? (lastTime % endTime > time % endTime) : (lastTime < endTime && time >= endTime)) { - var count = Math.floor(time / endTime); - if (current.onComplete) current.onComplete(i, count); - if (this.onComplete) this.onComplete(i, count); - } - - current.lastTime = current.time; - } - }, - clearTracks: function () { - for (var i = 0, n = this.tracks.length; i < n; i++) - this.clearTrack(i); - this.tracks.length = 0; - }, - clearTrack: function (trackIndex) { - if (trackIndex >= this.tracks.length) return; - var current = this.tracks[trackIndex]; - if (!current) return; - - if (current.onEnd) current.onEnd(trackIndex); - if (this.onEnd) this.onEnd(trackIndex); - - this.tracks[trackIndex] = null; - }, - _expandToIndex: function (index) { - if (index < this.tracks.length) return this.tracks[index]; - while (index >= this.tracks.length) - this.tracks.push(null); - return null; - }, - setCurrent: function (index, entry) { - var current = this._expandToIndex(index); - if (current) { - var previous = current.previous; - current.previous = null; - - if (current.onEnd) current.onEnd(index); - if (this.onEnd) this.onEnd(index); - - entry.mixDuration = this.data.getMix(current.animation, entry.animation); - if (entry.mixDuration > 0) { - entry.mixTime = 0; - // If a mix is in progress, mix from the closest animation. - if (previous && current.mixTime / current.mixDuration < 0.5) - entry.previous = previous; - else - entry.previous = current; - } - } - - this.tracks[index] = entry; - - if (entry.onStart) entry.onStart(index); - if (this.onStart) this.onStart(index); - }, - setAnimationByName: function (trackIndex, animationName, loop) { - var animation = this.data.skeletonData.findAnimation(animationName); - if (!animation) throw "Animation not found: " + animationName; - return this.setAnimation(trackIndex, animation, loop); - }, - /** Set the current animation. Any queued animations are cleared. */ - setAnimation: function (trackIndex, animation, loop) { - var entry = new spine.TrackEntry(); - entry.animation = animation; - entry.loop = loop; - entry.endTime = animation.duration; - this.setCurrent(trackIndex, entry); - return entry; - }, - addAnimationByName: function (trackIndex, animationName, loop, delay) { - var animation = this.data.skeletonData.findAnimation(animationName); - if (!animation) throw "Animation not found: " + animationName; - return this.addAnimation(trackIndex, animation, loop, delay); - }, - /** Adds an animation to be played delay seconds after the current or last queued animation. - * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ - addAnimation: function (trackIndex, animation, loop, delay) { - var entry = new spine.TrackEntry(); - entry.animation = animation; - entry.loop = loop; - entry.endTime = animation.duration; - - var last = this._expandToIndex(trackIndex); - if (last) { - while (last.next) - last = last.next; - last.next = entry; - } else - this.tracks[trackIndex] = entry; - - if (delay <= 0) { - if (last) - delay += last.endTime - this.data.getMix(last.animation, animation); - else - delay = 0; - } - entry.delay = delay; - - return entry; - }, - /** May be null. */ - getCurrent: function (trackIndex) { - if (trackIndex >= this.tracks.length) return null; - return this.tracks[trackIndex]; - } -}; - -spine.SkeletonJson = function (attachmentLoader) { - this.attachmentLoader = attachmentLoader; -}; -spine.SkeletonJson.prototype = { - scale: 1, - readSkeletonData: function (root, name) { - var skeletonData = new spine.SkeletonData(); - skeletonData.name = name; - - // Skeleton. - var skeletonMap = root["skeleton"]; - if (skeletonMap) { - skeletonData.hash = skeletonMap["hash"]; - skeletonData.version = skeletonMap["spine"]; - skeletonData.width = skeletonMap["width"] || 0; - skeletonData.height = skeletonMap["height"] || 0; - } - - // Bones. - var bones = root["bones"]; - for (var i = 0, n = bones.length; i < n; i++) { - var boneMap = bones[i]; - var parent = null; - if (boneMap["parent"]) { - parent = skeletonData.findBone(boneMap["parent"]); - if (!parent) throw "Parent bone not found: " + boneMap["parent"]; - } - var boneData = new spine.BoneData(boneMap["name"], parent); - boneData.length = (boneMap["length"] || 0) * this.scale; - boneData.x = (boneMap["x"] || 0) * this.scale; - boneData.y = (boneMap["y"] || 0) * this.scale; - boneData.rotation = (boneMap["rotation"] || 0); - boneData.scaleX = boneMap.hasOwnProperty("scaleX") ? boneMap["scaleX"] : 1; - boneData.scaleY = boneMap.hasOwnProperty("scaleY") ? boneMap["scaleY"] : 1; - boneData.inheritScale = boneMap.hasOwnProperty("inheritScale") ? boneMap["inheritScale"] : true; - boneData.inheritRotation = boneMap.hasOwnProperty("inheritRotation") ? boneMap["inheritRotation"] : true; - skeletonData.bones.push(boneData); - } - - // IK constraints. - var ik = root["ik"]; - if (ik) { - for (var i = 0, n = ik.length; i < n; i++) { - var ikMap = ik[i]; - var ikConstraintData = new spine.IkConstraintData(ikMap["name"]); - - var bones = ikMap["bones"]; - for (var ii = 0, nn = bones.length; ii < nn; ii++) { - var bone = skeletonData.findBone(bones[ii]); - if (!bone) throw "IK bone not found: " + bones[ii]; - ikConstraintData.bones.push(bone); - } - - ikConstraintData.target = skeletonData.findBone(ikMap["target"]); - if (!ikConstraintData.target) throw "Target bone not found: " + ikMap["target"]; - - ikConstraintData.bendDirection = (!ikMap.hasOwnProperty("bendPositive") || ikMap["bendPositive"]) ? 1 : -1; - ikConstraintData.mix = ikMap.hasOwnProperty("mix") ? ikMap["mix"] : 1; - - skeletonData.ikConstraints.push(ikConstraintData); - } - } - - // Slots. - var slots = root["slots"]; - for (var i = 0, n = slots.length; i < n; i++) { - var slotMap = slots[i]; - var boneData = skeletonData.findBone(slotMap["bone"]); - if (!boneData) throw "Slot bone not found: " + slotMap["bone"]; - var slotData = new spine.SlotData(slotMap["name"], boneData); - - var color = slotMap["color"]; - if (color) { - slotData.r = this.toColor(color, 0); - slotData.g = this.toColor(color, 1); - slotData.b = this.toColor(color, 2); - slotData.a = this.toColor(color, 3); - } - - slotData.attachmentName = slotMap["attachment"]; - slotData.additiveBlending = slotMap["additive"] && slotMap["additive"] == "true"; - - skeletonData.slots.push(slotData); - } - - // Skins. - var skins = root["skins"]; - for (var skinName in skins) { - if (!skins.hasOwnProperty(skinName)) continue; - var skinMap = skins[skinName]; - var skin = new spine.Skin(skinName); - for (var slotName in skinMap) { - if (!skinMap.hasOwnProperty(slotName)) continue; - var slotIndex = skeletonData.findSlotIndex(slotName); - var slotEntry = skinMap[slotName]; - for (var attachmentName in slotEntry) { - if (!slotEntry.hasOwnProperty(attachmentName)) continue; - var attachment = this.readAttachment(skin, attachmentName, slotEntry[attachmentName]); - if (attachment) skin.addAttachment(slotIndex, attachmentName, attachment); - } - } - skeletonData.skins.push(skin); - if (skin.name == "default") skeletonData.defaultSkin = skin; - } - - // Events. - var events = root["events"]; - for (var eventName in events) { - if (!events.hasOwnProperty(eventName)) continue; - var eventMap = events[eventName]; - var eventData = new spine.EventData(eventName); - eventData.intValue = eventMap["int"] || 0; - eventData.floatValue = eventMap["float"] || 0; - eventData.stringValue = eventMap["string"] || null; - skeletonData.events.push(eventData); - } - - // Animations. - var animations = root["animations"]; - for (var animationName in animations) { - if (!animations.hasOwnProperty(animationName)) continue; - this.readAnimation(animationName, animations[animationName], skeletonData); - } - - return skeletonData; - }, - readAttachment: function (skin, name, map) { - name = map["name"] || name; - - var type = spine.AttachmentType[map["type"] || "region"]; - var path = map["path"] || name; - - var scale = this.scale; - if (type == spine.AttachmentType.region) { - var region = this.attachmentLoader.newRegionAttachment(skin, name, path); - if (!region) return null; - region.path = path; - region.x = (map["x"] || 0) * scale; - region.y = (map["y"] || 0) * scale; - region.scaleX = map.hasOwnProperty("scaleX") ? map["scaleX"] : 1; - region.scaleY = map.hasOwnProperty("scaleY") ? map["scaleY"] : 1; - region.rotation = map["rotation"] || 0; - region.width = (map["width"] || 0) * scale; - region.height = (map["height"] || 0) * scale; - - var color = map["color"]; - if (color) { - region.r = this.toColor(color, 0); - region.g = this.toColor(color, 1); - region.b = this.toColor(color, 2); - region.a = this.toColor(color, 3); - } - - region.updateOffset(); - return region; - } else if (type == spine.AttachmentType.mesh) { - var mesh = this.attachmentLoader.newMeshAttachment(skin, name, path); - if (!mesh) return null; - mesh.path = path; - mesh.vertices = this.getFloatArray(map, "vertices", scale); - mesh.triangles = this.getIntArray(map, "triangles"); - mesh.regionUVs = this.getFloatArray(map, "uvs", 1); - mesh.updateUVs(); - - color = map["color"]; - if (color) { - mesh.r = this.toColor(color, 0); - mesh.g = this.toColor(color, 1); - mesh.b = this.toColor(color, 2); - mesh.a = this.toColor(color, 3); - } - - mesh.hullLength = (map["hull"] || 0) * 2; - if (map["edges"]) mesh.edges = this.getIntArray(map, "edges"); - mesh.width = (map["width"] || 0) * scale; - mesh.height = (map["height"] || 0) * scale; - return mesh; - } else if (type == spine.AttachmentType.skinnedmesh) { - var mesh = this.attachmentLoader.newSkinnedMeshAttachment(skin, name, path); - if (!mesh) return null; - mesh.path = path; - - var uvs = this.getFloatArray(map, "uvs", 1); - var vertices = this.getFloatArray(map, "vertices", 1); - var weights = []; - var bones = []; - for (var i = 0, n = vertices.length; i < n; ) { - var boneCount = vertices[i++] | 0; - bones[bones.length] = boneCount; - for (var nn = i + boneCount * 4; i < nn; ) { - bones[bones.length] = vertices[i]; - weights[weights.length] = vertices[i + 1] * scale; - weights[weights.length] = vertices[i + 2] * scale; - weights[weights.length] = vertices[i + 3]; - i += 4; - } - } - mesh.bones = bones; - mesh.weights = weights; - mesh.triangles = this.getIntArray(map, "triangles"); - mesh.regionUVs = uvs; - mesh.updateUVs(); - - color = map["color"]; - if (color) { - mesh.r = this.toColor(color, 0); - mesh.g = this.toColor(color, 1); - mesh.b = this.toColor(color, 2); - mesh.a = this.toColor(color, 3); - } - - mesh.hullLength = (map["hull"] || 0) * 2; - if (map["edges"]) mesh.edges = this.getIntArray(map, "edges"); - mesh.width = (map["width"] || 0) * scale; - mesh.height = (map["height"] || 0) * scale; - return mesh; - } else if (type == spine.AttachmentType.boundingbox) { - var attachment = this.attachmentLoader.newBoundingBoxAttachment(skin, name); - var vertices = map["vertices"]; - for (var i = 0, n = vertices.length; i < n; i++) - attachment.vertices.push(vertices[i] * scale); - return attachment; - } - throw "Unknown attachment type: " + type; - }, - readAnimation: function (name, map, skeletonData) { - var timelines = []; - var duration = 0; - - var slots = map["slots"]; - for (var slotName in slots) { - if (!slots.hasOwnProperty(slotName)) continue; - var slotMap = slots[slotName]; - var slotIndex = skeletonData.findSlotIndex(slotName); - - for (var timelineName in slotMap) { - if (!slotMap.hasOwnProperty(timelineName)) continue; - var values = slotMap[timelineName]; - if (timelineName == "color") { - var timeline = new spine.ColorTimeline(values.length); - timeline.slotIndex = slotIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - var color = valueMap["color"]; - var r = this.toColor(color, 0); - var g = this.toColor(color, 1); - var b = this.toColor(color, 2); - var a = this.toColor(color, 3); - timeline.setFrame(frameIndex, valueMap["time"], r, g, b, a); - this.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 5 - 5]); - - } else if (timelineName == "attachment") { - var timeline = new spine.AttachmentTimeline(values.length); - timeline.slotIndex = slotIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); - - } else - throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; - } - } - - var bones = map["bones"]; - for (var boneName in bones) { - if (!bones.hasOwnProperty(boneName)) continue; - var boneIndex = skeletonData.findBoneIndex(boneName); - if (boneIndex == -1) throw "Bone not found: " + boneName; - var boneMap = bones[boneName]; - - for (var timelineName in boneMap) { - if (!boneMap.hasOwnProperty(timelineName)) continue; - var values = boneMap[timelineName]; - if (timelineName == "rotate") { - var timeline = new spine.RotateTimeline(values.length); - timeline.boneIndex = boneIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - timeline.setFrame(frameIndex, valueMap["time"], valueMap["angle"]); - this.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 2 - 2]); - - } else if (timelineName == "translate" || timelineName == "scale") { - var timeline; - var timelineScale = 1; - if (timelineName == "scale") - timeline = new spine.ScaleTimeline(values.length); - else { - timeline = new spine.TranslateTimeline(values.length); - timelineScale = this.scale; - } - timeline.boneIndex = boneIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - var x = (valueMap["x"] || 0) * timelineScale; - var y = (valueMap["y"] || 0) * timelineScale; - timeline.setFrame(frameIndex, valueMap["time"], x, y); - this.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - - } else if (timelineName == "flipX" || timelineName == "flipY") { - var x = timelineName == "flipX"; - var timeline = x ? new spine.FlipXTimeline(values.length) : new spine.FlipYTimeline(values.length); - timeline.boneIndex = boneIndex; - - var field = x ? "x" : "y"; - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - timeline.setFrame(frameIndex, valueMap["time"], valueMap[field] || false); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 2 - 2]); - } else - throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; - } - } - - var ikMap = map["ik"]; - for (var ikConstraintName in ikMap) { - if (!ikMap.hasOwnProperty(ikConstraintName)) continue; - var ikConstraint = skeletonData.findIkConstraint(ikConstraintName); - var values = ikMap[ikConstraintName]; - var timeline = new spine.IkConstraintTimeline(values.length); - timeline.ikConstraintIndex = skeletonData.ikConstraints.indexOf(ikConstraint); - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - var mix = valueMap.hasOwnProperty("mix") ? valueMap["mix"] : 1; - var bendDirection = (!valueMap.hasOwnProperty("bendPositive") || valueMap["bendPositive"]) ? 1 : -1; - timeline.setFrame(frameIndex, valueMap["time"], mix, bendDirection); - this.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.frameCount * 3 - 3]); - } - - var ffd = map["ffd"]; - for (var skinName in ffd) { - var skin = skeletonData.findSkin(skinName); - var slotMap = ffd[skinName]; - for (slotName in slotMap) { - var slotIndex = skeletonData.findSlotIndex(slotName); - var meshMap = slotMap[slotName]; - for (var meshName in meshMap) { - var values = meshMap[meshName]; - var timeline = new spine.FfdTimeline(values.length); - var attachment = skin.getAttachment(slotIndex, meshName); - if (!attachment) throw "FFD attachment not found: " + meshName; - timeline.slotIndex = slotIndex; - timeline.attachment = attachment; - - var isMesh = attachment.type == spine.AttachmentType.mesh; - var vertexCount; - if (isMesh) - vertexCount = attachment.vertices.length; - else - vertexCount = attachment.weights.length / 3 * 2; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - var vertices; - if (!valueMap["vertices"]) { - if (isMesh) - vertices = attachment.vertices; - else { - vertices = []; - vertices.length = vertexCount; - } - } else { - var verticesValue = valueMap["vertices"]; - var vertices = []; - vertices.length = vertexCount; - var start = valueMap["offset"] || 0; - var nn = verticesValue.length; - if (this.scale == 1) { - for (var ii = 0; ii < nn; ii++) - vertices[ii + start] = verticesValue[ii]; - } else { - for (var ii = 0; ii < nn; ii++) - vertices[ii + start] = verticesValue[ii] * this.scale; - } - if (isMesh) { - var meshVertices = attachment.vertices; - for (var ii = 0, nn = vertices.length; ii < nn; ii++) - vertices[ii] += meshVertices[ii]; - } - } - - timeline.setFrame(frameIndex, valueMap["time"], vertices); - this.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines[timelines.length] = timeline; - duration = Math.max(duration, timeline.frames[timeline.frameCount - 1]); - } - } - } - - var drawOrderValues = map["drawOrder"]; - if (!drawOrderValues) drawOrderValues = map["draworder"]; - if (drawOrderValues) { - var timeline = new spine.DrawOrderTimeline(drawOrderValues.length); - var slotCount = skeletonData.slots.length; - var frameIndex = 0; - for (var i = 0, n = drawOrderValues.length; i < n; i++) { - var drawOrderMap = drawOrderValues[i]; - var drawOrder = null; - if (drawOrderMap["offsets"]) { - drawOrder = []; - drawOrder.length = slotCount; - for (var ii = slotCount - 1; ii >= 0; ii--) - drawOrder[ii] = -1; - var offsets = drawOrderMap["offsets"]; - var unchanged = []; - unchanged.length = slotCount - offsets.length; - var originalIndex = 0, unchangedIndex = 0; - for (var ii = 0, nn = offsets.length; ii < nn; ii++) { - var offsetMap = offsets[ii]; - var slotIndex = skeletonData.findSlotIndex(offsetMap["slot"]); - if (slotIndex == -1) throw "Slot not found: " + offsetMap["slot"]; - // Collect unchanged items. - while (originalIndex != slotIndex) - unchanged[unchangedIndex++] = originalIndex++; - // Set changed items. - drawOrder[originalIndex + offsetMap["offset"]] = originalIndex++; - } - // Collect remaining unchanged items. - while (originalIndex < slotCount) - unchanged[unchangedIndex++] = originalIndex++; - // Fill in unchanged items. - for (var ii = slotCount - 1; ii >= 0; ii--) - if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex]; - } - timeline.setFrame(frameIndex++, drawOrderMap["time"], drawOrder); - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); - } - - var events = map["events"]; - if (events) { - var timeline = new spine.EventTimeline(events.length); - var frameIndex = 0; - for (var i = 0, n = events.length; i < n; i++) { - var eventMap = events[i]; - var eventData = skeletonData.findEvent(eventMap["name"]); - if (!eventData) throw "Event not found: " + eventMap["name"]; - var event = new spine.Event(eventData); - event.intValue = eventMap.hasOwnProperty("int") ? eventMap["int"] : eventData.intValue; - event.floatValue = eventMap.hasOwnProperty("float") ? eventMap["float"] : eventData.floatValue; - event.stringValue = eventMap.hasOwnProperty("string") ? eventMap["string"] : eventData.stringValue; - timeline.setFrame(frameIndex++, eventMap["time"], event); - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); - } - - skeletonData.animations.push(new spine.Animation(name, timelines, duration)); - }, - readCurve: function (timeline, frameIndex, valueMap) { - var curve = valueMap["curve"]; - if (!curve) - timeline.curves.setLinear(frameIndex); - else if (curve == "stepped") - timeline.curves.setStepped(frameIndex); - else if (curve instanceof Array) - timeline.curves.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); - }, - toColor: function (hexString, colorIndex) { - if (hexString.length != 8) throw "Color hexidecimal length must be 8, recieved: " + hexString; - return parseInt(hexString.substring(colorIndex * 2, (colorIndex * 2) + 2), 16) / 255; - }, - getFloatArray: function (map, name, scale) { - var list = map[name]; - var values = new spine.Float32Array(list.length); - var i = 0, n = list.length; - if (scale == 1) { - for (; i < n; i++) - values[i] = list[i]; - } else { - for (; i < n; i++) - values[i] = list[i] * scale; - } - return values; - }, - getIntArray: function (map, name) { - var list = map[name]; - var values = new spine.Uint16Array(list.length); - for (var i = 0, n = list.length; i < n; i++) - values[i] = list[i] | 0; - return values; - } -}; - -spine.Atlas = function (atlasText, textureLoader) { - this.textureLoader = textureLoader; - this.pages = []; - this.regions = []; - - var reader = new spine.AtlasReader(atlasText); - var tuple = []; - tuple.length = 4; - var page = null; - while (true) { - var line = reader.readLine(); - if (line === null) break; - line = reader.trim(line); - if (!line.length) - page = null; - else if (!page) { - page = new spine.AtlasPage(); - page.name = line; - - if (reader.readTuple(tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker. - page.width = parseInt(tuple[0]); - page.height = parseInt(tuple[1]); - reader.readTuple(tuple); - } - page.format = spine.Atlas.Format[tuple[0]]; - - reader.readTuple(tuple); - page.minFilter = spine.Atlas.TextureFilter[tuple[0]]; - page.magFilter = spine.Atlas.TextureFilter[tuple[1]]; - - var direction = reader.readValue(); - page.uWrap = spine.Atlas.TextureWrap.clampToEdge; - page.vWrap = spine.Atlas.TextureWrap.clampToEdge; - if (direction == "x") - page.uWrap = spine.Atlas.TextureWrap.repeat; - else if (direction == "y") - page.vWrap = spine.Atlas.TextureWrap.repeat; - else if (direction == "xy") - page.uWrap = page.vWrap = spine.Atlas.TextureWrap.repeat; - - textureLoader.load(page, line, this); - - this.pages.push(page); - - } else { - var region = new spine.AtlasRegion(); - region.name = line; - region.page = page; - - region.rotate = reader.readValue() == "true"; - - reader.readTuple(tuple); - var x = parseInt(tuple[0]); - var y = parseInt(tuple[1]); - - reader.readTuple(tuple); - var width = parseInt(tuple[0]); - var height = parseInt(tuple[1]); - - region.u = x / page.width; - region.v = y / page.height; - if (region.rotate) { - region.u2 = (x + height) / page.width; - region.v2 = (y + width) / page.height; - } else { - region.u2 = (x + width) / page.width; - region.v2 = (y + height) / page.height; - } - region.x = x; - region.y = y; - region.width = Math.abs(width); - region.height = Math.abs(height); - - if (reader.readTuple(tuple) == 4) { // split is optional - region.splits = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; - - if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits - region.pads = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; - - reader.readTuple(tuple); - } - } - - region.originalWidth = parseInt(tuple[0]); - region.originalHeight = parseInt(tuple[1]); - - reader.readTuple(tuple); - region.offsetX = parseInt(tuple[0]); - region.offsetY = parseInt(tuple[1]); - - region.index = parseInt(reader.readValue()); - - this.regions.push(region); - } - } -}; -spine.Atlas.prototype = { - findRegion: function (name) { - var regions = this.regions; - for (var i = 0, n = regions.length; i < n; i++) - if (regions[i].name == name) return regions[i]; - return null; - }, - dispose: function () { - var pages = this.pages; - for (var i = 0, n = pages.length; i < n; i++) - this.textureLoader.unload(pages[i].rendererObject); - }, - updateUVs: function (page) { - var regions = this.regions; - for (var i = 0, n = regions.length; i < n; i++) { - var region = regions[i]; - if (region.page != page) continue; - region.u = region.x / page.width; - region.v = region.y / page.height; - if (region.rotate) { - region.u2 = (region.x + region.height) / page.width; - region.v2 = (region.y + region.width) / page.height; - } else { - region.u2 = (region.x + region.width) / page.width; - region.v2 = (region.y + region.height) / page.height; - } - } - } -}; - -spine.Atlas.Format = { - alpha: 0, - intensity: 1, - luminanceAlpha: 2, - rgb565: 3, - rgba4444: 4, - rgb888: 5, - rgba8888: 6 -}; - -spine.Atlas.TextureFilter = { - nearest: 0, - linear: 1, - mipMap: 2, - mipMapNearestNearest: 3, - mipMapLinearNearest: 4, - mipMapNearestLinear: 5, - mipMapLinearLinear: 6 -}; - -spine.Atlas.TextureWrap = { - mirroredRepeat: 0, - clampToEdge: 1, - repeat: 2 -}; - -spine.AtlasPage = function () {}; -spine.AtlasPage.prototype = { - name: null, - format: null, - minFilter: null, - magFilter: null, - uWrap: null, - vWrap: null, - rendererObject: null, - width: 0, - height: 0 -}; - -spine.AtlasRegion = function () {}; -spine.AtlasRegion.prototype = { - page: null, - name: null, - x: 0, y: 0, - width: 0, height: 0, - u: 0, v: 0, u2: 0, v2: 0, - offsetX: 0, offsetY: 0, - originalWidth: 0, originalHeight: 0, - index: 0, - rotate: false, - splits: null, - pads: null -}; - -spine.AtlasReader = function (text) { - this.lines = text.split(/\r\n|\r|\n/); -}; -spine.AtlasReader.prototype = { - index: 0, - trim: function (value) { - return value.replace(/^\s+|\s+$/g, ""); - }, - readLine: function () { - if (this.index >= this.lines.length) return null; - return this.lines[this.index++]; - }, - readValue: function () { - var line = this.readLine(); - var colon = line.indexOf(":"); - if (colon == -1) throw "Invalid line: " + line; - return this.trim(line.substring(colon + 1)); - }, - /** Returns the number of tuple values read (1, 2 or 4). */ - readTuple: function (tuple) { - var line = this.readLine(); - var colon = line.indexOf(":"); - if (colon == -1) throw "Invalid line: " + line; - var i = 0, lastMatch = colon + 1; - for (; i < 3; i++) { - var comma = line.indexOf(",", lastMatch); - if (comma == -1) break; - tuple[i] = this.trim(line.substr(lastMatch, comma - lastMatch)); - lastMatch = comma + 1; - } - tuple[i] = this.trim(line.substring(lastMatch)); - return i + 1; - } -}; - -spine.AtlasAttachmentLoader = function (atlas) { - this.atlas = atlas; -}; -spine.AtlasAttachmentLoader.prototype = { - newRegionAttachment: function (skin, name, path) { - var region = this.atlas.findRegion(path); - if (!region) throw "Region not found in atlas: " + path + " (region attachment: " + name + ")"; - var attachment = new spine.RegionAttachment(name); - attachment.rendererObject = region; - attachment.setUVs(region.u, region.v, region.u2, region.v2, region.rotate); - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - return attachment; - }, - newMeshAttachment: function (skin, name, path) { - var region = this.atlas.findRegion(path); - if (!region) throw "Region not found in atlas: " + path + " (mesh attachment: " + name + ")"; - var attachment = new spine.MeshAttachment(name); - attachment.rendererObject = region; - attachment.regionU = region.u; - attachment.regionV = region.v; - attachment.regionU2 = region.u2; - attachment.regionV2 = region.v2; - attachment.regionRotate = region.rotate; - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - return attachment; - }, - newSkinnedMeshAttachment: function (skin, name, path) { - var region = this.atlas.findRegion(path); - if (!region) throw "Region not found in atlas: " + path + " (skinned mesh attachment: " + name + ")"; - var attachment = new spine.SkinnedMeshAttachment(name); - attachment.rendererObject = region; - attachment.regionU = region.u; - attachment.regionV = region.v; - attachment.regionU2 = region.u2; - attachment.regionV2 = region.v2; - attachment.regionRotate = region.rotate; - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - return attachment; - }, - newBoundingBoxAttachment: function (skin, name) { - return new spine.BoundingBoxAttachment(name); - } -}; - -spine.SkeletonBounds = function () { - this.polygonPool = []; - this.polygons = []; - this.boundingBoxes = []; -}; -spine.SkeletonBounds.prototype = { - minX: 0, minY: 0, maxX: 0, maxY: 0, - update: function (skeleton, updateAabb) { - var slots = skeleton.slots; - var slotCount = slots.length; - var x = skeleton.x, y = skeleton.y; - var boundingBoxes = this.boundingBoxes; - var polygonPool = this.polygonPool; - var polygons = this.polygons; - - boundingBoxes.length = 0; - for (var i = 0, n = polygons.length; i < n; i++) - polygonPool.push(polygons[i]); - polygons.length = 0; - - for (var i = 0; i < slotCount; i++) { - var slot = slots[i]; - var boundingBox = slot.attachment; - if (boundingBox.type != spine.AttachmentType.boundingbox) continue; - boundingBoxes.push(boundingBox); - - var poolCount = polygonPool.length, polygon; - if (poolCount > 0) { - polygon = polygonPool[poolCount - 1]; - polygonPool.splice(poolCount - 1, 1); - } else - polygon = []; - polygons.push(polygon); - - polygon.length = boundingBox.vertices.length; - boundingBox.computeWorldVertices(x, y, slot.bone, polygon); - } - - if (updateAabb) this.aabbCompute(); - }, - aabbCompute: function () { - var polygons = this.polygons; - var minX = Number.MAX_VALUE, minY = Number.MAX_VALUE, maxX = Number.MIN_VALUE, maxY = Number.MIN_VALUE; - for (var i = 0, n = polygons.length; i < n; i++) { - var vertices = polygons[i]; - for (var ii = 0, nn = vertices.length; ii < nn; ii += 2) { - var x = vertices[ii]; - var y = vertices[ii + 1]; - minX = Math.min(minX, x); - minY = Math.min(minY, y); - maxX = Math.max(maxX, x); - maxY = Math.max(maxY, y); - } - } - this.minX = minX; - this.minY = minY; - this.maxX = maxX; - this.maxY = maxY; - }, - /** Returns true if the axis aligned bounding box contains the point. */ - aabbContainsPoint: function (x, y) { - return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY; - }, - /** Returns true if the axis aligned bounding box intersects the line segment. */ - aabbIntersectsSegment: function (x1, y1, x2, y2) { - var minX = this.minX, minY = this.minY, maxX = this.maxX, maxY = this.maxY; - if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) - return false; - var m = (y2 - y1) / (x2 - x1); - var y = m * (minX - x1) + y1; - if (y > minY && y < maxY) return true; - y = m * (maxX - x1) + y1; - if (y > minY && y < maxY) return true; - var x = (minY - y1) / m + x1; - if (x > minX && x < maxX) return true; - x = (maxY - y1) / m + x1; - if (x > minX && x < maxX) return true; - return false; - }, - /** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ - aabbIntersectsSkeleton: function (bounds) { - return this.minX < bounds.maxX && this.maxX > bounds.minX && this.minY < bounds.maxY && this.maxY > bounds.minY; - }, - /** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more - * efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */ - containsPoint: function (x, y) { - var polygons = this.polygons; - for (var i = 0, n = polygons.length; i < n; i++) - if (this.polygonContainsPoint(polygons[i], x, y)) return this.boundingBoxes[i]; - return null; - }, - /** Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually - * more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true. */ - intersectsSegment: function (x1, y1, x2, y2) { - var polygons = this.polygons; - for (var i = 0, n = polygons.length; i < n; i++) - if (polygons[i].intersectsSegment(x1, y1, x2, y2)) return this.boundingBoxes[i]; - return null; - }, - /** Returns true if the polygon contains the point. */ - polygonContainsPoint: function (polygon, x, y) { - var nn = polygon.length; - var prevIndex = nn - 2; - var inside = false; - for (var ii = 0; ii < nn; ii += 2) { - var vertexY = polygon[ii + 1]; - var prevY = polygon[prevIndex + 1]; - if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { - var vertexX = polygon[ii]; - if (vertexX + (y - vertexY) / (prevY - vertexY) * (polygon[prevIndex] - vertexX) < x) inside = !inside; - } - prevIndex = ii; - } - return inside; - }, - /** Returns true if the polygon contains the line segment. */ - polygonIntersectsSegment: function (polygon, x1, y1, x2, y2) { - var nn = polygon.length; - var width12 = x1 - x2, height12 = y1 - y2; - var det1 = x1 * y2 - y1 * x2; - var x3 = polygon[nn - 2], y3 = polygon[nn - 1]; - for (var ii = 0; ii < nn; ii += 2) { - var x4 = polygon[ii], y4 = polygon[ii + 1]; - var det2 = x3 * y4 - y3 * x4; - var width34 = x3 - x4, height34 = y3 - y4; - var det3 = width12 * height34 - height12 * width34; - var x = (det1 * width34 - width12 * det2) / det3; - if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { - var y = (det1 * height34 - height12 * det2) / det3; - if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; - } - x3 = x4; - y3 = y4; - } - return false; - }, - getPolygon: function (attachment) { - var index = this.boundingBoxes.indexOf(attachment); - return index == -1 ? null : this.polygons[index]; - }, - getWidth: function () { - return this.maxX - this.minX; - }, - getHeight: function () { - return this.maxY - this.minY; - } -}; - -},{}],95:[function(require,module,exports){ -/** - * @file Main export of the PIXI spine library - * @author Mat Groves - * @copyright 2013-2015 GoodBoyDigital - * @license {@link https://github.com/GoodBoyDigital/pixi.js/blob/master/LICENSE|MIT License} - */ - -/** - * @namespace PIXI - */ -module.exports = { - Spine: require('./Spine') -}; - -},{"./Spine":93}],96:[function(require,module,exports){ -var core = require('../core'); - -/** - * A BitmapText object will create a line or multiple lines of text using bitmap font. To - * split a line you can use '\n', '\r' or '\r\n' in your string. You can generate the fnt files using: - * - * http://www.angelcode.com/products/bmfont/ for windows or - * http://www.bmglyph.com/ for mac. - * - * @class - * @extends DisplayObjectContainer - * @namespace PIXI - * @param text {string} The copy that you would like the text to display - * @param style {object} The style parameters - * @param style.font {string} The size (optional) and bitmap font id (required) eq 'Arial' or '20px Arial' (must have loaded previously) - * @param [style.align='left'] {string} Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text - */ -function BitmapText(text, style) { - core.DisplayObjectContainer.call(this); - - /** - * The width of the overall text, different from fontSize, - * which is defined in the style object - * - * @member {number} - * @readOnly - */ - this.textWidth = 0; - - /** - * The height of the overall text, different from fontSize, - * which is defined in the style object - * - * @member {number} - * @readOnly - */ - this.textHeight = 0; - - /** - * Private tracker for the letter sprite pool. - * - * @member {Sprite[]} - * @private - */ - this._pool = []; - - /** - * Private tracker for the current style. - * - * @member {object} - * @private - */ - this._style = { - tint: style.tint, - align: style.align, - fontName: null, - fontSize: 0 - }; - this.font = style.font; // run font setter - - /** - * Private tracker for the current text. - * - * @member {string} - * @private - */ - this._text = text; - - /** - * The dirty state of this object. - * - * @member {boolean} - */ - this.dirty = false; - - this.updateText(); -} - -// constructor -BitmapText.prototype = Object.create(core.DisplayObjectContainer.prototype); -BitmapText.prototype.constructor = BitmapText; -module.exports = BitmapText; - -Object.defineProperties(BitmapText.prototype, { - /** - * The tint of the BitmapText object - * - * @member {number} - * @memberof BitmapText# - */ - tint: { - get: function () { - return this._style.tint; - }, - set: function (value) { - this._style.tint = (typeof value === 'number' && value >= 0) ? value : 0xFFFFFF; - - this.dirty = true; - } - }, - - /** - * The tint of the BitmapText object - * - * @member {string} - * @default 'left' - * @memberof BitmapText# - */ - align: { - get: function () { - return this._style.align; - }, - set: function (value) { - this._style.align = value; - - this.dirty = true; - } - }, - - /** - * The tint of the BitmapText object - * - * @member {Font} - * @memberof BitmapText# - */ - font: { - get: function () { - return this._style.font; - }, - set: function (value) { - value = value.split(' '); - - // TODO - This should be object-based not string based like it has been. - this._style.fontName = value[value.length - 1]; - this._style.fontSize = value.length >= 2 ? parseInt(value[value.length - 2], 10) : BitmapText.fonts[this.fontName].size; - - this.dirty = true; - } - }, - - /** - * The text of the BitmapText object - * - * @member {string} - * @memberof BitmapText# - */ - text: { - get: function () { - return this._text; - }, - set: function (value) { - this._text = value; - - this.dirty = true; - } - } -}); - -/** - * Renders text and updates it when needed - * - * @private - */ -BitmapText.prototype.updateText = function () { - var data = BitmapText.fonts[this.fontName]; - var pos = new core.math.Point(); - var prevCharCode = null; - var chars = []; - var maxLineWidth = 0; - var lineWidths = []; - var line = 0; - var scale = this.fontSize / data.size; - - for (var i = 0; i < this.text.length; i++) { - var charCode = this.text.charCodeAt(i); - - if (/(?:\r\n|\r|\n)/.test(this.text.charAt(i))) { - lineWidths.push(pos.x); - maxLineWidth = Math.max(maxLineWidth, pos.x); - line++; - - pos.x = 0; - pos.y += data.lineHeight; - prevCharCode = null; - continue; - } - - var charData = data.chars[charCode]; - - if (!charData) { - continue; - } - - if (prevCharCode && charData.kerning[prevCharCode]) { - pos.x += charData.kerning[prevCharCode]; - } - - chars.push({texture:charData.texture, line: line, charCode: charCode, position: new core.math.Point(pos.x + charData.xOffset, pos.y + charData.yOffset)}); - pos.x += charData.xAdvance; - - prevCharCode = charCode; - } - - lineWidths.push(pos.x); - maxLineWidth = Math.max(maxLineWidth, pos.x); - - var lineAlignOffsets = []; - - for (i = 0; i <= line; i++) { - var alignOffset = 0; - - if (this.style.align === 'right') { - alignOffset = maxLineWidth - lineWidths[i]; - } - else if (this.style.align === 'center') { - alignOffset = (maxLineWidth - lineWidths[i]) / 2; - } - - lineAlignOffsets.push(alignOffset); - } - - var lenChildren = this.children.length; - var lenChars = chars.length; - var tint = this.tint; - - for (i = 0; i < lenChars; i++) { - var c = i < lenChildren ? this.children[i] : this._pool.pop(); // get old child if have. if not - take from pool. - - if (c) { - c.setTexture(chars[i].texture); // check if got one before. - } - else { - c = new core.Sprite(chars[i].texture); // if no create new one. - } - - c.position.x = (chars[i].position.x + lineAlignOffsets[chars[i].line]) * scale; - c.position.y = chars[i].position.y * scale; - c.scale.x = c.scale.y = scale; - c.tint = tint; - - if (!c.parent) { - this.addChild(c); - } - } - - // remove unnecessary children. - // and put their into the pool. - while(this.children.length > lenChars) { - var child = this.getChildAt(this.children.length - 1); - this._pool.push(child); - this.removeChild(child); - } - - this.textWidth = maxLineWidth * scale; - this.textHeight = (pos.y + data.lineHeight) * scale; -}; - -/** - * Updates the transform of this object - * - * @private - */ -BitmapText.prototype.updateTransform = function () { - if (this.dirty) { - this.updateText(); - this.dirty = false; - } - - this.displayObjectContainerUpdateTransform(); -}; - -BitmapText.fonts = {}; - -},{"../core":9}],97:[function(require,module,exports){ -var core = require('../core'); - -/** - * A Text Object will create a line or multiple lines of text. To split a line you can use '\n' in your text string, - * or add a wordWrap property set to true and and wordWrapWidth property with a value in the style object. - * - * @class - * @extends Sprite - * @namespace PIXI - * @param text {string} The copy that you would like the text to display - * @param [style] {object} The style parameters - * @param [style.font] {string} default 'bold 20px Arial' The style and size of the font - * @param [style.fill='black'] {String|Number} A canvas fillstyle that will be used on the text e.g 'red', '#00FF00' - * @param [style.align='left'] {string} Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text - * @param [style.stroke] {String|Number} A canvas fillstyle that will be used on the text stroke e.g 'blue', '#FCFF00' - * @param [style.strokeThickness=0] {number} A number that represents the thickness of the stroke. Default is 0 (no stroke) - * @param [style.wordWrap=false] {boolean} Indicates if word wrap should be used - * @param [style.wordWrapWidth=100] {number} The width at which text will wrap, it needs wordWrap to be set to true - * @param [style.dropShadow=false] {boolean} Set a drop shadow for the text - * @param [style.dropShadowColor='#000000'] {string} A fill style to be used on the dropshadow e.g 'red', '#00FF00' - * @param [style.dropShadowAngle=Math.PI/4] {number} Set a angle of the drop shadow - * @param [style.dropShadowDistance=5] {number} Set a distance of the drop shadow - */ -function Text(text, style) { - /** - * The canvas element that everything is drawn to - * - * @member {HTMLCanvasElement} - */ - this.canvas = document.createElement('canvas'); - - /** - * The canvas 2d context that everything is drawn with - * @member {HTMLCanvasElement} - */ - this.context = this.canvas.getContext('2d'); - - /** - * The resolution of the canvas. - * @member {number} - */ - this.resolution = 1; - - core.Sprite.call(this, core.Texture.fromCanvas(this.canvas)); - - this.setText(text); - this.setStyle(style); -} - -// constructor -Text.prototype = Object.create(core.Sprite.prototype); -Text.prototype.constructor = Text; -module.exports = Text; - -Object.defineProperties(Text.prototype, { - /** - * The width of the Text, setting this will actually modify the scale to achieve the value set - * - * @member {number} - * @memberof Text# - */ - width: { - get: function () { - if (this.dirty) { - this.updateText(); - this.dirty = false; - } - - return this.scale.x * this.texture.frame.width; - }, - set: function (value) { - this.scale.x = value / this.texture.frame.width; - this._width = value; - } - }, - - /** - * The height of the Text, setting this will actually modify the scale to achieve the value set - * - * @member {number} - * @memberof Text# - */ - height: { - get: function () { - if (this.dirty) { - this.updateText(); - this.dirty = false; - } - - return this.scale.y * this.texture.frame.height; - }, - set: function (value) { - this.scale.y = value / this.texture.frame.height; - this._height = value; - } - } -}); - -/** - * Set the style of the text - * - * @param [style] {object} The style parameters - * @param [style.font='bold 20pt Arial'] {string} The style and size of the font - * @param [style.fill='black'] {object} A canvas fillstyle that will be used on the text eg 'red', '#00FF00' - * @param [style.align='left'] {string} Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text - * @param [style.stroke='black'] {string} A canvas fillstyle that will be used on the text stroke eg 'blue', '#FCFF00' - * @param [style.strokeThickness=0] {number} A number that represents the thickness of the stroke. Default is 0 (no stroke) - * @param [style.wordWrap=false] {boolean} Indicates if word wrap should be used - * @param [style.wordWrapWidth=100] {number} The width at which text will wrap - * @param [style.dropShadow=false] {boolean} Set a drop shadow for the text - * @param [style.dropShadowColor='#000000'] {string} A fill style to be used on the dropshadow e.g 'red', '#00FF00' - * @param [style.dropShadowAngle=Math.PI/4] {number} Set a angle of the drop shadow - * @param [style.dropShadowDistance=5] {number} Set a distance of the drop shadow - */ -Text.prototype.setStyle = function (style) { - style = style || {}; - style.font = style.font || 'bold 20pt Arial'; - style.fill = style.fill || 'black'; - style.align = style.align || 'left'; - style.stroke = style.stroke || 'black'; //provide a default, see: https://github.com/GoodBoyDigital/pixi.js/issues/136 - style.strokeThickness = style.strokeThickness || 0; - style.wordWrap = style.wordWrap || false; - style.wordWrapWidth = style.wordWrapWidth || 100; - - style.dropShadow = style.dropShadow || false; - style.dropShadowAngle = style.dropShadowAngle || Math.PI / 6; - style.dropShadowDistance = style.dropShadowDistance || 4; - style.dropShadowColor = style.dropShadowColor || 'black'; - - this.style = style; - this.dirty = true; -}; - -/** - * Set the copy for the text object. To split a line you can use '\n'. - * - * @param text {string} The copy that you would like the text to display - */ -Text.prototype.setText = function (text) { - this.text = text.toString() || ' '; - this.dirty = true; -}; - -/** - * Renders text and updates it when needed - * - * @private - */ -Text.prototype.updateText = function () { - this.texture.baseTexture.resolution = this.resolution; - - this.context.font = this.style.font; - - var outputText = this.text; - - // word wrap - // preserve original text - if (this.style.wordWrap) { - outputText = this.wordWrap(this.text); - } - - //split text into lines - var lines = outputText.split(/(?:\r\n|\r|\n)/); - - //calculate text width - var lineWidths = []; - var maxLineWidth = 0; - var fontProperties = this.determineFontProperties(this.style.font); - for (var i = 0; i < lines.length; i++) { - var lineWidth = this.context.measureText(lines[i]).width; - lineWidths[i] = lineWidth; - maxLineWidth = Math.max(maxLineWidth, lineWidth); - } - - var width = maxLineWidth + this.style.strokeThickness; - if (this.style.dropShadow) { - width += this.style.dropShadowDistance; - } - - this.canvas.width = ( width + this.context.lineWidth ) * this.resolution; - - //calculate text height - var lineHeight = fontProperties.fontSize + this.style.strokeThickness; - - var height = lineHeight * lines.length; - if (this.style.dropShadow) { - height += this.style.dropShadowDistance; - } - - this.canvas.height = height * this.resolution; - - this.context.scale( this.resolution, this.resolution); - - if (navigator.isCocoonJS) { - this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); - } - - // used for debugging.. - //this.context.fillStyle ="#FF0000" - //this.context.fillRect(0, 0, this.canvas.width,this.canvas.height); - - this.context.font = this.style.font; - this.context.strokeStyle = this.style.stroke; - this.context.lineWidth = this.style.strokeThickness; - this.context.textBaseline = 'alphabetic'; - //this.context.lineJoin = 'round'; - - var linePositionX; - var linePositionY; - - if (this.style.dropShadow) { - this.context.fillStyle = this.style.dropShadowColor; - - var xShadowOffset = Math.cos(this.style.dropShadowAngle) * this.style.dropShadowDistance; - var yShadowOffset = Math.sin(this.style.dropShadowAngle) * this.style.dropShadowDistance; - - for (i = 0; i < lines.length; i++) { - linePositionX = this.style.strokeThickness / 2; - linePositionY = (this.style.strokeThickness / 2 + i * lineHeight) + fontProperties.ascent; - - if (this.style.align === 'right') { - linePositionX += maxLineWidth - lineWidths[i]; - } - else if (this.style.align === 'center') { - linePositionX += (maxLineWidth - lineWidths[i]) / 2; - } - - if (this.style.fill) { - this.context.fillText(lines[i], linePositionX + xShadowOffset, linePositionY + yShadowOffset); - } - - // if (dropShadow) - } - } - - //set canvas text styles - this.context.fillStyle = this.style.fill; - - //draw lines line by line - for (i = 0; i < lines.length; i++) { - linePositionX = this.style.strokeThickness / 2; - linePositionY = (this.style.strokeThickness / 2 + i * lineHeight) + fontProperties.ascent; - - if (this.style.align === 'right') { - linePositionX += maxLineWidth - lineWidths[i]; - } - else if (this.style.align === 'center') { - linePositionX += (maxLineWidth - lineWidths[i]) / 2; - } - - if (this.style.stroke && this.style.strokeThickness) { - this.context.strokeText(lines[i], linePositionX, linePositionY); - } - - if (this.style.fill) { - this.context.fillText(lines[i], linePositionX, linePositionY); - } - - // if (dropShadow) - } - - this.updateTexture(); -}; - -/** - * Updates texture size based on canvas size - * - * @private - */ -Text.prototype.updateTexture = function () { - this.texture.baseTexture.width = this.canvas.width; - this.texture.baseTexture.height = this.canvas.height; - this.texture.crop.width = this.texture.frame.width = this.canvas.width; - this.texture.crop.height = this.texture.frame.height = this.canvas.height; - - this._width = this.canvas.width; - this._height = this.canvas.height; - - // update the dirty base textures - this.texture.baseTexture.dirty(); -}; - -/** - * Renders the object using the WebGL renderer -* - * @param renderer {WebGLRenderer} - */ -Text.prototype.renderWebGL = function (renderer) { - if (this.dirty) { - this.resolution = renderer.resolution; - - this.updateText(); - this.dirty = false; - } - - core.Sprite.prototype.renderWebGL.call(this, renderer); -}; - -/** - * Renders the object using the Canvas renderer -* - * @param renderer {CanvasRenderer} - */ -Text.prototype.renderCanvas = function (renderer) { - if (this.dirty) { - this.resolution = renderer.resolution; - - this.updateText(); - this.dirty = false; - } - - core.Sprite.prototype.renderCanvas.call(this, renderer); -}; - -/** - * Calculates the ascent, descent and fontSize of a given fontStyle -* - * @param fontStyle {object} - * @private - */ -Text.prototype.determineFontProperties = function (fontStyle) { - var properties = Text.fontPropertiesCache[fontStyle]; - - if (!properties) { - properties = {}; - - var canvas = Text.fontPropertiesCanvas; - var context = Text.fontPropertiesContext; - - context.font = fontStyle; - - var width = Math.ceil(context.measureText('|Mq').width); - var baseline = Math.ceil(context.measureText('M').width); - var height = 2 * baseline; - - baseline = baseline * 1.4 | 0; - - canvas.width = width; - canvas.height = height; - - context.fillStyle = '#f00'; - context.fillRect(0, 0, width, height); - - context.font = fontStyle; - - context.textBaseline = 'alphabetic'; - context.fillStyle = '#000'; - context.fillText('|MÉq', 0, baseline); - - var imagedata = context.getImageData(0, 0, width, height).data; - var pixels = imagedata.length; - var line = width * 4; - - var i, j; - - var idx = 0; - var stop = false; - - // ascent. scan from top to bottom until we find a non red pixel - for (i = 0; i < baseline; i++) { - for (j = 0; j < line; j += 4) { - if (imagedata[idx + j] !== 255) { - stop = true; - break; - } - } - if (!stop) { - idx += line; - } - else { - break; - } - } - - properties.ascent = baseline - i; - - idx = pixels - line; - stop = false; - - // descent. scan from bottom to top until we find a non red pixel - for (i = height; i > baseline; i--) { - for (j = 0; j < line; j += 4) { - if (imagedata[idx + j] !== 255) { - stop = true; - break; - } - } - if (!stop) { - idx -= line; - } - else { - break; - } - } - - properties.descent = i - baseline; - //TODO might need a tweak. kind of a temp fix! - properties.descent += 6; - properties.fontSize = properties.ascent + properties.descent; - - Text.fontPropertiesCache[fontStyle] = properties; - } - - return properties; -}; - -/** - * Applies newlines to a string to have it optimally fit into the horizontal - * bounds set by the Text object's wordWrapWidth property. - * - * @param text {string} - * @private - */ -Text.prototype.wordWrap = function (text) { - // Greedy wrapping algorithm that will wrap words as the line grows longer - // than its horizontal bounds. - var result = ''; - var lines = text.split('\n'); - for (var i = 0; i < lines.length; i++) { - var spaceLeft = this.style.wordWrapWidth; - var words = lines[i].split(' '); - for (var j = 0; j < words.length; j++) { - var wordWidth = this.context.measureText(words[j]).width; - var wordWidthWithSpace = wordWidth + this.context.measureText(' ').width; - if (j === 0 || wordWidthWithSpace > spaceLeft) { - // Skip printing the newline if it's the first word of the line that is - // greater than the word wrap width. - if (j > 0) { - result += '\n'; - } - result += words[j]; - spaceLeft = this.style.wordWrapWidth - wordWidth; - } - else { - spaceLeft -= wordWidthWithSpace; - result += ' ' + words[j]; - } - } - - if (i < lines.length-1) { - result += '\n'; - } - } - return result; -}; - -/** - * Returns the bounds of the Text as a rectangle. The bounds calculation takes the worldTransform into account. - * - * @param matrix {Matrix} the transformation matrix of the Text - * @return {Rectangle} the framing rectangle - */ -Text.prototype.getBounds = function (matrix) { - if (this.dirty) { - this.updateText(); - this.dirty = false; - } - - return core.Sprite.prototype.getBounds.call(this, matrix); -}; - -/** - * Destroys this text object. - * - * @param destroyBaseTexture {boolean} whether to destroy the base texture as well - */ -Text.prototype.destroy = function (destroyBaseTexture) { - // make sure to reset the the context and canvas.. dont want this hanging around in memory! - this.context = null; - this.canvas = null; - - this.texture.destroy(destroyBaseTexture === undefined ? true : destroyBaseTexture); -}; - -Text.fontPropertiesCache = {}; -Text.fontPropertiesCanvas = document.createElement('canvas'); -Text.fontPropertiesContext = Text.fontPropertiesCanvas.getContext('2d'); - -},{"../core":9}],98:[function(require,module,exports){ -/** - * @file Main export of the PIXI text library - * @author Mat Groves - * @copyright 2013-2015 GoodBoyDigital - * @license {@link https://github.com/GoodBoyDigital/pixi.js/blob/master/LICENSE|MIT License} - */ - -/** - * @namespace PIXI - */ -module.exports = { - Text: require('./Text'), - BitmapText: require('./BitmapText') -}; - -},{"./BitmapText":96,"./Text":97}]},{},[1])(1) -}); -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvaW5kZXgiLCJub2RlX21vZHVsZXMvd2ViZ2wtZW5hYmxlZC9pbmRleC5qcyIsInBhY2thZ2UuanNvbiIsInNyYy9jb3JlL2NvbnN0LmpzIiwic3JjL2NvcmUvZGlzcGxheS9EaXNwbGF5T2JqZWN0LmpzIiwic3JjL2NvcmUvZGlzcGxheS9EaXNwbGF5T2JqZWN0Q29udGFpbmVyLmpzIiwic3JjL2NvcmUvZGlzcGxheS9TcHJpdGUuanMiLCJzcmMvY29yZS9kaXNwbGF5L1Nwcml0ZUJhdGNoLmpzIiwic3JjL2NvcmUvaW5kZXguanMiLCJzcmMvY29yZS9tYXRoL01hdHJpeC5qcyIsInNyYy9jb3JlL21hdGgvUG9pbnQuanMiLCJzcmMvY29yZS9tYXRoL2luZGV4LmpzIiwic3JjL2NvcmUvbWF0aC9zaGFwZXMvQ2lyY2xlLmpzIiwic3JjL2NvcmUvbWF0aC9zaGFwZXMvRWxsaXBzZS5qcyIsInNyYy9jb3JlL21hdGgvc2hhcGVzL1BvbHlnb24uanMiLCJzcmMvY29yZS9tYXRoL3NoYXBlcy9SZWN0YW5nbGUuanMiLCJzcmMvY29yZS9tYXRoL3NoYXBlcy9Sb3VuZGVkUmVjdGFuZ2xlLmpzIiwic3JjL2NvcmUvcHJpbWl0aXZlcy9HcmFwaGljcy5qcyIsInNyYy9jb3JlL3ByaW1pdGl2ZXMvR3JhcGhpY3NEYXRhLmpzIiwic3JjL2NvcmUvcmVuZGVyZXJzL2NhbnZhcy9DYW52YXNSZW5kZXJlci5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy9jYW52YXMvdXRpbHMvQ2FudmFzQnVmZmVyLmpzIiwic3JjL2NvcmUvcmVuZGVyZXJzL2NhbnZhcy91dGlscy9DYW52YXNHcmFwaGljcy5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy9jYW52YXMvdXRpbHMvQ2FudmFzTWFza01hbmFnZXIuanMiLCJzcmMvY29yZS9yZW5kZXJlcnMvY2FudmFzL3V0aWxzL0NhbnZhc1RpbnRlci5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy93ZWJnbC9XZWJHTFJlbmRlcmVyLmpzIiwic3JjL2NvcmUvcmVuZGVyZXJzL3dlYmdsL21hbmFnZXJzL1dlYkdMQmxlbmRNb2RlTWFuYWdlci5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy93ZWJnbC9tYW5hZ2Vycy9XZWJHTEZpbHRlck1hbmFnZXIuanMiLCJzcmMvY29yZS9yZW5kZXJlcnMvd2ViZ2wvbWFuYWdlcnMvV2ViR0xNYW5hZ2VyLmpzIiwic3JjL2NvcmUvcmVuZGVyZXJzL3dlYmdsL21hbmFnZXJzL1dlYkdMTWFza01hbmFnZXIuanMiLCJzcmMvY29yZS9yZW5kZXJlcnMvd2ViZ2wvbWFuYWdlcnMvV2ViR0xTaGFkZXJNYW5hZ2VyLmpzIiwic3JjL2NvcmUvcmVuZGVyZXJzL3dlYmdsL21hbmFnZXJzL1dlYkdMU3RlbmNpbE1hbmFnZXIuanMiLCJzcmMvY29yZS9yZW5kZXJlcnMvd2ViZ2wvc2hhZGVycy9Db21wbGV4UHJpbWl0aXZlU2hhZGVyLmpzIiwic3JjL2NvcmUvcmVuZGVyZXJzL3dlYmdsL3NoYWRlcnMvRmFzdFNoYWRlci5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy93ZWJnbC9zaGFkZXJzL1ByaW1pdGl2ZVNoYWRlci5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy93ZWJnbC9zaGFkZXJzL1NoYWRlci5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy93ZWJnbC9zaGFkZXJzL1N0cmlwU2hhZGVyLmpzIiwic3JjL2NvcmUvcmVuZGVyZXJzL3dlYmdsL3V0aWxzL0ZpbHRlclRleHR1cmUuanMiLCJzcmMvY29yZS9yZW5kZXJlcnMvd2ViZ2wvdXRpbHMvV2ViR0xGYXN0U3ByaXRlQmF0Y2guanMiLCJzcmMvY29yZS9yZW5kZXJlcnMvd2ViZ2wvdXRpbHMvV2ViR0xHcmFwaGljcy5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy93ZWJnbC91dGlscy9XZWJHTEdyYXBoaWNzRGF0YS5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy93ZWJnbC91dGlscy9XZWJHTFNwcml0ZUJhdGNoLmpzIiwic3JjL2NvcmUvdGV4dHVyZXMvQmFzZVRleHR1cmUuanMiLCJzcmMvY29yZS90ZXh0dXJlcy9SZW5kZXJUZXh0dXJlLmpzIiwic3JjL2NvcmUvdGV4dHVyZXMvVGV4dHVyZS5qcyIsInNyYy9jb3JlL3RleHR1cmVzL1RleHR1cmVVdnMuanMiLCJzcmMvY29yZS90ZXh0dXJlcy9WaWRlb0Jhc2VUZXh0dXJlLmpzIiwic3JjL2NvcmUvdXRpbHMvRXZlbnREYXRhLmpzIiwic3JjL2NvcmUvdXRpbHMvUG9seUsuanMiLCJzcmMvY29yZS91dGlscy9ldmVudFRhcmdldC5qcyIsInNyYy9jb3JlL3V0aWxzL2luZGV4LmpzIiwic3JjL2V4dHJhcy9Nb3ZpZUNsaXAuanMiLCJzcmMvZXh0cmFzL1JvcGUuanMiLCJzcmMvZXh0cmFzL1N0cmlwLmpzIiwic3JjL2V4dHJhcy9UaWxpbmdTcHJpdGUuanMiLCJzcmMvZXh0cmFzL2luZGV4LmpzIiwic3JjL2ZpbHRlcnMvQWJzdHJhY3RGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9BbHBoYU1hc2tGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9Bc2NpaUZpbHRlci5qcyIsInNyYy9maWx0ZXJzL0JsdXJGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9CbHVyWEZpbHRlci5qcyIsInNyYy9maWx0ZXJzL0JsdXJZRmlsdGVyLmpzIiwic3JjL2ZpbHRlcnMvQ29sb3JNYXRyaXhGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9Db2xvclN0ZXBGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9Db252b2x1dGlvbkZpbHRlci5qcyIsInNyYy9maWx0ZXJzL0Nyb3NzSGF0Y2hGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9EaXNwbGFjZW1lbnRGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9Eb3RTY3JlZW5GaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9GaWx0ZXJCbG9jay5qcyIsInNyYy9maWx0ZXJzL0dyYXlGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9JbnZlcnRGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9Ob2lzZUZpbHRlci5qcyIsInNyYy9maWx0ZXJzL05vcm1hbE1hcEZpbHRlci5qcyIsInNyYy9maWx0ZXJzL1BpeGVsYXRlRmlsdGVyLmpzIiwic3JjL2ZpbHRlcnMvUkdCU3BsaXRGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9TZXBpYUZpbHRlci5qcyIsInNyYy9maWx0ZXJzL1NtYXJ0Qmx1ckZpbHRlci5qcyIsInNyYy9maWx0ZXJzL1RpbHRTaGlmdEZpbHRlci5qcyIsInNyYy9maWx0ZXJzL1RpbHRTaGlmdFhGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9UaWx0U2hpZnRZRmlsdGVyLmpzIiwic3JjL2ZpbHRlcnMvVHdpc3RGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9pbmRleC5qcyIsInNyYy9pbnRlcmFjdGlvbi9JbnRlcmFjdGlvbkRhdGEuanMiLCJzcmMvaW50ZXJhY3Rpb24vSW50ZXJhY3Rpb25NYW5hZ2VyLmpzIiwic3JjL2ludGVyYWN0aW9uL2luZGV4LmpzIiwic3JjL2xvYWRlcnMvQXRsYXNMb2FkZXIuanMiLCJzcmMvbG9hZGVycy9CaXRtYXBGb250TG9hZGVyLmpzIiwic3JjL2xvYWRlcnMvSW1hZ2VMb2FkZXIuanMiLCJzcmMvbG9hZGVycy9Kc29uTG9hZGVyLmpzIiwic3JjL2xvYWRlcnMvU3BpbmVMb2FkZXIuanMiLCJzcmMvbG9hZGVycy9TcGluZVRleHR1cmVMb2FkZXIuanMiLCJzcmMvbG9hZGVycy9TcHJpdGVTaGVldExvYWRlci5qcyIsInNyYy9sb2FkZXJzL2luZGV4LmpzIiwic3JjL3NwaW5lL1NwaW5lLmpzIiwic3JjL3NwaW5lL1NwaW5lUnVudGltZS5qcyIsInNyYy9zcGluZS9pbmRleC5qcyIsInNyYy90ZXh0L0JpdG1hcFRleHQuanMiLCJzcmMvdGV4dC9UZXh0LmpzIiwic3JjL3RleHQvaW5kZXguanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL1lBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVrQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDamFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25GQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM2lDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNVVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcFRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9pQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6Y0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hRQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyY0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbGJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxeEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNtQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6WkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0VEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqY0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqYkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25FQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2h4QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbE9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25QQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xrRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNiQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaFJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwibW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgY29yZTogICAgICAgICAgIHJlcXVpcmUoJy4vY29yZScpLFxuICAgIGV4dHJhczogICAgICAgICByZXF1aXJlKCcuL2V4dHJhcycpLFxuICAgIGZpbHRlcnM6ICAgICAgICByZXF1aXJlKCcuL2ZpbHRlcnMnKSxcbiAgICBpbnRlcmFjdGlvbjogICAgcmVxdWlyZSgnLi9pbnRlcmFjdGlvbicpLFxuICAgIGxvYWRlcnM6ICAgICAgICByZXF1aXJlKCcuL2xvYWRlcnMnKSxcbiAgICBzcGluZTogICAgICAgICAgcmVxdWlyZSgnLi9zcGluZScpLFxuICAgIHRleHQ6ICAgICAgICAgICByZXF1aXJlKCcuL3RleHQnKVxufTtcbiIsIm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gd2ViZ2xFbmFibGVkKCkge1xuICB0cnkge1xuICAgIHZhciBjYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcbiAgICByZXR1cm4gISEod2luZG93LldlYkdMUmVuZGVyaW5nQ29udGV4dCAmJiAoY2FudmFzLmdldENvbnRleHQoJ3dlYmdsJykgfHwgY2FudmFzLmdldENvbnRleHQoJ2V4cGVyaW1lbnRhbC13ZWJnbCcpKSk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn07XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gIFwibmFtZVwiOiBcInBpeGkuanNcIixcbiAgXCJ2ZXJzaW9uXCI6IFwiMy4wLjBcIixcbiAgXCJkZXNjcmlwdGlvblwiOiBcIlBpeGkuanMgaXMgYSBmYXN0IGxpZ2h0d2VpZ2h0IDJEIGxpYnJhcnkgdGhhdCB3b3JrcyBhY3Jvc3MgYWxsIGRldmljZXMuXCIsXG4gIFwiYXV0aG9yXCI6IFwiTWF0IEdyb3Zlc1wiLFxuICBcImNvbnRyaWJ1dG9yc1wiOiBbXG4gICAgXCJDaGFkIEVuZ2xlciA8Y2hhZEBwYW50aGVyZGV2LmNvbT5cIixcbiAgICBcIlJpY2hhcmQgRGF2ZXkgPHJkYXZleUBnbWFpbC5jb20+XCJcbiAgXSxcbiAgXCJtYWluXCI6IFwiLi9zcmMvaW5kZXguanNcIixcbiAgXCJob21lcGFnZVwiOiBcImh0dHA6Ly9nb29kYm95ZGlnaXRhbC5jb20vXCIsXG4gIFwiYnVnc1wiOiBcImh0dHBzOi8vZ2l0aHViLmNvbS9Hb29kQm95RGlnaXRhbC9waXhpLmpzL2lzc3Vlc1wiLFxuICBcImxpY2Vuc2VcIjogXCJNSVRcIixcbiAgXCJyZXBvc2l0b3J5XCI6IHtcbiAgICBcInR5cGVcIjogXCJnaXRcIixcbiAgICBcInVybFwiOiBcImh0dHBzOi8vZ2l0aHViLmNvbS9Hb29kQm95RGlnaXRhbC9waXhpLmpzLmdpdFwiXG4gIH0sXG4gIFwic2NyaXB0c1wiOiB7XG4gICAgXCJ0ZXN0XCI6IFwiZ3VscCB0ZXN0XCIsXG4gICAgXCJkb2NzXCI6IFwiLi9ub2RlX21vZHVsZXMvLmJpbi9qc2RvYyAtYyAuL2d1bHAvdXRpbC9qc2RvYy5jb25mLmpzb25cIlxuICB9LFxuICBcImRldkRlcGVuZGVuY2llc1wiOiB7XG4gICAgXCJicm93c2VyaWZ5XCI6IFwiXjguMC4yXCIsXG4gICAgXCJjaGFpXCI6IFwiXjEuMTAuMFwiLFxuICAgIFwiZGVsXCI6IFwiXjEuMS4wXCIsXG4gICAgXCJndWxwXCI6IFwiXjMuOC4xMFwiLFxuICAgIFwiZ3VscC1qc2hpbnRcIjogXCJeMS45LjBcIixcbiAgICBcImd1bHAtcGx1bWJlclwiOiBcIl4wLjYuNlwiLFxuICAgIFwiZ3VscC1yZW5hbWVcIjogXCJeMS4yLjBcIixcbiAgICBcImd1bHAtdWdsaWZ5XCI6IFwiXjEuMC4yXCIsXG4gICAgXCJndWxwLXV0aWxcIjogXCJeMy4wLjFcIixcbiAgICBcImluay1kb2NzdHJhcFwiOiBcIl4wLjQuMTJcIixcbiAgICBcImpzZG9jXCI6IFwiXjMuMy4wLWFscGhhMTNcIixcbiAgICBcImpzaGludC1zdW1tYXJ5XCI6IFwiXjAuNC4wXCIsXG4gICAgXCJrYXJtYVwiOiBcIl4wLjEyLjI4XCIsXG4gICAgXCJrYXJtYS1maXJlZm94LWxhdW5jaGVyXCI6IFwiXjAuMS4wXCIsXG4gICAgXCJrYXJtYS1tb2NoYVwiOiBcIl4wLjEuMTBcIixcbiAgICBcImthcm1hLXNwZWMtcmVwb3J0ZXJcIjogXCJeMC4wLjE2XCIsXG4gICAgXCJtb2NoYVwiOiBcIl4yLjEuMFwiLFxuICAgIFwicmVxdWlyZS1kaXJcIjogXCJeMC4xLjBcIixcbiAgICBcInJ1bi1zZXF1ZW5jZVwiOiBcIl4xLjAuMlwiLFxuICAgIFwidmlueWwtYnVmZmVyXCI6IFwiXjEuMC4wXCIsXG4gICAgXCJ2aW55bC1zb3VyY2Utc3RyZWFtXCI6IFwiXjEuMC4wXCIsXG4gICAgXCJ3YXRjaGlmeVwiOiBcIl4yLjIuMVwiXG4gIH0sXG4gIFwiZGVwZW5kZW5jaWVzXCI6IHtcbiAgICBcIndlYmdsLWVuYWJsZWRcIjogXCJeMS4wLjJcIlxuICB9XG59XG4iLCIvKipcbiAqIENvbnN0YW50IHZhbHVlcyB1c2VkIGluIHBpeGlcbiAqXG4gKiBAbWl4aW4gY29uc3RcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgLyoqXG4gICAgICogQ29uc3RhbnQgdG8gaWRlbnRpZnkgdGhlIFdFQkdMIFJlbmRlcmVyIFR5cGVcbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAY29uc3RhbnRcbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gV0VCR0xfUkVOREVSRVJcbiAgICAgKi9cbiAgICBXRUJHTF9SRU5ERVJFUjogMSxcblxuICAgIC8qKlxuICAgICAqIENvbnN0YW50IHRvIGlkZW50aWZ5IHRoZSBDQU5WQVMgUmVuZGVyZXIgVHlwZVxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBjb25zdGFudFxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBDQU5WQVNfUkVOREVSRVJcbiAgICAgKi9cbiAgICBDQU5WQVNfUkVOREVSRVI6IDIsXG5cbiAgICAvKipcbiAgICAgKiBTdHJpbmcgb2YgdGhlIGN1cnJlbnQgUElYSSB2ZXJzaW9uXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQGNvbnN0YW50XG4gICAgICogQHByb3BlcnR5IHtzdHJpbmd9IFZFUlNJT05cbiAgICAgKi9cbiAgICBWRVJTSU9OOiByZXF1aXJlKCcuLi8uLi9wYWNrYWdlLmpzb24nKS52ZXJzaW9uLFxuXG4gICAgLyoqXG4gICAgICogVmFyaW91cyBibGVuZCBtb2RlcyBzdXBwb3J0ZWQgYnkgUElYSS4gSU1QT1JUQU5UIC0gVGhlIFdlYkdMIHJlbmRlcmVyIG9ubHkgc3VwcG9ydHNcbiAgICAgKiB0aGUgTk9STUFMLCBBREQsIE1VTFRJUExZIGFuZCBTQ1JFRU4gYmxlbmQgbW9kZXMuIEFueXRoaW5nIGVsc2Ugd2lsbCBzaWxlbnRseSBhY3QgbGlrZVxuICAgICAqIE5PUk1BTC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAY29uc3RhbnRcbiAgICAgKiBAcHJvcGVydHkge29iamVjdH0gYmxlbmRNb2Rlc1xuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibGVuZE1vZGVzLk5PUk1BTFxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibGVuZE1vZGVzLkFERFxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibGVuZE1vZGVzLk1VTFRJUExZXG4gICAgICogQHByb3BlcnR5IHtudW1iZXJ9IGJsZW5kTW9kZXMuU0NSRUVOXG4gICAgICogQHByb3BlcnR5IHtudW1iZXJ9IGJsZW5kTW9kZXMuT1ZFUkxBWVxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibGVuZE1vZGVzLkRBUktFTlxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibGVuZE1vZGVzLkxJR0hURU5cbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gYmxlbmRNb2Rlcy5DT0xPUl9ET0RHRVxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibGVuZE1vZGVzLkNPTE9SX0JVUk5cbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gYmxlbmRNb2Rlcy5IQVJEX0xJR0hUXG4gICAgICogQHByb3BlcnR5IHtudW1iZXJ9IGJsZW5kTW9kZXMuU09GVF9MSUdIVFxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibGVuZE1vZGVzLkRJRkZFUkVOQ0VcbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gYmxlbmRNb2Rlcy5FWENMVVNJT05cbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gYmxlbmRNb2Rlcy5IVUVcbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gYmxlbmRNb2Rlcy5TQVRVUkFUSU9OXG4gICAgICogQHByb3BlcnR5IHtudW1iZXJ9IGJsZW5kTW9kZXMuQ09MT1JcbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gYmxlbmRNb2Rlcy5MVU1JTk9TSVRZXG4gICAgICovXG4gICAgYmxlbmRNb2Rlczoge1xuICAgICAgICBOT1JNQUw6ICAgICAgICAgMCxcbiAgICAgICAgQUREOiAgICAgICAgICAgIDEsXG4gICAgICAgIE1VTFRJUExZOiAgICAgICAyLFxuICAgICAgICBTQ1JFRU46ICAgICAgICAgMyxcbiAgICAgICAgT1ZFUkxBWTogICAgICAgIDQsXG4gICAgICAgIERBUktFTjogICAgICAgICA1LFxuICAgICAgICBMSUdIVEVOOiAgICAgICAgNixcbiAgICAgICAgQ09MT1JfRE9ER0U6ICAgIDcsXG4gICAgICAgIENPTE9SX0JVUk46ICAgICA4LFxuICAgICAgICBIQVJEX0xJR0hUOiAgICAgOSxcbiAgICAgICAgU09GVF9MSUdIVDogICAgIDEwLFxuICAgICAgICBESUZGRVJFTkNFOiAgICAgMTEsXG4gICAgICAgIEVYQ0xVU0lPTjogICAgICAxMixcbiAgICAgICAgSFVFOiAgICAgICAgICAgIDEzLFxuICAgICAgICBTQVRVUkFUSU9OOiAgICAgMTQsXG4gICAgICAgIENPTE9SOiAgICAgICAgICAxNSxcbiAgICAgICAgTFVNSU5PU0lUWTogICAgIDE2XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBzY2FsZSBtb2RlcyB0aGF0IGFyZSBzdXBwb3J0ZWQgYnkgcGl4aS5cbiAgICAgKlxuICAgICAqIFRoZSBERUZBVUxUIHNjYWxlIG1vZGUgYWZmZWN0cyB0aGUgZGVmYXVsdCBzY2FsaW5nIG1vZGUgb2YgZnV0dXJlIG9wZXJhdGlvbnMuXG4gICAgICogSXQgY2FuIGJlIHJlLWFzc2lnbmVkIHRvIGVpdGhlciBMSU5FQVIgb3IgTkVBUkVTVCwgZGVwZW5kaW5nIHVwb24gc3VpdGFiaWxpdHkuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQGNvbnN0YW50XG4gICAgICogQHByb3BlcnR5IHtvYmplY3R9IHNjYWxlTW9kZXNcbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gc2NhbGVNb2Rlcy5ERUZBVUxUPUxJTkVBUlxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBzY2FsZU1vZGVzLkxJTkVBUiBTbW9vdGggc2NhbGluZ1xuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBzY2FsZU1vZGVzLk5FQVJFU1QgUGl4ZWxhdGluZyBzY2FsaW5nXG4gICAgICovXG4gICAgc2NhbGVNb2Rlczoge1xuICAgICAgICBERUZBVUxUOiAgICAwLFxuICAgICAgICBMSU5FQVI6ICAgICAwLFxuICAgICAgICBORUFSRVNUOiAgICAxXG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBwcmVmaXggdGhhdCBkZW5vdGVzIGEgVVJMIGlzIGZvciBhIHJldGluYSBhc3NldFxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBjb25zdGFudFxuICAgICAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBSRVRJTkFfUFJFRklYXG4gICAgICovXG4gICAgUkVUSU5BX1BSRUZJWDogJ0AyeCcsXG5cbiAgICAvKipcbiAgICAgKiBUaGUgZGVmYXVsdCByZW5kZXIgb3B0aW9ucyBpZiBub25lIGFyZSBzdXBwbGllZCB0byB7QGxpbmsgUElYSS5XZWJHTFJlbmRlcmVyfVxuICAgICAqIG9yIHtAbGluayBQSVhJLkNhbnZhc1JlbmRlcmVyfS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAY29uc3RhbnRcbiAgICAgKiBAcHJvcGVydHkge29iamVjdH0gZGVmYXVsdFJlbmRlck9wdGlvbnNcbiAgICAgKiBAcHJvcGVydHkge0hUTUxDYW52YXNFbGVtZW50fSBkZWZhdWx0UmVuZGVyT3B0aW9ucy52aWV3PW51bGxcbiAgICAgKiBAcHJvcGVydHkge2Jvb2xlYW59IGRlZmF1bHRSZW5kZXJPcHRpb25zLnRyYW5zcGFyZW50PWZhbHNlXG4gICAgICogQHByb3BlcnR5IHtib29sZWFufSBkZWZhdWx0UmVuZGVyT3B0aW9ucy5hbnRpYWxpYXM9ZmFsc2VcbiAgICAgKiBAcHJvcGVydHkge2Jvb2xlYW59IGRlZmF1bHRSZW5kZXJPcHRpb25zLnByZXNlcnZlRHJhd2luZ0J1ZmZlcj1mYWxzZVxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBkZWZhdWx0UmVuZGVyT3B0aW9ucy5yZXNvbHV0aW9uPTFcbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gZGVmYXVsdFJlbmRlck9wdGlvbnMuYmFja2dyb3VuZENvbG9yPTB4MDAwMDAwXG4gICAgICogQHByb3BlcnR5IHtib29sZWFufSBkZWZhdWx0UmVuZGVyT3B0aW9ucy5jbGVhckJlZm9yZVJlbmRlcj10cnVlXG4gICAgICogQHByb3BlcnR5IHtib29sZWFufSBkZWZhdWx0UmVuZGVyT3B0aW9ucy5hdXRvUmVzaXplPWZhbHNlXG4gICAgICovXG4gICAgZGVmYXVsdFJlbmRlck9wdGlvbnM6IHtcbiAgICAgICAgdmlldzogbnVsbCxcbiAgICAgICAgcmVzb2x1dGlvbjogMSxcbiAgICAgICAgYW50aWFsaWFzOiBmYWxzZSxcbiAgICAgICAgYXV0b1Jlc2l6ZTogZmFsc2UsXG4gICAgICAgIHRyYW5zcGFyZW50OiBmYWxzZSxcbiAgICAgICAgYmFja2dyb3VuZENvbG9yOiAweDAwMDAwMCxcbiAgICAgICAgY2xlYXJCZWZvcmVSZW5kZXI6IHRydWUsXG4gICAgICAgIHByZXNlcnZlRHJhd2luZ0J1ZmZlcjogZmFsc2VcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ29uc3RhbnRzIHRoYXQgaWRlbnRpZnkgc2hhcGVzLCBtYWlubHkgdG8gcHJldmVudCBgaW5zdGFuY2VvZmAgY2FsbHMuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQGNvbnN0YW50XG4gICAgICogQHByb3BlcnR5IHtvYmplY3R9IFNIQVBFU1xuICAgICAqIEBwcm9wZXJ0eSB7b2JqZWN0fSBTSEFQRVMuUE9MWT0wXG4gICAgICogQHByb3BlcnR5IHtvYmplY3R9IFNIQVBFUy5SRUNUPTFcbiAgICAgKiBAcHJvcGVydHkge29iamVjdH0gU0hBUEVTLkNJUkM9MlxuICAgICAqIEBwcm9wZXJ0eSB7b2JqZWN0fSBTSEFQRVMuRUxJUD0zXG4gICAgICogQHByb3BlcnR5IHtvYmplY3R9IFNIQVBFUy5SUkVDPTRcbiAgICAgKi9cbiAgICBTSEFQRVM6IHtcbiAgICAgICAgUE9MWTogMCxcbiAgICAgICAgUkVDVDogMSxcbiAgICAgICAgQ0lSQzogMixcbiAgICAgICAgRUxJUDogMyxcbiAgICAgICAgUlJFQzogNFxuICAgIH1cbn07XG4iLCJ2YXIgbWF0aCA9IHJlcXVpcmUoJy4uL21hdGgnKTtcblxuLyoqXG4gKiBUaGUgYmFzZSBjbGFzcyBmb3IgYWxsIG9iamVjdHMgdGhhdCBhcmUgcmVuZGVyZWQgb24gdGhlIHNjcmVlbi5cbiAqIFRoaXMgaXMgYW4gYWJzdHJhY3QgY2xhc3MgYW5kIHNob3VsZCBub3QgYmUgdXNlZCBvbiBpdHMgb3duIHJhdGhlciBpdCBzaG91bGQgYmUgZXh0ZW5kZWQuXG4gKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gRGlzcGxheU9iamVjdCgpIHtcbiAgICAvKipcbiAgICAgKiBUaGUgY29vcmRpbmF0ZSBvZiB0aGUgb2JqZWN0IHJlbGF0aXZlIHRvIHRoZSBsb2NhbCBjb29yZGluYXRlcyBvZiB0aGUgcGFyZW50LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICovXG4gICAgdGhpcy5wb3NpdGlvbiA9IG5ldyBtYXRoLlBvaW50KCk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgc2NhbGUgZmFjdG9yIG9mIHRoZSBvYmplY3QuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKi9cbiAgICB0aGlzLnNjYWxlID0gbmV3IG1hdGguUG9pbnQoMSwgMSk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgcGl2b3QgcG9pbnQgb2YgdGhlIGRpc3BsYXlPYmplY3QgdGhhdCBpdCByb3RhdGVzIGFyb3VuZFxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICovXG4gICAgdGhpcy5waXZvdCA9IG5ldyBtYXRoLlBvaW50KDAsIDApO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHJvdGF0aW9uIG9mIHRoZSBvYmplY3QgaW4gcmFkaWFucy5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLnJvdGF0aW9uID0gMDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBvcGFjaXR5IG9mIHRoZSBvYmplY3QuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5hbHBoYSA9IDE7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdmlzaWJpbGl0eSBvZiB0aGUgb2JqZWN0LiBJZiBmYWxzZSB0aGUgb2JqZWN0IHdpbGwgbm90IGJlIGRyYXduLCBhbmRcbiAgICAgKiB0aGUgdXBkYXRlVHJhbnNmb3JtIGZ1bmN0aW9uIHdpbGwgbm90IGJlIGNhbGxlZC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy52aXNpYmxlID0gdHJ1ZTtcblxuICAgIC8qKlxuICAgICAqIENhbiB0aGlzIG9iamVjdCBiZSByZW5kZXJlZCwgaWYgZmFsc2UgdGhlIG9iamVjdCB3aWxsIG5vdCBiZSBkcmF3biBidXQgdGhlIHVwZGF0ZVRyYW5zZm9ybVxuICAgICAqIG1ldGhvZHMgd2lsbCBzdGlsbCBiZSBjYWxsZWQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMucmVuZGVyYWJsZSA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGRpc3BsYXkgb2JqZWN0IGNvbnRhaW5lciB0aGF0IGNvbnRhaW5zIHRoaXMgZGlzcGxheSBvYmplY3QuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtEaXNwbGF5T2JqZWN0Q29udGFpbmVyfVxuICAgICAqIEByZWFkT25seVxuICAgICAqL1xuICAgIHRoaXMucGFyZW50ID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBtdWx0aXBsaWVkIGFscGhhIG9mIHRoZSBkaXNwbGF5T2JqZWN0XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQHJlYWRPbmx5XG4gICAgICovXG4gICAgdGhpcy53b3JsZEFscGhhID0gMTtcblxuICAgIC8qKlxuICAgICAqIEN1cnJlbnQgdHJhbnNmb3JtIG9mIHRoZSBvYmplY3QgYmFzZWQgb24gd29ybGQgKHBhcmVudCkgZmFjdG9yc1xuICAgICAqXG4gICAgICogQG1lbWJlciB7TWF0cml4fVxuICAgICAqIEByZWFkT25seVxuICAgICAqL1xuICAgIHRoaXMud29ybGRUcmFuc2Zvcm0gPSBuZXcgbWF0aC5NYXRyaXgoKTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBhcmVhIHRoZSBmaWx0ZXIgaXMgYXBwbGllZCB0by4gVGhpcyBpcyB1c2VkIGFzIG1vcmUgb2YgYW4gb3B0aW1pc2F0aW9uXG4gICAgICogcmF0aGVyIHRoYW4gZmlndXJpbmcgb3V0IHRoZSBkaW1lbnNpb25zIG9mIHRoZSBkaXNwbGF5T2JqZWN0IGVhY2ggZnJhbWUgeW91IGNhbiBzZXQgdGhpcyByZWN0YW5nbGVcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1JlY3RhbmdsZX1cbiAgICAgKi9cbiAgICB0aGlzLmZpbHRlckFyZWEgPSBudWxsO1xuXG4gICAgLyoqXG4gICAgICogY2FjaGVkIHNpbiByb3RhdGlvblxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fc3IgPSAwO1xuXG4gICAgLyoqXG4gICAgICogY2FjaGVkIGNvcyByb3RhdGlvblxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fY3IgPSAxO1xuXG4gICAgLyoqXG4gICAgICogVGhlIG9yaWdpbmFsLCBjYWNoZWQgYm91bmRzIG9mIHRoZSBvYmplY3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1JlY3RhbmdsZX1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuX2JvdW5kcyA9IG5ldyBtYXRoLlJlY3RhbmdsZSgwLCAwLCAxLCAxKTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBtb3N0IHVwLXRvLWRhdGUgYm91bmRzIG9mIHRoZSBvYmplY3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1JlY3RhbmdsZX1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuX2N1cnJlbnRCb3VuZHMgPSBudWxsO1xuXG4gICAgLyoqXG4gICAgICogVGhlIG9yaWdpbmFsLCBjYWNoZWQgbWFzayBvZiB0aGUgb2JqZWN0XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtSZWN0YW5nbGV9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl9tYXNrID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqIENhY2hlZCBpbnRlcm5hbCBmbGFnLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuX2NhY2hlSXNEaXJ0eSA9IGZhbHNlO1xufVxuXG4vLyBjb25zdHJ1Y3RvclxuRGlzcGxheU9iamVjdC5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBEaXNwbGF5T2JqZWN0O1xubW9kdWxlLmV4cG9ydHMgPSBEaXNwbGF5T2JqZWN0O1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhEaXNwbGF5T2JqZWN0LnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSBwb3NpdGlvbiBvZiB0aGUgZGlzcGxheU9iamVjdCBvbiB0aGUgeCBheGlzIHJlbGF0aXZlIHRvIHRoZSBsb2NhbCBjb29yZGluYXRlcyBvZiB0aGUgcGFyZW50LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBEaXNwbGF5T2JqZWN0I1xuICAgICAqL1xuICAgIHg6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wb3NpdGlvbi54O1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy5wb3NpdGlvbi54ID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIHBvc2l0aW9uIG9mIHRoZSBkaXNwbGF5T2JqZWN0IG9uIHRoZSB5IGF4aXMgcmVsYXRpdmUgdG8gdGhlIGxvY2FsIGNvb3JkaW5hdGVzIG9mIHRoZSBwYXJlbnQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIERpc3BsYXlPYmplY3QjXG4gICAgICovXG4gICAgeToge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnBvc2l0aW9uLnk7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnBvc2l0aW9uLnkgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBJbmRpY2F0ZXMgaWYgdGhlIHNwcml0ZSBpcyBnbG9iYWxseSB2aXNpYmxlLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAbWVtYmVyb2YgRGlzcGxheU9iamVjdCNcbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKi9cbiAgICB3b3JsZFZpc2libGU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgaXRlbSA9IHRoaXM7XG5cbiAgICAgICAgICAgIGRvIHtcbiAgICAgICAgICAgICAgICBpZiAoIWl0ZW0udmlzaWJsZSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaXRlbSA9IGl0ZW0ucGFyZW50O1xuICAgICAgICAgICAgfSB3aGlsZShpdGVtKTtcblxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU2V0cyBhIG1hc2sgZm9yIHRoZSBkaXNwbGF5T2JqZWN0LiBBIG1hc2sgaXMgYW4gb2JqZWN0IHRoYXQgbGltaXRzIHRoZSB2aXNpYmlsaXR5IG9mIGFuIG9iamVjdCB0byB0aGUgc2hhcGUgb2YgdGhlIG1hc2sgYXBwbGllZCB0byBpdC5cbiAgICAgKiBJbiBQSVhJIGEgcmVndWxhciBtYXNrIG11c3QgYmUgYSBQSVhJLkdyYXBoaWNzIG9iamVjdC4gVGhpcyBhbGxvd3MgZm9yIG11Y2ggZmFzdGVyIG1hc2tpbmcgaW4gY2FudmFzIGFzIGl0IHV0aWxpc2VzIHNoYXBlIGNsaXBwaW5nLlxuICAgICAqIFRvIHJlbW92ZSBhIG1hc2ssIHNldCB0aGlzIHByb3BlcnR5IHRvIG51bGwuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtHcmFwaGljc31cbiAgICAgKiBAbWVtYmVyb2YgRGlzcGxheU9iamVjdCNcbiAgICAgKi9cbiAgICBtYXNrOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX21hc2s7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICAgICAgICAgIHRoaXMuX21hc2suaXNNYXNrID0gZmFsc2U7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuX21hc2sgPSB2YWx1ZTtcblxuICAgICAgICAgICAgaWYgKHRoaXMuX21hc2spIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9tYXNrLmlzTWFzayA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgZmlsdGVycyBmb3IgdGhlIGRpc3BsYXlPYmplY3QuXG4gICAgICogKiBJTVBPUlRBTlQ6IFRoaXMgaXMgYSB3ZWJHTCBvbmx5IGZlYXR1cmUgYW5kIHdpbGwgYmUgaWdub3JlZCBieSB0aGUgY2FudmFzIHJlbmRlcmVyLlxuICAgICAqIFRvIHJlbW92ZSBmaWx0ZXJzIHNpbXBseSBzZXQgdGhpcyBwcm9wZXJ0eSB0byAnbnVsbCdcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0ZpbHRlcltdfVxuICAgICAqIEBtZW1iZXJvZiBEaXNwbGF5T2JqZWN0I1xuICAgICAqL1xuICAgIGZpbHRlcnM6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fZmlsdGVycztcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIGlmICh2YWx1ZSkge1xuICAgICAgICAgICAgICAgIC8vIG5vdyBwdXQgYWxsIHRoZSBwYXNzZXMgaW4gb25lIHBsYWNlLi5cbiAgICAgICAgICAgICAgICB2YXIgcGFzc2VzID0gW107XG5cbiAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZhbHVlLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBmaWx0ZXJQYXNzZXMgPSB2YWx1ZVtpXS5wYXNzZXM7XG5cbiAgICAgICAgICAgICAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBmaWx0ZXJQYXNzZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhc3Nlcy5wdXNoKGZpbHRlclBhc3Nlc1tqXSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBUT0RPIGNoYW5nZSB0aGlzIGFzIGl0IGlzIGxlZ2FjeVxuICAgICAgICAgICAgICAgIHRoaXMuX2ZpbHRlckJsb2NrID0geyB0YXJnZXQ6IHRoaXMsIGZpbHRlclBhc3NlczogcGFzc2VzIH07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuX2ZpbHRlcnMgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG4vKlxuICogVXBkYXRlcyB0aGUgb2JqZWN0IHRyYW5zZm9ybSBmb3IgcmVuZGVyaW5nXG4gKlxuICogVE9ETyAtIE9wdGltaXphdGlvbiBwYXNzIVxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkRpc3BsYXlPYmplY3QucHJvdG90eXBlLnVwZGF0ZVRyYW5zZm9ybSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoIXRoaXMucGFyZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBjcmVhdGUgc29tZSBtYXRyaXggcmVmcyBmb3IgZWFzeSBhY2Nlc3NcbiAgICB2YXIgcHQgPSB0aGlzLnBhcmVudC53b3JsZFRyYW5zZm9ybTtcbiAgICB2YXIgd3QgPSB0aGlzLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgLy8gdGVtcG9yYXJ5IG1hdHJpeCB2YXJpYWJsZXNcbiAgICB2YXIgYSwgYiwgYywgZCwgdHgsIHR5O1xuXG4gICAgLy8gc28gaWYgcm90YXRpb24gaXMgYmV0d2VlbiAwIHRoZW4gd2UgY2FuIHNpbXBsaWZ5IHRoZSBtdWx0aXBsaWNhdGlvbiBwcm9jZXNzLi5cbiAgICBpZiAodGhpcy5yb3RhdGlvbiAlIG1hdGguUElfMikge1xuICAgICAgICAvLyBjaGVjayB0byBzZWUgaWYgdGhlIHJvdGF0aW9uIGlzIHRoZSBzYW1lIGFzIHRoZSBwcmV2aW91cyByZW5kZXIuIFRoaXMgbWVhbnMgd2Ugb25seSBuZWVkIHRvIHVzZSBzaW4gYW5kIGNvcyB3aGVuIHJvdGF0aW9uIGFjdHVhbGx5IGNoYW5nZXNcbiAgICAgICAgaWYgKHRoaXMucm90YXRpb24gIT09IHRoaXMucm90YXRpb25DYWNoZSkge1xuICAgICAgICAgICAgdGhpcy5yb3RhdGlvbkNhY2hlID0gdGhpcy5yb3RhdGlvbjtcbiAgICAgICAgICAgIHRoaXMuX3NyID0gTWF0aC5zaW4odGhpcy5yb3RhdGlvbik7XG4gICAgICAgICAgICB0aGlzLl9jciA9IE1hdGguY29zKHRoaXMucm90YXRpb24pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZ2V0IHRoZSBtYXRyaXggdmFsdWVzIG9mIHRoZSBkaXNwbGF5b2JqZWN0IGJhc2VkIG9uIGl0cyB0cmFuc2Zvcm0gcHJvcGVydGllcy4uXG4gICAgICAgIGEgID0gIHRoaXMuX2NyICogdGhpcy5zY2FsZS54O1xuICAgICAgICBiICA9ICB0aGlzLl9zciAqIHRoaXMuc2NhbGUueDtcbiAgICAgICAgYyAgPSAtdGhpcy5fc3IgKiB0aGlzLnNjYWxlLnk7XG4gICAgICAgIGQgID0gIHRoaXMuX2NyICogdGhpcy5zY2FsZS55O1xuICAgICAgICB0eCA9ICB0aGlzLnBvc2l0aW9uLng7XG4gICAgICAgIHR5ID0gIHRoaXMucG9zaXRpb24ueTtcblxuICAgICAgICAvLyBjaGVjayBmb3IgcGl2b3QuLiBub3Qgb2Z0ZW4gdXNlZCBzbyBnZWFyZWQgdG93YXJkcyB0aGF0IGZhY3QhXG4gICAgICAgIGlmICh0aGlzLnBpdm90LnggfHwgdGhpcy5waXZvdC55KSB7XG4gICAgICAgICAgICB0eCAtPSB0aGlzLnBpdm90LnggKiBhICsgdGhpcy5waXZvdC55ICogYztcbiAgICAgICAgICAgIHR5IC09IHRoaXMucGl2b3QueCAqIGIgKyB0aGlzLnBpdm90LnkgKiBkO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gY29uY2F0IHRoZSBwYXJlbnQgbWF0cml4IHdpdGggdGhlIG9iamVjdHMgdHJhbnNmb3JtLlxuICAgICAgICB3dC5hICA9IGEgICogcHQuYSArIGIgICogcHQuYztcbiAgICAgICAgd3QuYiAgPSBhICAqIHB0LmIgKyBiICAqIHB0LmQ7XG4gICAgICAgIHd0LmMgID0gYyAgKiBwdC5hICsgZCAgKiBwdC5jO1xuICAgICAgICB3dC5kICA9IGMgICogcHQuYiArIGQgICogcHQuZDtcbiAgICAgICAgd3QudHggPSB0eCAqIHB0LmEgKyB0eSAqIHB0LmMgKyBwdC50eDtcbiAgICAgICAgd3QudHkgPSB0eCAqIHB0LmIgKyB0eSAqIHB0LmQgKyBwdC50eTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIC8vIGxldHMgZG8gdGhlIGZhc3QgdmVyc2lvbiBhcyB3ZSBrbm93IHRoZXJlIGlzIG5vIHJvdGF0aW9uLi5cbiAgICAgICAgYSAgPSB0aGlzLnNjYWxlLng7XG4gICAgICAgIGQgID0gdGhpcy5zY2FsZS55O1xuXG4gICAgICAgIHR4ID0gdGhpcy5wb3NpdGlvbi54IC0gdGhpcy5waXZvdC54ICogYTtcbiAgICAgICAgdHkgPSB0aGlzLnBvc2l0aW9uLnkgLSB0aGlzLnBpdm90LnkgKiBkO1xuXG4gICAgICAgIHd0LmEgID0gYSAgKiBwdC5hO1xuICAgICAgICB3dC5iICA9IGEgICogcHQuYjtcbiAgICAgICAgd3QuYyAgPSBkICAqIHB0LmM7XG4gICAgICAgIHd0LmQgID0gZCAgKiBwdC5kO1xuICAgICAgICB3dC50eCA9IHR4ICogcHQuYSArIHR5ICogcHQuYyArIHB0LnR4O1xuICAgICAgICB3dC50eSA9IHR4ICogcHQuYiArIHR5ICogcHQuZCArIHB0LnR5O1xuICAgIH1cblxuICAgIC8vIG11bHRpcGx5IHRoZSBhbHBoYXMuLlxuICAgIHRoaXMud29ybGRBbHBoYSA9IHRoaXMuYWxwaGEgKiB0aGlzLnBhcmVudC53b3JsZEFscGhhO1xufTtcblxuLy8gcGVyZm9ybWFuY2UgaW5jcmVhc2UgdG8gYXZvaWQgdXNpbmcgY2FsbC4uICgxMHggZmFzdGVyKVxuRGlzcGxheU9iamVjdC5wcm90b3R5cGUuZGlzcGxheU9iamVjdFVwZGF0ZVRyYW5zZm9ybSA9IERpc3BsYXlPYmplY3QucHJvdG90eXBlLnVwZGF0ZVRyYW5zZm9ybTtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIGJvdW5kcyBvZiB0aGUgZGlzcGxheU9iamVjdCBhcyBhIHJlY3RhbmdsZSBvYmplY3RcbiAqXG4gKiBAcGFyYW0gbWF0cml4IHtNYXRyaXh9XG4gKiBAcmV0dXJuIHtSZWN0YW5nbGV9IHRoZSByZWN0YW5ndWxhciBib3VuZGluZyBhcmVhXG4gKi9cbkRpc3BsYXlPYmplY3QucHJvdG90eXBlLmdldEJvdW5kcyA9IGZ1bmN0aW9uICgvKiBtYXRyaXggKi8pIHtcbiAgICByZXR1cm4gbWF0aC5SZWN0YW5nbGUuRU1QVFk7XG59O1xuXG4vKipcbiAqIFJldHJpZXZlcyB0aGUgbG9jYWwgYm91bmRzIG9mIHRoZSBkaXNwbGF5T2JqZWN0IGFzIGEgcmVjdGFuZ2xlIG9iamVjdFxuICpcbiAqIEByZXR1cm4ge1JlY3RhbmdsZX0gdGhlIHJlY3Rhbmd1bGFyIGJvdW5kaW5nIGFyZWFcbiAqL1xuRGlzcGxheU9iamVjdC5wcm90b3R5cGUuZ2V0TG9jYWxCb3VuZHMgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0Qm91bmRzKG1hdGguTWF0cml4LklERU5USVRZKTtcbn07XG5cbi8qKlxuICogQ2FsY3VsYXRlcyB0aGUgZ2xvYmFsIHBvc2l0aW9uIG9mIHRoZSBkaXNwbGF5IG9iamVjdFxuICpcbiAqIEBwYXJhbSBwb3NpdGlvbiB7UG9pbnR9IFRoZSB3b3JsZCBvcmlnaW4gdG8gY2FsY3VsYXRlIGZyb21cbiAqIEByZXR1cm4ge1BvaW50fSBBIHBvaW50IG9iamVjdCByZXByZXNlbnRpbmcgdGhlIHBvc2l0aW9uIG9mIHRoaXMgb2JqZWN0XG4gKi9cbkRpc3BsYXlPYmplY3QucHJvdG90eXBlLnRvR2xvYmFsID0gZnVuY3Rpb24gKHBvc2l0aW9uKSB7XG4gICAgLy8gZG9uJ3QgbmVlZCB0byB1W2RhdGUgdGhlIGxvdFxuICAgIHRoaXMuZGlzcGxheU9iamVjdFVwZGF0ZVRyYW5zZm9ybSgpO1xuICAgIHJldHVybiB0aGlzLndvcmxkVHJhbnNmb3JtLmFwcGx5KHBvc2l0aW9uKTtcbn07XG5cbi8qKlxuICogQ2FsY3VsYXRlcyB0aGUgbG9jYWwgcG9zaXRpb24gb2YgdGhlIGRpc3BsYXkgb2JqZWN0IHJlbGF0aXZlIHRvIGFub3RoZXIgcG9pbnRcbiAqXG4gKiBAcGFyYW0gcG9zaXRpb24ge1BvaW50fSBUaGUgd29ybGQgb3JpZ2luIHRvIGNhbGN1bGF0ZSBmcm9tXG4gKiBAcGFyYW0gW2Zyb21dIHtEaXNwbGF5T2JqZWN0fSBUaGUgRGlzcGxheU9iamVjdCB0byBjYWxjdWxhdGUgdGhlIGdsb2JhbCBwb3NpdGlvbiBmcm9tXG4gKiBAcmV0dXJuIHtQb2ludH0gQSBwb2ludCBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSBwb3NpdGlvbiBvZiB0aGlzIG9iamVjdFxuICovXG5EaXNwbGF5T2JqZWN0LnByb3RvdHlwZS50b0xvY2FsID0gZnVuY3Rpb24gKHBvc2l0aW9uLCBmcm9tKSB7XG4gICAgaWYgKGZyb20pIHtcbiAgICAgICAgcG9zaXRpb24gPSBmcm9tLnRvR2xvYmFsKHBvc2l0aW9uKTtcbiAgICB9XG5cbiAgICAvLyBkb24ndCBuZWVkIHRvIHVwZGF0ZSB0aGUgbG90XG4gICAgdGhpcy5kaXNwbGF5T2JqZWN0VXBkYXRlVHJhbnNmb3JtKCk7XG4gICAgcmV0dXJuIHRoaXMud29ybGRUcmFuc2Zvcm0uYXBwbHlJbnZlcnNlKHBvc2l0aW9uKTtcbn07XG5cbi8qKlxuICogUmVuZGVycyB0aGUgb2JqZWN0IHVzaW5nIHRoZSBXZWJHTCByZW5kZXJlclxuICpcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcn0gVGhlIHJlbmRlcmVyXG4gKiBAcHJpdmF0ZVxuICovXG5EaXNwbGF5T2JqZWN0LnByb3RvdHlwZS5yZW5kZXJXZWJHTCA9IGZ1bmN0aW9uICgvKiByZW5kZXJlciAqLykge1xuICAgIC8vIE9WRVJXUklURTtcbn07XG5cbi8qKlxuICogUmVuZGVycyB0aGUgb2JqZWN0IHVzaW5nIHRoZSBDYW52YXMgcmVuZGVyZXJcbiAqXG4gKiBAcGFyYW0gcmVuZGVyZXIge0NhbnZhc1JlbmRlcmVyfSBUaGUgcmVuZGVyZXJcbiAqIEBwcml2YXRlXG4gKi9cbkRpc3BsYXlPYmplY3QucHJvdG90eXBlLnJlbmRlckNhbnZhcyA9IGZ1bmN0aW9uICgvKiByZW5kZXJlciAqLykge1xuICAgIC8vIE9WRVJXUklURTtcbn07XG4iLCJ2YXIgbWF0aCA9IHJlcXVpcmUoJy4uL21hdGgnKSxcbiAgICBEaXNwbGF5T2JqZWN0ID0gcmVxdWlyZSgnLi9EaXNwbGF5T2JqZWN0JyksXG4gICAgUmVuZGVyVGV4dHVyZSA9IHJlcXVpcmUoJy4uL3RleHR1cmVzL1JlbmRlclRleHR1cmUnKSxcbiAgICAvLyBTcHJpdGUgPSByZXF1aXJlKCcuL1Nwcml0ZScpLFxuICAgIF90ZW1wTWF0cml4ID0gbmV3IG1hdGguTWF0cml4KCk7XG5cbi8qKlxuICogQSBEaXNwbGF5T2JqZWN0Q29udGFpbmVyIHJlcHJlc2VudHMgYSBjb2xsZWN0aW9uIG9mIGRpc3BsYXkgb2JqZWN0cy5cbiAqIEl0IGlzIHRoZSBiYXNlIGNsYXNzIG9mIGFsbCBkaXNwbGF5IG9iamVjdHMgdGhhdCBhY3QgYXMgYSBjb250YWluZXIgZm9yIG90aGVyIG9iamVjdHMuXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBEaXNwbGF5T2JqZWN0XG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gRGlzcGxheU9iamVjdENvbnRhaW5lcigpIHtcbiAgICBEaXNwbGF5T2JqZWN0LmNhbGwodGhpcyk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgYXJyYXkgb2YgY2hpbGRyZW4gb2YgdGhpcyBjb250YWluZXIuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtEaXNwbGF5T2JqZWN0W119XG4gICAgICogQHJlYWRvbmx5XG4gICAgICovXG4gICAgdGhpcy5jaGlsZHJlbiA9IFtdO1xuXG4gICAgLyoqXG4gICAgICogQ2FjaGVkIGludGVybmFsIGZsYWcuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fY2FjaGVBc0JpdG1hcCA9IGZhbHNlO1xuXG4gICAgdGhpcy5fY2FjaGVkU3ByaXRlID0gbnVsbDtcbn1cblxuLy8gY29uc3RydWN0b3JcbkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShEaXNwbGF5T2JqZWN0LnByb3RvdHlwZSk7XG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IERpc3BsYXlPYmplY3RDb250YWluZXI7XG5tb2R1bGUuZXhwb3J0cyA9IERpc3BsYXlPYmplY3RDb250YWluZXI7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKERpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHdpZHRoIG9mIHRoZSBkaXNwbGF5T2JqZWN0Q29udGFpbmVyLCBzZXR0aW5nIHRoaXMgd2lsbCBhY3R1YWxseSBtb2RpZnkgdGhlIHNjYWxlIHRvIGFjaGlldmUgdGhlIHZhbHVlIHNldFxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBEaXNwbGF5T2JqZWN0Q29udGFpbmVyI1xuICAgICAqL1xuICAgIHdpZHRoOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuc2NhbGUueCAqIHRoaXMuZ2V0TG9jYWxCb3VuZHMoKS53aWR0aDtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcblxuICAgICAgICAgICAgdmFyIHdpZHRoID0gdGhpcy5nZXRMb2NhbEJvdW5kcygpLndpZHRoO1xuXG4gICAgICAgICAgICBpZih3aWR0aCAhPT0gMCkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2NhbGUueCA9IHZhbHVlIC8gd2lkdGg7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNjYWxlLnggPSAxO1xuICAgICAgICAgICAgfVxuXG5cbiAgICAgICAgICAgIHRoaXMuX3dpZHRoID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIGhlaWdodCBvZiB0aGUgZGlzcGxheU9iamVjdENvbnRhaW5lciwgc2V0dGluZyB0aGlzIHdpbGwgYWN0dWFsbHkgbW9kaWZ5IHRoZSBzY2FsZSB0byBhY2hpZXZlIHRoZSB2YWx1ZSBzZXRcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgRGlzcGxheU9iamVjdENvbnRhaW5lciNcbiAgICAgKi9cbiAgICBoZWlnaHQ6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gIHRoaXMuc2NhbGUueSAqIHRoaXMuZ2V0TG9jYWxCb3VuZHMoKS5oZWlnaHQ7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG5cbiAgICAgICAgICAgIHZhciBoZWlnaHQgPSB0aGlzLmdldExvY2FsQm91bmRzKCkuaGVpZ2h0O1xuXG4gICAgICAgICAgICBpZiAoaGVpZ2h0ICE9PSAwKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zY2FsZS55ID0gdmFsdWUgLyBoZWlnaHQgO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zY2FsZS55ID0gMTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5faGVpZ2h0ID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU2V0IGlmIHRoaXMgZGlzcGxheSBvYmplY3QgaXMgY2FjaGVkIGFzIGEgYml0bWFwLlxuICAgICAqIFRoaXMgYmFzaWNhbGx5IHRha2VzIGEgc25hcCBzaG90IG9mIHRoZSBkaXNwbGF5IG9iamVjdCBhcyBpdCBpcyBhdCB0aGF0IG1vbWVudC4gSXQgY2FuIHByb3ZpZGUgYSBwZXJmb3JtYW5jZSBiZW5lZml0IGZvciBjb21wbGV4IHN0YXRpYyBkaXNwbGF5T2JqZWN0cy5cbiAgICAgKiBUbyByZW1vdmUgc2ltcGx5IHNldCB0aGlzIHByb3BlcnR5IHRvICdudWxsJ1xuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAbWVtYmVyb2YgRGlzcGxheU9iamVjdCNcbiAgICAgKi9cbiAgICBjYWNoZUFzQml0bWFwOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2NhY2hlQXNCaXRtYXA7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5fY2FjaGVBc0JpdG1hcCA9PT0gdmFsdWUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHRoaXMuX2dlbmVyYXRlQ2FjaGVkU3ByaXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9kZXN0cm95Q2FjaGVkU3ByaXRlKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuX2NhY2hlQXNCaXRtYXAgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG4vKipcbiAqIEFkZHMgYSBjaGlsZCB0byB0aGUgY29udGFpbmVyLlxuICpcbiAqIEBwYXJhbSBjaGlsZCB7RGlzcGxheU9iamVjdH0gVGhlIERpc3BsYXlPYmplY3QgdG8gYWRkIHRvIHRoZSBjb250YWluZXJcbiAqIEByZXR1cm4ge0Rpc3BsYXlPYmplY3R9IFRoZSBjaGlsZCB0aGF0IHdhcyBhZGRlZC5cbiAqL1xuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUuYWRkQ2hpbGQgPSBmdW5jdGlvbiAoY2hpbGQpIHtcbiAgICByZXR1cm4gdGhpcy5hZGRDaGlsZEF0KGNoaWxkLCB0aGlzLmNoaWxkcmVuLmxlbmd0aCk7XG59O1xuXG4vKipcbiAqIEFkZHMgYSBjaGlsZCB0byB0aGUgY29udGFpbmVyIGF0IGEgc3BlY2lmaWVkIGluZGV4LiBJZiB0aGUgaW5kZXggaXMgb3V0IG9mIGJvdW5kcyBhbiBlcnJvciB3aWxsIGJlIHRocm93blxuICpcbiAqIEBwYXJhbSBjaGlsZCB7RGlzcGxheU9iamVjdH0gVGhlIGNoaWxkIHRvIGFkZFxuICogQHBhcmFtIGluZGV4IHtOdW1iZXJ9IFRoZSBpbmRleCB0byBwbGFjZSB0aGUgY2hpbGQgaW5cbiAqIEByZXR1cm4ge0Rpc3BsYXlPYmplY3R9IFRoZSBjaGlsZCB0aGF0IHdhcyBhZGRlZC5cbiAqL1xuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUuYWRkQ2hpbGRBdCA9IGZ1bmN0aW9uIChjaGlsZCwgaW5kZXgpIHtcbiAgICAvLyBwcmV2ZW50IGFkZGluZyBzZWxmIGFzIGNoaWxkXG4gICAgaWYgKGNoaWxkID09PSB0aGlzKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoaW5kZXggPj0gMCAmJiBpbmRleCA8PSB0aGlzLmNoaWxkcmVuLmxlbmd0aCkge1xuICAgICAgICBpZiAoY2hpbGQucGFyZW50KSB7XG4gICAgICAgICAgICBjaGlsZC5wYXJlbnQucmVtb3ZlQ2hpbGQoY2hpbGQpO1xuICAgICAgICB9XG5cbiAgICAgICAgY2hpbGQucGFyZW50ID0gdGhpcztcblxuICAgICAgICB0aGlzLmNoaWxkcmVuLnNwbGljZShpbmRleCwgMCwgY2hpbGQpO1xuXG4gICAgICAgIHJldHVybiBjaGlsZDtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihjaGlsZCArICdhZGRDaGlsZEF0OiBUaGUgaW5kZXggJysgaW5kZXggKycgc3VwcGxpZWQgaXMgb3V0IG9mIGJvdW5kcyAnICsgdGhpcy5jaGlsZHJlbi5sZW5ndGgpO1xuICAgIH1cbn07XG5cbi8qKlxuICogU3dhcHMgdGhlIHBvc2l0aW9uIG9mIDIgRGlzcGxheSBPYmplY3RzIHdpdGhpbiB0aGlzIGNvbnRhaW5lci5cbiAqXG4gKiBAcGFyYW0gY2hpbGQge0Rpc3BsYXlPYmplY3R9XG4gKiBAcGFyYW0gY2hpbGQyIHtEaXNwbGF5T2JqZWN0fVxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5zd2FwQ2hpbGRyZW4gPSBmdW5jdGlvbiAoY2hpbGQsIGNoaWxkMikge1xuICAgIGlmIChjaGlsZCA9PT0gY2hpbGQyKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgaW5kZXgxID0gdGhpcy5nZXRDaGlsZEluZGV4KGNoaWxkKTtcbiAgICB2YXIgaW5kZXgyID0gdGhpcy5nZXRDaGlsZEluZGV4KGNoaWxkMik7XG5cbiAgICBpZiAoaW5kZXgxIDwgMCB8fCBpbmRleDIgPCAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignc3dhcENoaWxkcmVuOiBCb3RoIHRoZSBzdXBwbGllZCBEaXNwbGF5T2JqZWN0cyBtdXN0IGJlIGEgY2hpbGQgb2YgdGhlIGNhbGxlci4nKTtcbiAgICB9XG5cbiAgICB0aGlzLmNoaWxkcmVuW2luZGV4MV0gPSBjaGlsZDI7XG4gICAgdGhpcy5jaGlsZHJlbltpbmRleDJdID0gY2hpbGQ7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdGhlIGluZGV4IHBvc2l0aW9uIG9mIGEgY2hpbGQgRGlzcGxheU9iamVjdCBpbnN0YW5jZVxuICpcbiAqIEBwYXJhbSBjaGlsZCB7RGlzcGxheU9iamVjdH0gVGhlIERpc3BsYXlPYmplY3QgaW5zdGFuY2UgdG8gaWRlbnRpZnlcbiAqIEByZXR1cm4ge051bWJlcn0gVGhlIGluZGV4IHBvc2l0aW9uIG9mIHRoZSBjaGlsZCBkaXNwbGF5IG9iamVjdCB0byBpZGVudGlmeVxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5nZXRDaGlsZEluZGV4ID0gZnVuY3Rpb24gKGNoaWxkKSB7XG4gICAgdmFyIGluZGV4ID0gdGhpcy5jaGlsZHJlbi5pbmRleE9mKGNoaWxkKTtcblxuICAgIGlmIChpbmRleCA9PT0gLTEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdUaGUgc3VwcGxpZWQgRGlzcGxheU9iamVjdCBtdXN0IGJlIGEgY2hpbGQgb2YgdGhlIGNhbGxlcicpO1xuICAgIH1cblxuICAgIHJldHVybiBpbmRleDtcbn07XG5cbi8qKlxuICogQ2hhbmdlcyB0aGUgcG9zaXRpb24gb2YgYW4gZXhpc3RpbmcgY2hpbGQgaW4gdGhlIGRpc3BsYXkgb2JqZWN0IGNvbnRhaW5lclxuICpcbiAqIEBwYXJhbSBjaGlsZCB7RGlzcGxheU9iamVjdH0gVGhlIGNoaWxkIERpc3BsYXlPYmplY3QgaW5zdGFuY2UgZm9yIHdoaWNoIHlvdSB3YW50IHRvIGNoYW5nZSB0aGUgaW5kZXggbnVtYmVyXG4gKiBAcGFyYW0gaW5kZXgge051bWJlcn0gVGhlIHJlc3VsdGluZyBpbmRleCBudW1iZXIgZm9yIHRoZSBjaGlsZCBkaXNwbGF5IG9iamVjdFxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5zZXRDaGlsZEluZGV4ID0gZnVuY3Rpb24gKGNoaWxkLCBpbmRleCkge1xuICAgIGlmIChpbmRleCA8IDAgfHwgaW5kZXggPj0gdGhpcy5jaGlsZHJlbi5sZW5ndGgpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdUaGUgc3VwcGxpZWQgaW5kZXggaXMgb3V0IG9mIGJvdW5kcycpO1xuICAgIH1cblxuICAgIHZhciBjdXJyZW50SW5kZXggPSB0aGlzLmdldENoaWxkSW5kZXgoY2hpbGQpO1xuXG4gICAgdGhpcy5jaGlsZHJlbi5zcGxpY2UoY3VycmVudEluZGV4LCAxKTsgLy9yZW1vdmUgZnJvbSBvbGQgcG9zaXRpb25cbiAgICB0aGlzLmNoaWxkcmVuLnNwbGljZShpbmRleCwgMCwgY2hpbGQpOyAvL2FkZCBhdCBuZXcgcG9zaXRpb25cbn07XG5cbi8qKlxuICogUmV0dXJucyB0aGUgY2hpbGQgYXQgdGhlIHNwZWNpZmllZCBpbmRleFxuICpcbiAqIEBwYXJhbSBpbmRleCB7TnVtYmVyfSBUaGUgaW5kZXggdG8gZ2V0IHRoZSBjaGlsZCBmcm9tXG4gKiBAcmV0dXJuIHtEaXNwbGF5T2JqZWN0fSBUaGUgY2hpbGQgYXQgdGhlIGdpdmVuIGluZGV4LCBpZiBhbnkuXG4gKi9cbkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLmdldENoaWxkQXQgPSBmdW5jdGlvbiAoaW5kZXgpIHtcbiAgICBpZiAoaW5kZXggPCAwIHx8IGluZGV4ID49IHRoaXMuY2hpbGRyZW4ubGVuZ3RoKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignZ2V0Q2hpbGRBdDogU3VwcGxpZWQgaW5kZXggJyArIGluZGV4ICsgJyBkb2VzIG5vdCBleGlzdCBpbiB0aGUgY2hpbGQgbGlzdCwgb3IgdGhlIHN1cHBsaWVkIERpc3BsYXlPYmplY3QgbXVzdCBiZSBhIGNoaWxkIG9mIHRoZSBjYWxsZXInKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5jaGlsZHJlbltpbmRleF07XG59O1xuXG4vKipcbiAqIFJlbW92ZXMgYSBjaGlsZCBmcm9tIHRoZSBjb250YWluZXIuXG4gKlxuICogQHBhcmFtIGNoaWxkIHtEaXNwbGF5T2JqZWN0fSBUaGUgRGlzcGxheU9iamVjdCB0byByZW1vdmVcbiAqIEByZXR1cm4ge0Rpc3BsYXlPYmplY3R9IFRoZSBjaGlsZCB0aGF0IHdhcyByZW1vdmVkLlxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5yZW1vdmVDaGlsZCA9IGZ1bmN0aW9uIChjaGlsZCkge1xuICAgIHZhciBpbmRleCA9IHRoaXMuY2hpbGRyZW4uaW5kZXhPZihjaGlsZCk7XG5cbiAgICBpZiAoaW5kZXggPT09IC0xKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5yZW1vdmVDaGlsZEF0KGluZGV4KTtcbn07XG5cbi8qKlxuICogUmVtb3ZlcyBhIGNoaWxkIGZyb20gdGhlIHNwZWNpZmllZCBpbmRleCBwb3NpdGlvbi5cbiAqXG4gKiBAcGFyYW0gaW5kZXgge051bWJlcn0gVGhlIGluZGV4IHRvIGdldCB0aGUgY2hpbGQgZnJvbVxuICogQHJldHVybiB7RGlzcGxheU9iamVjdH0gVGhlIGNoaWxkIHRoYXQgd2FzIHJlbW92ZWQuXG4gKi9cbkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLnJlbW92ZUNoaWxkQXQgPSBmdW5jdGlvbiAoaW5kZXgpIHtcbiAgICB2YXIgY2hpbGQgPSB0aGlzLmdldENoaWxkQXQoaW5kZXgpO1xuXG4gICAgY2hpbGQucGFyZW50ID0gbnVsbDtcbiAgICB0aGlzLmNoaWxkcmVuLnNwbGljZShpbmRleCwgMSk7XG5cbiAgICByZXR1cm4gY2hpbGQ7XG59O1xuXG4vKipcbiAqIFJlbW92ZXMgYWxsIGNoaWxkcmVuIGZyb20gdGhpcyBjb250YWluZXIgdGhhdCBhcmUgd2l0aGluIHRoZSBiZWdpbiBhbmQgZW5kIGluZGV4ZXMuXG4gKlxuICogQHBhcmFtIGJlZ2luSW5kZXgge051bWJlcn0gVGhlIGJlZ2lubmluZyBwb3NpdGlvbi4gRGVmYXVsdCB2YWx1ZSBpcyAwLlxuICogQHBhcmFtIGVuZEluZGV4IHtOdW1iZXJ9IFRoZSBlbmRpbmcgcG9zaXRpb24uIERlZmF1bHQgdmFsdWUgaXMgc2l6ZSBvZiB0aGUgY29udGFpbmVyLlxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5yZW1vdmVDaGlsZHJlbiA9IGZ1bmN0aW9uIChiZWdpbkluZGV4LCBlbmRJbmRleCkge1xuICAgIHZhciBiZWdpbiA9IGJlZ2luSW5kZXggfHwgMDtcbiAgICB2YXIgZW5kID0gdHlwZW9mIGVuZEluZGV4ID09PSAnbnVtYmVyJyA/IGVuZEluZGV4IDogdGhpcy5jaGlsZHJlbi5sZW5ndGg7XG4gICAgdmFyIHJhbmdlID0gZW5kIC0gYmVnaW47XG5cbiAgICBpZiAocmFuZ2UgPiAwICYmIHJhbmdlIDw9IGVuZCkge1xuICAgICAgICB2YXIgcmVtb3ZlZCA9IHRoaXMuY2hpbGRyZW4uc3BsaWNlKGJlZ2luLCByYW5nZSk7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByZW1vdmVkLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICByZW1vdmVkW2ldLnBhcmVudCA9IG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVtb3ZlZDtcbiAgICB9XG4gICAgZWxzZSBpZiAocmFuZ2UgPT09IDAgJiYgdGhpcy5jaGlsZHJlbi5sZW5ndGggPT09IDApIHtcbiAgICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3JlbW92ZUNoaWxkcmVuOiBudW1lcmljIHZhbHVlcyBhcmUgb3V0c2lkZSB0aGUgYWNjZXB0YWJsZSByYW5nZS4nKTtcbiAgICB9XG59O1xuXG4vKipcbiAqIEdlbmVyYXRlcyBhbmQgdXBkYXRlcyB0aGUgY2FjaGVkIHNwcml0ZSBmb3IgdGhpcyBvYmplY3QuXG4gKlxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS51cGRhdGVDYWNoZWRTcHJpdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5fZ2VuZXJhdGVDYWNoZWRTcHJpdGUoKTtcbn07XG5cbi8qKlxuICogVXNlZnVsIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhIHRleHR1cmUgb2YgdGhlIGRpc3BsYXlPYmplY3Qgb2JqZWN0IHRoYXQgY2FuIHRoZW4gYmUgdXNlZCB0byBjcmVhdGUgc3ByaXRlc1xuICogVGhpcyBjYW4gYmUgcXVpdGUgdXNlZnVsIGlmIHlvdXIgZGlzcGxheU9iamVjdCBpcyBzdGF0aWMgLyBjb21wbGljYXRlZCBhbmQgbmVlZHMgdG8gYmUgcmV1c2VkIG11bHRpcGxlIHRpbWVzLlxuICpcbiAqIEBwYXJhbSByZXNvbHV0aW9uIHtOdW1iZXJ9IFRoZSByZXNvbHV0aW9uIG9mIHRoZSB0ZXh0dXJlIGJlaW5nIGdlbmVyYXRlZFxuICogQHBhcmFtIHNjYWxlTW9kZSB7TnVtYmVyfSBTZWUge3sjY3Jvc3NMaW5rIFwiUElYSS9zY2FsZU1vZGVzOnByb3BlcnR5XCJ9fVBJWEkuc2NhbGVNb2Rlc3t7L2Nyb3NzTGlua319IGZvciBwb3NzaWJsZSB2YWx1ZXNcbiAqIEBwYXJhbSByZW5kZXJlciB7Q2FudmFzUmVuZGVyZXJ8V2ViR0xSZW5kZXJlcn0gVGhlIHJlbmRlcmVyIHVzZWQgdG8gZ2VuZXJhdGUgdGhlIHRleHR1cmUuXG4gKiBAcmV0dXJuIHtUZXh0dXJlfSBhIHRleHR1cmUgb2YgdGhlIGdyYXBoaWNzIG9iamVjdFxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5nZW5lcmF0ZVRleHR1cmUgPSBmdW5jdGlvbiAocmVzb2x1dGlvbiwgc2NhbGVNb2RlLCByZW5kZXJlcikge1xuICAgIHZhciBib3VuZHMgPSB0aGlzLmdldExvY2FsQm91bmRzKCk7XG5cbiAgICB2YXIgcmVuZGVyVGV4dHVyZSA9IG5ldyBSZW5kZXJUZXh0dXJlKHJlbmRlcmVyLCBib3VuZHMud2lkdGggfCAwLCBib3VuZHMuaGVpZ2h0IHwgMCwgcmVuZGVyZXIsIHNjYWxlTW9kZSwgcmVzb2x1dGlvbik7XG5cbiAgICBfdGVtcE1hdHJpeC50eCA9IC1ib3VuZHMueDtcbiAgICBfdGVtcE1hdHJpeC50eSA9IC1ib3VuZHMueTtcblxuICAgIHJlbmRlclRleHR1cmUucmVuZGVyKHRoaXMsIF90ZW1wTWF0cml4KTtcblxuICAgIHJldHVybiByZW5kZXJUZXh0dXJlO1xufTtcblxuLypcbiAqIFVwZGF0ZXMgdGhlIHRyYW5zZm9ybSBvbiBhbGwgY2hpbGRyZW4gb2YgdGhpcyBjb250YWluZXIgZm9yIHJlbmRlcmluZ1xuICpcbiAqIEBwcml2YXRlXG4gKi9cbkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLnVwZGF0ZVRyYW5zZm9ybSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoIXRoaXMudmlzaWJsZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5kaXNwbGF5T2JqZWN0VXBkYXRlVHJhbnNmb3JtKCk7XG5cbiAgICBpZiAodGhpcy5fY2FjaGVBc0JpdG1hcCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgZm9yICh2YXIgaSA9IDAsIGogPSB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGo7ICsraSkge1xuICAgICAgICB0aGlzLmNoaWxkcmVuW2ldLnVwZGF0ZVRyYW5zZm9ybSgpO1xuICAgIH1cbn07XG5cbi8vIHBlcmZvcm1hbmNlIGluY3JlYXNlIHRvIGF2b2lkIHVzaW5nIGNhbGwuLiAoMTB4IGZhc3RlcilcbkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLmRpc3BsYXlPYmplY3RDb250YWluZXJVcGRhdGVUcmFuc2Zvcm0gPSBEaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS51cGRhdGVUcmFuc2Zvcm07XG5cbi8qKlxuICogUmV0cmlldmVzIHRoZSBib3VuZHMgb2YgdGhlIGRpc3BsYXlPYmplY3RDb250YWluZXIgYXMgYSByZWN0YW5nbGUuIFRoZSBib3VuZHMgY2FsY3VsYXRpb24gdGFrZXMgYWxsIHZpc2libGUgY2hpbGRyZW4gaW50byBjb25zaWRlcmF0aW9uLlxuICpcbiAqIEByZXR1cm4ge1JlY3RhbmdsZX0gVGhlIHJlY3Rhbmd1bGFyIGJvdW5kaW5nIGFyZWFcbiAqL1xuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUuZ2V0Qm91bmRzID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICh0aGlzLmNoaWxkcmVuLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gbWF0aC5SZWN0YW5nbGUuRU1QVFk7XG4gICAgfVxuXG4gICAgLy8gVE9ETyB0aGUgYm91bmRzIGhhdmUgYWxyZWFkeSBiZWVuIGNhbGN1bGF0ZWQgdGhpcyByZW5kZXIgc2Vzc2lvbiBzbyByZXR1cm4gd2hhdCB3ZSBoYXZlXG5cbiAgICB2YXIgbWluWCA9IEluZmluaXR5O1xuICAgIHZhciBtaW5ZID0gSW5maW5pdHk7XG5cbiAgICB2YXIgbWF4WCA9IC1JbmZpbml0eTtcbiAgICB2YXIgbWF4WSA9IC1JbmZpbml0eTtcblxuICAgIHZhciBjaGlsZEJvdW5kcztcbiAgICB2YXIgY2hpbGRNYXhYO1xuICAgIHZhciBjaGlsZE1heFk7XG5cbiAgICB2YXIgY2hpbGRWaXNpYmxlID0gZmFsc2U7XG5cbiAgICBmb3IgKHZhciBpID0gMCwgaiA9IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgKytpKSB7XG4gICAgICAgIHZhciBjaGlsZCA9IHRoaXMuY2hpbGRyZW5baV07XG5cbiAgICAgICAgaWYgKCFjaGlsZC52aXNpYmxlKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNoaWxkVmlzaWJsZSA9IHRydWU7XG5cbiAgICAgICAgY2hpbGRCb3VuZHMgPSB0aGlzLmNoaWxkcmVuW2ldLmdldEJvdW5kcygpO1xuXG4gICAgICAgIG1pblggPSBtaW5YIDwgY2hpbGRCb3VuZHMueCA/IG1pblggOiBjaGlsZEJvdW5kcy54O1xuICAgICAgICBtaW5ZID0gbWluWSA8IGNoaWxkQm91bmRzLnkgPyBtaW5ZIDogY2hpbGRCb3VuZHMueTtcblxuICAgICAgICBjaGlsZE1heFggPSBjaGlsZEJvdW5kcy53aWR0aCArIGNoaWxkQm91bmRzLng7XG4gICAgICAgIGNoaWxkTWF4WSA9IGNoaWxkQm91bmRzLmhlaWdodCArIGNoaWxkQm91bmRzLnk7XG5cbiAgICAgICAgbWF4WCA9IG1heFggPiBjaGlsZE1heFggPyBtYXhYIDogY2hpbGRNYXhYO1xuICAgICAgICBtYXhZID0gbWF4WSA+IGNoaWxkTWF4WSA/IG1heFkgOiBjaGlsZE1heFk7XG4gICAgfVxuXG4gICAgaWYgKCFjaGlsZFZpc2libGUpIHtcbiAgICAgICAgcmV0dXJuIG1hdGguUmVjdGFuZ2xlLkVNUFRZO1xuICAgIH1cblxuICAgIHRoaXMuX2JvdW5kcy54ID0gbWluWDtcbiAgICB0aGlzLl9ib3VuZHMueSA9IG1pblk7XG4gICAgdGhpcy5fYm91bmRzLndpZHRoID0gbWF4WCAtIG1pblg7XG4gICAgdGhpcy5fYm91bmRzLmhlaWdodCA9IG1heFkgLSBtaW5ZO1xuXG4gICAgLy8gVE9ETzogc3RvcmUgYSByZWZlcmVuY2Ugc28gdGhhdCBpZiB0aGlzIGZ1bmN0aW9uIGdldHMgY2FsbGVkIGFnYWluIGluIHRoZSByZW5kZXIgY3ljbGUgd2UgZG8gbm90IGhhdmUgdG8gcmVjYWxjdWxhdGVcbiAgICAvL3RoaXMuX2N1cnJlbnRCb3VuZHMgPSBib3VuZHM7XG5cbiAgICByZXR1cm4gdGhpcy5fYm91bmRzO1xufTtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIG5vbi1nbG9iYWwgbG9jYWwgYm91bmRzIG9mIHRoZSBkaXNwbGF5T2JqZWN0Q29udGFpbmVyIGFzIGEgcmVjdGFuZ2xlLlxuICogVGhlIGNhbGN1bGF0aW9uIHRha2VzIGFsbCB2aXNpYmxlIGNoaWxkcmVuIGludG8gY29uc2lkZXJhdGlvbi5cbiAqXG4gKiBAcmV0dXJuIHtSZWN0YW5nbGV9IFRoZSByZWN0YW5ndWxhciBib3VuZGluZyBhcmVhXG4gKi9cbkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLmdldExvY2FsQm91bmRzID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBtYXRyaXhDYWNoZSA9IHRoaXMud29ybGRUcmFuc2Zvcm07XG5cbiAgICB0aGlzLndvcmxkVHJhbnNmb3JtID0gbWF0aC5NYXRyaXguSURFTlRJVFk7XG5cbiAgICBmb3IgKHZhciBpID0gMCwgaiA9IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgKytpKSB7XG4gICAgICAgIHRoaXMuY2hpbGRyZW5baV0udXBkYXRlVHJhbnNmb3JtKCk7XG4gICAgfVxuXG4gICAgdGhpcy53b3JsZFRyYW5zZm9ybSA9IG1hdHJpeENhY2hlO1xuXG4gICAgcmV0dXJuIHRoaXMuZ2V0Qm91bmRzKCk7XG59O1xuXG4vKipcbiAqIFJlbmRlcnMgdGhlIG9iamVjdCB1c2luZyB0aGUgV2ViR0wgcmVuZGVyZXJcbiAqXG4gKiBUT0RPIC0gT3B0aW1pemF0aW9uIHBhc3MhXG4gKlxuICogQHBhcmFtIHJlbmRlcmVyIHtXZWJHTFJlbmRlcmVyfSBUaGUgcmVuZGVyZXJcbiAqL1xuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUucmVuZGVyV2ViR0wgPSBmdW5jdGlvbiAocmVuZGVyZXIpIHtcbiAgICAvLyBpZiB0aGUgb2JqZWN0IGlzIG5vdCB2aXNpYmxlIG9yIHRoZSBhbHBoYSBpcyAwIHRoZW4gbm8gbmVlZCB0byByZW5kZXIgdGhpcyBlbGVtZW50XG4gICAgaWYgKCF0aGlzLnZpc2libGUgfHwgdGhpcy5hbHBoYSA8PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fY2FjaGVBc0JpdG1hcCkge1xuICAgICAgICB0aGlzLl9yZW5kZXJDYWNoZWRTcHJpdGUocmVuZGVyZXIpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIGksIGo7XG5cbiAgICAvLyBkbyBhIHF1aWNrIGNoZWNrIHRvIHNlZSBpZiB0aGlzIGVsZW1lbnQgaGFzIGEgbWFzayBvciBhIGZpbHRlci5cbiAgICBpZiAodGhpcy5fbWFzayB8fCB0aGlzLl9maWx0ZXJzKSB7XG4gICAgICAgIC8vIHB1c2ggZmlsdGVyIGZpcnN0IGFzIHdlIG5lZWQgdG8gZW5zdXJlIHRoZSBzdGVuY2lsIGJ1ZmZlciBpcyBjb3JyZWN0IGZvciBhbnkgbWFza2luZ1xuICAgICAgICBpZiAodGhpcy5fZmlsdGVycykge1xuICAgICAgICAgICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guZmx1c2goKTtcbiAgICAgICAgICAgIHJlbmRlcmVyLmZpbHRlck1hbmFnZXIucHVzaEZpbHRlcih0aGlzLl9maWx0ZXJCbG9jayk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICAgICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guc3RvcCgpO1xuICAgICAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucHVzaE1hc2sodGhpcy5tYXNrLCByZW5kZXJlcik7XG4gICAgICAgICAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5zdGFydCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gYWRkIHRoaXMgb2JqZWN0IHRvIHRoZSBiYXRjaCwgb25seSByZW5kZXJlZCBpZiBpdCBoYXMgYSB0ZXh0dXJlLlxuICAgICAgICBpZiAodGhpcy50ZXh0dXJlKSB7XG4gICAgICAgICAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5yZW5kZXIodGhpcyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBub3cgbG9vcCB0aHJvdWdoIHRoZSBjaGlsZHJlbiBhbmQgbWFrZSBzdXJlIHRoZXkgZ2V0IHJlbmRlcmVkXG4gICAgICAgIGZvciAoaSA9IDAsIGogPSB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuICAgICAgICAgICAgdGhpcy5jaGlsZHJlbltpXS5yZW5kZXJXZWJHTChyZW5kZXJlcik7XG4gICAgICAgIH1cblxuICAgICAgICAvLyB0aW1lIHRvIHN0b3AgdGhlIHNwcml0ZSBiYXRjaCBhcyBlaXRoZXIgYSBtYXNrIGVsZW1lbnQgb3IgYSBmaWx0ZXIgZHJhdyB3aWxsIGhhcHBlbiBuZXh0XG4gICAgICAgIHJlbmRlcmVyLnNwcml0ZUJhdGNoLnN0b3AoKTtcblxuICAgICAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucG9wTWFzayh0aGlzLl9tYXNrLCByZW5kZXJlcik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5fZmlsdGVycykge1xuICAgICAgICAgICAgcmVuZGVyZXIuZmlsdGVyTWFuYWdlci5wb3BGaWx0ZXIoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlbmRlcmVyLnNwcml0ZUJhdGNoLnN0YXJ0KCk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBpZiAodGhpcy50ZXh0dXJlKSB7XG4gICAgICAgICAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5yZW5kZXIodGhpcyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBzaW1wbGUgcmVuZGVyIGNoaWxkcmVuIVxuICAgICAgICBmb3IgKGkgPSAwLCBqID0gdGhpcy5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyArK2kpIHtcbiAgICAgICAgICAgIHRoaXMuY2hpbGRyZW5baV0ucmVuZGVyV2ViR0wocmVuZGVyZXIpO1xuICAgICAgICB9XG5cbiAgICB9XG59O1xuXG4vKipcbiAqIFJlbmRlcnMgdGhlIG9iamVjdCB1c2luZyB0aGUgQ2FudmFzIHJlbmRlcmVyXG4gKlxuICogQHBhcmFtIHJlbmRlcmVyIHtDYW52YXNSZW5kZXJlcn0gVGhlIHJlbmRlcmVyXG4gKi9cbkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLnJlbmRlckNhbnZhcyA9IGZ1bmN0aW9uIChyZW5kZXJlcikge1xuICAgIGlmICghdGhpcy52aXNpYmxlIHx8IHRoaXMuYWxwaGEgPD0gMCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX2NhY2hlQXNCaXRtYXApIHtcbiAgICAgICAgdGhpcy5fcmVuZGVyQ2FjaGVkU3ByaXRlKHJlbmRlcmVyKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0aGlzLl9tYXNrKSB7XG4gICAgICAgIHJlbmRlcmVyLm1hc2tNYW5hZ2VyLnB1c2hNYXNrKHRoaXMuX21hc2ssIHJlbmRlcmVyKTtcbiAgICB9XG5cbiAgICBmb3IgKHZhciBpID0gMCwgaiA9IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgKytpKSB7XG4gICAgICAgIHRoaXMuY2hpbGRyZW5baV0ucmVuZGVyQ2FudmFzKHJlbmRlcmVyKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICByZW5kZXJlci5tYXNrTWFuYWdlci5wb3BNYXNrKHJlbmRlcmVyKTtcbiAgICB9XG59O1xuXG4vKipcbiAqIEludGVybmFsIG1ldGhvZC5cbiAqXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ8Q2FudmFzUmVuZGVyZXJ9IFRoZSByZW5kZXJlclxuICogQHByaXZhdGVcbiAqL1xuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUuX3JlbmRlckNhY2hlZFNwcml0ZSA9IGZ1bmN0aW9uIChyZW5kZXJlcikge1xuICAgIHRoaXMuX2NhY2hlZFNwcml0ZS53b3JsZEFscGhhID0gdGhpcy53b3JsZEFscGhhO1xuXG4gICAgaWYgKHJlbmRlcmVyLmdsKSB7XG4gICAgICAgIHRoaXMuX2NhY2hlZFNwcml0ZS5yZW5kZXJXZWJHTChyZW5kZXJlcik7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLl9jYWNoZWRTcHJpdGUucmVuZGVyQ2FudmFzKHJlbmRlcmVyKTtcbiAgICB9XG59O1xuXG4vKipcbiAqIEludGVybmFsIG1ldGhvZC5cbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5fZ2VuZXJhdGVDYWNoZWRTcHJpdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGJvdW5kcyA9IHRoaXMuZ2V0TG9jYWxCb3VuZHMoKTtcblxuICAgIGlmICghdGhpcy5fY2FjaGVkU3ByaXRlKSB7XG4gICAgICAgIC8vIFRPRE8gLSBSZW5kZXJUZXh0dXJlIG5vdyAqcmVxdWlyZXMqIGEgcmVuZGVyZXIgaW5zdGFuY2UsIHNvIHRoaXMgaXMgbGlrZSBicm9rZW5cbiAgICAgICAgLy8gYmVjYXVzZSBgcmVuZGVyZXJgIGlzbid0IGFjdHVhbGx5IGluIHNjb3BlIGhlcmUgOlBcbiAgICAgICAgdmFyIHJlbmRlclRleHR1cmUgPSBuZXcgUmVuZGVyVGV4dHVyZShyZW5kZXJlciwgYm91bmRzLndpZHRoIHwgMCwgYm91bmRzLmhlaWdodCB8IDApO1xuXG4gICAgICAgIHRoaXMuX2NhY2hlZFNwcml0ZSA9IG5ldyBTcHJpdGUocmVuZGVyVGV4dHVyZSk7XG4gICAgICAgIHRoaXMuX2NhY2hlZFNwcml0ZS53b3JsZFRyYW5zZm9ybSA9IHRoaXMud29ybGRUcmFuc2Zvcm07XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLl9jYWNoZWRTcHJpdGUudGV4dHVyZS5yZXNpemUoYm91bmRzLndpZHRoIHwgMCwgYm91bmRzLmhlaWdodCB8IDApO1xuICAgIH1cblxuICAgIHZhciB0ZW1wRmlsdGVycyA9IHRoaXMuX2ZpbHRlcnM7XG4gICAgdGhpcy5fZmlsdGVycyA9IG51bGw7XG5cbiAgICB0aGlzLl9jYWNoZWRTcHJpdGUuZmlsdGVycyA9IHRlbXBGaWx0ZXJzO1xuXG4gICAgX3RlbXBNYXRyaXgudHggPSAtYm91bmRzLng7XG4gICAgX3RlbXBNYXRyaXgudHkgPSAtYm91bmRzLnk7XG5cbiAgICB0aGlzLl9jYWNoZWRTcHJpdGUudGV4dHVyZS5yZW5kZXIodGhpcywgX3RlbXBNYXRyaXgsIHRydWUpO1xuXG4gICAgdGhpcy5fY2FjaGVkU3ByaXRlLmFuY2hvci54ID0gLShib3VuZHMueCAvIGJvdW5kcy53aWR0aCk7XG4gICAgdGhpcy5fY2FjaGVkU3ByaXRlLmFuY2hvci55ID0gLShib3VuZHMueSAvIGJvdW5kcy5oZWlnaHQpO1xuXG4gICAgdGhpcy5fZmlsdGVycyA9IHRlbXBGaWx0ZXJzO1xufTtcblxuLyoqXG4gKiBEZXN0cm95cyB0aGUgY2FjaGVkIHNwcml0ZS5cbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5fZGVzdHJveUNhY2hlZFNwcml0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoIXRoaXMuX2NhY2hlZFNwcml0ZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gVE9ETzogUG9vbCB0aGlzIHNwcml0ZVxuICAgIHRoaXMuX2NhY2hlZFNwcml0ZS5kZXN0cm95KHRydWUsIHRydWUpO1xuICAgIHRoaXMuX2NhY2hlZFNwcml0ZSA9IG51bGw7XG59O1xuIiwidmFyIG1hdGggPSByZXF1aXJlKCcuLi9tYXRoJyksXG4gICAgVGV4dHVyZSA9IHJlcXVpcmUoJy4uL3RleHR1cmVzL1RleHR1cmUnKSxcbiAgICBEaXNwbGF5T2JqZWN0Q29udGFpbmVyID0gcmVxdWlyZSgnLi9EaXNwbGF5T2JqZWN0Q29udGFpbmVyJyksXG4gICAgQ2FudmFzVGludGVyID0gcmVxdWlyZSgnLi4vcmVuZGVyZXJzL2NhbnZhcy91dGlscy9DYW52YXNUaW50ZXInKSxcbiAgICB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzJyksXG4gICAgQ09OU1QgPSByZXF1aXJlKCcuLi9jb25zdCcpO1xuXG4vKipcbiAqIFRoZSBTcHJpdGUgb2JqZWN0IGlzIHRoZSBiYXNlIGZvciBhbGwgdGV4dHVyZWQgb2JqZWN0cyB0aGF0IGFyZSByZW5kZXJlZCB0byB0aGUgc2NyZWVuXG4gKlxuICogQSBzcHJpdGUgY2FuIGJlIGNyZWF0ZWQgZGlyZWN0bHkgZnJvbSBhbiBpbWFnZSBsaWtlIHRoaXM6XG4gKlxuICogYGBganNcbiAqIHZhciBzcHJpdGUgPSBuZXcgU3ByaXRlLmZyb21JbWFnZSgnYXNzZXRzL2ltYWdlLnBuZycpO1xuICogYGBgXG4gKlxuICogQGNsYXNzIFNwcml0ZVxuICogQGV4dGVuZHMgRGlzcGxheU9iamVjdENvbnRhaW5lclxuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gdGV4dHVyZSB7VGV4dHVyZX0gVGhlIHRleHR1cmUgZm9yIHRoaXMgc3ByaXRlXG4gKi9cbmZ1bmN0aW9uIFNwcml0ZSh0ZXh0dXJlKSB7XG4gICAgRGlzcGxheU9iamVjdENvbnRhaW5lci5jYWxsKHRoaXMpO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGFuY2hvciBzZXRzIHRoZSBvcmlnaW4gcG9pbnQgb2YgdGhlIHRleHR1cmUuXG4gICAgICogVGhlIGRlZmF1bHQgaXMgMCwwIHRoaXMgbWVhbnMgdGhlIHRleHR1cmUncyBvcmlnaW4gaXMgdGhlIHRvcCBsZWZ0XG4gICAgICogU2V0dGluZyB0aGFuIGFuY2hvciB0byAwLjUsMC41IG1lYW5zIHRoZSB0ZXh0dXJlcyBvcmlnaW4gaXMgY2VudGVyZWRcbiAgICAgKiBTZXR0aW5nIHRoZSBhbmNob3IgdG8gMSwxIHdvdWxkIG1lYW4gdGhlIHRleHR1cmVzIG9yaWdpbiBwb2ludHMgd2lsbCBiZSB0aGUgYm90dG9tIHJpZ2h0IGNvcm5lclxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICovXG4gICAgdGhpcy5hbmNob3IgPSBuZXcgbWF0aC5Qb2ludCgpO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHRleHR1cmUgdGhhdCB0aGUgc3ByaXRlIGlzIHVzaW5nXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtUZXh0dXJlfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fdGV4dHVyZSA9IG51bGw7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgd2lkdGggb2YgdGhlIHNwcml0ZSAodGhpcyBpcyBpbml0aWFsbHkgc2V0IGJ5IHRoZSB0ZXh0dXJlKVxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fd2lkdGggPSAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGhlaWdodCBvZiB0aGUgc3ByaXRlICh0aGlzIGlzIGluaXRpYWxseSBzZXQgYnkgdGhlIHRleHR1cmUpXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl9oZWlnaHQgPSAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHRpbnQgYXBwbGllZCB0byB0aGUgc3ByaXRlLiBUaGlzIGlzIGEgaGV4IHZhbHVlLiBBIHZhbHVlIG9mIDB4RkZGRkZGIHdpbGwgcmVtb3ZlIGFueSB0aW50IGVmZmVjdC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAweEZGRkZGRlxuICAgICAqL1xuICAgIHRoaXMudGludCA9IDB4RkZGRkZGO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGJsZW5kIG1vZGUgdG8gYmUgYXBwbGllZCB0byB0aGUgc3ByaXRlLiBTZXQgdG8gQ09OU1QuYmxlbmRNb2Rlcy5OT1JNQUwgdG8gcmVtb3ZlIGFueSBibGVuZCBtb2RlLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IENPTlNULmJsZW5kTW9kZXMuTk9STUFMO1xuICAgICAqL1xuICAgIHRoaXMuYmxlbmRNb2RlID0gQ09OU1QuYmxlbmRNb2Rlcy5OT1JNQUw7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgc2hhZGVyIHRoYXQgd2lsbCBiZSB1c2VkIHRvIHJlbmRlciB0aGUgc3ByaXRlLiBTZXQgdG8gbnVsbCB0byByZW1vdmUgYSBjdXJyZW50IHNoYWRlci5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0Fic3RyYWN0RmlsdGVyfVxuICAgICAqL1xuICAgIHRoaXMuc2hhZGVyID0gbnVsbDtcblxuICAgIHRoaXMucmVuZGVyYWJsZSA9IHRydWU7XG5cbiAgICAvLyBjYWxsIHRleHR1cmUgc2V0dGVyXG4gICAgdGhpcy50ZXh0dXJlID0gdGV4dHVyZSB8fCBUZXh0dXJlLkVNUFRZO1xufVxuXG5TcHJpdGUucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoZGVzdHJveVRleHR1cmUsIGRlc3Ryb3lCYXNlVGV4dHVyZSkge1xuICAgIERpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLmRlc3Ryb3kuY2FsbCh0aGlzKTtcblxuICAgIHRoaXMuYW5jaG9yID0gbnVsbDtcblxuICAgIGlmIChkZXN0cm95VGV4dHVyZSkge1xuICAgICAgICB0aGlzLl90ZXh0dXJlLmRlc3Ryb3koZGVzdHJveUJhc2VUZXh0dXJlKTtcbiAgICB9XG5cbiAgICB0aGlzLl90ZXh0dXJlID0gbnVsbDtcbiAgICB0aGlzLnNoYWRlciA9IG51bGw7XG59O1xuXG4vLyBjb25zdHJ1Y3RvclxuU3ByaXRlLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUpO1xuU3ByaXRlLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFNwcml0ZTtcbm1vZHVsZS5leHBvcnRzID0gU3ByaXRlO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhTcHJpdGUucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHdpZHRoIG9mIHRoZSBzcHJpdGUsIHNldHRpbmcgdGhpcyB3aWxsIGFjdHVhbGx5IG1vZGlmeSB0aGUgc2NhbGUgdG8gYWNoaWV2ZSB0aGUgdmFsdWUgc2V0XG4gICAgICpcbiAgICAgKiBAbWVtYmVyXG4gICAgICogQG1lbWJlcm9mIFNwcml0ZSNcbiAgICAgKi9cbiAgICB3aWR0aDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnNjYWxlLnggKiB0aGlzLnRleHR1cmUuZnJhbWUud2lkdGg7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnNjYWxlLnggPSB2YWx1ZSAvIHRoaXMudGV4dHVyZS5mcmFtZS53aWR0aDtcbiAgICAgICAgICAgIHRoaXMuX3dpZHRoID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIGhlaWdodCBvZiB0aGUgc3ByaXRlLCBzZXR0aW5nIHRoaXMgd2lsbCBhY3R1YWxseSBtb2RpZnkgdGhlIHNjYWxlIHRvIGFjaGlldmUgdGhlIHZhbHVlIHNldFxuICAgICAqXG4gICAgICogQG1lbWJlclxuICAgICAqIEBtZW1iZXJvZiBTcHJpdGUjXG4gICAgICovXG4gICAgaGVpZ2h0OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICB0aGlzLnNjYWxlLnkgKiB0aGlzLnRleHR1cmUuZnJhbWUuaGVpZ2h0O1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy5zY2FsZS55ID0gdmFsdWUgLyB0aGlzLnRleHR1cmUuZnJhbWUuaGVpZ2h0O1xuICAgICAgICAgICAgdGhpcy5faGVpZ2h0ID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIGhlaWdodCBvZiB0aGUgc3ByaXRlLCBzZXR0aW5nIHRoaXMgd2lsbCBhY3R1YWxseSBtb2RpZnkgdGhlIHNjYWxlIHRvIGFjaGlldmUgdGhlIHZhbHVlIHNldFxuICAgICAqXG4gICAgICogQG1lbWJlclxuICAgICAqIEBtZW1iZXJvZiBTcHJpdGUjXG4gICAgICovXG4gICAgdGV4dHVyZToge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiAgdGhpcy5fdGV4dHVyZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLl90ZXh0dXJlID09PSB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5fdGV4dHVyZSA9IHZhbHVlO1xuICAgICAgICAgICAgdGhpcy5jYWNoZWRUaW50ID0gMHhGRkZGRkY7XG5cbiAgICAgICAgICAgIGlmICh2YWx1ZSkge1xuICAgICAgICAgICAgICAgIC8vIHdhaXQgZm9yIHRoZSB0ZXh0dXJlIHRvIGxvYWRcbiAgICAgICAgICAgICAgICBpZiAodmFsdWUuYmFzZVRleHR1cmUuaGFzTG9hZGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX29uVGV4dHVyZVVwZGF0ZSgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUub25jZSgndXBkYXRlJywgdGhpcy5fb25UZXh0dXJlVXBkYXRlLmJpbmQodGhpcykpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0sXG59KTtcblxuLyoqXG4gKiBXaGVuIHRoZSB0ZXh0dXJlIGlzIHVwZGF0ZWQsIHRoaXMgZXZlbnQgd2lsbCBmaXJlIHRvIHVwZGF0ZSB0aGUgc2NhbGUgYW5kIGZyYW1lXG4gKlxuICogQHByaXZhdGVcbiAqL1xuU3ByaXRlLnByb3RvdHlwZS5fb25UZXh0dXJlVXBkYXRlID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIHNvIGlmIF93aWR0aCBpcyAwIHRoZW4gd2lkdGggd2FzIG5vdCBzZXQuLlxuICAgIGlmICh0aGlzLl93aWR0aCkge1xuICAgICAgICB0aGlzLnNjYWxlLnggPSB0aGlzLl93aWR0aCAvIHRoaXMudGV4dHVyZS5mcmFtZS53aWR0aDtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5faGVpZ2h0KSB7XG4gICAgICAgIHRoaXMuc2NhbGUueSA9IHRoaXMuX2hlaWdodCAvIHRoaXMudGV4dHVyZS5mcmFtZS5oZWlnaHQ7XG4gICAgfVxufTtcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBib3VuZHMgb2YgdGhlIFNwcml0ZSBhcyBhIHJlY3RhbmdsZS4gVGhlIGJvdW5kcyBjYWxjdWxhdGlvbiB0YWtlcyB0aGUgd29ybGRUcmFuc2Zvcm0gaW50byBhY2NvdW50LlxuICpcbiAqIEBwYXJhbSBtYXRyaXgge01hdHJpeH0gdGhlIHRyYW5zZm9ybWF0aW9uIG1hdHJpeCBvZiB0aGUgc3ByaXRlXG4gKiBAcmV0dXJuIHtSZWN0YW5nbGV9IHRoZSBmcmFtaW5nIHJlY3RhbmdsZVxuICovXG5TcHJpdGUucHJvdG90eXBlLmdldEJvdW5kcyA9IGZ1bmN0aW9uIChtYXRyaXgpIHtcbiAgICB2YXIgd2lkdGggPSB0aGlzLnRleHR1cmUuZnJhbWUud2lkdGg7XG4gICAgdmFyIGhlaWdodCA9IHRoaXMudGV4dHVyZS5mcmFtZS5oZWlnaHQ7XG5cbiAgICB2YXIgdzAgPSB3aWR0aCAqICgxLXRoaXMuYW5jaG9yLngpO1xuICAgIHZhciB3MSA9IHdpZHRoICogLXRoaXMuYW5jaG9yLng7XG5cbiAgICB2YXIgaDAgPSBoZWlnaHQgKiAoMS10aGlzLmFuY2hvci55KTtcbiAgICB2YXIgaDEgPSBoZWlnaHQgKiAtdGhpcy5hbmNob3IueTtcblxuICAgIHZhciB3b3JsZFRyYW5zZm9ybSA9IG1hdHJpeCB8fCB0aGlzLndvcmxkVHJhbnNmb3JtIDtcblxuICAgIHZhciBhID0gd29ybGRUcmFuc2Zvcm0uYTtcbiAgICB2YXIgYiA9IHdvcmxkVHJhbnNmb3JtLmI7XG4gICAgdmFyIGMgPSB3b3JsZFRyYW5zZm9ybS5jO1xuICAgIHZhciBkID0gd29ybGRUcmFuc2Zvcm0uZDtcbiAgICB2YXIgdHggPSB3b3JsZFRyYW5zZm9ybS50eDtcbiAgICB2YXIgdHkgPSB3b3JsZFRyYW5zZm9ybS50eTtcblxuICAgIHZhciBtaW5YLFxuICAgICAgICBtYXhYLFxuICAgICAgICBtaW5ZLFxuICAgICAgICBtYXhZO1xuXG4gICAgaWYoYiA9PT0gMCAmJiBjID09PSAwKVxuICAgIHtcbiAgICAgICAgLy8gc2NhbGUgbWF5IGJlIG5lZ2F0aXZlIVxuICAgICAgICBpZiAoYSA8IDApIHtcbiAgICAgICAgICAgIGEgKj0gLTE7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZCA8IDApIHtcbiAgICAgICAgICAgIGQgKj0gLTE7XG4gICAgICAgIH1cblxuICAgICAgICAvLyB0aGlzIG1lYW5zIHRoZXJlIGlzIG5vIHJvdGF0aW9uIGdvaW5nIG9uIHJpZ2h0PyBSSUdIVD9cbiAgICAgICAgLy8gaWYgdGhhdHMgdGhlIGNhc2UgdGhlbiB3ZSBjYW4gYXZvaWQgY2hlY2tpbmcgdGhlIGJvdW5kIHZhbHVlcyEgeWF5XG4gICAgICAgIG1pblggPSBhICogdzEgKyB0eDtcbiAgICAgICAgbWF4WCA9IGEgKiB3MCArIHR4O1xuICAgICAgICBtaW5ZID0gZCAqIGgxICsgdHk7XG4gICAgICAgIG1heFkgPSBkICogaDAgKyB0eTtcbiAgICB9XG4gICAgZWxzZVxuICAgIHtcbiAgICAgICAgdmFyIHgxID0gYSAqIHcxICsgYyAqIGgxICsgdHg7XG4gICAgICAgIHZhciB5MSA9IGQgKiBoMSArIGIgKiB3MSArIHR5O1xuXG4gICAgICAgIHZhciB4MiA9IGEgKiB3MCArIGMgKiBoMSArIHR4O1xuICAgICAgICB2YXIgeTIgPSBkICogaDEgKyBiICogdzAgKyB0eTtcblxuICAgICAgICB2YXIgeDMgPSBhICogdzAgKyBjICogaDAgKyB0eDtcbiAgICAgICAgdmFyIHkzID0gZCAqIGgwICsgYiAqIHcwICsgdHk7XG5cbiAgICAgICAgdmFyIHg0ID0gIGEgKiB3MSArIGMgKiBoMCArIHR4O1xuICAgICAgICB2YXIgeTQgPSAgZCAqIGgwICsgYiAqIHcxICsgdHk7XG5cbiAgICAgICAgbWluWCA9IHgxO1xuICAgICAgICBtaW5YID0geDIgPCBtaW5YID8geDIgOiBtaW5YO1xuICAgICAgICBtaW5YID0geDMgPCBtaW5YID8geDMgOiBtaW5YO1xuICAgICAgICBtaW5YID0geDQgPCBtaW5YID8geDQgOiBtaW5YO1xuXG4gICAgICAgIG1pblkgPSB5MTtcbiAgICAgICAgbWluWSA9IHkyIDwgbWluWSA/IHkyIDogbWluWTtcbiAgICAgICAgbWluWSA9IHkzIDwgbWluWSA/IHkzIDogbWluWTtcbiAgICAgICAgbWluWSA9IHk0IDwgbWluWSA/IHk0IDogbWluWTtcblxuICAgICAgICBtYXhYID0geDE7XG4gICAgICAgIG1heFggPSB4MiA+IG1heFggPyB4MiA6IG1heFg7XG4gICAgICAgIG1heFggPSB4MyA+IG1heFggPyB4MyA6IG1heFg7XG4gICAgICAgIG1heFggPSB4NCA+IG1heFggPyB4NCA6IG1heFg7XG5cbiAgICAgICAgbWF4WSA9IHkxO1xuICAgICAgICBtYXhZID0geTIgPiBtYXhZID8geTIgOiBtYXhZO1xuICAgICAgICBtYXhZID0geTMgPiBtYXhZID8geTMgOiBtYXhZO1xuICAgICAgICBtYXhZID0geTQgPiBtYXhZID8geTQgOiBtYXhZO1xuICAgIH1cblxuICAgIHZhciBib3VuZHMgPSB0aGlzLl9ib3VuZHM7XG5cbiAgICBib3VuZHMueCA9IG1pblg7XG4gICAgYm91bmRzLndpZHRoID0gbWF4WCAtIG1pblg7XG5cbiAgICBib3VuZHMueSA9IG1pblk7XG4gICAgYm91bmRzLmhlaWdodCA9IG1heFkgLSBtaW5ZO1xuXG4gICAgLy8gc3RvcmUgYSByZWZlcmVuY2Ugc28gdGhhdCBpZiB0aGlzIGZ1bmN0aW9uIGdldHMgY2FsbGVkIGFnYWluIGluIHRoZSByZW5kZXIgY3ljbGUgd2UgZG8gbm90IGhhdmUgdG8gcmVjYWxjdWxhdGVcbiAgICB0aGlzLl9jdXJyZW50Qm91bmRzID0gYm91bmRzO1xuXG4gICAgcmV0dXJuIGJvdW5kcztcbn07XG5cbi8qKlxuKiBSZW5kZXJzIHRoZSBvYmplY3QgdXNpbmcgdGhlIENhbnZhcyByZW5kZXJlclxuKlxuKiBAcGFyYW0gcmVuZGVyZXIge0NhbnZhc1JlbmRlcmVyfSBUaGUgcmVuZGVyZXJcbiovXG5TcHJpdGUucHJvdG90eXBlLnJlbmRlckNhbnZhcyA9IGZ1bmN0aW9uIChyZW5kZXJlcikge1xuICAgIGlmICghdGhpcy52aXNpYmxlIHx8IHRoaXMuYWxwaGEgPD0gMCB8fCB0aGlzLnRleHR1cmUuY3JvcC53aWR0aCA8PSAwIHx8IHRoaXMudGV4dHVyZS5jcm9wLmhlaWdodCA8PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5ibGVuZE1vZGUgIT09IHJlbmRlcmVyLmN1cnJlbnRCbGVuZE1vZGUpIHtcbiAgICAgICAgcmVuZGVyZXIuY3VycmVudEJsZW5kTW9kZSA9IHRoaXMuYmxlbmRNb2RlO1xuICAgICAgICByZW5kZXJlci5jb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9IHJlbmRlcmVyLmJsZW5kTW9kZXNbcmVuZGVyZXIuY3VycmVudEJsZW5kTW9kZV07XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX21hc2spIHtcbiAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucHVzaE1hc2sodGhpcy5fbWFzaywgcmVuZGVyZXIpO1xuICAgIH1cblxuICAgIC8vICBJZ25vcmUgbnVsbCBzb3VyY2VzXG4gICAgaWYgKHRoaXMudGV4dHVyZS52YWxpZCkge1xuICAgICAgICB2YXIgcmVzb2x1dGlvbiA9IHRoaXMudGV4dHVyZS5iYXNlVGV4dHVyZS5yZXNvbHV0aW9uIC8gcmVuZGVyZXIucmVzb2x1dGlvbjtcblxuICAgICAgICByZW5kZXJlci5jb250ZXh0Lmdsb2JhbEFscGhhID0gdGhpcy53b3JsZEFscGhhO1xuXG4gICAgICAgIC8vIElmIHNtb290aGluZ0VuYWJsZWQgaXMgc3VwcG9ydGVkIGFuZCB3ZSBuZWVkIHRvIGNoYW5nZSB0aGUgc21vb3RoaW5nIHByb3BlcnR5IGZvciB0aGlzIHRleHR1cmVcbiAgICAgICAgaWYgKHJlbmRlcmVyLnNtb290aFByb3BlcnR5ICYmIHJlbmRlcmVyLnNjYWxlTW9kZSAhPT0gdGhpcy50ZXh0dXJlLmJhc2VUZXh0dXJlLnNjYWxlTW9kZSkge1xuICAgICAgICAgICAgcmVuZGVyZXIuc2NhbGVNb2RlID0gdGhpcy50ZXh0dXJlLmJhc2VUZXh0dXJlLnNjYWxlTW9kZTtcbiAgICAgICAgICAgIHJlbmRlcmVyLmNvbnRleHRbcmVuZGVyZXIuc21vb3RoUHJvcGVydHldID0gKHJlbmRlcmVyLnNjYWxlTW9kZSA9PT0gQ09OU1Quc2NhbGVNb2Rlcy5MSU5FQVIpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSWYgdGhlIHRleHR1cmUgaXMgdHJpbW1lZCB3ZSBvZmZzZXQgYnkgdGhlIHRyaW0geC95LCBvdGhlcndpc2Ugd2UgdXNlIHRoZSBmcmFtZSBkaW1lbnNpb25zXG4gICAgICAgIHZhciBkeCA9ICh0aGlzLnRleHR1cmUudHJpbSA/IHRoaXMudGV4dHVyZS50cmltLnggOiAwKSAtICh0aGlzLmFuY2hvci54ICogdGhpcy50ZXh0dXJlLnRyaW0ud2lkdGgpO1xuICAgICAgICB2YXIgZHkgPSAodGhpcy50ZXh0dXJlLnRyaW0gPyB0aGlzLnRleHR1cmUudHJpbS55IDogMCkgLSAodGhpcy5hbmNob3IueSAqIHRoaXMudGV4dHVyZS50cmltLmhlaWdodCk7XG5cbiAgICAgICAgLy8gQWxsb3cgZm9yIHBpeGVsIHJvdW5kaW5nXG4gICAgICAgIGlmIChyZW5kZXJlci5yb3VuZFBpeGVscykge1xuICAgICAgICAgICAgcmVuZGVyZXIuY29udGV4dC5zZXRUcmFuc2Zvcm0oXG4gICAgICAgICAgICAgICAgdGhpcy53b3JsZFRyYW5zZm9ybS5hLFxuICAgICAgICAgICAgICAgIHRoaXMud29ybGRUcmFuc2Zvcm0uYixcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkVHJhbnNmb3JtLmMsXG4gICAgICAgICAgICAgICAgdGhpcy53b3JsZFRyYW5zZm9ybS5kLFxuICAgICAgICAgICAgICAgICh0aGlzLndvcmxkVHJhbnNmb3JtLnR4ICogcmVuZGVyZXIucmVzb2x1dGlvbikgfCAwLFxuICAgICAgICAgICAgICAgICh0aGlzLndvcmxkVHJhbnNmb3JtLnR5ICogcmVuZGVyZXIucmVzb2x1dGlvbikgfCAwXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBkeCA9IGR4IHwgMDtcbiAgICAgICAgICAgIGR5ID0gZHkgfCAwO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmVuZGVyZXIuY29udGV4dC5zZXRUcmFuc2Zvcm0oXG4gICAgICAgICAgICAgICAgdGhpcy53b3JsZFRyYW5zZm9ybS5hLFxuICAgICAgICAgICAgICAgIHRoaXMud29ybGRUcmFuc2Zvcm0uYixcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkVHJhbnNmb3JtLmMsXG4gICAgICAgICAgICAgICAgdGhpcy53b3JsZFRyYW5zZm9ybS5kLFxuICAgICAgICAgICAgICAgIHRoaXMud29ybGRUcmFuc2Zvcm0udHggKiByZW5kZXJlci5yZXNvbHV0aW9uLFxuICAgICAgICAgICAgICAgIHRoaXMud29ybGRUcmFuc2Zvcm0udHkgKiByZW5kZXJlci5yZXNvbHV0aW9uXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMudGludCAhPT0gMHhGRkZGRkYpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLmNhY2hlZFRpbnQgIT09IHRoaXMudGludCkge1xuICAgICAgICAgICAgICAgIHRoaXMuY2FjaGVkVGludCA9IHRoaXMudGludDtcblxuICAgICAgICAgICAgICAgIC8vIFRPRE8gY2xlYW4gdXAgY2FjaGluZyAtIGhvdyB0byBjbGVhbiB1cCB0aGUgY2FjaGVzP1xuICAgICAgICAgICAgICAgIHRoaXMudGludGVkVGV4dHVyZSA9IENhbnZhc1RpbnRlci5nZXRUaW50ZWRUZXh0dXJlKHRoaXMsIHRoaXMudGludCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJlbmRlcmVyLmNvbnRleHQuZHJhd0ltYWdlKFxuICAgICAgICAgICAgICAgIHRoaXMudGludGVkVGV4dHVyZSxcbiAgICAgICAgICAgICAgICAwLFxuICAgICAgICAgICAgICAgIDAsXG4gICAgICAgICAgICAgICAgdGhpcy50ZXh0dXJlLmNyb3Aud2lkdGgsXG4gICAgICAgICAgICAgICAgdGhpcy50ZXh0dXJlLmNyb3AuaGVpZ2h0LFxuICAgICAgICAgICAgICAgIGR4IC8gcmVzb2x1dGlvbixcbiAgICAgICAgICAgICAgICBkeSAvIHJlc29sdXRpb24sXG4gICAgICAgICAgICAgICAgdGhpcy50ZXh0dXJlLmNyb3Aud2lkdGggLyByZXNvbHV0aW9uLFxuICAgICAgICAgICAgICAgIHRoaXMudGV4dHVyZS5jcm9wLmhlaWdodCAvIHJlc29sdXRpb25cbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZW5kZXJlci5jb250ZXh0LmRyYXdJbWFnZShcbiAgICAgICAgICAgICAgICB0aGlzLnRleHR1cmUuYmFzZVRleHR1cmUuc291cmNlLFxuICAgICAgICAgICAgICAgIHRoaXMudGV4dHVyZS5jcm9wLngsXG4gICAgICAgICAgICAgICAgdGhpcy50ZXh0dXJlLmNyb3AueSxcbiAgICAgICAgICAgICAgICB0aGlzLnRleHR1cmUuY3JvcC53aWR0aCxcbiAgICAgICAgICAgICAgICB0aGlzLnRleHR1cmUuY3JvcC5oZWlnaHQsXG4gICAgICAgICAgICAgICAgZHggLyByZXNvbHV0aW9uLFxuICAgICAgICAgICAgICAgIGR5IC8gcmVzb2x1dGlvbixcbiAgICAgICAgICAgICAgICB0aGlzLnRleHR1cmUuY3JvcC53aWR0aCAvIHJlc29sdXRpb24sXG4gICAgICAgICAgICAgICAgdGhpcy50ZXh0dXJlLmNyb3AuaGVpZ2h0IC8gcmVzb2x1dGlvblxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZvciAodmFyIGkgPSAwLCBqID0gdGhpcy5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyBpKyspIHtcbiAgICAgICAgdGhpcy5jaGlsZHJlbltpXS5yZW5kZXJDYW52YXMocmVuZGVyZXIpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLl9tYXNrKSB7XG4gICAgICAgIHJlbmRlcmVyLm1hc2tNYW5hZ2VyLnBvcE1hc2socmVuZGVyZXIpO1xuICAgIH1cbn07XG5cbi8vIHNvbWUgaGVscGVyIGZ1bmN0aW9ucy4uXG5cbi8qKlxuICogSGVscGVyIGZ1bmN0aW9uIHRoYXQgY3JlYXRlcyBhIHNwcml0ZSB0aGF0IHdpbGwgY29udGFpbiBhIHRleHR1cmUgZnJvbSB0aGUgVGV4dHVyZUNhY2hlIGJhc2VkIG9uIHRoZSBmcmFtZUlkXG4gKiBUaGUgZnJhbWUgaWRzIGFyZSBjcmVhdGVkIHdoZW4gYSBUZXh0dXJlIHBhY2tlciBmaWxlIGhhcyBiZWVuIGxvYWRlZFxuICpcbiAqIEBzdGF0aWNcbiAqIEBwYXJhbSBmcmFtZUlkIHtTdHJpbmd9IFRoZSBmcmFtZSBJZCBvZiB0aGUgdGV4dHVyZSBpbiB0aGUgY2FjaGVcbiAqIEByZXR1cm4ge1Nwcml0ZX0gQSBuZXcgU3ByaXRlIHVzaW5nIGEgdGV4dHVyZSBmcm9tIHRoZSB0ZXh0dXJlIGNhY2hlIG1hdGNoaW5nIHRoZSBmcmFtZUlkXG4gKi9cblNwcml0ZS5mcm9tRnJhbWUgPSBmdW5jdGlvbiAoZnJhbWVJZCkge1xuICAgIHZhciB0ZXh0dXJlID0gdXRpbHMuVGV4dHVyZUNhY2hlW2ZyYW1lSWRdO1xuXG4gICAgaWYgKCF0ZXh0dXJlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVGhlIGZyYW1lSWQgXCInICsgZnJhbWVJZCArICdcIiBkb2VzIG5vdCBleGlzdCBpbiB0aGUgdGV4dHVyZSBjYWNoZScgKyB0aGlzKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IFNwcml0ZSh0ZXh0dXJlKTtcbn07XG5cbi8qKlxuICogSGVscGVyIGZ1bmN0aW9uIHRoYXQgY3JlYXRlcyBhIHNwcml0ZSB0aGF0IHdpbGwgY29udGFpbiBhIHRleHR1cmUgYmFzZWQgb24gYW4gaW1hZ2UgdXJsXG4gKiBJZiB0aGUgaW1hZ2UgaXMgbm90IGluIHRoZSB0ZXh0dXJlIGNhY2hlIGl0IHdpbGwgYmUgbG9hZGVkXG4gKlxuICogQHN0YXRpY1xuICogQHBhcmFtIGltYWdlSWQge1N0cmluZ30gVGhlIGltYWdlIHVybCBvZiB0aGUgdGV4dHVyZVxuICogQHJldHVybiB7U3ByaXRlfSBBIG5ldyBTcHJpdGUgdXNpbmcgYSB0ZXh0dXJlIGZyb20gdGhlIHRleHR1cmUgY2FjaGUgbWF0Y2hpbmcgdGhlIGltYWdlIGlkXG4gKi9cblNwcml0ZS5mcm9tSW1hZ2UgPSBmdW5jdGlvbiAoaW1hZ2VJZCwgY3Jvc3NvcmlnaW4sIHNjYWxlTW9kZSkge1xuICAgIHJldHVybiBuZXcgU3ByaXRlKFRleHR1cmUuZnJvbUltYWdlKGltYWdlSWQsIGNyb3Nzb3JpZ2luLCBzY2FsZU1vZGUpKTtcbn07XG4iLCJ2YXIgRGlzcGxheU9iamVjdENvbnRhaW5lciA9IHJlcXVpcmUoJy4vRGlzcGxheU9iamVjdENvbnRhaW5lcicpLFxuICAgIFdlYkdMRmFzdFNwcml0ZUJhdGNoID0gcmVxdWlyZSgnLi4vcmVuZGVyZXJzL3dlYmdsL3V0aWxzL1dlYkdMRmFzdFNwcml0ZUJhdGNoJyk7XG5cbi8qKlxuICogVGhlIFNwcml0ZUJhdGNoIGNsYXNzIGlzIGEgcmVhbGx5IGZhc3QgdmVyc2lvbiBvZiB0aGUgRGlzcGxheU9iamVjdENvbnRhaW5lciBidWlsdCBzb2xlbHkgZm9yIHNwZWVkLFxuICogc28gdXNlIHdoZW4geW91IG5lZWQgYSBsb3Qgb2Ygc3ByaXRlcyBvciBwYXJ0aWNsZXMuIFRoZSB0cmFkZW9mZiBvZiB0aGUgU3ByaXRlQmF0Y2ggaXMgdGhhdCBhZHZhbmNlZFxuICogZnVuY3Rpb25hbGl0eSB3aWxsIG5vdCB3b3JrLiBTcHJpdGVCYXRjaCBpbXBsZW1lbnRzIG9ubHkgdGhlIGJhc2ljIG9iamVjdCB0cmFuc2Zvcm0gKHBvc2l0aW9uLCBzY2FsZSwgcm90YXRpb24pLlxuICogQW55IG90aGVyIGZ1bmN0aW9uYWxpdHkgbGlrZSB0aW50aW5nLCBtYXNraW5nLCBldGMgd2lsbCBub3Qgd29yayBvbiBzcHJpdGVzIGluIHRoaXMgYmF0Y2guXG4gKlxuICogSXQncyBleHRyZW1lbHkgZWFzeSB0byB1c2UgOlxuICpcbiAqIGBgYGpzXG4gKiB2YXIgY29udGFpbmVyID0gbmV3IFNwcml0ZUJhdGNoKCk7XG4gKlxuICogZm9yKHZhciBpID0gMDsgaSA8IDEwMDsgKytpKSB7XG4gKiAgICAgdmFyIHNwcml0ZSA9IG5ldyBQSVhJLlNwcml0ZS5mcm9tSW1hZ2UoXCJteUltYWdlLnBuZ1wiKTtcbiAqICAgICBjb250YWluZXIuYWRkQ2hpbGQoc3ByaXRlKTtcbiAqIH1cbiAqIGBgYFxuICpcbiAqIEFuZCBoZXJlIHlvdSBoYXZlIGEgaHVuZHJlZCBzcHJpdGVzIHRoYXQgd2lsbCBiZSByZW5kZXJlciBhdCB0aGUgc3BlZWQgb2YgbGlnaHQuXG4gKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuXG4vL1RPRE8gUkVOQU1FIHRvIFBBUlRJQ0xFIENPTlRBSU5FUj9cbmZ1bmN0aW9uIFNwcml0ZUJhdGNoKCkge1xuICAgIERpc3BsYXlPYmplY3RDb250YWluZXIuY2FsbCh0aGlzKTtcbn1cblxuU3ByaXRlQmF0Y2gucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShEaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZSk7XG5TcHJpdGVCYXRjaC5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBTcHJpdGVCYXRjaDtcbm1vZHVsZS5leHBvcnRzID0gU3ByaXRlQmF0Y2g7XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgb2JqZWN0IHRyYW5zZm9ybSBmb3IgcmVuZGVyaW5nXG4gKlxuICogQHByaXZhdGVcbiAqL1xuU3ByaXRlQmF0Y2gucHJvdG90eXBlLnVwZGF0ZVRyYW5zZm9ybSA9IGZ1bmN0aW9uICgpIHtcbiAgICAvLyBUT0RPIGRvbid0IG5lZWQgdG8hXG4gICAgdGhpcy5kaXNwbGF5T2JqZWN0VXBkYXRlVHJhbnNmb3JtKCk7XG4gICAgLy8gIFBJWEkuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUudXBkYXRlVHJhbnNmb3JtLmNhbGwoIHRoaXMgKTtcbn07XG5cbi8qKlxuICogUmVuZGVycyB0aGUgb2JqZWN0IHVzaW5nIHRoZSBXZWJHTCByZW5kZXJlclxuICpcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcn0gVGhlIHdlYmdsIHJlbmRlcmVyXG4gKiBAcHJpdmF0ZVxuICovXG5TcHJpdGVCYXRjaC5wcm90b3R5cGUucmVuZGVyV2ViR0wgPSBmdW5jdGlvbiAocmVuZGVyZXIpIHtcbiAgICBpZiAoIXRoaXMudmlzaWJsZSB8fCB0aGlzLmFscGhhIDw9IDAgfHwgIXRoaXMuY2hpbGRyZW4ubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5zdG9wKCk7XG5cbiAgICByZW5kZXJlci5zaGFkZXJNYW5hZ2VyLnNldFNoYWRlcihyZW5kZXJlci5zaGFkZXJNYW5hZ2VyLmZhc3RTaGFkZXIpO1xuXG4gICAgcmVuZGVyZXIuZmFzdFNwcml0ZUJhdGNoLmJlZ2luKHRoaXMpO1xuICAgIHJlbmRlcmVyLmZhc3RTcHJpdGVCYXRjaC5yZW5kZXIodGhpcyk7XG5cbiAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5zdGFydCgpO1xufTtcblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBvYmplY3QgdXNpbmcgdGhlIENhbnZhcyByZW5kZXJlclxuICpcbiAqIEBwYXJhbSByZW5kZXJlciB7Q2FudmFzUmVuZGVyZXJ9IFRoZSBjYW52YXMgcmVuZGVyZXJcbiAqIEBwcml2YXRlXG4gKi9cblNwcml0ZUJhdGNoLnByb3RvdHlwZS5yZW5kZXJDYW52YXMgPSBmdW5jdGlvbiAocmVuZGVyZXIpIHtcbiAgICBpZiAoIXRoaXMudmlzaWJsZSB8fCB0aGlzLmFscGhhIDw9IDAgfHwgIXRoaXMuY2hpbGRyZW4ubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgY29udGV4dCA9IHJlbmRlcmVyLmNvbnRleHQ7XG4gICAgdmFyIHRyYW5zZm9ybSA9IHRoaXMud29ybGRUcmFuc2Zvcm07XG4gICAgdmFyIGlzUm90YXRlZCA9IHRydWU7XG5cbiAgICBjb250ZXh0Lmdsb2JhbEFscGhhID0gdGhpcy53b3JsZEFscGhhO1xuXG4gICAgdGhpcy5kaXNwbGF5T2JqZWN0VXBkYXRlVHJhbnNmb3JtKCk7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgdmFyIGNoaWxkID0gdGhpcy5jaGlsZHJlbltpXTtcblxuICAgICAgICBpZiAoIWNoaWxkLnZpc2libGUpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGZyYW1lID0gY2hpbGQudGV4dHVyZS5mcmFtZTtcblxuICAgICAgICBjb250ZXh0Lmdsb2JhbEFscGhhID0gdGhpcy53b3JsZEFscGhhICogY2hpbGQuYWxwaGE7XG5cbiAgICAgICAgaWYgKGNoaWxkLnJvdGF0aW9uICUgKE1hdGguUEkgKiAyKSA9PT0gMCkge1xuICAgICAgICAgICAgLy8gdGhpcyBpcyB0aGUgZmFzdGVzdCAgd2F5IHRvIG9wdGltaXNlISAtIGlmIHJvdGF0aW9uIGlzIDAgdGhlbiB3ZSBjYW4gYXZvaWQgYW55IGtpbmQgb2Ygc2V0VHJhbnNmb3JtIGNhbGxcbiAgICAgICAgICAgIGlmIChpc1JvdGF0ZWQpIHtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnNldFRyYW5zZm9ybShcbiAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtLmEsXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybS5iLFxuICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0uYyxcbiAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtLmQsXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybS50eCxcbiAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtLnR5XG4gICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgIGlzUm90YXRlZCA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb250ZXh0LmRyYXdJbWFnZShcbiAgICAgICAgICAgICAgICBjaGlsZC50ZXh0dXJlLmJhc2VUZXh0dXJlLnNvdXJjZSxcbiAgICAgICAgICAgICAgICBmcmFtZS54LFxuICAgICAgICAgICAgICAgIGZyYW1lLnksXG4gICAgICAgICAgICAgICAgZnJhbWUud2lkdGgsXG4gICAgICAgICAgICAgICAgZnJhbWUuaGVpZ2h0LFxuICAgICAgICAgICAgICAgICgoY2hpbGQuYW5jaG9yLngpICogKC1mcmFtZS53aWR0aCAqIGNoaWxkLnNjYWxlLngpICsgY2hpbGQucG9zaXRpb24ueCAgKyAwLjUpIHwgMCxcbiAgICAgICAgICAgICAgICAoKGNoaWxkLmFuY2hvci55KSAqICgtZnJhbWUuaGVpZ2h0ICogY2hpbGQuc2NhbGUueSkgKyBjaGlsZC5wb3NpdGlvbi55ICArIDAuNSkgfCAwLFxuICAgICAgICAgICAgICAgIGZyYW1lLndpZHRoICogY2hpbGQuc2NhbGUueCxcbiAgICAgICAgICAgICAgICBmcmFtZS5oZWlnaHQgKiBjaGlsZC5zY2FsZS55XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgaWYgKCFpc1JvdGF0ZWQpIHtcbiAgICAgICAgICAgICAgICBpc1JvdGF0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjaGlsZC5kaXNwbGF5T2JqZWN0VXBkYXRlVHJhbnNmb3JtKCk7XG5cbiAgICAgICAgICAgIHZhciBjaGlsZFRyYW5zZm9ybSA9IGNoaWxkLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgICAgICAgICBpZiAocmVuZGVyZXIucm91bmRQaXhlbHMpIHtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnNldFRyYW5zZm9ybShcbiAgICAgICAgICAgICAgICAgICAgY2hpbGRUcmFuc2Zvcm0uYSxcbiAgICAgICAgICAgICAgICAgICAgY2hpbGRUcmFuc2Zvcm0uYixcbiAgICAgICAgICAgICAgICAgICAgY2hpbGRUcmFuc2Zvcm0uYyxcbiAgICAgICAgICAgICAgICAgICAgY2hpbGRUcmFuc2Zvcm0uZCxcbiAgICAgICAgICAgICAgICAgICAgY2hpbGRUcmFuc2Zvcm0udHggfCAwLFxuICAgICAgICAgICAgICAgICAgICBjaGlsZFRyYW5zZm9ybS50eSB8IDBcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5zZXRUcmFuc2Zvcm0oXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkVHJhbnNmb3JtLmEsXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkVHJhbnNmb3JtLmIsXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkVHJhbnNmb3JtLmMsXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkVHJhbnNmb3JtLmQsXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkVHJhbnNmb3JtLnR4LFxuICAgICAgICAgICAgICAgICAgICBjaGlsZFRyYW5zZm9ybS50eVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnRleHQuZHJhd0ltYWdlKFxuICAgICAgICAgICAgICAgIGNoaWxkLnRleHR1cmUuYmFzZVRleHR1cmUuc291cmNlLFxuICAgICAgICAgICAgICAgIGZyYW1lLngsXG4gICAgICAgICAgICAgICAgZnJhbWUueSxcbiAgICAgICAgICAgICAgICBmcmFtZS53aWR0aCxcbiAgICAgICAgICAgICAgICBmcmFtZS5oZWlnaHQsXG4gICAgICAgICAgICAgICAgKChjaGlsZC5hbmNob3IueCkgKiAoLWZyYW1lLndpZHRoKSArIDAuNSkgfCAwLFxuICAgICAgICAgICAgICAgICgoY2hpbGQuYW5jaG9yLnkpICogKC1mcmFtZS5oZWlnaHQpICsgMC41KSB8IDAsXG4gICAgICAgICAgICAgICAgZnJhbWUud2lkdGgsXG4gICAgICAgICAgICAgICAgZnJhbWUuaGVpZ2h0XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxufTtcbiIsIi8qKlxuICogQGZpbGUgICAgICAgIE1haW4gZXhwb3J0IG9mIHRoZSBQSVhJIGNvcmUgbGlicmFyeVxuICogQGF1dGhvciAgICAgIE1hdCBHcm92ZXMgPG1hdEBnb29kYm95ZGlnaXRhbC5jb20+XG4gKiBAY29weXJpZ2h0ICAgMjAxMy0yMDE1IEdvb2RCb3lEaWdpdGFsXG4gKiBAbGljZW5zZSAgICAge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9Hb29kQm95RGlnaXRhbC9waXhpLmpzL2Jsb2IvbWFzdGVyL0xJQ0VOU0V8TUlUIExpY2Vuc2V9XG4gKi9cblxuLyoqXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xudmFyIGNvcmUgPSBtb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBDT05TVDogcmVxdWlyZSgnLi9jb25zdCcpLFxuXG4gICAgLy8gdXRpbHNcbiAgICB1dGlsczogcmVxdWlyZSgnLi91dGlscycpLFxuICAgIG1hdGg6IHJlcXVpcmUoJy4vbWF0aCcpLFxuXG4gICAgLy8gZGlzcGxheVxuICAgIERpc3BsYXlPYmplY3Q6ICAgICAgICAgIHJlcXVpcmUoJy4vZGlzcGxheS9EaXNwbGF5T2JqZWN0JyksXG4gICAgRGlzcGxheU9iamVjdENvbnRhaW5lcjogcmVxdWlyZSgnLi9kaXNwbGF5L0Rpc3BsYXlPYmplY3RDb250YWluZXInKSxcbiAgICBTcHJpdGU6ICAgICAgICAgICAgICAgICByZXF1aXJlKCcuL2Rpc3BsYXkvU3ByaXRlJyksXG4gICAgU3ByaXRlQmF0Y2g6ICAgICAgICAgICAgcmVxdWlyZSgnLi9kaXNwbGF5L1Nwcml0ZUJhdGNoJyksXG5cbiAgICAvLyBwcmltaXRpdmVzXG4gICAgR3JhcGhpY3M6ICAgICAgICAgICAgICAgcmVxdWlyZSgnLi9wcmltaXRpdmVzL0dyYXBoaWNzJyksXG4gICAgR3JhcGhpY3NEYXRhOiAgICAgICAgICAgcmVxdWlyZSgnLi9wcmltaXRpdmVzL0dyYXBoaWNzRGF0YScpLFxuXG4gICAgLy8gdGV4dHVyZXNcbiAgICBUZXh0dXJlOiAgICAgICAgICAgICAgICByZXF1aXJlKCcuL3RleHR1cmVzL1RleHR1cmUnKSxcbiAgICBCYXNlVGV4dHVyZTogICAgICAgICAgICByZXF1aXJlKCcuL3RleHR1cmVzL0Jhc2VUZXh0dXJlJyksXG4gICAgUmVuZGVyVGV4dHVyZTogICAgICAgICAgcmVxdWlyZSgnLi90ZXh0dXJlcy9SZW5kZXJUZXh0dXJlJyksXG4gICAgVmlkZW9CYXNlVGV4dHVyZTogICAgICAgcmVxdWlyZSgnLi90ZXh0dXJlcy9WaWRlb0Jhc2VUZXh0dXJlJyksXG5cbiAgICAvLyByZW5kZXJlcnMgLSBjYW52YXNcbiAgICBDYW52YXNSZW5kZXJlcjogICAgICAgICByZXF1aXJlKCcuL3JlbmRlcmVycy9jYW52YXMvQ2FudmFzUmVuZGVyZXInKSxcbiAgICBDYW52YXNHcmFwaGljczogICAgICAgICByZXF1aXJlKCcuL3JlbmRlcmVycy9jYW52YXMvdXRpbHMvQ2FudmFzR3JhcGhpY3MnKSxcbiAgICBDYW52YXNCdWZmZXI6ICAgICAgICAgICByZXF1aXJlKCcuL3JlbmRlcmVycy9jYW52YXMvdXRpbHMvQ2FudmFzQnVmZmVyJyksXG5cbiAgICAvLyByZW5kZXJlcnMgLSB3ZWJnbFxuICAgIFdlYkdMUmVuZGVyZXI6ICAgICAgICAgcmVxdWlyZSgnLi9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xSZW5kZXJlcicpLFxuICAgIFdlYkdMR3JhcGhpY3M6ICAgICAgICAgcmVxdWlyZSgnLi9yZW5kZXJlcnMvd2ViZ2wvdXRpbHMvV2ViR0xHcmFwaGljcycpLFxuXG4gICAgLyoqXG4gICAgICogVGhpcyBoZWxwZXIgZnVuY3Rpb24gd2lsbCBhdXRvbWF0aWNhbGx5IGRldGVjdCB3aGljaCByZW5kZXJlciB5b3Ugc2hvdWxkIGJlIHVzaW5nLlxuICAgICAqIFdlYkdMIGlzIHRoZSBwcmVmZXJyZWQgcmVuZGVyZXIgYXMgaXQgaXMgYSBsb3QgZmFzdGVyLiBJZiB3ZWJHTCBpcyBub3Qgc3VwcG9ydGVkIGJ5XG4gICAgICogdGhlIGJyb3dzZXIgdGhlbiB0aGlzIGZ1bmN0aW9uIHdpbGwgcmV0dXJuIGEgY2FudmFzIHJlbmRlcmVyXG4gICAgICpcbiAgICAgKiBAcGFyYW0gd2lkdGg9ODAwIHtudW1iZXJ9IHRoZSB3aWR0aCBvZiB0aGUgcmVuZGVyZXJzIHZpZXdcbiAgICAgKiBAcGFyYW0gaGVpZ2h0PTYwMCB7bnVtYmVyfSB0aGUgaGVpZ2h0IG9mIHRoZSByZW5kZXJlcnMgdmlld1xuICAgICAqIEBwYXJhbSBbb3B0aW9uc10ge29iamVjdH0gVGhlIG9wdGlvbmFsIHJlbmRlcmVyIHBhcmFtZXRlcnNcbiAgICAgKiBAcGFyYW0gW29wdGlvbnMudmlld10ge0hUTUxDYW52YXNFbGVtZW50fSB0aGUgY2FudmFzIHRvIHVzZSBhcyBhIHZpZXcsIG9wdGlvbmFsXG4gICAgICogQHBhcmFtIFtvcHRpb25zLnRyYW5zcGFyZW50PWZhbHNlXSB7Ym9vbGVhbn0gSWYgdGhlIHJlbmRlciB2aWV3IGlzIHRyYW5zcGFyZW50LCBkZWZhdWx0IGZhbHNlXG4gICAgICogQHBhcmFtIFtvcHRpb25zLmFudGlhbGlhcz1mYWxzZV0ge2Jvb2xlYW59IHNldHMgYW50aWFsaWFzIChvbmx5IGFwcGxpY2FibGUgaW4gY2hyb21lIGF0IHRoZSBtb21lbnQpXG4gICAgICogQHBhcmFtIFtvcHRpb25zLnByZXNlcnZlRHJhd2luZ0J1ZmZlcj1mYWxzZV0ge2Jvb2xlYW59IGVuYWJsZXMgZHJhd2luZyBidWZmZXIgcHJlc2VydmF0aW9uLCBlbmFibGUgdGhpcyBpZiB5b3VcbiAgICAgKiAgICAgIG5lZWQgdG8gY2FsbCB0b0RhdGFVcmwgb24gdGhlIHdlYmdsIGNvbnRleHRcbiAgICAgKiBAcGFyYW0gW29wdGlvbnMucmVzb2x1dGlvbj0xXSB7bnVtYmVyfSB0aGUgcmVzb2x1dGlvbiBvZiB0aGUgcmVuZGVyZXIgcmV0aW5hIHdvdWxkIGJlIDJcbiAgICAgKiBAcGFyYW0gW25vV2ViR0w9ZmFsc2VdIHtCb29sZWFufSBwcmV2ZW50cyBzZWxlY3Rpb24gb2YgV2ViR0wgcmVuZGVyZXIsIGV2ZW4gaWYgc3VjaCBpcyBwcmVzZW50XG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHtXZWJHTFJlbmRlcmVyfENhbnZhc1JlbmRlcmVyfSBSZXR1cm5zIFdlYkdMIHJlbmRlcmVyIGlmIGF2YWlsYWJsZSwgb3RoZXJ3aXNlIENhbnZhc1JlbmRlcmVyXG4gICAgICovXG4gICAgYXV0b0RldGVjdFJlbmRlcmVyOiBmdW5jdGlvbiAod2lkdGgsIGhlaWdodCwgb3B0aW9ucywgbm9XZWJHTCkge1xuICAgICAgICB3aWR0aCA9IHdpZHRoIHx8IDgwMDtcbiAgICAgICAgaGVpZ2h0ID0gaGVpZ2h0IHx8IDYwMDtcblxuICAgICAgICBpZiAoIW5vV2ViR0wgJiYgcmVxdWlyZSgnd2ViZ2wtZW5hYmxlZCcpKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgY29yZS5XZWJHTFJlbmRlcmVyKHdpZHRoLCBoZWlnaHQsIG9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5ldyBjb3JlLkNhbnZhc1JlbmRlcmVyKHdpZHRoLCBoZWlnaHQsIG9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGlzIGhlbHBlciBmdW5jdGlvbiB3aWxsIGF1dG9tYXRpY2FsbHkgZGV0ZWN0IHdoaWNoIHJlbmRlcmVyIHlvdSBzaG91bGQgYmUgdXNpbmcuIFRoaXMgZnVuY3Rpb24gaXMgdmVyeVxuICAgICAqIHNpbWlsYXIgdG8gdGhlIGF1dG9EZXRlY3RSZW5kZXJlciBmdW5jdGlvbiBleGNlcHQgdGhhdCBpcyB3aWxsIHJldHVybiBhIGNhbnZhcyByZW5kZXJlciBmb3IgYW5kcm9pZC5cbiAgICAgKiBFdmVuIHRob3VnaHQgYm90aCBhbmRyb2lkIGNocm9tZSBzdXBwb3J0cyB3ZWJHTCB0aGUgY2FudmFzIGltcGxlbWVudGF0aW9uIHBlcmZvcm0gYmV0dGVyIGF0IHRoZSB0aW1lIG9mIHdyaXRpbmcuXG4gICAgICogVGhpcyBmdW5jdGlvbiB3aWxsIGxpa2VseSBjaGFuZ2UgYW5kIHVwZGF0ZSBhcyB3ZWJHTCBwZXJmb3JtYW5jZSBpbXByb3ZlcyBvbiB0aGVzZSBkZXZpY2VzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHdpZHRoPTgwMCB7bnVtYmVyfSB0aGUgd2lkdGggb2YgdGhlIHJlbmRlcmVycyB2aWV3XG4gICAgICogQHBhcmFtIGhlaWdodD02MDAge251bWJlcn0gdGhlIGhlaWdodCBvZiB0aGUgcmVuZGVyZXJzIHZpZXdcbiAgICAgKiBAcGFyYW0gW29wdGlvbnNdIHtvYmplY3R9IFRoZSBvcHRpb25hbCByZW5kZXJlciBwYXJhbWV0ZXJzXG4gICAgICogQHBhcmFtIFtvcHRpb25zLnZpZXddIHtIVE1MQ2FudmFzRWxlbWVudH0gdGhlIGNhbnZhcyB0byB1c2UgYXMgYSB2aWV3LCBvcHRpb25hbFxuICAgICAqIEBwYXJhbSBbb3B0aW9ucy50cmFuc3BhcmVudD1mYWxzZV0ge2Jvb2xlYW59IElmIHRoZSByZW5kZXIgdmlldyBpcyB0cmFuc3BhcmVudCwgZGVmYXVsdCBmYWxzZVxuICAgICAqIEBwYXJhbSBbb3B0aW9ucy5hbnRpYWxpYXM9ZmFsc2VdIHtib29sZWFufSBzZXRzIGFudGlhbGlhcyAob25seSBhcHBsaWNhYmxlIGluIGNocm9tZSBhdCB0aGUgbW9tZW50KVxuICAgICAqIEBwYXJhbSBbb3B0aW9ucy5wcmVzZXJ2ZURyYXdpbmdCdWZmZXI9ZmFsc2VdIHtib29sZWFufSBlbmFibGVzIGRyYXdpbmcgYnVmZmVyIHByZXNlcnZhdGlvbiwgZW5hYmxlIHRoaXMgaWYgeW91XG4gICAgICogICAgICBuZWVkIHRvIGNhbGwgdG9EYXRhVXJsIG9uIHRoZSB3ZWJnbCBjb250ZXh0XG4gICAgICogQHBhcmFtIFtvcHRpb25zLnJlc29sdXRpb249MV0ge251bWJlcn0gdGhlIHJlc29sdXRpb24gb2YgdGhlIHJlbmRlcmVyIHJldGluYSB3b3VsZCBiZSAyXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHtXZWJHTFJlbmRlcmVyfENhbnZhc1JlbmRlcmVyfSBSZXR1cm5zIFdlYkdMIHJlbmRlcmVyIGlmIGF2YWlsYWJsZSwgb3RoZXJ3aXNlIENhbnZhc1JlbmRlcmVyXG4gICAgICovXG4gICAgYXV0b0RldGVjdFJlY29tbWVuZGVkUmVuZGVyZXI6IGZ1bmN0aW9uICh3aWR0aCwgaGVpZ2h0LCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBpc0FuZHJvaWQgPSAvQW5kcm9pZC9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCk7XG5cbiAgICAgICAgcmV0dXJuIGNvcmUuYXV0b0RldGVjdFJlbmRlcmVyKHdpZHRoLCBoZWlnaHQsIG9wdGlvbnMsIGlzQW5kcm9pZCk7XG4gICAgfVxufTtcbiIsInZhciBQb2ludCA9IHJlcXVpcmUoJy4vUG9pbnQnKTtcblxuLyoqXG4gKiBUaGUgTWF0cml4IGNsYXNzIGlzIG5vdyBhbiBvYmplY3QsIHdoaWNoIG1ha2VzIGl0IGEgbG90IGZhc3RlcixcbiAqIGhlcmUgaXMgYSByZXByZXNlbnRhdGlvbiBvZiBpdCA6XG4gKiB8IGEgfCBiIHwgdHh8XG4gKiB8IGMgfCBkIHwgdHl8XG4gKiB8IDAgfCAwIHwgMSB8XG4gKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gTWF0cml4KCkge1xuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAxXG4gICAgICovXG4gICAgdGhpcy5hID0gMTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy5iID0gMDtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy5jID0gMDtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAxXG4gICAgICovXG4gICAgdGhpcy5kID0gMTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy50eCA9IDA7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMudHkgPSAwO1xufVxuXG5NYXRyaXgucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gTWF0cml4O1xubW9kdWxlLmV4cG9ydHMgPSBNYXRyaXg7XG5cbi8qKlxuICogQ3JlYXRlcyBhIE1hdHJpeCBvYmplY3QgYmFzZWQgb24gdGhlIGdpdmVuIGFycmF5LiBUaGUgRWxlbWVudCB0byBNYXRyaXggbWFwcGluZyBvcmRlciBpcyBhcyBmb2xsb3dzOlxuICpcbiAqIGEgPSBhcnJheVswXVxuICogYiA9IGFycmF5WzFdXG4gKiBjID0gYXJyYXlbM11cbiAqIGQgPSBhcnJheVs0XVxuICogdHggPSBhcnJheVsyXVxuICogdHkgPSBhcnJheVs1XVxuICpcbiAqIEBwYXJhbSBhcnJheSB7bnVtYmVyW119IFRoZSBhcnJheSB0aGF0IHRoZSBtYXRyaXggd2lsbCBiZSBwb3B1bGF0ZWQgZnJvbS5cbiAqL1xuTWF0cml4LnByb3RvdHlwZS5mcm9tQXJyYXkgPSBmdW5jdGlvbiAoYXJyYXkpIHtcbiAgICB0aGlzLmEgPSBhcnJheVswXTtcbiAgICB0aGlzLmIgPSBhcnJheVsxXTtcbiAgICB0aGlzLmMgPSBhcnJheVszXTtcbiAgICB0aGlzLmQgPSBhcnJheVs0XTtcbiAgICB0aGlzLnR4ID0gYXJyYXlbMl07XG4gICAgdGhpcy50eSA9IGFycmF5WzVdO1xufTtcblxuLyoqXG4gKiBDcmVhdGVzIGFuIGFycmF5IGZyb20gdGhlIGN1cnJlbnQgTWF0cml4IG9iamVjdC5cbiAqXG4gKiBAcGFyYW0gdHJhbnNwb3NlIHtib29sZWFufSBXaGV0aGVyIHdlIG5lZWQgdG8gdHJhbnNwb3NlIHRoZSBtYXRyaXggb3Igbm90XG4gKiBAcmV0dXJuIHtudW1iZXJbXX0gdGhlIG5ld2x5IGNyZWF0ZWQgYXJyYXkgd2hpY2ggY29udGFpbnMgdGhlIG1hdHJpeFxuICovXG5NYXRyaXgucHJvdG90eXBlLnRvQXJyYXkgPSBmdW5jdGlvbiAodHJhbnNwb3NlKSB7XG4gICAgaWYgKCF0aGlzLmFycmF5KSB7XG4gICAgICAgIHRoaXMuYXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KDkpO1xuICAgIH1cblxuICAgIHZhciBhcnJheSA9IHRoaXMuYXJyYXk7XG5cbiAgICBpZiAodHJhbnNwb3NlKSB7XG4gICAgICAgIGFycmF5WzBdID0gdGhpcy5hO1xuICAgICAgICBhcnJheVsxXSA9IHRoaXMuYjtcbiAgICAgICAgYXJyYXlbMl0gPSAwO1xuICAgICAgICBhcnJheVszXSA9IHRoaXMuYztcbiAgICAgICAgYXJyYXlbNF0gPSB0aGlzLmQ7XG4gICAgICAgIGFycmF5WzVdID0gMDtcbiAgICAgICAgYXJyYXlbNl0gPSB0aGlzLnR4O1xuICAgICAgICBhcnJheVs3XSA9IHRoaXMudHk7XG4gICAgICAgIGFycmF5WzhdID0gMTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGFycmF5WzBdID0gdGhpcy5hO1xuICAgICAgICBhcnJheVsxXSA9IHRoaXMuYztcbiAgICAgICAgYXJyYXlbMl0gPSB0aGlzLnR4O1xuICAgICAgICBhcnJheVszXSA9IHRoaXMuYjtcbiAgICAgICAgYXJyYXlbNF0gPSB0aGlzLmQ7XG4gICAgICAgIGFycmF5WzVdID0gdGhpcy50eTtcbiAgICAgICAgYXJyYXlbNl0gPSAwO1xuICAgICAgICBhcnJheVs3XSA9IDA7XG4gICAgICAgIGFycmF5WzhdID0gMTtcbiAgICB9XG5cbiAgICByZXR1cm4gYXJyYXk7XG59O1xuXG4vKipcbiAqIEdldCBhIG5ldyBwb3NpdGlvbiB3aXRoIHRoZSBjdXJyZW50IHRyYW5zZm9ybWF0aW9uIGFwcGxpZWQuXG4gKiBDYW4gYmUgdXNlZCB0byBnbyBmcm9tIGEgY2hpbGQncyBjb29yZGluYXRlIHNwYWNlIHRvIHRoZSB3b3JsZCBjb29yZGluYXRlIHNwYWNlLiAoZS5nLiByZW5kZXJpbmcpXG4gKlxuICogQHBhcmFtIHBvcyB7UG9pbnR9IFRoZSBvcmlnaW5cbiAqIEBwYXJhbSBbbmV3UG9zXSB7UG9pbnR9IFRoZSBwb2ludCB0aGF0IHRoZSBuZXcgcG9zaXRpb24gaXMgYXNzaWduZWQgdG8gKGFsbG93ZWQgdG8gYmUgc2FtZSBhcyBpbnB1dClcbiAqIEByZXR1cm4ge1BvaW50fSBUaGUgbmV3IHBvaW50LCB0cmFuc2Zvcm1lZCB0aHJvdWdoIHRoaXMgbWF0cml4XG4gKi9cbk1hdHJpeC5wcm90b3R5cGUuYXBwbHkgPSBmdW5jdGlvbiAocG9zLCBuZXdQb3MpIHtcbiAgICBuZXdQb3MgPSBuZXdQb3MgfHwgbmV3IFBvaW50KCk7XG5cbiAgICBuZXdQb3MueCA9IHRoaXMuYSAqIHBvcy54ICsgdGhpcy5jICogcG9zLnkgKyB0aGlzLnR4O1xuICAgIG5ld1Bvcy55ID0gdGhpcy5iICogcG9zLnggKyB0aGlzLmQgKiBwb3MueSArIHRoaXMudHk7XG5cbiAgICByZXR1cm4gbmV3UG9zO1xufTtcblxuLyoqXG4gKiBHZXQgYSBuZXcgcG9zaXRpb24gd2l0aCB0aGUgaW52ZXJzZSBvZiB0aGUgY3VycmVudCB0cmFuc2Zvcm1hdGlvbiBhcHBsaWVkLlxuICogQ2FuIGJlIHVzZWQgdG8gZ28gZnJvbSB0aGUgd29ybGQgY29vcmRpbmF0ZSBzcGFjZSB0byBhIGNoaWxkJ3MgY29vcmRpbmF0ZSBzcGFjZS4gKGUuZy4gaW5wdXQpXG4gKlxuICogQHBhcmFtIHBvcyB7UG9pbnR9IFRoZSBvcmlnaW5cbiAqIEBwYXJhbSBbbmV3UG9zXSB7UG9pbnR9IFRoZSBwb2ludCB0aGF0IHRoZSBuZXcgcG9zaXRpb24gaXMgYXNzaWduZWQgdG8gKGFsbG93ZWQgdG8gYmUgc2FtZSBhcyBpbnB1dClcbiAqIEByZXR1cm4ge1BvaW50fSBUaGUgbmV3IHBvaW50LCBpbnZlcnNlLXRyYW5zZm9ybWVkIHRocm91Z2ggdGhpcyBtYXRyaXhcbiAqL1xuTWF0cml4LnByb3RvdHlwZS5hcHBseUludmVyc2UgPSBmdW5jdGlvbiAocG9zLCBuZXdQb3MpIHtcbiAgICBuZXdQb3MgPSBuZXdQb3MgfHwgbmV3IFBvaW50KCk7XG5cbiAgICB2YXIgaWQgPSAxIC8gKHRoaXMuYSAqIHRoaXMuZCArIHRoaXMuYyAqIC10aGlzLmIpO1xuXG4gICAgbmV3UG9zLnggPSB0aGlzLmQgKiBpZCAqIHBvcy54ICsgLXRoaXMuYyAqIGlkICogcG9zLnkgKyAodGhpcy50eSAqIHRoaXMuYyAtIHRoaXMudHggKiB0aGlzLmQpICogaWQ7XG4gICAgbmV3UG9zLnkgPSB0aGlzLmEgKiBpZCAqIHBvcy55ICsgLXRoaXMuYiAqIGlkICogcG9zLnggKyAoLXRoaXMudHkgKiB0aGlzLmEgKyB0aGlzLnR4ICogdGhpcy5iKSAqIGlkO1xuXG4gICAgcmV0dXJuIG5ld1Bvcztcbn07XG5cbi8qKlxuICogVHJhbnNsYXRlcyB0aGUgbWF0cml4IG9uIHRoZSB4IGFuZCB5LlxuICpcbiAqIEBwYXJhbSB7bnVtYmVyfSB4XG4gKiBAcGFyYW0ge251bWJlcn0geVxuICogQHJldHVybiB7TWF0cml4fSBUaGlzIG1hdHJpeC4gR29vZCBmb3IgY2hhaW5pbmcgbWV0aG9kIGNhbGxzLlxuICovXG5NYXRyaXgucHJvdG90eXBlLnRyYW5zbGF0ZSA9IGZ1bmN0aW9uICh4LCB5KSB7XG4gICAgdGhpcy50eCArPSB4O1xuICAgIHRoaXMudHkgKz0geTtcblxuICAgIHJldHVybiB0aGlzO1xufTtcblxuLyoqXG4gKiBBcHBsaWVzIGEgc2NhbGUgdHJhbnNmb3JtYXRpb24gdG8gdGhlIG1hdHJpeC5cbiAqXG4gKiBAcGFyYW0ge251bWJlcn0geCBUaGUgYW1vdW50IHRvIHNjYWxlIGhvcml6b250YWxseVxuICogQHBhcmFtIHtudW1iZXJ9IHkgVGhlIGFtb3VudCB0byBzY2FsZSB2ZXJ0aWNhbGx5XG4gKiBAcmV0dXJuIHtNYXRyaXh9IFRoaXMgbWF0cml4LiBHb29kIGZvciBjaGFpbmluZyBtZXRob2QgY2FsbHMuXG4gKi9cbk1hdHJpeC5wcm90b3R5cGUuc2NhbGUgPSBmdW5jdGlvbiAoeCwgeSkge1xuICAgIHRoaXMuYSAqPSB4O1xuICAgIHRoaXMuZCAqPSB5O1xuICAgIHRoaXMuYyAqPSB4O1xuICAgIHRoaXMuYiAqPSB5O1xuICAgIHRoaXMudHggKj0geDtcbiAgICB0aGlzLnR5ICo9IHk7XG5cbiAgICByZXR1cm4gdGhpcztcbn07XG5cblxuLyoqXG4gKiBBcHBsaWVzIGEgcm90YXRpb24gdHJhbnNmb3JtYXRpb24gdG8gdGhlIG1hdHJpeC5cbiAqXG4gKiBAcGFyYW0ge251bWJlcn0gYW5nbGUgLSBUaGUgYW5nbGUgaW4gcmFkaWFucy5cbiAqIEByZXR1cm4ge01hdHJpeH0gVGhpcyBtYXRyaXguIEdvb2QgZm9yIGNoYWluaW5nIG1ldGhvZCBjYWxscy5cbiAqL1xuTWF0cml4LnByb3RvdHlwZS5yb3RhdGUgPSBmdW5jdGlvbiAoYW5nbGUpIHtcbiAgICB2YXIgY29zID0gTWF0aC5jb3MoIGFuZ2xlICk7XG4gICAgdmFyIHNpbiA9IE1hdGguc2luKCBhbmdsZSApO1xuXG4gICAgdmFyIGExID0gdGhpcy5hO1xuICAgIHZhciBjMSA9IHRoaXMuYztcbiAgICB2YXIgdHgxID0gdGhpcy50eDtcblxuICAgIHRoaXMuYSA9IGExICogY29zLXRoaXMuYiAqIHNpbjtcbiAgICB0aGlzLmIgPSBhMSAqIHNpbit0aGlzLmIgKiBjb3M7XG4gICAgdGhpcy5jID0gYzEgKiBjb3MtdGhpcy5kICogc2luO1xuICAgIHRoaXMuZCA9IGMxICogc2luK3RoaXMuZCAqIGNvcztcbiAgICB0aGlzLnR4ID0gdHgxICogY29zIC0gdGhpcy50eSAqIHNpbjtcbiAgICB0aGlzLnR5ID0gdHgxICogc2luICsgdGhpcy50eSAqIGNvcztcblxuICAgIHJldHVybiB0aGlzO1xufTtcblxuLyoqXG4gKiBBcHBlbmRzIHRoZSBnaXZlbiBNYXRyaXggdG8gdGhpcyBNYXRyaXguXG4gKlxuICogQHBhcmFtIHtNYXRyaXh9IG1hdHJpeFxuICogQHJldHVybiB7TWF0cml4fSBUaGlzIG1hdHJpeC4gR29vZCBmb3IgY2hhaW5pbmcgbWV0aG9kIGNhbGxzLlxuICovXG5NYXRyaXgucHJvdG90eXBlLmFwcGVuZCA9IGZ1bmN0aW9uIChtYXRyaXgpIHtcbiAgICB2YXIgYTEgPSB0aGlzLmE7XG4gICAgdmFyIGIxID0gdGhpcy5iO1xuICAgIHZhciBjMSA9IHRoaXMuYztcbiAgICB2YXIgZDEgPSB0aGlzLmQ7XG5cbiAgICB0aGlzLmEgID0gbWF0cml4LmEgKiBhMSArIG1hdHJpeC5iICogYzE7XG4gICAgdGhpcy5iICA9IG1hdHJpeC5hICogYjEgKyBtYXRyaXguYiAqIGQxO1xuICAgIHRoaXMuYyAgPSBtYXRyaXguYyAqIGExICsgbWF0cml4LmQgKiBjMTtcbiAgICB0aGlzLmQgID0gbWF0cml4LmMgKiBiMSArIG1hdHJpeC5kICogZDE7XG5cbiAgICB0aGlzLnR4ID0gbWF0cml4LnR4ICogYTEgKyBtYXRyaXgudHkgKiBjMSArIHRoaXMudHg7XG4gICAgdGhpcy50eSA9IG1hdHJpeC50eCAqIGIxICsgbWF0cml4LnR5ICogZDEgKyB0aGlzLnR5O1xuXG4gICAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqIFJlc2V0cyB0aGlzIE1hdGl4IHRvIGFuIGlkZW50aXR5IChkZWZhdWx0KSBtYXRyaXguXG4gKlxuICogQHJldHVybiB7TWF0cml4fSBUaGlzIG1hdHJpeC4gR29vZCBmb3IgY2hhaW5pbmcgbWV0aG9kIGNhbGxzLlxuICovXG5NYXRyaXgucHJvdG90eXBlLmlkZW50aXR5ID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuYSA9IDE7XG4gICAgdGhpcy5iID0gMDtcbiAgICB0aGlzLmMgPSAwO1xuICAgIHRoaXMuZCA9IDE7XG4gICAgdGhpcy50eCA9IDA7XG4gICAgdGhpcy50eSA9IDA7XG5cbiAgICByZXR1cm4gdGhpcztcbn07XG5cbk1hdHJpeC5JREVOVElUWSA9IG5ldyBNYXRyaXgoKTtcbiIsIi8qKlxuICogVGhlIFBvaW50IG9iamVjdCByZXByZXNlbnRzIGEgbG9jYXRpb24gaW4gYSB0d28tZGltZW5zaW9uYWwgY29vcmRpbmF0ZSBzeXN0ZW0sIHdoZXJlIHggcmVwcmVzZW50c1xuICogdGhlIGhvcml6b250YWwgYXhpcyBhbmQgeSByZXByZXNlbnRzIHRoZSB2ZXJ0aWNhbCBheGlzLlxuICpcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gW3g9MF0ge251bWJlcn0gcG9zaXRpb24gb2YgdGhlIHBvaW50IG9uIHRoZSB4IGF4aXNcbiAqIEBwYXJhbSBbeT0wXSB7bnVtYmVyfSBwb3NpdGlvbiBvZiB0aGUgcG9pbnQgb24gdGhlIHkgYXhpc1xuICovXG5mdW5jdGlvbiBQb2ludCh4LCB5KSB7XG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDBcbiAgICAgKi9cbiAgICB0aGlzLnggPSB4IHx8IDA7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMueSA9IHkgfHwgMDtcbn1cblxuUG9pbnQucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gUG9pbnQ7XG5tb2R1bGUuZXhwb3J0cyA9IFBvaW50O1xuXG4vKipcbiAqIENyZWF0ZXMgYSBjbG9uZSBvZiB0aGlzIHBvaW50XG4gKlxuICogQHJldHVybiB7UG9pbnR9IGEgY29weSBvZiB0aGUgcG9pbnRcbiAqL1xuUG9pbnQucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBuZXcgUG9pbnQodGhpcy54LCB0aGlzLnkpO1xufTtcblxuLyoqXG4gKiBTZXRzIHRoZSBwb2ludCB0byBhIG5ldyB4IGFuZCB5IHBvc2l0aW9uLlxuICogSWYgeSBpcyBvbWl0dGVkLCBib3RoIHggYW5kIHkgd2lsbCBiZSBzZXQgdG8geC5cbiAqXG4gKiBAcGFyYW0gW3g9MF0ge251bWJlcn0gcG9zaXRpb24gb2YgdGhlIHBvaW50IG9uIHRoZSB4IGF4aXNcbiAqIEBwYXJhbSBbeT0wXSB7bnVtYmVyfSBwb3NpdGlvbiBvZiB0aGUgcG9pbnQgb24gdGhlIHkgYXhpc1xuICovXG5Qb2ludC5wcm90b3R5cGUuc2V0ID0gZnVuY3Rpb24gKHgsIHkpIHtcbiAgICB0aGlzLnggPSB4IHx8IDA7XG4gICAgdGhpcy55ID0geSB8fCAoICh5ICE9PSAwKSA/IHRoaXMueCA6IDAgKSA7XG59O1xuIiwiLyoqXG4gKiBAbmFtZXNwYWNlIFBJWEkubWF0aFxuICovXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICAvKipcbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gUElfMiAtIE1hdGguUEkgeCAyXG4gICAgICogQGNvbnN0YW50XG4gICAgICogQHN0YXRpY1xuICAgICAqL1xuICAgIFBJXzI6IE1hdGguUEkgKiAyLFxuXG4gICAgLyoqXG4gICAgICogQHByb3BlcnR5IHtudW1iZXJ9IFJBRF9UT19ERUcgLSBDb25zdGFudCBjb252ZXJzaW9uIGZhY3RvciBmb3IgY29udmVydGluZyByYWRpYW5zIHRvIGRlZ3JlZXNcbiAgICAgKiBAY29uc3RhbnRcbiAgICAgKiBAc3RhdGljXG4gICAgICovXG4gICAgUkFEX1RPX0RFRzogMTgwIC8gTWF0aC5QSSxcblxuICAgIC8qKlxuICAgICAqIEBwcm9wZXJ0eSB7TnVtYmVyfSBERUdfVE9fUkFEIC0gQ29uc3RhbnQgY29udmVyc2lvbiBmYWN0b3IgZm9yIGNvbnZlcnRpbmcgZGVncmVlcyB0byByYWRpYW5zXG4gICAgICogQGNvbnN0YW50XG4gICAgICogQHN0YXRpY1xuICAgICAqL1xuICAgIERFR19UT19SQUQ6IE1hdGguUEkgLyAxODAsXG5cbiAgICBQb2ludDogICAgICByZXF1aXJlKCcuL1BvaW50JyksXG4gICAgTWF0cml4OiAgICAgcmVxdWlyZSgnLi9NYXRyaXgnKSxcblxuICAgIENpcmNsZTogICAgIHJlcXVpcmUoJy4vc2hhcGVzL0NpcmNsZScpLFxuICAgIEVsbGlwc2U6ICAgIHJlcXVpcmUoJy4vc2hhcGVzL0VsbGlwc2UnKSxcbiAgICBQb2x5Z29uOiAgICByZXF1aXJlKCcuL3NoYXBlcy9Qb2x5Z29uJyksXG4gICAgUmVjdGFuZ2xlOiAgcmVxdWlyZSgnLi9zaGFwZXMvUmVjdGFuZ2xlJyksXG4gICAgUm91bmRlZFJlY3RhbmdsZTogcmVxdWlyZSgnLi9zaGFwZXMvUm91bmRlZFJlY3RhbmdsZScpXG59O1xuIiwidmFyIFJlY3RhbmdsZSA9IHJlcXVpcmUoJy4vUmVjdGFuZ2xlJyksXG4gICAgQ09OU1QgPSByZXF1aXJlKCcuLi8uLi9jb25zdCcpO1xuXG4vKipcbiAqIFRoZSBDaXJjbGUgb2JqZWN0IGNhbiBiZSB1c2VkIHRvIHNwZWNpZnkgYSBoaXQgYXJlYSBmb3IgZGlzcGxheU9iamVjdHNcbiAqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmRpbmF0ZSBvZiB0aGUgY2VudGVyIG9mIHRoaXMgY2lyY2xlXG4gKiBAcGFyYW0geSB7bnVtYmVyfSBUaGUgWSBjb29yZGluYXRlIG9mIHRoZSBjZW50ZXIgb2YgdGhpcyBjaXJjbGVcbiAqIEBwYXJhbSByYWRpdXMge251bWJlcn0gVGhlIHJhZGl1cyBvZiB0aGUgY2lyY2xlXG4gKi9cbmZ1bmN0aW9uIENpcmNsZSh4LCB5LCByYWRpdXMpIHtcbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMueCA9IHggfHwgMDtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy55ID0geSB8fCAwO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDBcbiAgICAgKi9cbiAgICB0aGlzLnJhZGl1cyA9IHJhZGl1cyB8fCAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHR5cGUgb2YgdGhlIG9iamVjdCwgbWFpbmx5IHVzZWQgdG8gYXZvaWQgYGluc3RhbmNlb2ZgIGNoZWNrc1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMudHlwZSA9IENPTlNULlNIQVBFUy5DSVJDO1xufVxuXG5DaXJjbGUucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQ2lyY2xlO1xubW9kdWxlLmV4cG9ydHMgPSBDaXJjbGU7XG5cbi8qKlxuICogQ3JlYXRlcyBhIGNsb25lIG9mIHRoaXMgQ2lyY2xlIGluc3RhbmNlXG4gKlxuICogQG1ldGhvZCBjbG9uZVxuICogQHJldHVybiB7Q2lyY2xlfSBhIGNvcHkgb2YgdGhlIENpcmNsZVxuICovXG5DaXJjbGUucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBuZXcgQ2lyY2xlKHRoaXMueCwgdGhpcy55LCB0aGlzLnJhZGl1cyk7XG59O1xuXG4vKipcbiAqIENoZWNrcyB3aGV0aGVyIHRoZSB4IGFuZCB5IGNvb3JkaW5hdGVzIGdpdmVuIGFyZSBjb250YWluZWQgd2l0aGluIHRoaXMgY2lyY2xlXG4gKlxuICogQG1ldGhvZCBjb250YWluc1xuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHBhcmFtIHkge251bWJlcn0gVGhlIFkgY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHJldHVybiB7Ym9vbGVhbn0gV2hldGhlciB0aGUgeC95IGNvb3JkaW5hdGVzIGFyZSB3aXRoaW4gdGhpcyBDaXJjbGVcbiAqL1xuQ2lyY2xlLnByb3RvdHlwZS5jb250YWlucyA9IGZ1bmN0aW9uICh4LCB5KSB7XG4gICAgaWYgKHRoaXMucmFkaXVzIDw9IDApIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHZhciBkeCA9ICh0aGlzLnggLSB4KSxcbiAgICAgICAgZHkgPSAodGhpcy55IC0geSksXG4gICAgICAgIHIyID0gdGhpcy5yYWRpdXMgKiB0aGlzLnJhZGl1cztcblxuICAgIGR4ICo9IGR4O1xuICAgIGR5ICo9IGR5O1xuXG4gICAgcmV0dXJuIChkeCArIGR5IDw9IHIyKTtcbn07XG5cbi8qKlxuKiBSZXR1cm5zIHRoZSBmcmFtaW5nIHJlY3RhbmdsZSBvZiB0aGUgY2lyY2xlIGFzIGEgUmVjdGFuZ2xlIG9iamVjdFxuKlxuKiBAbWV0aG9kIGdldEJvdW5kc1xuKiBAcmV0dXJuIHtSZWN0YW5nbGV9IHRoZSBmcmFtaW5nIHJlY3RhbmdsZVxuKi9cbkNpcmNsZS5wcm90b3R5cGUuZ2V0Qm91bmRzID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBuZXcgUmVjdGFuZ2xlKHRoaXMueCAtIHRoaXMucmFkaXVzLCB0aGlzLnkgLSB0aGlzLnJhZGl1cywgdGhpcy5yYWRpdXMgKiAyLCB0aGlzLnJhZGl1cyAqIDIpO1xufTtcbiIsInZhciBSZWN0YW5nbGUgPSByZXF1aXJlKCcuL1JlY3RhbmdsZScpLFxuICAgIENPTlNUID0gcmVxdWlyZSgnLi4vLi4vY29uc3QnKTtcblxuLyoqXG4gKiBUaGUgRWxsaXBzZSBvYmplY3QgY2FuIGJlIHVzZWQgdG8gc3BlY2lmeSBhIGhpdCBhcmVhIGZvciBkaXNwbGF5T2JqZWN0c1xuICpcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0geCB7bnVtYmVyfSBUaGUgWCBjb29yZGluYXRlIG9mIHRoZSBjZW50ZXIgb2YgdGhlIGVsbGlwc2VcbiAqIEBwYXJhbSB5IHtudW1iZXJ9IFRoZSBZIGNvb3JkaW5hdGUgb2YgdGhlIGNlbnRlciBvZiB0aGUgZWxsaXBzZVxuICogQHBhcmFtIHdpZHRoIHtudW1iZXJ9IFRoZSBoYWxmIHdpZHRoIG9mIHRoaXMgZWxsaXBzZVxuICogQHBhcmFtIGhlaWdodCB7bnVtYmVyfSBUaGUgaGFsZiBoZWlnaHQgb2YgdGhpcyBlbGxpcHNlXG4gKi9cbmZ1bmN0aW9uIEVsbGlwc2UoeCwgeSwgd2lkdGgsIGhlaWdodCkge1xuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy54ID0geCB8fCAwO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDBcbiAgICAgKi9cbiAgICB0aGlzLnkgPSB5IHx8IDA7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMud2lkdGggPSB3aWR0aCB8fCAwO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDBcbiAgICAgKi9cbiAgICB0aGlzLmhlaWdodCA9IGhlaWdodCB8fCAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHR5cGUgb2YgdGhlIG9iamVjdCwgbWFpbmx5IHVzZWQgdG8gYXZvaWQgYGluc3RhbmNlb2ZgIGNoZWNrc1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMudHlwZSA9IENPTlNULlNIQVBFUy5FTElQO1xufVxuXG5FbGxpcHNlLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEVsbGlwc2U7XG5tb2R1bGUuZXhwb3J0cyA9IEVsbGlwc2U7XG5cbi8qKlxuICogQ3JlYXRlcyBhIGNsb25lIG9mIHRoaXMgRWxsaXBzZSBpbnN0YW5jZVxuICpcbiAqIEBtZXRob2QgY2xvbmVcbiAqIEByZXR1cm4ge0VsbGlwc2V9IGEgY29weSBvZiB0aGUgZWxsaXBzZVxuICovXG5FbGxpcHNlLnByb3RvdHlwZS5jbG9uZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gbmV3IEVsbGlwc2UodGhpcy54LCB0aGlzLnksIHRoaXMud2lkdGgsIHRoaXMuaGVpZ2h0KTtcbn07XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgdGhlIHggYW5kIHkgY29vcmRpbmF0ZXMgZ2l2ZW4gYXJlIGNvbnRhaW5lZCB3aXRoaW4gdGhpcyBlbGxpcHNlXG4gKlxuICogQG1ldGhvZCBjb250YWluc1xuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHBhcmFtIHkge251bWJlcn0gVGhlIFkgY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHJldHVybiB7Ym9vbGVhbn0gV2hldGhlciB0aGUgeC95IGNvb3JkcyBhcmUgd2l0aGluIHRoaXMgZWxsaXBzZVxuICovXG5FbGxpcHNlLnByb3RvdHlwZS5jb250YWlucyA9IGZ1bmN0aW9uICh4LCB5KSB7XG4gICAgaWYgKHRoaXMud2lkdGggPD0gMCB8fCB0aGlzLmhlaWdodCA8PSAwKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvL25vcm1hbGl6ZSB0aGUgY29vcmRzIHRvIGFuIGVsbGlwc2Ugd2l0aCBjZW50ZXIgMCwwXG4gICAgdmFyIG5vcm14ID0gKCh4IC0gdGhpcy54KSAvIHRoaXMud2lkdGgpLFxuICAgICAgICBub3JteSA9ICgoeSAtIHRoaXMueSkgLyB0aGlzLmhlaWdodCk7XG5cbiAgICBub3JteCAqPSBub3JteDtcbiAgICBub3JteSAqPSBub3JteTtcblxuICAgIHJldHVybiAobm9ybXggKyBub3JteSA8PSAxKTtcbn07XG5cbi8qKlxuKiBSZXR1cm5zIHRoZSBmcmFtaW5nIHJlY3RhbmdsZSBvZiB0aGUgZWxsaXBzZSBhcyBhIFJlY3RhbmdsZSBvYmplY3RcbipcbiogQG1ldGhvZCBnZXRCb3VuZHNcbiogQHJldHVybiB7UmVjdGFuZ2xlfSB0aGUgZnJhbWluZyByZWN0YW5nbGVcbiovXG5FbGxpcHNlLnByb3RvdHlwZS5nZXRCb3VuZHMgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIG5ldyBSZWN0YW5nbGUodGhpcy54IC0gdGhpcy53aWR0aCwgdGhpcy55IC0gdGhpcy5oZWlnaHQsIHRoaXMud2lkdGgsIHRoaXMuaGVpZ2h0KTtcbn07XG4iLCJ2YXIgUG9pbnQgPSByZXF1aXJlKCcuLi9Qb2ludCcpLFxuICAgIENPTlNUID0gcmVxdWlyZSgnLi4vLi4vY29uc3QnKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHBvaW50cyoge1BvaW50W118bnVtYmVyW118UG9pbnQuLi58bnVtYmVyLi4ufSBUaGlzIGNhbiBiZSBhbiBhcnJheSBvZiBQb2ludHMgdGhhdCBmb3JtIHRoZSBwb2x5Z29uLFxuICogICAgICBhIGZsYXQgYXJyYXkgb2YgbnVtYmVycyB0aGF0IHdpbGwgYmUgaW50ZXJwcmV0ZWQgYXMgW3gseSwgeCx5LCAuLi5dLCBvciB0aGUgYXJndW1lbnRzIHBhc3NlZCBjYW4gYmVcbiAqICAgICAgYWxsIHRoZSBwb2ludHMgb2YgdGhlIHBvbHlnb24gZS5nLiBgbmV3IFBvbHlnb24obmV3IFBvaW50KCksIG5ldyBQb2ludCgpLCAuLi4pYCwgb3IgdGhlXG4gKiAgICAgIGFyZ3VtZW50cyBwYXNzZWQgY2FuIGJlIGZsYXQgeCx5IHZhbHVlcyBlLmcuIGBuZXcgUG9seWdvbih4LHksIHgseSwgeCx5LCAuLi4pYCB3aGVyZSBgeGAgYW5kIGB5YCBhcmVcbiAqICAgICAgTnVtYmVycy5cbiAqL1xuZnVuY3Rpb24gUG9seWdvbihwb2ludHMpIHtcbiAgICAvL2lmIHBvaW50cyBpc24ndCBhbiBhcnJheSwgdXNlIGFyZ3VtZW50cyBhcyB0aGUgYXJyYXlcbiAgICBpZiAoIShwb2ludHMgaW5zdGFuY2VvZiBBcnJheSkpIHtcbiAgICAgICAgcG9pbnRzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICB9XG5cbiAgICAvL2lmIHRoaXMgaXMgYSBmbGF0IGFycmF5IG9mIG51bWJlcnMsIGNvbnZlcnQgaXQgdG8gcG9pbnRzXG4gICAgaWYgKHBvaW50c1swXSBpbnN0YW5jZW9mIFBvaW50KSB7XG4gICAgICAgIHZhciBwID0gW107XG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBpbCA9IHBvaW50cy5sZW5ndGg7IGkgPCBpbDsgaSsrKSB7XG4gICAgICAgICAgICBwLnB1c2gocG9pbnRzW2ldLngsIHBvaW50c1tpXS55KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHBvaW50cyA9IHA7XG4gICAgfVxuXG4gICAgdGhpcy5jbG9zZWQgPSB0cnVlO1xuXG4gICAgLyoqXG4gICAgICogQW4gYXJyYXkgb2YgdGhlIHBvaW50cyBvZiB0aGlzIHBvbHlnb25cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1BvaW50W119XG4gICAgICovXG4gICAgdGhpcy5wb2ludHMgPSBwb2ludHM7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdHlwZSBvZiB0aGUgb2JqZWN0LCBtYWlubHkgdXNlZCB0byBhdm9pZCBgaW5zdGFuY2VvZmAgY2hlY2tzXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy50eXBlID0gQ09OU1QuU0hBUEVTLlBPTFk7XG59XG5cblBvbHlnb24ucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gUG9seWdvbjtcbm1vZHVsZS5leHBvcnRzID0gUG9seWdvbjtcblxuLyoqXG4gKiBDcmVhdGVzIGEgY2xvbmUgb2YgdGhpcyBwb2x5Z29uXG4gKlxuICogQHJldHVybiB7UG9seWdvbn0gYSBjb3B5IG9mIHRoZSBwb2x5Z29uXG4gKi9cblBvbHlnb24ucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBuZXcgUG9seWdvbih0aGlzLnBvaW50cy5zbGljZSgpKTtcbn07XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgdGhlIHggYW5kIHkgY29vcmRpbmF0ZXMgcGFzc2VkIHRvIHRoaXMgZnVuY3Rpb24gYXJlIGNvbnRhaW5lZCB3aXRoaW4gdGhpcyBwb2x5Z29uXG4gKlxuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHBhcmFtIHkge251bWJlcn0gVGhlIFkgY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHJldHVybiB7Ym9vbGVhbn0gV2hldGhlciB0aGUgeC95IGNvb3JkaW5hdGVzIGFyZSB3aXRoaW4gdGhpcyBwb2x5Z29uXG4gKi9cblBvbHlnb24ucHJvdG90eXBlLmNvbnRhaW5zID0gZnVuY3Rpb24gKHgsIHkpIHtcbiAgICB2YXIgaW5zaWRlID0gZmFsc2U7XG5cbiAgICAvLyB1c2Ugc29tZSByYXljYXN0aW5nIHRvIHRlc3QgaGl0c1xuICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9zdWJzdGFjay9wb2ludC1pbi1wb2x5Z29uL2Jsb2IvbWFzdGVyL2luZGV4LmpzXG4gICAgdmFyIGxlbmd0aCA9IHRoaXMucG9pbnRzLmxlbmd0aCAvIDI7XG5cbiAgICBmb3IgKHZhciBpID0gMCwgaiA9IGxlbmd0aCAtIDE7IGkgPCBsZW5ndGg7IGogPSBpKyspIHtcbiAgICAgICAgdmFyIHhpID0gdGhpcy5wb2ludHNbaSAqIDJdLCB5aSA9IHRoaXMucG9pbnRzW2kgKiAyICsgMV0sXG4gICAgICAgICAgICB4aiA9IHRoaXMucG9pbnRzW2ogKiAyXSwgeWogPSB0aGlzLnBvaW50c1tqICogMiArIDFdLFxuICAgICAgICAgICAgaW50ZXJzZWN0ID0gKCh5aSA+IHkpICE9PSAoeWogPiB5KSkgJiYgKHggPCAoeGogLSB4aSkgKiAoeSAtIHlpKSAvICh5aiAtIHlpKSArIHhpKTtcblxuICAgICAgICBpZiAoaW50ZXJzZWN0KSB7XG4gICAgICAgICAgICBpbnNpZGUgPSAhaW5zaWRlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGluc2lkZTtcbn07XG4iLCJ2YXIgQ09OU1QgPSByZXF1aXJlKCcuLi8uLi9jb25zdCcpO1xuXG4vKipcbiAqIHRoZSBSZWN0YW5nbGUgb2JqZWN0IGlzIGFuIGFyZWEgZGVmaW5lZCBieSBpdHMgcG9zaXRpb24sIGFzIGluZGljYXRlZCBieSBpdHMgdG9wLWxlZnQgY29ybmVyIHBvaW50ICh4LCB5KSBhbmQgYnkgaXRzIHdpZHRoIGFuZCBpdHMgaGVpZ2h0LlxuICpcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0geCB7bnVtYmVyfSBUaGUgWCBjb29yZGluYXRlIG9mIHRoZSB1cHBlci1sZWZ0IGNvcm5lciBvZiB0aGUgcmVjdGFuZ2xlXG4gKiBAcGFyYW0geSB7bnVtYmVyfSBUaGUgWSBjb29yZGluYXRlIG9mIHRoZSB1cHBlci1sZWZ0IGNvcm5lciBvZiB0aGUgcmVjdGFuZ2xlXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gVGhlIG92ZXJhbGwgd2lkdGggb2YgdGhpcyByZWN0YW5nbGVcbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gVGhlIG92ZXJhbGwgaGVpZ2h0IG9mIHRoaXMgcmVjdGFuZ2xlXG4gKi9cbmZ1bmN0aW9uIFJlY3RhbmdsZSh4LCB5LCB3aWR0aCwgaGVpZ2h0KSB7XG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDBcbiAgICAgKi9cbiAgICB0aGlzLnggPSB4IHx8IDA7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMueSA9IHkgfHwgMDtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy53aWR0aCA9IHdpZHRoIHx8IDA7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0IHx8IDA7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdHlwZSBvZiB0aGUgb2JqZWN0LCBtYWlubHkgdXNlZCB0byBhdm9pZCBgaW5zdGFuY2VvZmAgY2hlY2tzXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy50eXBlID0gQ09OU1QuU0hBUEVTLlJFQ1Q7XG59XG5cblJlY3RhbmdsZS5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBSZWN0YW5nbGU7XG5tb2R1bGUuZXhwb3J0cyA9IFJlY3RhbmdsZTtcblxuLyoqXG4gKiBBIGNvbnN0YW50IGVtcHR5IHJlY3RhbmdsZS5cbiAqXG4gKiBAc3RhdGljXG4gKiBAY29uc3RhbnRcbiAqL1xuUmVjdGFuZ2xlLkVNUFRZID0gbmV3IFJlY3RhbmdsZSgwLCAwLCAwLCAwKTtcblxuXG4vKipcbiAqIENyZWF0ZXMgYSBjbG9uZSBvZiB0aGlzIFJlY3RhbmdsZVxuICpcbiAqIEByZXR1cm4ge1JlY3RhbmdsZX0gYSBjb3B5IG9mIHRoZSByZWN0YW5nbGVcbiAqL1xuUmVjdGFuZ2xlLnByb3RvdHlwZS5jbG9uZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gbmV3IFJlY3RhbmdsZSh0aGlzLngsIHRoaXMueSwgdGhpcy53aWR0aCwgdGhpcy5oZWlnaHQpO1xufTtcblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciB0aGUgeCBhbmQgeSBjb29yZGluYXRlcyBnaXZlbiBhcmUgY29udGFpbmVkIHdpdGhpbiB0aGlzIFJlY3RhbmdsZVxuICpcbiAqIEBwYXJhbSB4IHtudW1iZXJ9IFRoZSBYIGNvb3JkaW5hdGUgb2YgdGhlIHBvaW50IHRvIHRlc3RcbiAqIEBwYXJhbSB5IHtudW1iZXJ9IFRoZSBZIGNvb3JkaW5hdGUgb2YgdGhlIHBvaW50IHRvIHRlc3RcbiAqIEByZXR1cm4ge2Jvb2xlYW59IFdoZXRoZXIgdGhlIHgveSBjb29yZGluYXRlcyBhcmUgd2l0aGluIHRoaXMgUmVjdGFuZ2xlXG4gKi9cblJlY3RhbmdsZS5wcm90b3R5cGUuY29udGFpbnMgPSBmdW5jdGlvbiAoeCwgeSkge1xuICAgIGlmICh0aGlzLndpZHRoIDw9IDAgfHwgdGhpcy5oZWlnaHQgPD0gMCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKHggPj0gdGhpcy54ICYmIHggPD0gdGhpcy54ICsgdGhpcy53aWR0aCkge1xuICAgICAgICBpZiAoeSA+PSB0aGlzLnkgJiYgeSA8PSB0aGlzLnkgKyB0aGlzLmhlaWdodCkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2U7XG59O1xuIiwidmFyIENPTlNUID0gcmVxdWlyZSgnLi4vLi4vY29uc3QnKTtcblxuLyoqXG4gKiBUaGUgUm91bmRlZCBSZWN0YW5nbGUgb2JqZWN0IGlzIGFuIGFyZWEgZGVmaW5lZCBieSBpdHMgcG9zaXRpb24gYW5kIGhhcyBuaWNlIHJvdW5kZWQgY29ybmVycywgYXMgaW5kaWNhdGVkIGJ5IGl0cyB0b3AtbGVmdCBjb3JuZXIgcG9pbnQgKHgsIHkpIGFuZCBieSBpdHMgd2lkdGggYW5kIGl0cyBoZWlnaHQuXG4gKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSB4IHtudW1iZXJ9IFRoZSBYIGNvb3JkaW5hdGUgb2YgdGhlIHVwcGVyLWxlZnQgY29ybmVyIG9mIHRoZSByb3VuZGVkIHJlY3RhbmdsZVxuICogQHBhcmFtIHkge251bWJlcn0gVGhlIFkgY29vcmRpbmF0ZSBvZiB0aGUgdXBwZXItbGVmdCBjb3JuZXIgb2YgdGhlIHJvdW5kZWQgcmVjdGFuZ2xlXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gVGhlIG92ZXJhbGwgd2lkdGggb2YgdGhpcyByb3VuZGVkIHJlY3RhbmdsZVxuICogQHBhcmFtIGhlaWdodCB7bnVtYmVyfSBUaGUgb3ZlcmFsbCBoZWlnaHQgb2YgdGhpcyByb3VuZGVkIHJlY3RhbmdsZVxuICogQHBhcmFtIHJhZGl1cyB7bnVtYmVyfSBDb250cm9scyB0aGUgcmFkaXVzIG9mIHRoZSByb3VuZGVkIGNvcm5lcnNcbiAqL1xuZnVuY3Rpb24gUm91bmRlZFJlY3RhbmdsZSh4LCB5LCB3aWR0aCwgaGVpZ2h0LCByYWRpdXMpIHtcbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMueCA9IHggfHwgMDtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy55ID0geSB8fCAwO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDBcbiAgICAgKi9cbiAgICB0aGlzLndpZHRoID0gd2lkdGggfHwgMDtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy5oZWlnaHQgPSBoZWlnaHQgfHwgMDtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAyMFxuICAgICAqL1xuICAgIHRoaXMucmFkaXVzID0gcmFkaXVzIHx8IDIwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHR5cGUgb2YgdGhlIG9iamVjdCwgbWFpbmx5IHVzZWQgdG8gYXZvaWQgYGluc3RhbmNlb2ZgIGNoZWNrc1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMudHlwZSA9IENPTlNULlNIQVBFUy5SUkVDO1xufVxuXG5Sb3VuZGVkUmVjdGFuZ2xlLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFJvdW5kZWRSZWN0YW5nbGU7XG5tb2R1bGUuZXhwb3J0cyA9IFJvdW5kZWRSZWN0YW5nbGU7XG5cbi8qKlxuICogQ3JlYXRlcyBhIGNsb25lIG9mIHRoaXMgUm91bmRlZCBSZWN0YW5nbGVcbiAqXG4gKiBAcmV0dXJuIHtSb3VuZGVkUmVjdGFuZ2xlfSBhIGNvcHkgb2YgdGhlIHJvdW5kZWQgcmVjdGFuZ2xlXG4gKi9cblJvdW5kZWRSZWN0YW5nbGUucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBuZXcgUm91bmRlZFJlY3RhbmdsZSh0aGlzLngsIHRoaXMueSwgdGhpcy53aWR0aCwgdGhpcy5oZWlnaHQsIHRoaXMucmFkaXVzKTtcbn07XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgdGhlIHggYW5kIHkgY29vcmRpbmF0ZXMgZ2l2ZW4gYXJlIGNvbnRhaW5lZCB3aXRoaW4gdGhpcyBSb3VuZGVkIFJlY3RhbmdsZVxuICpcbiAqIEBwYXJhbSB4IHtudW1iZXJ9IFRoZSBYIGNvb3JkaW5hdGUgb2YgdGhlIHBvaW50IHRvIHRlc3RcbiAqIEBwYXJhbSB5IHtudW1iZXJ9IFRoZSBZIGNvb3JkaW5hdGUgb2YgdGhlIHBvaW50IHRvIHRlc3RcbiAqIEByZXR1cm4ge2Jvb2xlYW59IFdoZXRoZXIgdGhlIHgveSBjb29yZGluYXRlcyBhcmUgd2l0aGluIHRoaXMgUm91bmRlZCBSZWN0YW5nbGVcbiAqL1xuUm91bmRlZFJlY3RhbmdsZS5wcm90b3R5cGUuY29udGFpbnMgPSBmdW5jdGlvbiAoeCwgeSkge1xuICAgIGlmICh0aGlzLndpZHRoIDw9IDAgfHwgdGhpcy5oZWlnaHQgPD0gMCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKHggPj0gdGhpcy54ICYmIHggPD0gdGhpcy54ICsgdGhpcy53aWR0aCkge1xuICAgICAgICBpZiAoeSA+PSB0aGlzLnkgJiYgeSA8PSB0aGlzLnkgKyB0aGlzLmhlaWdodCkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2U7XG59O1xuIiwidmFyIERpc3BsYXlPYmplY3RDb250YWluZXIgPSByZXF1aXJlKCcuLi9kaXNwbGF5L0Rpc3BsYXlPYmplY3RDb250YWluZXInKSxcbiAgICBTcHJpdGUgPSByZXF1aXJlKCcuLi9kaXNwbGF5L1Nwcml0ZScpLFxuICAgIFRleHR1cmUgPSByZXF1aXJlKCcuLi90ZXh0dXJlcy9UZXh0dXJlJyksXG4gICAgQ2FudmFzQnVmZmVyID0gcmVxdWlyZSgnLi4vcmVuZGVyZXJzL2NhbnZhcy91dGlscy9DYW52YXNCdWZmZXInKSxcbiAgICBDYW52YXNHcmFwaGljcyA9IHJlcXVpcmUoJy4uL3JlbmRlcmVycy9jYW52YXMvdXRpbHMvQ2FudmFzR3JhcGhpY3MnKSxcbiAgICBXZWJHTEdyYXBoaWNzID0gcmVxdWlyZSgnLi4vcmVuZGVyZXJzL3dlYmdsL3V0aWxzL1dlYkdMR3JhcGhpY3MnKSxcbiAgICBHcmFwaGljc0RhdGEgPSByZXF1aXJlKCcuL0dyYXBoaWNzRGF0YScpLFxuICAgIG1hdGggPSByZXF1aXJlKCcuLi9tYXRoJyksXG4gICAgQ09OU1QgPSByZXF1aXJlKCcuLi9jb25zdCcpO1xuXG4vKipcbiAqIFRoZSBHcmFwaGljcyBjbGFzcyBjb250YWlucyBtZXRob2RzIHVzZWQgdG8gZHJhdyBwcmltaXRpdmUgc2hhcGVzIHN1Y2ggYXMgbGluZXMsIGNpcmNsZXMgYW5kXG4gKiByZWN0YW5nbGVzIHRvIHRoZSBkaXNwbGF5LCBhbmQgY29sb3IgYW5kIGZpbGwgdGhlbS5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIERpc3BsYXlPYmplY3RDb250YWluZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBHcmFwaGljcygpIHtcbiAgICBEaXNwbGF5T2JqZWN0Q29udGFpbmVyLmNhbGwodGhpcyk7XG5cbiAgICB0aGlzLnJlbmRlcmFibGUgPSB0cnVlO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGFscGhhIHZhbHVlIHVzZWQgd2hlbiBmaWxsaW5nIHRoZSBHcmFwaGljcyBvYmplY3QuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMVxuICAgICAqL1xuICAgIHRoaXMuZmlsbEFscGhhID0gMTtcblxuICAgIC8qKlxuICAgICAqIFRoZSB3aWR0aCAodGhpY2tuZXNzKSBvZiBhbnkgbGluZXMgZHJhd24uXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMubGluZVdpZHRoID0gMDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBjb2xvciBvZiBhbnkgbGluZXMgZHJhd24uXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtzdHJpbmd9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMubGluZUNvbG9yID0gMDtcblxuICAgIC8qKlxuICAgICAqIEdyYXBoaWNzIGRhdGFcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0dyYXBoaWNzRGF0YVtdfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5ncmFwaGljc0RhdGEgPSBbXTtcblxuICAgIC8qKlxuICAgICAqIFRoZSB0aW50IGFwcGxpZWQgdG8gdGhlIGdyYXBoaWMgc2hhcGUuIFRoaXMgaXMgYSBoZXggdmFsdWUuIEFwcGx5IGEgdmFsdWUgb2YgMHhGRkZGRkYgdG8gcmVzZXQgdGhlIHRpbnQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMHhGRkZGRkZcbiAgICAgKi9cbiAgICB0aGlzLnRpbnQgPSAweEZGRkZGRjtcblxuICAgIC8qKlxuICAgICAqIFRoZSBibGVuZCBtb2RlIHRvIGJlIGFwcGxpZWQgdG8gdGhlIGdyYXBoaWMgc2hhcGUuIEFwcGx5IGEgdmFsdWUgb2YgYmxlbmRNb2Rlcy5OT1JNQUwgdG8gcmVzZXQgdGhlIGJsZW5kIG1vZGUuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgQ09OU1QuYmxlbmRNb2Rlcy5OT1JNQUw7XG4gICAgICovXG4gICAgdGhpcy5ibGVuZE1vZGUgPSBDT05TVC5ibGVuZE1vZGVzLk5PUk1BTDtcblxuICAgIC8qKlxuICAgICAqIEN1cnJlbnQgcGF0aFxuICAgICAqXG4gICAgICogQG1lbWJlciB7R3JhcGhpY3NEYXRhfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5jdXJyZW50UGF0aCA9IG51bGw7XG5cbiAgICAvKipcbiAgICAgKiBBcnJheSBjb250YWluaW5nIHNvbWUgV2ViR0wtcmVsYXRlZCBwcm9wZXJ0aWVzIHVzZWQgYnkgdGhlIFdlYkdMIHJlbmRlcmVyLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7b2JqZWN0PG51bWJlciwgb2JqZWN0Pn1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIC8vIFRPRE8gLSBfd2ViZ2wgc2hvdWxkIHVzZSBhIHByb3RvdHlwZSBvYmplY3QsIG5vdCBhIHJhbmRvbSB1bmRvY3VtZW50ZWQgb2JqZWN0Li4uXG4gICAgdGhpcy5fd2ViR0wgPSB7fTtcblxuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgdGhpcyBzaGFwZSBpcyBiZWluZyB1c2VkIGFzIGEgbWFzay5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5pc01hc2sgPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBib3VuZHMnIHBhZGRpbmcgdXNlZCBmb3IgYm91bmRzIGNhbGN1bGF0aW9uLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMuYm91bmRzUGFkZGluZyA9IDA7XG5cbiAgICAvKipcbiAgICAgKiBBIGNhY2hlIG9mIHRoZSBsb2NhbCBib3VuZHMgdG8gcHJldmVudCByZWNhbGN1bGF0aW9uLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7UmVjdGFuZ2xlfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fbG9jYWxCb3VuZHMgPSBuZXcgbWF0aC5SZWN0YW5nbGUoMCwwLDEsMSk7XG5cbiAgICAvKipcbiAgICAgKiBVc2VkIHRvIGRldGVjdCBpZiB0aGUgZ3JhcGhpY3Mgb2JqZWN0IGhhcyBjaGFuZ2VkLiBJZiB0aGlzIGlzIHNldCB0byB0cnVlIHRoZW4gdGhlIGdyYXBoaWNzXG4gICAgICogb2JqZWN0IHdpbGwgYmUgcmVjYWxjdWxhdGVkLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuXG4gICAgLyoqXG4gICAgICogVXNlZCB0byBkZXRlY3QgaWYgdGhlIFdlYkdMIGdyYXBoaWNzIG9iamVjdCBoYXMgY2hhbmdlZC4gSWYgdGhpcyBpcyBzZXQgdG8gdHJ1ZSB0aGVuIHRoZVxuICAgICAqIGdyYXBoaWNzIG9iamVjdCB3aWxsIGJlIHJlY2FsY3VsYXRlZC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLmdsRGlydHkgPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqIFVzZWQgdG8gZGV0ZWN0IGlmIHRoZSBjYWNoZWQgc3ByaXRlIG9iamVjdCBuZWVkcyB0byBiZSB1cGRhdGVkLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuY2FjaGVkU3ByaXRlRGlydHkgPSBmYWxzZTtcbn1cblxuLy8gY29uc3RydWN0b3JcbkdyYXBoaWNzLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUpO1xuR3JhcGhpY3MucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gR3JhcGhpY3M7XG5tb2R1bGUuZXhwb3J0cyA9IEdyYXBoaWNzO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhHcmFwaGljcy5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBXaGVuIGNhY2hlQXNCaXRtYXAgaXMgc2V0IHRvIHRydWUgdGhlIGdyYXBoaWNzIG9iamVjdCB3aWxsIGJlIHJlbmRlcmVkIGFzIGlmIGl0IHdhcyBhIHNwcml0ZS5cbiAgICAgKiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3VyIGdyYXBoaWNzIGVsZW1lbnQgZG9lcyBub3QgY2hhbmdlIG9mdGVuLCBhcyBpdCB3aWxsIHNwZWVkIHVwIHRoZSByZW5kZXJpbmdcbiAgICAgKiBvZiB0aGUgb2JqZWN0IGluIGV4Y2hhbmdlIGZvciB0YWtpbmcgdXAgdGV4dHVyZSBtZW1vcnkuIEl0IGlzIGFsc28gdXNlZnVsIGlmIHlvdSBuZWVkIHRoZSBncmFwaGljc1xuICAgICAqIG9iamVjdCB0byBiZSBhbnRpLWFsaWFzZWQsIGJlY2F1c2UgaXQgd2lsbCBiZSByZW5kZXJlZCB1c2luZyBjYW52YXMuIFRoaXMgaXMgbm90IHJlY29tbWVuZGVkIGlmXG4gICAgICogeW91IGFyZSBjb25zdGFudGx5IHJlZHJhd2luZyB0aGUgZ3JhcGhpY3MgZWxlbWVudC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICogQG1lbWJlcm9mIEdyYXBoaWNzI1xuICAgICAqIEBkZWZhdWx0IGZhbHNlXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBjYWNoZUFzQml0bWFwOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2NhY2hlQXNCaXRtYXA7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLl9jYWNoZUFzQml0bWFwID0gdmFsdWU7XG5cbiAgICAgICAgICAgIGlmICh0aGlzLl9jYWNoZUFzQml0bWFwKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fZ2VuZXJhdGVDYWNoZWRTcHJpdGUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuZGVzdHJveUNhY2hlZFNwcml0ZSgpO1xuICAgICAgICAgICAgICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufSk7XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldyBHcmFwaGljcyBvYmplY3Qgd2l0aCB0aGUgc2FtZSB2YWx1ZXMgYXMgdGhpcyBvbmUuXG4gKlxuICogQHJldHVybiB7R3JhcGhpY3N9XG4gKi9cbkdyYXBoaWNzRGF0YS5wcm90b3R5cGUuY2xvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGNsb25lID0gbmV3IEdyYXBoaWNzKCk7XG5cbiAgICBjbG9uZS5yZW5kZXJhYmxlICAgID0gdGhpcy5yZW5kZXJhYmxlO1xuICAgIGNsb25lLmZpbGxBbHBoYSAgICAgPSB0aGlzLmZpbGxBbHBoYTtcbiAgICBjbG9uZS5saW5lV2lkdGggICAgID0gdGhpcy5saW5lV2lkdGg7XG4gICAgY2xvbmUubGluZUNvbG9yICAgICA9IHRoaXMubGluZUNvbG9yO1xuICAgIGNsb25lLnRpbnQgICAgICAgICAgPSB0aGlzLnRpbnQ7XG4gICAgY2xvbmUuYmxlbmRNb2RlICAgICA9IHRoaXMuYmxlbmRNb2RlO1xuICAgIGNsb25lLmlzTWFzayAgICAgICAgPSB0aGlzLmlzTWFzaztcbiAgICBjbG9uZS5ib3VuZHNQYWRkaW5nID0gdGhpcy5ib3VuZHNQYWRkaW5nO1xuICAgIGNsb25lLmRpcnR5ICAgICAgICAgPSB0aGlzLmRpcnR5O1xuICAgIGNsb25lLmdsRGlydHkgICAgICAgPSB0aGlzLmdsRGlydHk7XG4gICAgY2xvbmUuY2FjaGVkU3ByaXRlRGlydHkgPSB0aGlzLmNhY2hlZFNwcml0ZURpcnR5O1xuXG4gICAgLy8gY29weSBncmFwaGljcyBkYXRhXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmdyYXBoaWNzRGF0YS5sZW5ndGg7ICsraSkge1xuICAgICAgICBjbG9uZS5ncmFwaGljc0RhdGEucHVzaCh0aGlzLmdyYXBoaWNzRGF0YS5jbG9uZSgpKTtcbiAgICB9XG5cbiAgICBjbG9uZS5jdXJyZW50UGF0aCA9IGNsb25lLmdyYXBoaWNzRGF0YVtjbG9uZS5ncmFwaGljc0RhdGEubGVuZ3RoIC0gMV07XG5cbiAgICBjbG9uZS51cGRhdGVMb2NhbEJvdW5kcygpO1xuXG4gICAgcmV0dXJuIGNsb25lO1xufTtcblxuLyoqXG4gKiBTcGVjaWZpZXMgdGhlIGxpbmUgc3R5bGUgdXNlZCBmb3Igc3Vic2VxdWVudCBjYWxscyB0byBHcmFwaGljcyBtZXRob2RzIHN1Y2ggYXMgdGhlIGxpbmVUbygpIG1ldGhvZCBvciB0aGUgZHJhd0NpcmNsZSgpIG1ldGhvZC5cbiAqXG4gKiBAcGFyYW0gbGluZVdpZHRoIHtudW1iZXJ9IHdpZHRoIG9mIHRoZSBsaW5lIHRvIGRyYXcsIHdpbGwgdXBkYXRlIHRoZSBvYmplY3RzIHN0b3JlZCBzdHlsZVxuICogQHBhcmFtIGNvbG9yIHtudW1iZXJ9IGNvbG9yIG9mIHRoZSBsaW5lIHRvIGRyYXcsIHdpbGwgdXBkYXRlIHRoZSBvYmplY3RzIHN0b3JlZCBzdHlsZVxuICogQHBhcmFtIGFscGhhIHtudW1iZXJ9IGFscGhhIG9mIHRoZSBsaW5lIHRvIGRyYXcsIHdpbGwgdXBkYXRlIHRoZSBvYmplY3RzIHN0b3JlZCBzdHlsZVxuICogQHJldHVybiB7R3JhcGhpY3N9XG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5saW5lU3R5bGUgPSBmdW5jdGlvbiAobGluZVdpZHRoLCBjb2xvciwgYWxwaGEpIHtcbiAgICB0aGlzLmxpbmVXaWR0aCA9IGxpbmVXaWR0aCB8fCAwO1xuICAgIHRoaXMubGluZUNvbG9yID0gY29sb3IgfHwgMDtcbiAgICB0aGlzLmxpbmVBbHBoYSA9IChhcmd1bWVudHMubGVuZ3RoIDwgMykgPyAxIDogYWxwaGE7XG5cbiAgICBpZiAodGhpcy5jdXJyZW50UGF0aCkge1xuICAgICAgICBpZiAodGhpcy5jdXJyZW50UGF0aC5zaGFwZS5wb2ludHMubGVuZ3RoKSB7XG4gICAgICAgICAgICAvLyBoYWxmd2F5IHRocm91Z2ggYSBsaW5lPyBzdGFydCBhIG5ldyBvbmUhXG4gICAgICAgICAgICB0aGlzLmRyYXdTaGFwZSggbmV3IG1hdGguUG9seWdvbiggdGhpcy5jdXJyZW50UGF0aC5zaGFwZS5wb2ludHMuc2xpY2UoLTIpICkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy8gb3RoZXJ3aXNlIGl0cyBlbXB0eSBzbyBsZXRzIGp1c3Qgc2V0IHRoZSBsaW5lIHByb3BlcnRpZXNcbiAgICAgICAgICAgIHRoaXMuY3VycmVudFBhdGgubGluZVdpZHRoID0gdGhpcy5saW5lV2lkdGg7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRQYXRoLmxpbmVDb2xvciA9IHRoaXMubGluZUNvbG9yO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50UGF0aC5saW5lQWxwaGEgPSB0aGlzLmxpbmVBbHBoYTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xufTtcblxuLyoqXG4gKiBNb3ZlcyB0aGUgY3VycmVudCBkcmF3aW5nIHBvc2l0aW9uIHRvIHgsIHkuXG4gKlxuICogQHBhcmFtIHgge251bWJlcn0gdGhlIFggY29vcmRpbmF0ZSB0byBtb3ZlIHRvXG4gKiBAcGFyYW0geSB7bnVtYmVyfSB0aGUgWSBjb29yZGluYXRlIHRvIG1vdmUgdG9cbiAqIEByZXR1cm4ge0dyYXBoaWNzfVxuICAqL1xuR3JhcGhpY3MucHJvdG90eXBlLm1vdmVUbyA9IGZ1bmN0aW9uICh4LCB5KSB7XG4gICAgdGhpcy5kcmF3U2hhcGUobmV3IG1hdGguUG9seWdvbihbeCx5XSkpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqIERyYXdzIGEgbGluZSB1c2luZyB0aGUgY3VycmVudCBsaW5lIHN0eWxlIGZyb20gdGhlIGN1cnJlbnQgZHJhd2luZyBwb3NpdGlvbiB0byAoeCwgeSk7XG4gKiBUaGUgY3VycmVudCBkcmF3aW5nIHBvc2l0aW9uIGlzIHRoZW4gc2V0IHRvICh4LCB5KS5cbiAqXG4gKiBAcGFyYW0geCB7bnVtYmVyfSB0aGUgWCBjb29yZGluYXRlIHRvIGRyYXcgdG9cbiAqIEBwYXJhbSB5IHtudW1iZXJ9IHRoZSBZIGNvb3JkaW5hdGUgdG8gZHJhdyB0b1xuICogQHJldHVybiB7R3JhcGhpY3N9XG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5saW5lVG8gPSBmdW5jdGlvbiAoeCwgeSkge1xuICAgIHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzLnB1c2goeCwgeSk7XG4gICAgdGhpcy5kaXJ0eSA9IHRydWU7XG5cbiAgICByZXR1cm4gdGhpcztcbn07XG5cbi8qKlxuICogQ2FsY3VsYXRlIHRoZSBwb2ludHMgZm9yIGEgcXVhZHJhdGljIGJlemllciBjdXJ2ZSBhbmQgdGhlbiBkcmF3cyBpdC5cbiAqIEJhc2VkIG9uOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy83ODUwOTcvaG93LWRvLWktaW1wbGVtZW50LWEtYmV6aWVyLWN1cnZlLWluLWNcbiAqXG4gKiBAcGFyYW0gY3BYIHtudW1iZXJ9IENvbnRyb2wgcG9pbnQgeFxuICogQHBhcmFtIGNwWSB7bnVtYmVyfSBDb250cm9sIHBvaW50IHlcbiAqIEBwYXJhbSB0b1gge251bWJlcn0gRGVzdGluYXRpb24gcG9pbnQgeFxuICogQHBhcmFtIHRvWSB7bnVtYmVyfSBEZXN0aW5hdGlvbiBwb2ludCB5XG4gKiBAcmV0dXJuIHtHcmFwaGljc31cbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLnF1YWRyYXRpY0N1cnZlVG8gPSBmdW5jdGlvbiAoY3BYLCBjcFksIHRvWCwgdG9ZKSB7XG4gICAgaWYgKHRoaXMuY3VycmVudFBhdGgpIHtcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50UGF0aC5zaGFwZS5wb2ludHMgPSBbMCwgMF07XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHRoaXMubW92ZVRvKDAsMCk7XG4gICAgfVxuXG4gICAgdmFyIHhhLFxuICAgICAgICB5YSxcbiAgICAgICAgbiA9IDIwLFxuICAgICAgICBwb2ludHMgPSB0aGlzLmN1cnJlbnRQYXRoLnNoYXBlLnBvaW50cztcblxuICAgIGlmIChwb2ludHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHRoaXMubW92ZVRvKDAsIDApO1xuICAgIH1cblxuICAgIHZhciBmcm9tWCA9IHBvaW50c1twb2ludHMubGVuZ3RoLTJdO1xuICAgIHZhciBmcm9tWSA9IHBvaW50c1twb2ludHMubGVuZ3RoLTFdO1xuXG4gICAgdmFyIGogPSAwO1xuICAgIGZvciAodmFyIGkgPSAxOyBpIDw9IG47ICsraSkge1xuICAgICAgICBqID0gaSAvIG47XG5cbiAgICAgICAgeGEgPSBmcm9tWCArICggKGNwWCAtIGZyb21YKSAqIGogKTtcbiAgICAgICAgeWEgPSBmcm9tWSArICggKGNwWSAtIGZyb21ZKSAqIGogKTtcblxuICAgICAgICBwb2ludHMucHVzaCggeGEgKyAoICgoY3BYICsgKCAodG9YIC0gY3BYKSAqIGogKSkgLSB4YSkgKiBqICksXG4gICAgICAgICAgICAgICAgICAgICB5YSArICggKChjcFkgKyAoICh0b1kgLSBjcFkpICogaiApKSAtIHlhKSAqIGogKSApO1xuICAgIH1cblxuICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqIENhbGN1bGF0ZSB0aGUgcG9pbnRzIGZvciBhIGJlemllciBjdXJ2ZSBhbmQgdGhlbiBkcmF3cyBpdC5cbiAqXG4gKiBAcGFyYW0gY3BYIHtudW1iZXJ9IENvbnRyb2wgcG9pbnQgeFxuICogQHBhcmFtIGNwWSB7bnVtYmVyfSBDb250cm9sIHBvaW50IHlcbiAqIEBwYXJhbSBjcFgyIHtudW1iZXJ9IFNlY29uZCBDb250cm9sIHBvaW50IHhcbiAqIEBwYXJhbSBjcFkyIHtudW1iZXJ9IFNlY29uZCBDb250cm9sIHBvaW50IHlcbiAqIEBwYXJhbSB0b1gge251bWJlcn0gRGVzdGluYXRpb24gcG9pbnQgeFxuICogQHBhcmFtIHRvWSB7bnVtYmVyfSBEZXN0aW5hdGlvbiBwb2ludCB5XG4gKiBAcmV0dXJuIHtHcmFwaGljc31cbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLmJlemllckN1cnZlVG8gPSBmdW5jdGlvbiAoY3BYLCBjcFksIGNwWDIsIGNwWTIsIHRvWCwgdG9ZKSB7XG4gICAgaWYgKHRoaXMuY3VycmVudFBhdGgpIHtcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50UGF0aC5zaGFwZS5wb2ludHMgPSBbMCwgMF07XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHRoaXMubW92ZVRvKDAsMCk7XG4gICAgfVxuXG4gICAgdmFyIG4gPSAyMCxcbiAgICAgICAgZHQsXG4gICAgICAgIGR0MixcbiAgICAgICAgZHQzLFxuICAgICAgICB0MixcbiAgICAgICAgdDMsXG4gICAgICAgIHBvaW50cyA9IHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzO1xuXG4gICAgdmFyIGZyb21YID0gcG9pbnRzW3BvaW50cy5sZW5ndGgtMl07XG4gICAgdmFyIGZyb21ZID0gcG9pbnRzW3BvaW50cy5sZW5ndGgtMV07XG5cbiAgICB2YXIgaiA9IDA7XG5cbiAgICBmb3IgKHZhciBpID0gMTsgaSA8PSBuOyArK2kpIHtcbiAgICAgICAgaiA9IGkgLyBuO1xuXG4gICAgICAgIGR0ID0gKDEgLSBqKTtcbiAgICAgICAgZHQyID0gZHQgKiBkdDtcbiAgICAgICAgZHQzID0gZHQyICogZHQ7XG5cbiAgICAgICAgdDIgPSBqICogajtcbiAgICAgICAgdDMgPSB0MiAqIGo7XG5cbiAgICAgICAgcG9pbnRzLnB1c2goIGR0MyAqIGZyb21YICsgMyAqIGR0MiAqIGogKiBjcFggKyAzICogZHQgKiB0MiAqIGNwWDIgKyB0MyAqIHRvWCxcbiAgICAgICAgICAgICAgICAgICAgIGR0MyAqIGZyb21ZICsgMyAqIGR0MiAqIGogKiBjcFkgKyAzICogZHQgKiB0MiAqIGNwWTIgKyB0MyAqIHRvWSk7XG4gICAgfVxuXG4gICAgdGhpcy5kaXJ0eSA9IHRydWU7XG5cbiAgICByZXR1cm4gdGhpcztcbn07XG5cbi8qKlxuICogVGhlIGFyY1RvKCkgbWV0aG9kIGNyZWF0ZXMgYW4gYXJjL2N1cnZlIGJldHdlZW4gdHdvIHRhbmdlbnRzIG9uIHRoZSBjYW52YXMuXG4gKlxuICogXCJib3Jyb3dlZFwiIGZyb20gaHR0cHM6Ly9jb2RlLmdvb2dsZS5jb20vcC9meGNhbnZhcy8gLSB0aGFua3MgZ29vZ2xlIVxuICpcbiAqIEBwYXJhbSB4MSB7bnVtYmVyfSBUaGUgeC1jb29yZGluYXRlIG9mIHRoZSBiZWdpbm5pbmcgb2YgdGhlIGFyY1xuICogQHBhcmFtIHkxIHtudW1iZXJ9IFRoZSB5LWNvb3JkaW5hdGUgb2YgdGhlIGJlZ2lubmluZyBvZiB0aGUgYXJjXG4gKiBAcGFyYW0geDIge251bWJlcn0gVGhlIHgtY29vcmRpbmF0ZSBvZiB0aGUgZW5kIG9mIHRoZSBhcmNcbiAqIEBwYXJhbSB5MiB7bnVtYmVyfSBUaGUgeS1jb29yZGluYXRlIG9mIHRoZSBlbmQgb2YgdGhlIGFyY1xuICogQHBhcmFtIHJhZGl1cyB7bnVtYmVyfSBUaGUgcmFkaXVzIG9mIHRoZSBhcmNcbiAqIEByZXR1cm4ge0dyYXBoaWNzfVxuICovXG5HcmFwaGljcy5wcm90b3R5cGUuYXJjVG8gPSBmdW5jdGlvbiAoeDEsIHkxLCB4MiwgeTIsIHJhZGl1cykge1xuICAgIGlmICh0aGlzLmN1cnJlbnRQYXRoKSB7XG4gICAgICAgIGlmICh0aGlzLmN1cnJlbnRQYXRoLnNoYXBlLnBvaW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzLnB1c2goeDEsIHkxKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdGhpcy5tb3ZlVG8oeDEsIHkxKTtcbiAgICB9XG5cbiAgICB2YXIgcG9pbnRzID0gdGhpcy5jdXJyZW50UGF0aC5zaGFwZS5wb2ludHMsXG4gICAgICAgIGZyb21YID0gcG9pbnRzW3BvaW50cy5sZW5ndGgtMl0sXG4gICAgICAgIGZyb21ZID0gcG9pbnRzW3BvaW50cy5sZW5ndGgtMV0sXG4gICAgICAgIGExID0gZnJvbVkgLSB5MSxcbiAgICAgICAgYjEgPSBmcm9tWCAtIHgxLFxuICAgICAgICBhMiA9IHkyICAgLSB5MSxcbiAgICAgICAgYjIgPSB4MiAgIC0geDEsXG4gICAgICAgIG1tID0gTWF0aC5hYnMoYTEgKiBiMiAtIGIxICogYTIpO1xuXG4gICAgaWYgKG1tIDwgMS4wZS04IHx8IHJhZGl1cyA9PT0gMCkge1xuICAgICAgICBpZiAocG9pbnRzW3BvaW50cy5sZW5ndGgtMl0gIT09IHgxIHx8IHBvaW50c1twb2ludHMubGVuZ3RoLTFdICE9PSB5MSkge1xuICAgICAgICAgICAgcG9pbnRzLnB1c2goeDEsIHkxKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdmFyIGRkID0gYTEgKiBhMSArIGIxICogYjEsXG4gICAgICAgICAgICBjYyA9IGEyICogYTIgKyBiMiAqIGIyLFxuICAgICAgICAgICAgdHQgPSBhMSAqIGEyICsgYjEgKiBiMixcbiAgICAgICAgICAgIGsxID0gcmFkaXVzICogTWF0aC5zcXJ0KGRkKSAvIG1tLFxuICAgICAgICAgICAgazIgPSByYWRpdXMgKiBNYXRoLnNxcnQoY2MpIC8gbW0sXG4gICAgICAgICAgICBqMSA9IGsxICogdHQgLyBkZCxcbiAgICAgICAgICAgIGoyID0gazIgKiB0dCAvIGNjLFxuICAgICAgICAgICAgY3ggPSBrMSAqIGIyICsgazIgKiBiMSxcbiAgICAgICAgICAgIGN5ID0gazEgKiBhMiArIGsyICogYTEsXG4gICAgICAgICAgICBweCA9IGIxICogKGsyICsgajEpLFxuICAgICAgICAgICAgcHkgPSBhMSAqIChrMiArIGoxKSxcbiAgICAgICAgICAgIHF4ID0gYjIgKiAoazEgKyBqMiksXG4gICAgICAgICAgICBxeSA9IGEyICogKGsxICsgajIpLFxuICAgICAgICAgICAgc3RhcnRBbmdsZSA9IE1hdGguYXRhbjIocHkgLSBjeSwgcHggLSBjeCksXG4gICAgICAgICAgICBlbmRBbmdsZSAgID0gTWF0aC5hdGFuMihxeSAtIGN5LCBxeCAtIGN4KTtcblxuICAgICAgICB0aGlzLmFyYyhjeCArIHgxLCBjeSArIHkxLCByYWRpdXMsIHN0YXJ0QW5nbGUsIGVuZEFuZ2xlLCBiMSAqIGEyID4gYjIgKiBhMSk7XG4gICAgfVxuXG4gICAgdGhpcy5kaXJ0eSA9IHRydWU7XG5cbiAgICByZXR1cm4gdGhpcztcbn07XG5cbi8qKlxuICogVGhlIGFyYyBtZXRob2QgY3JlYXRlcyBhbiBhcmMvY3VydmUgKHVzZWQgdG8gY3JlYXRlIGNpcmNsZXMsIG9yIHBhcnRzIG9mIGNpcmNsZXMpLlxuICpcbiAqIEBwYXJhbSBjeCB7bnVtYmVyfSBUaGUgeC1jb29yZGluYXRlIG9mIHRoZSBjZW50ZXIgb2YgdGhlIGNpcmNsZVxuICogQHBhcmFtIGN5IHtudW1iZXJ9IFRoZSB5LWNvb3JkaW5hdGUgb2YgdGhlIGNlbnRlciBvZiB0aGUgY2lyY2xlXG4gKiBAcGFyYW0gcmFkaXVzIHtudW1iZXJ9IFRoZSByYWRpdXMgb2YgdGhlIGNpcmNsZVxuICogQHBhcmFtIHN0YXJ0QW5nbGUge251bWJlcn0gVGhlIHN0YXJ0aW5nIGFuZ2xlLCBpbiByYWRpYW5zICgwIGlzIGF0IHRoZSAzIG8nY2xvY2sgcG9zaXRpb24gb2YgdGhlIGFyYydzIGNpcmNsZSlcbiAqIEBwYXJhbSBlbmRBbmdsZSB7bnVtYmVyfSBUaGUgZW5kaW5nIGFuZ2xlLCBpbiByYWRpYW5zXG4gKiBAcGFyYW0gYW50aWNsb2Nrd2lzZSB7Ym9vbGVhbn0gT3B0aW9uYWwuIFNwZWNpZmllcyB3aGV0aGVyIHRoZSBkcmF3aW5nIHNob3VsZCBiZSBjb3VudGVyY2xvY2t3aXNlIG9yIGNsb2Nrd2lzZS4gRmFsc2UgaXMgZGVmYXVsdCwgYW5kIGluZGljYXRlcyBjbG9ja3dpc2UsIHdoaWxlIHRydWUgaW5kaWNhdGVzIGNvdW50ZXItY2xvY2t3aXNlLlxuICogQHJldHVybiB7R3JhcGhpY3N9XG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5hcmMgPSBmdW5jdGlvbiAoY3gsIGN5LCByYWRpdXMsIHN0YXJ0QW5nbGUsIGVuZEFuZ2xlLCBhbnRpY2xvY2t3aXNlKSB7XG4gICAgdmFyIHN0YXJ0WCA9IGN4ICsgTWF0aC5jb3Moc3RhcnRBbmdsZSkgKiByYWRpdXM7XG4gICAgdmFyIHN0YXJ0WSA9IGN5ICsgTWF0aC5zaW4oc3RhcnRBbmdsZSkgKiByYWRpdXM7XG4gICAgdmFyIHBvaW50cztcblxuICAgIC8vIFRPRE8gLSBUaGlzIGlmLWVsc2UgbWFrZXMgbm8gc2Vuc2UuIEl0IHVzZXMgY3VycmVudFBhdGggaW4gdGhlIGVsc2Ugd2hlcmUgaXQgZG9lc24ndCBleGlzdC4uLlxuICAgIGlmICh0aGlzLmN1cnJlbnRQYXRoKSB7XG4gICAgICAgIHBvaW50cyA9IHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzO1xuXG4gICAgICAgIGlmIChwb2ludHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICBwb2ludHMucHVzaChzdGFydFgsIHN0YXJ0WSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAocG9pbnRzW3BvaW50cy5sZW5ndGgtMl0gIT09IHN0YXJ0WCB8fCBwb2ludHNbcG9pbnRzLmxlbmd0aC0xXSAhPT0gc3RhcnRZKSB7XG4gICAgICAgICAgICBwb2ludHMucHVzaChzdGFydFgsIHN0YXJ0WSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHRoaXMubW92ZVRvKHN0YXJ0WCwgc3RhcnRZKTtcbiAgICAgICAgcG9pbnRzID0gdGhpcy5jdXJyZW50UGF0aC5zaGFwZS5wb2ludHM7XG4gICAgfVxuXG4gICAgaWYgKHN0YXJ0QW5nbGUgPT09IGVuZEFuZ2xlKSB7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIGlmICghYW50aWNsb2Nrd2lzZSAmJiBlbmRBbmdsZSA8PSBzdGFydEFuZ2xlKSB7XG4gICAgICAgIGVuZEFuZ2xlICs9IE1hdGguUEkgKiAyO1xuICAgIH1cbiAgICBlbHNlIGlmIChhbnRpY2xvY2t3aXNlICYmIHN0YXJ0QW5nbGUgPD0gZW5kQW5nbGUpIHtcbiAgICAgICAgc3RhcnRBbmdsZSArPSBNYXRoLlBJICogMjtcbiAgICB9XG5cbiAgICB2YXIgc3dlZXAgPSBhbnRpY2xvY2t3aXNlID8gKHN0YXJ0QW5nbGUgLSBlbmRBbmdsZSkgKi0xIDogKGVuZEFuZ2xlIC0gc3RhcnRBbmdsZSk7XG4gICAgdmFyIHNlZ3MgPSAoTWF0aC5hYnMoc3dlZXApLyAoTWF0aC5QSSAqIDIpKSAqIDQwO1xuXG4gICAgaWYgKHN3ZWVwID09PSAwKSB7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIHZhciB0aGV0YSA9IHN3ZWVwLyhzZWdzKjIpO1xuICAgIHZhciB0aGV0YTIgPSB0aGV0YSoyO1xuXG4gICAgdmFyIGNUaGV0YSA9IE1hdGguY29zKHRoZXRhKTtcbiAgICB2YXIgc1RoZXRhID0gTWF0aC5zaW4odGhldGEpO1xuXG4gICAgdmFyIHNlZ01pbnVzID0gc2VncyAtIDE7XG5cbiAgICB2YXIgcmVtYWluZGVyID0gKCBzZWdNaW51cyAlIDEgKSAvIHNlZ01pbnVzO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPD0gc2VnTWludXM7ICsraSkge1xuICAgICAgICB2YXIgcmVhbCA9ICBpICsgcmVtYWluZGVyICogaTtcbiAgICAgICAgdmFyIGFuZ2xlID0gKCh0aGV0YSkgKyBzdGFydEFuZ2xlICsgKHRoZXRhMiAqIHJlYWwpKTtcblxuICAgICAgICB2YXIgYyA9IE1hdGguY29zKGFuZ2xlKTtcbiAgICAgICAgdmFyIHMgPSAtTWF0aC5zaW4oYW5nbGUpO1xuXG4gICAgICAgIHBvaW50cy5wdXNoKCggKGNUaGV0YSAqICBjKSArIChzVGhldGEgKiBzKSApICogcmFkaXVzICsgY3gsXG4gICAgICAgICAgICAgICAgICAgICggKGNUaGV0YSAqIC1zKSArIChzVGhldGEgKiBjKSApICogcmFkaXVzICsgY3kpO1xuICAgIH1cblxuICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqIFNwZWNpZmllcyBhIHNpbXBsZSBvbmUtY29sb3IgZmlsbCB0aGF0IHN1YnNlcXVlbnQgY2FsbHMgdG8gb3RoZXIgR3JhcGhpY3MgbWV0aG9kc1xuICogKHN1Y2ggYXMgbGluZVRvKCkgb3IgZHJhd0NpcmNsZSgpKSB1c2Ugd2hlbiBkcmF3aW5nLlxuICpcbiAqIEBwYXJhbSBjb2xvciB7bnVtYmVyfSB0aGUgY29sb3Igb2YgdGhlIGZpbGxcbiAqIEBwYXJhbSBhbHBoYSB7bnVtYmVyfSB0aGUgYWxwaGEgb2YgdGhlIGZpbGxcbiAqIEByZXR1cm4ge0dyYXBoaWNzfVxuICovXG5HcmFwaGljcy5wcm90b3R5cGUuYmVnaW5GaWxsID0gZnVuY3Rpb24gKGNvbG9yLCBhbHBoYSkge1xuICAgIHRoaXMuZmlsbGluZyA9IHRydWU7XG4gICAgdGhpcy5maWxsQ29sb3IgPSBjb2xvciB8fCAwO1xuICAgIHRoaXMuZmlsbEFscGhhID0gKGFscGhhID09PSB1bmRlZmluZWQpID8gMSA6IGFscGhhO1xuXG4gICAgaWYgKHRoaXMuY3VycmVudFBhdGgpIHtcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzLmxlbmd0aCA8PSAyKSB7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRQYXRoLmZpbGwgPSB0aGlzLmZpbGxpbmc7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRQYXRoLmZpbGxDb2xvciA9IHRoaXMuZmlsbENvbG9yO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50UGF0aC5maWxsQWxwaGEgPSB0aGlzLmZpbGxBbHBoYTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbn07XG5cbi8qKlxuICogQXBwbGllcyBhIGZpbGwgdG8gdGhlIGxpbmVzIGFuZCBzaGFwZXMgdGhhdCB3ZXJlIGFkZGVkIHNpbmNlIHRoZSBsYXN0IGNhbGwgdG8gdGhlIGJlZ2luRmlsbCgpIG1ldGhvZC5cbiAqXG4gKiBAcmV0dXJuIHtHcmFwaGljc31cbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLmVuZEZpbGwgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5maWxsaW5nID0gZmFsc2U7XG4gICAgdGhpcy5maWxsQ29sb3IgPSBudWxsO1xuICAgIHRoaXMuZmlsbEFscGhhID0gMTtcblxuICAgIHJldHVybiB0aGlzO1xufTtcblxuLyoqXG4gKlxuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmQgb2YgdGhlIHRvcC1sZWZ0IG9mIHRoZSByZWN0YW5nbGVcbiAqIEBwYXJhbSB5IHtudW1iZXJ9IFRoZSBZIGNvb3JkIG9mIHRoZSB0b3AtbGVmdCBvZiB0aGUgcmVjdGFuZ2xlXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gVGhlIHdpZHRoIG9mIHRoZSByZWN0YW5nbGVcbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gVGhlIGhlaWdodCBvZiB0aGUgcmVjdGFuZ2xlXG4gKiBAcmV0dXJuIHtHcmFwaGljc31cbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLmRyYXdSZWN0ID0gZnVuY3Rpb24gKCB4LCB5LCB3aWR0aCwgaGVpZ2h0ICkge1xuICAgIHRoaXMuZHJhd1NoYXBlKG5ldyBtYXRoLlJlY3RhbmdsZSh4LHksIHdpZHRoLCBoZWlnaHQpKTtcblxuICAgIHJldHVybiB0aGlzO1xufTtcblxuLyoqXG4gKlxuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmQgb2YgdGhlIHRvcC1sZWZ0IG9mIHRoZSByZWN0YW5nbGVcbiAqIEBwYXJhbSB5IHtudW1iZXJ9IFRoZSBZIGNvb3JkIG9mIHRoZSB0b3AtbGVmdCBvZiB0aGUgcmVjdGFuZ2xlXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gVGhlIHdpZHRoIG9mIHRoZSByZWN0YW5nbGVcbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gVGhlIGhlaWdodCBvZiB0aGUgcmVjdGFuZ2xlXG4gKiBAcGFyYW0gcmFkaXVzIHtudW1iZXJ9IFJhZGl1cyBvZiB0aGUgcmVjdGFuZ2xlIGNvcm5lcnNcbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLmRyYXdSb3VuZGVkUmVjdCA9IGZ1bmN0aW9uICggeCwgeSwgd2lkdGgsIGhlaWdodCwgcmFkaXVzICkge1xuICAgIHRoaXMuZHJhd1NoYXBlKG5ldyBtYXRoLlJvdW5kZWRSZWN0YW5nbGUoeCwgeSwgd2lkdGgsIGhlaWdodCwgcmFkaXVzKSk7XG5cbiAgICByZXR1cm4gdGhpcztcbn07XG5cbi8qKlxuICogRHJhd3MgYSBjaXJjbGUuXG4gKlxuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmRpbmF0ZSBvZiB0aGUgY2VudGVyIG9mIHRoZSBjaXJjbGVcbiAqIEBwYXJhbSB5IHtudW1iZXJ9IFRoZSBZIGNvb3JkaW5hdGUgb2YgdGhlIGNlbnRlciBvZiB0aGUgY2lyY2xlXG4gKiBAcGFyYW0gcmFkaXVzIHtudW1iZXJ9IFRoZSByYWRpdXMgb2YgdGhlIGNpcmNsZVxuICogQHJldHVybiB7R3JhcGhpY3N9XG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5kcmF3Q2lyY2xlID0gZnVuY3Rpb24gKHgsIHksIHJhZGl1cykge1xuICAgIHRoaXMuZHJhd1NoYXBlKG5ldyBtYXRoLkNpcmNsZSh4LHksIHJhZGl1cykpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqIERyYXdzIGFuIGVsbGlwc2UuXG4gKlxuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmRpbmF0ZSBvZiB0aGUgY2VudGVyIG9mIHRoZSBlbGxpcHNlXG4gKiBAcGFyYW0geSB7bnVtYmVyfSBUaGUgWSBjb29yZGluYXRlIG9mIHRoZSBjZW50ZXIgb2YgdGhlIGVsbGlwc2VcbiAqIEBwYXJhbSB3aWR0aCB7bnVtYmVyfSBUaGUgaGFsZiB3aWR0aCBvZiB0aGUgZWxsaXBzZVxuICogQHBhcmFtIGhlaWdodCB7bnVtYmVyfSBUaGUgaGFsZiBoZWlnaHQgb2YgdGhlIGVsbGlwc2VcbiAqIEByZXR1cm4ge0dyYXBoaWNzfVxuICovXG5HcmFwaGljcy5wcm90b3R5cGUuZHJhd0VsbGlwc2UgPSBmdW5jdGlvbiAoeCwgeSwgd2lkdGgsIGhlaWdodCkge1xuICAgIHRoaXMuZHJhd1NoYXBlKG5ldyBtYXRoLkVsbGlwc2UoeCwgeSwgd2lkdGgsIGhlaWdodCkpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqIERyYXdzIGEgcG9seWdvbiB1c2luZyB0aGUgZ2l2ZW4gcGF0aC5cbiAqXG4gKiBAcGFyYW0gcGF0aCB7QXJyYXl9IFRoZSBwYXRoIGRhdGEgdXNlZCB0byBjb25zdHJ1Y3QgdGhlIHBvbHlnb24uXG4gKiBAcmV0dXJuIHtHcmFwaGljc31cbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLmRyYXdQb2x5Z29uID0gZnVuY3Rpb24gKHBhdGgpIHtcbiAgICBpZiAoIShwYXRoIGluc3RhbmNlb2YgQXJyYXkpKSB7XG4gICAgICAgIHBhdGggPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuICAgIH1cblxuICAgIHRoaXMuZHJhd1NoYXBlKG5ldyBtYXRoLlBvbHlnb24ocGF0aCkpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqIENsZWFycyB0aGUgZ3JhcGhpY3MgdGhhdCB3ZXJlIGRyYXduIHRvIHRoaXMgR3JhcGhpY3Mgb2JqZWN0LCBhbmQgcmVzZXRzIGZpbGwgYW5kIGxpbmUgc3R5bGUgc2V0dGluZ3MuXG4gKlxuICogQHJldHVybiB7R3JhcGhpY3N9XG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5jbGVhciA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmxpbmVXaWR0aCA9IDA7XG4gICAgdGhpcy5maWxsaW5nID0gZmFsc2U7XG5cbiAgICB0aGlzLmRpcnR5ID0gdHJ1ZTtcbiAgICB0aGlzLmNsZWFyRGlydHkgPSB0cnVlO1xuICAgIHRoaXMuZ3JhcGhpY3NEYXRhID0gW107XG5cbiAgICByZXR1cm4gdGhpcztcbn07XG5cbi8qKlxuICogVXNlZnVsIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhIHRleHR1cmUgb2YgdGhlIGdyYXBoaWNzIG9iamVjdCB0aGF0IGNhbiB0aGVuIGJlIHVzZWQgdG8gY3JlYXRlIHNwcml0ZXNcbiAqIFRoaXMgY2FuIGJlIHF1aXRlIHVzZWZ1bCBpZiB5b3VyIGdlb21ldHJ5IGlzIGNvbXBsaWNhdGVkIGFuZCBuZWVkcyB0byBiZSByZXVzZWQgbXVsdGlwbGUgdGltZXMuXG4gKlxuICogQHBhcmFtIHJlc29sdXRpb24ge251bWJlcn0gVGhlIHJlc29sdXRpb24gb2YgdGhlIHRleHR1cmUgYmVpbmcgZ2VuZXJhdGVkXG4gKiBAcGFyYW0gc2NhbGVNb2RlIHtudW1iZXJ9IFNob3VsZCBiZSBvbmUgb2YgdGhlIHNjYWxlTW9kZSBjb25zdHNcbiAqIEByZXR1cm4ge1RleHR1cmV9IGEgdGV4dHVyZSBvZiB0aGUgZ3JhcGhpY3Mgb2JqZWN0XG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5nZW5lcmF0ZVRleHR1cmUgPSBmdW5jdGlvbiAocmVzb2x1dGlvbiwgc2NhbGVNb2RlKSB7XG4gICAgcmVzb2x1dGlvbiA9IHJlc29sdXRpb24gfHwgMTtcblxuICAgIHZhciBib3VuZHMgPSB0aGlzLmdldEJvdW5kcygpO1xuXG4gICAgdmFyIGNhbnZhc0J1ZmZlciA9IG5ldyBDYW52YXNCdWZmZXIoYm91bmRzLndpZHRoICogcmVzb2x1dGlvbiwgYm91bmRzLmhlaWdodCAqIHJlc29sdXRpb24pO1xuXG4gICAgdmFyIHRleHR1cmUgPSBUZXh0dXJlLmZyb21DYW52YXMoY2FudmFzQnVmZmVyLmNhbnZhcywgc2NhbGVNb2RlKTtcbiAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLnJlc29sdXRpb24gPSByZXNvbHV0aW9uO1xuXG4gICAgY2FudmFzQnVmZmVyLmNvbnRleHQuc2NhbGUocmVzb2x1dGlvbiwgcmVzb2x1dGlvbik7XG5cbiAgICBjYW52YXNCdWZmZXIuY29udGV4dC50cmFuc2xhdGUoLWJvdW5kcy54LC1ib3VuZHMueSk7XG5cbiAgICBDYW52YXNHcmFwaGljcy5yZW5kZXJHcmFwaGljcyh0aGlzLCBjYW52YXNCdWZmZXIuY29udGV4dCk7XG5cbiAgICByZXR1cm4gdGV4dHVyZTtcbn07XG5cbi8qKlxuICogUmVuZGVycyB0aGUgb2JqZWN0IHVzaW5nIHRoZSBXZWJHTCByZW5kZXJlclxuICpcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcn1cbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLnJlbmRlcldlYkdMID0gZnVuY3Rpb24gKHJlbmRlcmVyKSB7XG4gICAgLy8gaWYgdGhlIHNwcml0ZSBpcyBub3QgdmlzaWJsZSBvciB0aGUgYWxwaGEgaXMgMCB0aGVuIG5vIG5lZWQgdG8gcmVuZGVyIHRoaXMgZWxlbWVudFxuICAgIGlmICghdGhpcy52aXNpYmxlIHx8IHRoaXMuYWxwaGEgPD0gMCB8fCB0aGlzLmlzTWFzayA9PT0gdHJ1ZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX2NhY2hlQXNCaXRtYXApIHtcbiAgICAgICAgaWYgKHRoaXMuZGlydHkgfHwgdGhpcy5jYWNoZWRTcHJpdGVEaXJ0eSkge1xuICAgICAgICAgICAgdGhpcy5fZ2VuZXJhdGVDYWNoZWRTcHJpdGUoKTtcblxuICAgICAgICAgICAgLy8gd2Ugd2lsbCBhbHNvIG5lZWQgdG8gdXBkYXRlIHRoZSB0ZXh0dXJlIG9uIHRoZSBncHUgdG9vIVxuICAgICAgICAgICAgdGhpcy51cGRhdGVDYWNoZWRTcHJpdGVUZXh0dXJlKCk7XG5cbiAgICAgICAgICAgIHRoaXMuY2FjaGVkU3ByaXRlRGlydHkgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMuZGlydHkgPSBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuX2NhY2hlZFNwcml0ZS53b3JsZEFscGhhID0gdGhpcy53b3JsZEFscGhhO1xuXG4gICAgICAgIFNwcml0ZS5wcm90b3R5cGUucmVuZGVyV2ViR0wuY2FsbCh0aGlzLl9jYWNoZWRTcHJpdGUsIHJlbmRlcmVyKTtcblxuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5zdG9wKCk7XG4gICAgICAgIHJlbmRlcmVyLmJsZW5kTW9kZU1hbmFnZXIuc2V0QmxlbmRNb2RlKHRoaXMuYmxlbmRNb2RlKTtcblxuICAgICAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucHVzaE1hc2sodGhpcy5fbWFzaywgcmVuZGVyZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuX2ZpbHRlcnMpIHtcbiAgICAgICAgICAgIHJlbmRlcmVyLmZpbHRlck1hbmFnZXIucHVzaEZpbHRlcih0aGlzLl9maWx0ZXJCbG9jayk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBjaGVjayBibGVuZCBtb2RlXG4gICAgICAgIGlmICh0aGlzLmJsZW5kTW9kZSAhPT0gcmVuZGVyZXIuc3ByaXRlQmF0Y2guY3VycmVudEJsZW5kTW9kZSkge1xuICAgICAgICAgICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guY3VycmVudEJsZW5kTW9kZSA9IHRoaXMuYmxlbmRNb2RlO1xuXG4gICAgICAgICAgICB2YXIgYmxlbmRNb2RlV2ViR0wgPSByZW5kZXJlci5ibGVuZE1vZGVzW3JlbmRlcmVyLnNwcml0ZUJhdGNoLmN1cnJlbnRCbGVuZE1vZGVdO1xuXG4gICAgICAgICAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5nbC5ibGVuZEZ1bmMoYmxlbmRNb2RlV2ViR0xbMF0sIGJsZW5kTW9kZVdlYkdMWzFdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGNoZWNrIGlmIHRoZSB3ZWJnbCBncmFwaGljIG5lZWRzIHRvIGJlIHVwZGF0ZWRcbiAgICAgICAgaWYgKHRoaXMuZ2xEaXJ0eSkge1xuICAgICAgICAgICAgdGhpcy5kaXJ0eSA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLmdsRGlydHkgPSBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIFdlYkdMR3JhcGhpY3MucmVuZGVyR3JhcGhpY3ModGhpcywgcmVuZGVyZXIpO1xuXG4gICAgICAgIC8vIG9ubHkgcmVuZGVyIGlmIGl0IGhhcyBjaGlsZHJlbiFcbiAgICAgICAgaWYgKHRoaXMuY2hpbGRyZW4ubGVuZ3RoKSB7XG4gICAgICAgICAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5zdGFydCgpO1xuXG4gICAgICAgICAgICAgLy8gc2ltcGxlIHJlbmRlciBjaGlsZHJlbiFcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwLCBqID0gdGhpcy5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyArK2kpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNoaWxkcmVuW2ldLnJlbmRlcldlYkdMKHJlbmRlcmVyKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guc3RvcCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuX2ZpbHRlcnMpIHtcbiAgICAgICAgICAgIHJlbmRlcmVyLmZpbHRlck1hbmFnZXIucG9wRmlsdGVyKCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucG9wTWFzayh0aGlzLm1hc2ssIHJlbmRlcmVyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlbmRlcmVyLmRyYXdDb3VudCsrO1xuXG4gICAgICAgIHJlbmRlcmVyLnNwcml0ZUJhdGNoLnN0YXJ0KCk7XG4gICAgfVxufTtcblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBvYmplY3QgdXNpbmcgdGhlIENhbnZhcyByZW5kZXJlclxuICpcbiAqIEBwYXJhbSByZW5kZXJlciB7Q2FudmFzUmVuZGVyZXJ9XG4gKiBAcHJpdmF0ZVxuICovXG5HcmFwaGljcy5wcm90b3R5cGUucmVuZGVyQ2FudmFzID0gZnVuY3Rpb24gKHJlbmRlcmVyKSB7XG4gICAgLy8gaWYgdGhlIHNwcml0ZSBpcyBub3QgdmlzaWJsZSBvciB0aGUgYWxwaGEgaXMgMCB0aGVuIG5vIG5lZWQgdG8gcmVuZGVyIHRoaXMgZWxlbWVudFxuICAgIGlmICghdGhpcy52aXNpYmxlIHx8IHRoaXMuYWxwaGEgPD0gMCB8fCB0aGlzLmlzTWFzayA9PT0gdHJ1ZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX2NhY2hlQXNCaXRtYXApIHtcbiAgICAgICAgaWYgKHRoaXMuZGlydHkgfHwgdGhpcy5jYWNoZWRTcHJpdGVEaXJ0eSkge1xuICAgICAgICAgICAgdGhpcy5fZ2VuZXJhdGVDYWNoZWRTcHJpdGUoKTtcblxuICAgICAgICAgICAgLy8gd2Ugd2lsbCBhbHNvIG5lZWQgdG8gdXBkYXRlIHRoZSB0ZXh0dXJlXG4gICAgICAgICAgICB0aGlzLnVwZGF0ZUNhY2hlZFNwcml0ZVRleHR1cmUoKTtcblxuICAgICAgICAgICAgdGhpcy5jYWNoZWRTcHJpdGVEaXJ0eSA9IGZhbHNlO1xuICAgICAgICAgICAgdGhpcy5kaXJ0eSA9IGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fY2FjaGVkU3ByaXRlLmFscGhhID0gdGhpcy5hbHBoYTtcblxuICAgICAgICBTcHJpdGUucHJvdG90eXBlLnJlbmRlckNhbnZhcy5jYWxsKHRoaXMuX2NhY2hlZFNwcml0ZSwgcmVuZGVyZXIpO1xuXG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHZhciBjb250ZXh0ID0gcmVuZGVyZXIuY29udGV4dDtcbiAgICAgICAgdmFyIHRyYW5zZm9ybSA9IHRoaXMud29ybGRUcmFuc2Zvcm07XG5cbiAgICAgICAgaWYgKHRoaXMuYmxlbmRNb2RlICE9PSByZW5kZXJlci5jdXJyZW50QmxlbmRNb2RlKSB7XG4gICAgICAgICAgICByZW5kZXJlci5jdXJyZW50QmxlbmRNb2RlID0gdGhpcy5ibGVuZE1vZGU7XG4gICAgICAgICAgICBjb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9IHJlbmRlcmVyLmJsZW5kTW9kZXNbcmVuZGVyZXIuY3VycmVudEJsZW5kTW9kZV07XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucHVzaE1hc2sodGhpcy5fbWFzaywgcmVuZGVyZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHJlc29sdXRpb24gPSByZW5kZXJlci5yZXNvbHV0aW9uO1xuICAgICAgICBjb250ZXh0LnNldFRyYW5zZm9ybShcbiAgICAgICAgICAgIHRyYW5zZm9ybS5hICogcmVzb2x1dGlvbixcbiAgICAgICAgICAgIHRyYW5zZm9ybS5iICogcmVzb2x1dGlvbixcbiAgICAgICAgICAgIHRyYW5zZm9ybS5jICogcmVzb2x1dGlvbixcbiAgICAgICAgICAgIHRyYW5zZm9ybS5kICogcmVzb2x1dGlvbixcbiAgICAgICAgICAgIHRyYW5zZm9ybS50eCAqIHJlc29sdXRpb24sXG4gICAgICAgICAgICB0cmFuc2Zvcm0udHkgKiByZXNvbHV0aW9uXG4gICAgICAgICk7XG5cbiAgICAgICAgQ2FudmFzR3JhcGhpY3MucmVuZGVyR3JhcGhpY3ModGhpcywgY29udGV4dCk7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIGogPSB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGo7ICsraSkge1xuICAgICAgICAgICAgdGhpcy5jaGlsZHJlbltpXS5yZW5kZXJDYW52YXMocmVuZGVyZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuX21hc2spIHtcbiAgICAgICAgICAgIHJlbmRlcmVyLm1hc2tNYW5hZ2VyLnBvcE1hc2socmVuZGVyZXIpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIGJvdW5kcyBvZiB0aGUgZ3JhcGhpYyBzaGFwZSBhcyBhIHJlY3RhbmdsZSBvYmplY3RcbiAqXG4gKiBAcmV0dXJuIHtSZWN0YW5nbGV9IHRoZSByZWN0YW5ndWxhciBib3VuZGluZyBhcmVhXG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5nZXRCb3VuZHMgPSBmdW5jdGlvbiAobWF0cml4KSB7XG4gICAgLy8gcmV0dXJuIGFuIGVtcHR5IG9iamVjdCBpZiB0aGUgaXRlbSBpcyBhIG1hc2shXG4gICAgaWYgKHRoaXMuaXNNYXNrKSB7XG4gICAgICAgIHJldHVybiBtYXRoLlJlY3RhbmdsZS5FTVBUWTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnVwZGF0ZUxvY2FsQm91bmRzKCk7XG5cbiAgICAgICAgdGhpcy5nbERpcnR5ID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5jYWNoZWRTcHJpdGVEaXJ0eSA9IHRydWU7XG4gICAgICAgIHRoaXMuZGlydHkgPSBmYWxzZTtcbiAgICB9XG5cbiAgICB2YXIgYm91bmRzID0gdGhpcy5fbG9jYWxCb3VuZHM7XG5cbiAgICB2YXIgdzAgPSBib3VuZHMueDtcbiAgICB2YXIgdzEgPSBib3VuZHMud2lkdGggKyBib3VuZHMueDtcblxuICAgIHZhciBoMCA9IGJvdW5kcy55O1xuICAgIHZhciBoMSA9IGJvdW5kcy5oZWlnaHQgKyBib3VuZHMueTtcblxuICAgIHZhciB3b3JsZFRyYW5zZm9ybSA9IG1hdHJpeCB8fCB0aGlzLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgdmFyIGEgPSB3b3JsZFRyYW5zZm9ybS5hO1xuICAgIHZhciBiID0gd29ybGRUcmFuc2Zvcm0uYjtcbiAgICB2YXIgYyA9IHdvcmxkVHJhbnNmb3JtLmM7XG4gICAgdmFyIGQgPSB3b3JsZFRyYW5zZm9ybS5kO1xuICAgIHZhciB0eCA9IHdvcmxkVHJhbnNmb3JtLnR4O1xuICAgIHZhciB0eSA9IHdvcmxkVHJhbnNmb3JtLnR5O1xuXG4gICAgdmFyIHgxID0gYSAqIHcxICsgYyAqIGgxICsgdHg7XG4gICAgdmFyIHkxID0gZCAqIGgxICsgYiAqIHcxICsgdHk7XG5cbiAgICB2YXIgeDIgPSBhICogdzAgKyBjICogaDEgKyB0eDtcbiAgICB2YXIgeTIgPSBkICogaDEgKyBiICogdzAgKyB0eTtcblxuICAgIHZhciB4MyA9IGEgKiB3MCArIGMgKiBoMCArIHR4O1xuICAgIHZhciB5MyA9IGQgKiBoMCArIGIgKiB3MCArIHR5O1xuXG4gICAgdmFyIHg0ID0gIGEgKiB3MSArIGMgKiBoMCArIHR4O1xuICAgIHZhciB5NCA9ICBkICogaDAgKyBiICogdzEgKyB0eTtcblxuICAgIHZhciBtYXhYID0geDE7XG4gICAgdmFyIG1heFkgPSB5MTtcblxuICAgIHZhciBtaW5YID0geDE7XG4gICAgdmFyIG1pblkgPSB5MTtcblxuICAgIG1pblggPSB4MiA8IG1pblggPyB4MiA6IG1pblg7XG4gICAgbWluWCA9IHgzIDwgbWluWCA/IHgzIDogbWluWDtcbiAgICBtaW5YID0geDQgPCBtaW5YID8geDQgOiBtaW5YO1xuXG4gICAgbWluWSA9IHkyIDwgbWluWSA/IHkyIDogbWluWTtcbiAgICBtaW5ZID0geTMgPCBtaW5ZID8geTMgOiBtaW5ZO1xuICAgIG1pblkgPSB5NCA8IG1pblkgPyB5NCA6IG1pblk7XG5cbiAgICBtYXhYID0geDIgPiBtYXhYID8geDIgOiBtYXhYO1xuICAgIG1heFggPSB4MyA+IG1heFggPyB4MyA6IG1heFg7XG4gICAgbWF4WCA9IHg0ID4gbWF4WCA/IHg0IDogbWF4WDtcblxuICAgIG1heFkgPSB5MiA+IG1heFkgPyB5MiA6IG1heFk7XG4gICAgbWF4WSA9IHkzID4gbWF4WSA/IHkzIDogbWF4WTtcbiAgICBtYXhZID0geTQgPiBtYXhZID8geTQgOiBtYXhZO1xuXG4gICAgdGhpcy5fYm91bmRzLnggPSBtaW5YO1xuICAgIHRoaXMuX2JvdW5kcy53aWR0aCA9IG1heFggLSBtaW5YO1xuXG4gICAgdGhpcy5fYm91bmRzLnkgPSBtaW5ZO1xuICAgIHRoaXMuX2JvdW5kcy5oZWlnaHQgPSBtYXhZIC0gbWluWTtcblxuICAgIHJldHVybiB0aGlzLl9ib3VuZHM7XG59O1xuXG4vKipcbiAqIFVwZGF0ZSB0aGUgYm91bmRzIG9mIHRoZSBvYmplY3RcbiAqXG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS51cGRhdGVMb2NhbEJvdW5kcyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgbWluWCA9IEluZmluaXR5O1xuICAgIHZhciBtYXhYID0gLUluZmluaXR5O1xuXG4gICAgdmFyIG1pblkgPSBJbmZpbml0eTtcbiAgICB2YXIgbWF4WSA9IC1JbmZpbml0eTtcblxuICAgIGlmICh0aGlzLmdyYXBoaWNzRGF0YS5sZW5ndGgpIHtcbiAgICAgICAgdmFyIHNoYXBlLCBwb2ludHMsIHgsIHksIHcsIGg7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmdyYXBoaWNzRGF0YS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIGRhdGEgPSB0aGlzLmdyYXBoaWNzRGF0YVtpXTtcbiAgICAgICAgICAgIHZhciB0eXBlID0gZGF0YS50eXBlO1xuICAgICAgICAgICAgdmFyIGxpbmVXaWR0aCA9IGRhdGEubGluZVdpZHRoO1xuICAgICAgICAgICAgc2hhcGUgPSBkYXRhLnNoYXBlO1xuXG4gICAgICAgICAgICBpZiAodHlwZSA9PT0gQ09OU1QuU0hBUEVTLlJFQ1QgfHwgdHlwZSA9PT0gQ09OU1QuU0hBUEVTLlJSRUMpIHtcbiAgICAgICAgICAgICAgICB4ID0gc2hhcGUueCAtIGxpbmVXaWR0aC8yO1xuICAgICAgICAgICAgICAgIHkgPSBzaGFwZS55IC0gbGluZVdpZHRoLzI7XG4gICAgICAgICAgICAgICAgdyA9IHNoYXBlLndpZHRoICsgbGluZVdpZHRoO1xuICAgICAgICAgICAgICAgIGggPSBzaGFwZS5oZWlnaHQgKyBsaW5lV2lkdGg7XG5cbiAgICAgICAgICAgICAgICBtaW5YID0geCA8IG1pblggPyB4IDogbWluWDtcbiAgICAgICAgICAgICAgICBtYXhYID0geCArIHcgPiBtYXhYID8geCArIHcgOiBtYXhYO1xuXG4gICAgICAgICAgICAgICAgbWluWSA9IHkgPCBtaW5ZID8geSA6IG1pblk7XG4gICAgICAgICAgICAgICAgbWF4WSA9IHkgKyBoID4gbWF4WSA/IHkgKyBoIDogbWF4WTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKHR5cGUgPT09IENPTlNULlNIQVBFUy5DSVJDKSB7XG4gICAgICAgICAgICAgICAgeCA9IHNoYXBlLng7XG4gICAgICAgICAgICAgICAgeSA9IHNoYXBlLnk7XG4gICAgICAgICAgICAgICAgdyA9IHNoYXBlLnJhZGl1cyArIGxpbmVXaWR0aC8yO1xuICAgICAgICAgICAgICAgIGggPSBzaGFwZS5yYWRpdXMgKyBsaW5lV2lkdGgvMjtcblxuICAgICAgICAgICAgICAgIG1pblggPSB4IC0gdyA8IG1pblggPyB4IC0gdyA6IG1pblg7XG4gICAgICAgICAgICAgICAgbWF4WCA9IHggKyB3ID4gbWF4WCA/IHggKyB3IDogbWF4WDtcblxuICAgICAgICAgICAgICAgIG1pblkgPSB5IC0gaCA8IG1pblkgPyB5IC0gaCA6IG1pblk7XG4gICAgICAgICAgICAgICAgbWF4WSA9IHkgKyBoID4gbWF4WSA/IHkgKyBoIDogbWF4WTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKHR5cGUgPT09IENPTlNULlNIQVBFUy5FTElQKSB7XG4gICAgICAgICAgICAgICAgeCA9IHNoYXBlLng7XG4gICAgICAgICAgICAgICAgeSA9IHNoYXBlLnk7XG4gICAgICAgICAgICAgICAgdyA9IHNoYXBlLndpZHRoICsgbGluZVdpZHRoLzI7XG4gICAgICAgICAgICAgICAgaCA9IHNoYXBlLmhlaWdodCArIGxpbmVXaWR0aC8yO1xuXG4gICAgICAgICAgICAgICAgbWluWCA9IHggLSB3IDwgbWluWCA/IHggLSB3IDogbWluWDtcbiAgICAgICAgICAgICAgICBtYXhYID0geCArIHcgPiBtYXhYID8geCArIHcgOiBtYXhYO1xuXG4gICAgICAgICAgICAgICAgbWluWSA9IHkgLSBoIDwgbWluWSA/IHkgLSBoIDogbWluWTtcbiAgICAgICAgICAgICAgICBtYXhZID0geSArIGggPiBtYXhZID8geSArIGggOiBtYXhZO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gUE9MWVxuICAgICAgICAgICAgICAgIHBvaW50cyA9IHNoYXBlLnBvaW50cztcblxuICAgICAgICAgICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgcG9pbnRzLmxlbmd0aDsgaiArPSAyKSB7XG4gICAgICAgICAgICAgICAgICAgIHggPSBwb2ludHNbal07XG4gICAgICAgICAgICAgICAgICAgIHkgPSBwb2ludHNbaisxXTtcblxuICAgICAgICAgICAgICAgICAgICBtaW5YID0geC1saW5lV2lkdGggPCBtaW5YID8geC1saW5lV2lkdGggOiBtaW5YO1xuICAgICAgICAgICAgICAgICAgICBtYXhYID0geCtsaW5lV2lkdGggPiBtYXhYID8geCtsaW5lV2lkdGggOiBtYXhYO1xuXG4gICAgICAgICAgICAgICAgICAgIG1pblkgPSB5LWxpbmVXaWR0aCA8IG1pblkgPyB5LWxpbmVXaWR0aCA6IG1pblk7XG4gICAgICAgICAgICAgICAgICAgIG1heFkgPSB5K2xpbmVXaWR0aCA+IG1heFkgPyB5K2xpbmVXaWR0aCA6IG1heFk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBtaW5YID0gMDtcbiAgICAgICAgbWF4WCA9IDA7XG4gICAgICAgIG1pblkgPSAwO1xuICAgICAgICBtYXhZID0gMDtcbiAgICB9XG5cbiAgICB2YXIgcGFkZGluZyA9IHRoaXMuYm91bmRzUGFkZGluZztcblxuICAgIHRoaXMuX2xvY2FsQm91bmRzLnggPSBtaW5YIC0gcGFkZGluZztcbiAgICB0aGlzLl9sb2NhbEJvdW5kcy53aWR0aCA9IChtYXhYIC0gbWluWCkgKyBwYWRkaW5nICogMjtcblxuICAgIHRoaXMuX2xvY2FsQm91bmRzLnkgPSBtaW5ZIC0gcGFkZGluZztcbiAgICB0aGlzLl9sb2NhbEJvdW5kcy5oZWlnaHQgPSAobWF4WSAtIG1pblkpICsgcGFkZGluZyAqIDI7XG59O1xuXG4vKipcbiAqIEdlbmVyYXRlcyB0aGUgY2FjaGVkIHNwcml0ZSB3aGVuIHRoZSBzcHJpdGUgaGFzIGNhY2hlQXNCaXRtYXAgPSB0cnVlXG4gKlxuICogQHByaXZhdGVcbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLl9nZW5lcmF0ZUNhY2hlZFNwcml0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgYm91bmRzID0gdGhpcy5nZXRMb2NhbEJvdW5kcygpO1xuXG4gICAgaWYgKCF0aGlzLl9jYWNoZWRTcHJpdGUpIHtcbiAgICAgICAgdmFyIGNhbnZhc0J1ZmZlciA9IG5ldyBDYW52YXNCdWZmZXIoYm91bmRzLndpZHRoLCBib3VuZHMuaGVpZ2h0KTtcbiAgICAgICAgdmFyIHRleHR1cmUgPSBUZXh0dXJlLmZyb21DYW52YXMoY2FudmFzQnVmZmVyLmNhbnZhcyk7XG5cbiAgICAgICAgdGhpcy5fY2FjaGVkU3ByaXRlID0gbmV3IFNwcml0ZSh0ZXh0dXJlKTtcbiAgICAgICAgdGhpcy5fY2FjaGVkU3ByaXRlLmJ1ZmZlciA9IGNhbnZhc0J1ZmZlcjtcblxuICAgICAgICB0aGlzLl9jYWNoZWRTcHJpdGUud29ybGRUcmFuc2Zvcm0gPSB0aGlzLndvcmxkVHJhbnNmb3JtO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdGhpcy5fY2FjaGVkU3ByaXRlLmJ1ZmZlci5yZXNpemUoYm91bmRzLndpZHRoLCBib3VuZHMuaGVpZ2h0KTtcbiAgICB9XG5cbiAgICAvLyBsZXZlcmFnZSB0aGUgYW5jaG9yIHRvIGFjY291bnQgZm9yIHRoZSBvZmZzZXQgb2YgdGhlIGVsZW1lbnRcbiAgICB0aGlzLl9jYWNoZWRTcHJpdGUuYW5jaG9yLnggPSAtKCBib3VuZHMueCAvIGJvdW5kcy53aWR0aCApO1xuICAgIHRoaXMuX2NhY2hlZFNwcml0ZS5hbmNob3IueSA9IC0oIGJvdW5kcy55IC8gYm91bmRzLmhlaWdodCApO1xuXG4gICAgLy8gdGhpcy5fY2FjaGVkU3ByaXRlLmJ1ZmZlci5jb250ZXh0LnNhdmUoKTtcbiAgICB0aGlzLl9jYWNoZWRTcHJpdGUuYnVmZmVyLmNvbnRleHQudHJhbnNsYXRlKC1ib3VuZHMueCwtYm91bmRzLnkpO1xuXG4gICAgLy8gbWFrZSBzdXJlIHdlIHNldCB0aGUgYWxwaGEgb2YgdGhlIGdyYXBoaWNzIHRvIDEgZm9yIHRoZSByZW5kZXIuLlxuICAgIHRoaXMud29ybGRBbHBoYSA9IDE7XG5cbiAgICAvLyBub3cgcmVuZGVyIHRoZSBncmFwaGljLi5cbiAgICBDYW52YXNHcmFwaGljcy5yZW5kZXJHcmFwaGljcyh0aGlzLCB0aGlzLl9jYWNoZWRTcHJpdGUuYnVmZmVyLmNvbnRleHQpO1xuXG4gICAgdGhpcy5fY2FjaGVkU3ByaXRlLmFscGhhID0gdGhpcy5hbHBoYTtcbn07XG5cbi8qKlxuICogVXBkYXRlcyB0ZXh0dXJlIHNpemUgYmFzZWQgb24gY2FudmFzIHNpemVcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5HcmFwaGljcy5wcm90b3R5cGUudXBkYXRlQ2FjaGVkU3ByaXRlVGV4dHVyZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgY2FjaGVkU3ByaXRlID0gdGhpcy5fY2FjaGVkU3ByaXRlO1xuICAgIHZhciB0ZXh0dXJlID0gY2FjaGVkU3ByaXRlLnRleHR1cmU7XG4gICAgdmFyIGNhbnZhcyA9IGNhY2hlZFNwcml0ZS5idWZmZXIuY2FudmFzO1xuXG4gICAgdGV4dHVyZS5iYXNlVGV4dHVyZS53aWR0aCA9IGNhbnZhcy53aWR0aDtcbiAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLmhlaWdodCA9IGNhbnZhcy5oZWlnaHQ7XG4gICAgdGV4dHVyZS5jcm9wLndpZHRoID0gdGV4dHVyZS5mcmFtZS53aWR0aCA9IGNhbnZhcy53aWR0aDtcbiAgICB0ZXh0dXJlLmNyb3AuaGVpZ2h0ID0gdGV4dHVyZS5mcmFtZS5oZWlnaHQgPSBjYW52YXMuaGVpZ2h0O1xuXG4gICAgY2FjaGVkU3ByaXRlLl93aWR0aCA9IGNhbnZhcy53aWR0aDtcbiAgICBjYWNoZWRTcHJpdGUuX2hlaWdodCA9IGNhbnZhcy5oZWlnaHQ7XG5cbiAgICAvLyB1cGRhdGUgdGhlIGRpcnR5IGJhc2UgdGV4dHVyZXNcbiAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLmRpcnR5KCk7XG59O1xuXG4vKipcbiAqIERlc3Ryb3lzIGEgcHJldmlvdXMgY2FjaGVkIHNwcml0ZS5cbiAqXG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5kZXN0cm95Q2FjaGVkU3ByaXRlID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuX2NhY2hlZFNwcml0ZS50ZXh0dXJlLmRlc3Ryb3kodHJ1ZSk7XG5cbiAgICAvLyBsZXQgdGhlIGdjIGNvbGxlY3QgdGhlIHVudXNlZCBzcHJpdGVcbiAgICAvLyBUT0RPIGNvdWxkIGJlIG9iamVjdCBwb29sZWQhXG4gICAgdGhpcy5fY2FjaGVkU3ByaXRlID0gbnVsbDtcbn07XG5cbi8qKlxuICogRHJhd3MgdGhlIGdpdmVuIHNoYXBlIHRvIHRoaXMgR3JhcGhpY3Mgb2JqZWN0LiBDYW4gYmUgYW55IG9mIENpcmNsZSwgUmVjdGFuZ2xlLCBFbGxpcHNlLCBMaW5lIG9yIFBvbHlnb24uXG4gKlxuICogQHBhcmFtIHtDaXJjbGV8UmVjdGFuZ2xlfEVsbGlwc2V8TGluZXxQb2x5Z29ufSBzaGFwZSBUaGUgU2hhcGUgb2JqZWN0IHRvIGRyYXcuXG4gKiBAcmV0dXJuIHtHcmFwaGljc0RhdGF9IFRoZSBnZW5lcmF0ZWQgR3JhcGhpY3NEYXRhIG9iamVjdC5cbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLmRyYXdTaGFwZSA9IGZ1bmN0aW9uIChzaGFwZSkge1xuICAgIGlmICh0aGlzLmN1cnJlbnRQYXRoKSB7XG4gICAgICAgIC8vIGNoZWNrIGN1cnJlbnQgcGF0aCFcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzLmxlbmd0aCA8PSAyKSB7XG4gICAgICAgICAgICB0aGlzLmdyYXBoaWNzRGF0YS5wb3AoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMuY3VycmVudFBhdGggPSBudWxsO1xuXG4gICAgdmFyIGRhdGEgPSBuZXcgR3JhcGhpY3NEYXRhKHRoaXMubGluZVdpZHRoLCB0aGlzLmxpbmVDb2xvciwgdGhpcy5saW5lQWxwaGEsIHRoaXMuZmlsbENvbG9yLCB0aGlzLmZpbGxBbHBoYSwgdGhpcy5maWxsaW5nLCBzaGFwZSk7XG5cbiAgICB0aGlzLmdyYXBoaWNzRGF0YS5wdXNoKGRhdGEpO1xuXG4gICAgaWYgKGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLlBPTFkpIHtcbiAgICAgICAgZGF0YS5zaGFwZS5jbG9zZWQgPSB0aGlzLmZpbGxpbmc7XG4gICAgICAgIHRoaXMuY3VycmVudFBhdGggPSBkYXRhO1xuICAgIH1cblxuICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuXG4gICAgcmV0dXJuIGRhdGE7XG59O1xuIiwiLyoqXG4gKiBBIEdyYXBoaWNzRGF0YSBvYmplY3QuXG4gKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gR3JhcGhpY3NEYXRhKGxpbmVXaWR0aCwgbGluZUNvbG9yLCBsaW5lQWxwaGEsIGZpbGxDb2xvciwgZmlsbEFscGhhLCBmaWxsLCBzaGFwZSkge1xuICAgIHRoaXMubGluZVdpZHRoID0gbGluZVdpZHRoO1xuICAgIHRoaXMubGluZUNvbG9yID0gbGluZUNvbG9yO1xuICAgIHRoaXMubGluZUFscGhhID0gbGluZUFscGhhO1xuICAgIHRoaXMuX2xpbmVUaW50ID0gbGluZUNvbG9yO1xuXG4gICAgdGhpcy5maWxsQ29sb3IgPSBmaWxsQ29sb3I7XG4gICAgdGhpcy5maWxsQWxwaGEgPSBmaWxsQWxwaGE7XG4gICAgdGhpcy5fZmlsbFRpbnQgPSBmaWxsQ29sb3I7XG4gICAgdGhpcy5maWxsID0gZmlsbDtcblxuICAgIHRoaXMuc2hhcGUgPSBzaGFwZTtcbiAgICB0aGlzLnR5cGUgPSBzaGFwZS50eXBlO1xufVxuXG5HcmFwaGljc0RhdGEucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gR3JhcGhpY3NEYXRhO1xubW9kdWxlLmV4cG9ydHMgPSBHcmFwaGljc0RhdGE7XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldyBHcmFwaGljc0RhdGEgb2JqZWN0IHdpdGggdGhlIHNhbWUgdmFsdWVzIGFzIHRoaXMgb25lLlxuICpcbiAqIEByZXR1cm4ge0dyYXBoaWNzRGF0YX1cbiAqL1xuR3JhcGhpY3NEYXRhLnByb3RvdHlwZS5jbG9uZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gbmV3IEdyYXBoaWNzRGF0YShcbiAgICAgICAgdGhpcy5saW5lV2lkdGgsXG4gICAgICAgIHRoaXMubGluZUNvbG9yLFxuICAgICAgICB0aGlzLmxpbmVBbHBoYSxcbiAgICAgICAgdGhpcy5maWxsQ29sb3IsXG4gICAgICAgIHRoaXMuZmlsbEFscGhhLFxuICAgICAgICB0aGlzLmZpbGwsXG4gICAgICAgIHRoaXMuc2hhcGVcbiAgICApO1xufTtcbiIsInZhciBDYW52YXNNYXNrTWFuYWdlciA9IHJlcXVpcmUoJy4vdXRpbHMvQ2FudmFzTWFza01hbmFnZXInKSxcbiAgICB1dGlscyA9IHJlcXVpcmUoJy4uLy4uL3V0aWxzJyksXG4gICAgQ09OU1QgPSByZXF1aXJlKCcuLi8uLi9jb25zdCcpO1xuXG4vKipcbiAqIFRoZSBDYW52YXNSZW5kZXJlciBkcmF3cyB0aGUgc2NlbmUgYW5kIGFsbCBpdHMgY29udGVudCBvbnRvIGEgMmQgY2FudmFzLiBUaGlzIHJlbmRlcmVyIHNob3VsZCBiZSB1c2VkIGZvciBicm93c2VycyB0aGF0IGRvIG5vdCBzdXBwb3J0IHdlYkdMLlxuICogRG9uJ3QgZm9yZ2V0IHRvIGFkZCB0aGUgQ2FudmFzUmVuZGVyZXIudmlldyB0byB5b3VyIERPTSBvciB5b3Ugd2lsbCBub3Qgc2VlIGFueXRoaW5nIDopXG4gKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSBbd2lkdGg9ODAwXSB7bnVtYmVyfSB0aGUgd2lkdGggb2YgdGhlIGNhbnZhcyB2aWV3XG4gKiBAcGFyYW0gW2hlaWdodD02MDBdIHtudW1iZXJ9IHRoZSBoZWlnaHQgb2YgdGhlIGNhbnZhcyB2aWV3XG4gKiBAcGFyYW0gW29wdGlvbnNdIHtvYmplY3R9IFRoZSBvcHRpb25hbCByZW5kZXJlciBwYXJhbWV0ZXJzXG4gKiBAcGFyYW0gW29wdGlvbnMudmlld10ge0hUTUxDYW52YXNFbGVtZW50fSB0aGUgY2FudmFzIHRvIHVzZSBhcyBhIHZpZXcsIG9wdGlvbmFsXG4gKiBAcGFyYW0gW29wdGlvbnMudHJhbnNwYXJlbnQ9ZmFsc2VdIHtib29sZWFufSBJZiB0aGUgcmVuZGVyIHZpZXcgaXMgdHJhbnNwYXJlbnQsIGRlZmF1bHQgZmFsc2VcbiAqIEBwYXJhbSBbb3B0aW9ucy5hdXRvUmVzaXplPWZhbHNlXSB7Ym9vbGVhbn0gSWYgdGhlIHJlbmRlciB2aWV3IGlzIGF1dG9tYXRpY2FsbHkgcmVzaXplZCwgZGVmYXVsdCBmYWxzZVxuICogQHBhcmFtIFtvcHRpb25zLnJlc29sdXRpb249MV0ge251bWJlcn0gdGhlIHJlc29sdXRpb24gb2YgdGhlIHJlbmRlcmVyIHJldGluYSB3b3VsZCBiZSAyXG4gKiBAcGFyYW0gW29wdGlvbnMuY2xlYXJCZWZvcmVSZW5kZXI9dHJ1ZV0ge2Jvb2xlYW59IFRoaXMgc2V0cyBpZiB0aGUgQ2FudmFzUmVuZGVyZXIgd2lsbCBjbGVhciB0aGUgY2FudmFzIG9yIG5vdCBiZWZvcmUgdGhlIG5ldyByZW5kZXIgcGFzcy5cbiAqL1xuZnVuY3Rpb24gQ2FudmFzUmVuZGVyZXIod2lkdGgsIGhlaWdodCwgb3B0aW9ucykge1xuICAgIHV0aWxzLnNheUhlbGxvKCdDYW52YXMnKTtcblxuICAgIGlmIChvcHRpb25zKSB7XG4gICAgICAgIGZvciAodmFyIGkgaW4gQ09OU1QuZGVmYXVsdFJlbmRlck9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygb3B0aW9uc1tpXSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zW2ldID0gQ09OU1QuZGVmYXVsdFJlbmRlck9wdGlvbnNbaV07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIG9wdGlvbnMgPSBDT05TVC5kZWZhdWx0UmVuZGVyT3B0aW9ucztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgcmVuZGVyZXIgdHlwZS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLnR5cGUgPSBDT05TVC5DQU5WQVNfUkVOREVSRVI7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgcmVzb2x1dGlvbiBvZiB0aGUgY2FudmFzLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMucmVzb2x1dGlvbiA9IG9wdGlvbnMucmVzb2x1dGlvbjtcblxuICAgIC8qKlxuICAgICAqIFRoaXMgc2V0cyBpZiB0aGUgQ2FudmFzUmVuZGVyZXIgd2lsbCBjbGVhciB0aGUgY2FudmFzIG9yIG5vdCBiZWZvcmUgdGhlIG5ldyByZW5kZXIgcGFzcy5cbiAgICAgKiBJZiB0aGUgc2NlbmUgaXMgTk9UIHRyYW5zcGFyZW50IFBpeGkgd2lsbCB1c2UgYSBjYW52YXMgc2l6ZWQgZmlsbFJlY3Qgb3BlcmF0aW9uIGV2ZXJ5IGZyYW1lIHRvIHNldCB0aGUgY2FudmFzIGJhY2tncm91bmQgY29sb3IuXG4gICAgICogSWYgdGhlIHNjZW5lIGlzIHRyYW5zcGFyZW50IFBpeGkgd2lsbCB1c2UgY2xlYXJSZWN0IHRvIGNsZWFyIHRoZSBjYW52YXMgZXZlcnkgZnJhbWUuXG4gICAgICogRGlzYWJsZSB0aGlzIGJ5IHNldHRpbmcgdGhpcyB0byBmYWxzZS4gRm9yIGV4YW1wbGUgaWYgeW91ciBnYW1lIGhhcyBhIGNhbnZhcyBmaWxsaW5nIGJhY2tncm91bmQgaW1hZ2UgeW91IG9mdGVuIGRvbid0IG5lZWQgdGhpcyBzZXQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqIEBkZWZhdWx0XG4gICAgICovXG4gICAgdGhpcy5jbGVhckJlZm9yZVJlbmRlciA9IG9wdGlvbnMuY2xlYXJCZWZvcmVSZW5kZXI7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgYmFja2dyb3VuZCBjb2xvciBhcyBhIG51bWJlci5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuX2JhY2tncm91bmRDb2xvciA9IDB4MDAwMDAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGJhY2tncm91bmQgY29sb3IgYXMgYSBzdHJpbmcuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtzdHJpbmd9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl9iYWNrZ3JvdW5kQ29sb3JTdHJpbmcgPSAnIzAwMDAwMCc7XG5cbiAgICB0aGlzLmJhY2tncm91bmRDb2xvciA9IG9wdGlvbnMuYmFja2dyb3VuZENvbG9yIHx8IHRoaXMuX2JhY2tncm91bmRDb2xvcjsgLy8gcnVuIGJnIGNvbG9yIHNldHRlclxuXG4gICAgLyoqXG4gICAgICogV2hldGhlciB0aGUgcmVuZGVyIHZpZXcgaXMgdHJhbnNwYXJlbnRcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy50cmFuc3BhcmVudCA9IG9wdGlvbnMudHJhbnNwYXJlbnQ7XG5cbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRoZSByZW5kZXIgdmlldyBzaG91bGQgYmUgcmVzaXplZCBhdXRvbWF0aWNhbGx5XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMuYXV0b1Jlc2l6ZSA9IG9wdGlvbnMuYXV0b1Jlc2l6ZSB8fCBmYWxzZTtcblxuXG4gICAgLyoqXG4gICAgICogVGhlIHdpZHRoIG9mIHRoZSBjYW52YXMgdmlld1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDgwMFxuICAgICAqL1xuICAgIHRoaXMud2lkdGggPSB3aWR0aCB8fCA4MDA7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgaGVpZ2h0IG9mIHRoZSBjYW52YXMgdmlld1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDYwMFxuICAgICAqL1xuICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0IHx8IDYwMDtcblxuICAgIHRoaXMud2lkdGggKj0gdGhpcy5yZXNvbHV0aW9uO1xuICAgIHRoaXMuaGVpZ2h0ICo9IHRoaXMucmVzb2x1dGlvbjtcblxuICAgIC8qKlxuICAgICAqIFRoZSBjYW52YXMgZWxlbWVudCB0aGF0IGV2ZXJ5dGhpbmcgaXMgZHJhd24gdG8uXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtIVE1MQ2FudmFzRWxlbWVudH1cbiAgICAgKi9cbiAgICB0aGlzLnZpZXcgPSBvcHRpb25zLnZpZXcgfHwgZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgY2FudmFzIDJkIGNvbnRleHQgdGhhdCBldmVyeXRoaW5nIGlzIGRyYXduIHdpdGhcbiAgICAgKiBAbWVtYmVyIHtDYW52YXNSZW5kZXJpbmdDb250ZXh0MkR9XG4gICAgICovXG4gICAgdGhpcy5jb250ZXh0ID0gdGhpcy52aWV3LmdldENvbnRleHQoJzJkJywgeyBhbHBoYTogdGhpcy50cmFuc3BhcmVudCB9KTtcblxuICAgIC8qKlxuICAgICAqIEJvb2xlYW4gZmxhZyBjb250cm9sbGluZyBjYW52YXMgcmVmcmVzaC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5yZWZyZXNoID0gdHJ1ZTtcblxuICAgIHRoaXMudmlldy53aWR0aCA9IHRoaXMud2lkdGggKiB0aGlzLnJlc29sdXRpb247XG4gICAgdGhpcy52aWV3LmhlaWdodCA9IHRoaXMuaGVpZ2h0ICogdGhpcy5yZXNvbHV0aW9uO1xuXG4gICAgLyoqXG4gICAgICogSW50ZXJuYWwgdmFyLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMuY291bnQgPSAwO1xuXG4gICAgLyoqXG4gICAgICogSW5zdGFuY2Ugb2YgYSBDYW52YXNNYXNrTWFuYWdlciwgaGFuZGxlcyBtYXNraW5nIHdoZW4gdXNpbmcgdGhlIGNhbnZhcyByZW5kZXJlclxuICAgICAqIEBtZW1iZXIge0NhbnZhc01hc2tNYW5hZ2VyfVxuICAgICAqL1xuICAgIHRoaXMubWFza01hbmFnZXIgPSBuZXcgQ2FudmFzTWFza01hbmFnZXIoKTtcblxuICAgIC8qKlxuICAgICAqIElmIHRydWUgUGl4aSB3aWxsIE1hdGguZmxvb3IoKSB4L3kgdmFsdWVzIHdoZW4gcmVuZGVyaW5nLCBzdG9wcGluZyBwaXhlbCBpbnRlcnBvbGF0aW9uLlxuICAgICAqIEhhbmR5IGZvciBjcmlzcCBwaXhlbCBhcnQgYW5kIHNwZWVkIG9uIGxlZ2FjeSBkZXZpY2VzLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLnJvdW5kUGl4ZWxzID0gZmFsc2U7XG5cbiAgICB0aGlzLnNjYWxlTW9kZSA9IG51bGw7XG5cbiAgICB0aGlzLnNtb290aFByb3BlcnR5ID0gbnVsbDtcblxuICAgIGlmICh0aGlzLmNvbnRleHQuaW1hZ2VTbW9vdGhpbmdFbmFibGVkKSB7XG4gICAgICAgIHRoaXMuc21vb3RoUHJvcGVydHkgPSAnaW1hZ2VTbW9vdGhpbmdFbmFibGVkJztcbiAgICB9XG4gICAgZWxzZSBpZiAodGhpcy5jb250ZXh0LndlYmtpdEltYWdlU21vb3RoaW5nRW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNtb290aFByb3BlcnR5ID0gJ3dlYmtpdEltYWdlU21vb3RoaW5nRW5hYmxlZCc7XG4gICAgfVxuICAgIGVsc2UgaWYgKHRoaXMuY29udGV4dC5tb3pJbWFnZVNtb290aGluZ0VuYWJsZWQpIHtcbiAgICAgICAgdGhpcy5zbW9vdGhQcm9wZXJ0eSA9ICdtb3pJbWFnZVNtb290aGluZ0VuYWJsZWQnO1xuICAgIH1cbiAgICBlbHNlIGlmICh0aGlzLmNvbnRleHQub0ltYWdlU21vb3RoaW5nRW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNtb290aFByb3BlcnR5ID0gJ29JbWFnZVNtb290aGluZ0VuYWJsZWQnO1xuICAgIH1cbiAgICBlbHNlIGlmICh0aGlzLmNvbnRleHQubXNJbWFnZVNtb290aGluZ0VuYWJsZWQpIHtcbiAgICAgICAgdGhpcy5zbW9vdGhQcm9wZXJ0eSA9ICdtc0ltYWdlU21vb3RoaW5nRW5hYmxlZCc7XG4gICAgfVxuXG4gICAgdGhpcy5jdXJyZW50QmxlbmRNb2RlID0gQ09OU1QuYmxlbmRNb2Rlcy5OT1JNQUw7XG5cbiAgICB0aGlzLmJsZW5kTW9kZXMgPSBudWxsO1xuXG4gICAgdGhpcy5fbWFwQmxlbmRNb2RlcygpO1xuXG4gICAgdGhpcy5yZXNpemUod2lkdGgsIGhlaWdodCk7XG59XG5cbi8vIGNvbnN0cnVjdG9yXG5DYW52YXNSZW5kZXJlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDYW52YXNSZW5kZXJlcjtcbm1vZHVsZS5leHBvcnRzID0gQ2FudmFzUmVuZGVyZXI7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKENhbnZhc1JlbmRlcmVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSBiYWNrZ3JvdW5kIGNvbG9yIHRvIGZpbGwgaWYgbm90IHRyYW5zcGFyZW50XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIENhbnZhc1JlbmRlcmVyI1xuICAgICAqL1xuICAgIGJhY2tncm91bmRDb2xvcjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9iYWNrZ3JvdW5kQ29sb3I7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbCkge1xuICAgICAgICAgICAgdGhpcy5fYmFja2dyb3VuZENvbG9yID0gdmFsO1xuICAgICAgICAgICAgdGhpcy5fYmFja2dyb3VuZENvbG9yU3RyaW5nID0gdXRpbHMuaGV4MnN0cmluZyh2YWwpO1xuICAgICAgICB9XG4gICAgfVxufSk7XG5cbi8qKlxuICogUmVuZGVycyB0aGUgb2JqZWN0IHRvIHRoaXMgY2FudmFzIHZpZXdcbiAqXG4gKiBAcGFyYW0gb2JqZWN0IHtEaXNwbGF5T2JqZWN0fSB0aGUgb2JqZWN0IHRvIGJlIHJlbmRlcmVkXG4gKi9cbkNhbnZhc1JlbmRlcmVyLnByb3RvdHlwZS5yZW5kZXIgPSBmdW5jdGlvbiAob2JqZWN0KSB7XG4gICAgb2JqZWN0LnVwZGF0ZVRyYW5zZm9ybSgpO1xuXG4gICAgdGhpcy5jb250ZXh0LnNldFRyYW5zZm9ybSgxLDAsMCwxLDAsMCk7XG5cbiAgICB0aGlzLmNvbnRleHQuZ2xvYmFsQWxwaGEgPSAxO1xuXG4gICAgdGhpcy5jdXJyZW50QmxlbmRNb2RlID0gQ09OU1QuYmxlbmRNb2Rlcy5OT1JNQUw7XG4gICAgdGhpcy5jb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9IHRoaXMuYmxlbmRNb2Rlc1tDT05TVC5ibGVuZE1vZGVzLk5PUk1BTF07XG5cbiAgICBpZiAobmF2aWdhdG9yLmlzQ29jb29uSlMgJiYgdGhpcy52aWV3LnNjcmVlbmNhbnZhcykge1xuICAgICAgICB0aGlzLmNvbnRleHQuZmlsbFN0eWxlID0gJ2JsYWNrJztcbiAgICAgICAgdGhpcy5jb250ZXh0LmNsZWFyKCk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuY2xlYXJCZWZvcmVSZW5kZXIpIHtcbiAgICAgICAgaWYgKHRoaXMudHJhbnNwYXJlbnQpIHtcbiAgICAgICAgICAgIHRoaXMuY29udGV4dC5jbGVhclJlY3QoMCwgMCwgdGhpcy53aWR0aCwgdGhpcy5oZWlnaHQpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5jb250ZXh0LmZpbGxTdHlsZSA9IHRoaXMuX2JhY2tncm91bmRDb2xvclN0cmluZztcbiAgICAgICAgICAgIHRoaXMuY29udGV4dC5maWxsUmVjdCgwLCAwLCB0aGlzLndpZHRoICwgdGhpcy5oZWlnaHQpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5yZW5kZXJEaXNwbGF5T2JqZWN0KG9iamVjdCk7XG59O1xuXG4vKipcbiAqIFJlbW92ZXMgZXZlcnl0aGluZyBmcm9tIHRoZSByZW5kZXJlciBhbmQgb3B0aW9uYWxseSByZW1vdmVzIHRoZSBDYW52YXMgRE9NIGVsZW1lbnQuXG4gKlxuICogQHBhcmFtIFtyZW1vdmVWaWV3PWZhbHNlXSB7Ym9vbGVhbn0gUmVtb3ZlcyB0aGUgQ2FudmFzIGVsZW1lbnQgZnJvbSB0aGUgRE9NLlxuICovXG5DYW52YXNSZW5kZXJlci5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uIChyZW1vdmVWaWV3KSB7XG4gICAgaWYgKHJlbW92ZVZpZXcgJiYgdGhpcy52aWV3LnBhcmVudCkge1xuICAgICAgICB0aGlzLnZpZXcucGFyZW50LnJlbW92ZUNoaWxkKHRoaXMudmlldyk7XG4gICAgfVxuXG4gICAgdGhpcy52aWV3ID0gbnVsbDtcbiAgICB0aGlzLmNvbnRleHQgPSBudWxsO1xuICAgIHRoaXMubWFza01hbmFnZXIgPSBudWxsO1xufTtcblxuLyoqXG4gKiBSZXNpemVzIHRoZSBjYW52YXMgdmlldyB0byB0aGUgc3BlY2lmaWVkIHdpZHRoIGFuZCBoZWlnaHRcbiAqXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gdGhlIG5ldyB3aWR0aCBvZiB0aGUgY2FudmFzIHZpZXdcbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gdGhlIG5ldyBoZWlnaHQgb2YgdGhlIGNhbnZhcyB2aWV3XG4gKi9cbkNhbnZhc1JlbmRlcmVyLnByb3RvdHlwZS5yZXNpemUgPSBmdW5jdGlvbiAod2lkdGgsIGhlaWdodCkge1xuICAgIHRoaXMud2lkdGggPSB3aWR0aCAqIHRoaXMucmVzb2x1dGlvbjtcbiAgICB0aGlzLmhlaWdodCA9IGhlaWdodCAqIHRoaXMucmVzb2x1dGlvbjtcblxuICAgIHRoaXMudmlldy53aWR0aCA9IHRoaXMud2lkdGg7XG4gICAgdGhpcy52aWV3LmhlaWdodCA9IHRoaXMuaGVpZ2h0O1xuXG4gICAgaWYgKHRoaXMuYXV0b1Jlc2l6ZSkge1xuICAgICAgICB0aGlzLnZpZXcuc3R5bGUud2lkdGggPSB0aGlzLndpZHRoIC8gdGhpcy5yZXNvbHV0aW9uICsgJ3B4JztcbiAgICAgICAgdGhpcy52aWV3LnN0eWxlLmhlaWdodCA9IHRoaXMuaGVpZ2h0IC8gdGhpcy5yZXNvbHV0aW9uICsgJ3B4JztcbiAgICB9XG59O1xuXG4vKipcbiAqIFJlbmRlcnMgYSBkaXNwbGF5IG9iamVjdFxuICpcbiAqIEBwYXJhbSBkaXNwbGF5T2JqZWN0IHtEaXNwbGF5T2JqZWN0fSBUaGUgZGlzcGxheU9iamVjdCB0byByZW5kZXJcbiAqIEBwcml2YXRlXG4gKi9cbkNhbnZhc1JlbmRlcmVyLnByb3RvdHlwZS5yZW5kZXJEaXNwbGF5T2JqZWN0ID0gZnVuY3Rpb24gKGRpc3BsYXlPYmplY3QpIHtcbiAgICBkaXNwbGF5T2JqZWN0LnJlbmRlckNhbnZhcyh0aGlzKTtcbn07XG5cbi8qKlxuICogTWFwcyBQaXhpIGJsZW5kIG1vZGVzIHRvIGNhbnZhcyBibGVuZCBtb2Rlcy5cbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5DYW52YXNSZW5kZXJlci5wcm90b3R5cGUuX21hcEJsZW5kTW9kZXMgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKCF0aGlzLmJsZW5kTW9kZXMpIHtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzID0ge307XG5cbiAgICAgICAgaWYgKHV0aWxzLmNhblVzZU5ld0NhbnZhc0JsZW5kTW9kZXMoKSkge1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTk9STUFMXSAgICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQUREXSAgICAgICAgICAgPSAnbGlnaHRlcic7IC8vSVMgVEhJUyBPSz8/P1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTVVMVElQTFldICAgICAgPSAnbXVsdGlwbHknO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuU0NSRUVOXSAgICAgICAgPSAnc2NyZWVuJztcbiAgICAgICAgICAgIHRoaXMuYmxlbmRNb2Rlc1tDT05TVC5ibGVuZE1vZGVzLk9WRVJMQVldICAgICAgID0gJ292ZXJsYXknO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuREFSS0VOXSAgICAgICAgPSAnZGFya2VuJztcbiAgICAgICAgICAgIHRoaXMuYmxlbmRNb2Rlc1tDT05TVC5ibGVuZE1vZGVzLkxJR0hURU5dICAgICAgID0gJ2xpZ2h0ZW4nO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JfRE9ER0VdICAgPSAnY29sb3ItZG9kZ2UnO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JfQlVSTl0gICAgPSAnY29sb3ItYnVybic7XG4gICAgICAgICAgICB0aGlzLmJsZW5kTW9kZXNbQ09OU1QuYmxlbmRNb2Rlcy5IQVJEX0xJR0hUXSAgICA9ICdoYXJkLWxpZ2h0JztcbiAgICAgICAgICAgIHRoaXMuYmxlbmRNb2Rlc1tDT05TVC5ibGVuZE1vZGVzLlNPRlRfTElHSFRdICAgID0gJ3NvZnQtbGlnaHQnO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuRElGRkVSRU5DRV0gICAgPSAnZGlmZmVyZW5jZSc7XG4gICAgICAgICAgICB0aGlzLmJsZW5kTW9kZXNbQ09OU1QuYmxlbmRNb2Rlcy5FWENMVVNJT05dICAgICA9ICdleGNsdXNpb24nO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuSFVFXSAgICAgICAgICAgPSAnaHVlJztcbiAgICAgICAgICAgIHRoaXMuYmxlbmRNb2Rlc1tDT05TVC5ibGVuZE1vZGVzLlNBVFVSQVRJT05dICAgID0gJ3NhdHVyYXRpb24nO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JdICAgICAgICAgPSAnY29sb3InO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTFVNSU5PU0lUWV0gICAgPSAnbHVtaW5vc2l0eSc7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyB0aGlzIG1lYW5zIHRoYXQgdGhlIGJyb3dzZXIgZG9lcyBub3Qgc3VwcG9ydCB0aGUgY29vbCBuZXcgYmxlbmQgbW9kZXMgaW4gY2FudmFzICdjb3VnaCcgaWUgJ2NvdWdoJ1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTk9STUFMXSAgICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQUREXSAgICAgICAgICAgPSAnbGlnaHRlcic7IC8vSVMgVEhJUyBPSz8/P1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTVVMVElQTFldICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuU0NSRUVOXSAgICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuT1ZFUkxBWV0gICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuREFSS0VOXSAgICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTElHSFRFTl0gICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JfRE9ER0VdICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JfQlVSTl0gICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuSEFSRF9MSUdIVF0gICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuU09GVF9MSUdIVF0gICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuRElGRkVSRU5DRV0gICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuRVhDTFVTSU9OXSAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuSFVFXSAgICAgICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuU0FUVVJBVElPTl0gICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JdICAgICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTFVNSU5PU0lUWV0gICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICB9XG4gICAgfVxufTtcbiIsIi8qKlxuICogQ3JlYXRlcyBhIENhbnZhcyBlbGVtZW50IG9mIHRoZSBnaXZlbiBzaXplLlxuICpcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gdGhlIHdpZHRoIGZvciB0aGUgbmV3bHkgY3JlYXRlZCBjYW52YXNcbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gdGhlIGhlaWdodCBmb3IgdGhlIG5ld2x5IGNyZWF0ZWQgY2FudmFzXG4gKi9cbmZ1bmN0aW9uIENhbnZhc0J1ZmZlcih3aWR0aCwgaGVpZ2h0KSB7XG4gICAgLyoqXG4gICAgICogVGhlIENhbnZhcyBvYmplY3QgdGhhdCBiZWxvbmdzIHRvIHRoaXMgQ2FudmFzQnVmZmVyLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7SFRNTENhbnZhc0VsZW1lbnR9XG4gICAgICovXG4gICAgdGhpcy5jYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcblxuICAgIC8qKlxuICAgICAqIEEgQ2FudmFzUmVuZGVyaW5nQ29udGV4dDJEIG9iamVjdCByZXByZXNlbnRpbmcgYSB0d28tZGltZW5zaW9uYWwgcmVuZGVyaW5nIGNvbnRleHQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtDYW52YXNSZW5kZXJpbmdDb250ZXh0MkR9XG4gICAgICovXG4gICAgdGhpcy5jb250ZXh0ID0gdGhpcy5jYW52YXMuZ2V0Q29udGV4dCgnMmQnKTtcblxuICAgIHRoaXMuY2FudmFzLndpZHRoID0gd2lkdGg7XG4gICAgdGhpcy5jYW52YXMuaGVpZ2h0ID0gaGVpZ2h0O1xufVxuXG5DYW52YXNCdWZmZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQ2FudmFzQnVmZmVyO1xubW9kdWxlLmV4cG9ydHMgPSBDYW52YXNCdWZmZXI7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKENhbnZhc0J1ZmZlci5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBUaGUgd2lkdGggb2YgdGhlIGNhbnZhcyBidWZmZXIgaW4gcGl4ZWxzLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBDYW52YXNCdWZmZXIjXG4gICAgICovXG4gICAgd2lkdGg6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jYW52YXMud2lkdGg7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbCkge1xuICAgICAgICAgICAgdGhpcy5jYW52YXMud2lkdGggPSB2YWw7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIC8qKlxuICAgICAqIFRoZSBoZWlnaHQgb2YgdGhlIGNhbnZhcyBidWZmZXIgaW4gcGl4ZWxzLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBDYW52YXNCdWZmZXIjXG4gICAgICovXG4gICAgaGVpZ2h0OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY2FudmFzLmhlaWdodDtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsKSB7XG4gICAgICAgICAgICB0aGlzLmNhbnZhcy5oZWlnaHQgPSB2YWw7XG4gICAgICAgIH1cbiAgICB9XG59KTtcblxuLyoqXG4gKiBDbGVhcnMgdGhlIGNhbnZhcyB0aGF0IHdhcyBjcmVhdGVkIGJ5IHRoZSBDYW52YXNCdWZmZXIgY2xhc3MuXG4gKlxuICogQHByaXZhdGVcbiAqL1xuQ2FudmFzQnVmZmVyLnByb3RvdHlwZS5jbGVhciA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmNvbnRleHQuc2V0VHJhbnNmb3JtKDEsIDAsIDAsIDEsIDAsIDApO1xuICAgIHRoaXMuY29udGV4dC5jbGVhclJlY3QoMCwwLCB0aGlzLmNhbnZhcy53aWR0aCwgdGhpcy5jYW52YXMuaGVpZ2h0KTtcbn07XG5cbi8qKlxuICogUmVzaXplcyB0aGUgY2FudmFzIHRvIHRoZSBzcGVjaWZpZWQgd2lkdGggYW5kIGhlaWdodC5cbiAqXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gdGhlIG5ldyB3aWR0aCBvZiB0aGUgY2FudmFzXG4gKiBAcGFyYW0gaGVpZ2h0IHtudW1iZXJ9IHRoZSBuZXcgaGVpZ2h0IG9mIHRoZSBjYW52YXNcbiAqL1xuQ2FudmFzQnVmZmVyLnByb3RvdHlwZS5yZXNpemUgPSBmdW5jdGlvbiAod2lkdGgsIGhlaWdodCkge1xuICAgIHRoaXMuY2FudmFzLndpZHRoID0gd2lkdGg7XG4gICAgdGhpcy5jYW52YXMuaGVpZ2h0ID0gaGVpZ2h0O1xufTtcbiIsInZhciBDT05TVCA9IHJlcXVpcmUoJy4uLy4uLy4uL2NvbnN0Jyk7XG5cbi8qKlxuICogQSBzZXQgb2YgZnVuY3Rpb25zIHVzZWQgYnkgdGhlIGNhbnZhcyByZW5kZXJlciB0byBkcmF3IHRoZSBwcmltaXRpdmUgZ3JhcGhpY3MgZGF0YS5cbiAqXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xudmFyIENhbnZhc0dyYXBoaWNzID0gbW9kdWxlLmV4cG9ydHMgPSB7fTtcblxuLypcbiAqIFJlbmRlcnMgYSBHcmFwaGljcyBvYmplY3QgdG8gYSBjYW52YXMuXG4gKlxuICogQHBhcmFtIGdyYXBoaWNzIHtHcmFwaGljc30gdGhlIGFjdHVhbCBncmFwaGljcyBvYmplY3QgdG8gcmVuZGVyXG4gKiBAcGFyYW0gY29udGV4dCB7Q2FudmFzUmVuZGVyaW5nQ29udGV4dDJEfSB0aGUgMmQgZHJhd2luZyBtZXRob2Qgb2YgdGhlIGNhbnZhc1xuICovXG5DYW52YXNHcmFwaGljcy5yZW5kZXJHcmFwaGljcyA9IGZ1bmN0aW9uIChncmFwaGljcywgY29udGV4dCkge1xuICAgIHZhciB3b3JsZEFscGhhID0gZ3JhcGhpY3Mud29ybGRBbHBoYTtcblxuICAgIGlmIChncmFwaGljcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnVwZGF0ZUdyYXBoaWNzVGludChncmFwaGljcyk7XG4gICAgICAgIGdyYXBoaWNzLmRpcnR5ID0gZmFsc2U7XG4gICAgfVxuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBncmFwaGljcy5ncmFwaGljc0RhdGEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGRhdGEgPSBncmFwaGljcy5ncmFwaGljc0RhdGFbaV07XG4gICAgICAgIHZhciBzaGFwZSA9IGRhdGEuc2hhcGU7XG5cbiAgICAgICAgdmFyIGZpbGxDb2xvciA9IGRhdGEuX2ZpbGxUaW50O1xuICAgICAgICB2YXIgbGluZUNvbG9yID0gZGF0YS5fbGluZVRpbnQ7XG5cbiAgICAgICAgY29udGV4dC5saW5lV2lkdGggPSBkYXRhLmxpbmVXaWR0aDtcblxuICAgICAgICBpZiAoZGF0YS50eXBlID09PSBDT05TVC5TSEFQRVMuUE9MWSkge1xuICAgICAgICAgICAgY29udGV4dC5iZWdpblBhdGgoKTtcblxuICAgICAgICAgICAgdmFyIHBvaW50cyA9IHNoYXBlLnBvaW50cztcblxuICAgICAgICAgICAgY29udGV4dC5tb3ZlVG8ocG9pbnRzWzBdLCBwb2ludHNbMV0pO1xuXG4gICAgICAgICAgICBmb3IgKHZhciBqPTE7IGogPCBwb2ludHMubGVuZ3RoLzI7IGorKykge1xuICAgICAgICAgICAgICAgIGNvbnRleHQubGluZVRvKHBvaW50c1tqICogMl0sIHBvaW50c1tqICogMiArIDFdKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHNoYXBlLmNsb3NlZCkge1xuICAgICAgICAgICAgICAgIGNvbnRleHQubGluZVRvKHBvaW50c1swXSwgcG9pbnRzWzFdKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gaWYgdGhlIGZpcnN0IGFuZCBsYXN0IHBvaW50IGFyZSB0aGUgc2FtZSBjbG9zZSB0aGUgcGF0aCAtIG11Y2ggbmVhdGVyIDopXG4gICAgICAgICAgICBpZiAocG9pbnRzWzBdID09PSBwb2ludHNbcG9pbnRzLmxlbmd0aC0yXSAmJiBwb2ludHNbMV0gPT09IHBvaW50c1twb2ludHMubGVuZ3RoLTFdKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5jbG9zZVBhdGgoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGRhdGEuZmlsbCkge1xuICAgICAgICAgICAgICAgIGNvbnRleHQuZ2xvYmFsQWxwaGEgPSBkYXRhLmZpbGxBbHBoYSAqIHdvcmxkQWxwaGE7XG4gICAgICAgICAgICAgICAgY29udGV4dC5maWxsU3R5bGUgPSAnIycgKyAoJzAwMDAwJyArICggZmlsbENvbG9yIHwgMCkudG9TdHJpbmcoMTYpKS5zdWJzdHIoLTYpO1xuICAgICAgICAgICAgICAgIGNvbnRleHQuZmlsbCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRhdGEubGluZVdpZHRoKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IGRhdGEubGluZUFscGhhICogd29ybGRBbHBoYTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZVN0eWxlID0gJyMnICsgKCcwMDAwMCcgKyAoIGxpbmVDb2xvciB8IDApLnRvU3RyaW5nKDE2KSkuc3Vic3RyKC02KTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLlJFQ1QpIHtcblxuICAgICAgICAgICAgaWYgKGRhdGEuZmlsbENvbG9yIHx8IGRhdGEuZmlsbENvbG9yID09PSAwKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IGRhdGEuZmlsbEFscGhhICogd29ybGRBbHBoYTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LmZpbGxTdHlsZSA9ICcjJyArICgnMDAwMDAnICsgKCBmaWxsQ29sb3IgfCAwKS50b1N0cmluZygxNikpLnN1YnN0cigtNik7XG4gICAgICAgICAgICAgICAgY29udGV4dC5maWxsUmVjdChzaGFwZS54LCBzaGFwZS55LCBzaGFwZS53aWR0aCwgc2hhcGUuaGVpZ2h0KTtcblxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRhdGEubGluZVdpZHRoKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IGRhdGEubGluZUFscGhhICogd29ybGRBbHBoYTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZVN0eWxlID0gJyMnICsgKCcwMDAwMCcgKyAoIGxpbmVDb2xvciB8IDApLnRvU3RyaW5nKDE2KSkuc3Vic3RyKC02KTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZVJlY3Qoc2hhcGUueCwgc2hhcGUueSwgc2hhcGUud2lkdGgsIHNoYXBlLmhlaWdodCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZGF0YS50eXBlID09PSBDT05TVC5TSEFQRVMuQ0lSQykge1xuICAgICAgICAgICAgLy8gVE9ETyAtIG5lZWQgdG8gYmUgVW5kZWZpbmVkIVxuICAgICAgICAgICAgY29udGV4dC5iZWdpblBhdGgoKTtcbiAgICAgICAgICAgIGNvbnRleHQuYXJjKHNoYXBlLngsIHNoYXBlLnksIHNoYXBlLnJhZGl1cywwLDIqTWF0aC5QSSk7XG4gICAgICAgICAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuXG4gICAgICAgICAgICBpZiAoZGF0YS5maWxsKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IGRhdGEuZmlsbEFscGhhICogd29ybGRBbHBoYTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LmZpbGxTdHlsZSA9ICcjJyArICgnMDAwMDAnICsgKCBmaWxsQ29sb3IgfCAwKS50b1N0cmluZygxNikpLnN1YnN0cigtNik7XG4gICAgICAgICAgICAgICAgY29udGV4dC5maWxsKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZGF0YS5saW5lV2lkdGgpIHtcbiAgICAgICAgICAgICAgICBjb250ZXh0Lmdsb2JhbEFscGhhID0gZGF0YS5saW5lQWxwaGEgKiB3b3JsZEFscGhhO1xuICAgICAgICAgICAgICAgIGNvbnRleHQuc3Ryb2tlU3R5bGUgPSAnIycgKyAoJzAwMDAwJyArICggbGluZUNvbG9yIHwgMCkudG9TdHJpbmcoMTYpKS5zdWJzdHIoLTYpO1xuICAgICAgICAgICAgICAgIGNvbnRleHQuc3Ryb2tlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZGF0YS50eXBlID09PSBDT05TVC5TSEFQRVMuRUxJUCkge1xuICAgICAgICAgICAgLy8gZWxsaXBzZSBjb2RlIHRha2VuIGZyb206IGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMjE3Mjc5OC9ob3ctdG8tZHJhdy1hbi1vdmFsLWluLWh0bWw1LWNhbnZhc1xuXG4gICAgICAgICAgICB2YXIgdyA9IHNoYXBlLndpZHRoICogMjtcbiAgICAgICAgICAgIHZhciBoID0gc2hhcGUuaGVpZ2h0ICogMjtcblxuICAgICAgICAgICAgdmFyIHggPSBzaGFwZS54IC0gdy8yO1xuICAgICAgICAgICAgdmFyIHkgPSBzaGFwZS55IC0gaC8yO1xuXG4gICAgICAgICAgICBjb250ZXh0LmJlZ2luUGF0aCgpO1xuXG4gICAgICAgICAgICB2YXIga2FwcGEgPSAwLjU1MjI4NDgsXG4gICAgICAgICAgICAgICAgb3ggPSAodyAvIDIpICoga2FwcGEsIC8vIGNvbnRyb2wgcG9pbnQgb2Zmc2V0IGhvcml6b250YWxcbiAgICAgICAgICAgICAgICBveSA9IChoIC8gMikgKiBrYXBwYSwgLy8gY29udHJvbCBwb2ludCBvZmZzZXQgdmVydGljYWxcbiAgICAgICAgICAgICAgICB4ZSA9IHggKyB3LCAgICAgICAgICAgLy8geC1lbmRcbiAgICAgICAgICAgICAgICB5ZSA9IHkgKyBoLCAgICAgICAgICAgLy8geS1lbmRcbiAgICAgICAgICAgICAgICB4bSA9IHggKyB3IC8gMiwgICAgICAgLy8geC1taWRkbGVcbiAgICAgICAgICAgICAgICB5bSA9IHkgKyBoIC8gMjsgICAgICAgLy8geS1taWRkbGVcblxuICAgICAgICAgICAgY29udGV4dC5tb3ZlVG8oeCwgeW0pO1xuICAgICAgICAgICAgY29udGV4dC5iZXppZXJDdXJ2ZVRvKHgsIHltIC0gb3ksIHhtIC0gb3gsIHksIHhtLCB5KTtcbiAgICAgICAgICAgIGNvbnRleHQuYmV6aWVyQ3VydmVUbyh4bSArIG94LCB5LCB4ZSwgeW0gLSBveSwgeGUsIHltKTtcbiAgICAgICAgICAgIGNvbnRleHQuYmV6aWVyQ3VydmVUbyh4ZSwgeW0gKyBveSwgeG0gKyBveCwgeWUsIHhtLCB5ZSk7XG4gICAgICAgICAgICBjb250ZXh0LmJlemllckN1cnZlVG8oeG0gLSBveCwgeWUsIHgsIHltICsgb3ksIHgsIHltKTtcblxuICAgICAgICAgICAgY29udGV4dC5jbG9zZVBhdGgoKTtcblxuICAgICAgICAgICAgaWYgKGRhdGEuZmlsbCkge1xuICAgICAgICAgICAgICAgIGNvbnRleHQuZ2xvYmFsQWxwaGEgPSBkYXRhLmZpbGxBbHBoYSAqIHdvcmxkQWxwaGE7XG4gICAgICAgICAgICAgICAgY29udGV4dC5maWxsU3R5bGUgPSAnIycgKyAoJzAwMDAwJyArICggZmlsbENvbG9yIHwgMCkudG9TdHJpbmcoMTYpKS5zdWJzdHIoLTYpO1xuICAgICAgICAgICAgICAgIGNvbnRleHQuZmlsbCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRhdGEubGluZVdpZHRoKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IGRhdGEubGluZUFscGhhICogd29ybGRBbHBoYTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZVN0eWxlID0gJyMnICsgKCcwMDAwMCcgKyAoIGxpbmVDb2xvciB8IDApLnRvU3RyaW5nKDE2KSkuc3Vic3RyKC02KTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLlJSRUMpIHtcbiAgICAgICAgICAgIHZhciByeCA9IHNoYXBlLng7XG4gICAgICAgICAgICB2YXIgcnkgPSBzaGFwZS55O1xuICAgICAgICAgICAgdmFyIHdpZHRoID0gc2hhcGUud2lkdGg7XG4gICAgICAgICAgICB2YXIgaGVpZ2h0ID0gc2hhcGUuaGVpZ2h0O1xuICAgICAgICAgICAgdmFyIHJhZGl1cyA9IHNoYXBlLnJhZGl1cztcblxuICAgICAgICAgICAgdmFyIG1heFJhZGl1cyA9IE1hdGgubWluKHdpZHRoLCBoZWlnaHQpIC8gMiB8IDA7XG4gICAgICAgICAgICByYWRpdXMgPSByYWRpdXMgPiBtYXhSYWRpdXMgPyBtYXhSYWRpdXMgOiByYWRpdXM7XG5cbiAgICAgICAgICAgIGNvbnRleHQuYmVnaW5QYXRoKCk7XG4gICAgICAgICAgICBjb250ZXh0Lm1vdmVUbyhyeCwgcnkgKyByYWRpdXMpO1xuICAgICAgICAgICAgY29udGV4dC5saW5lVG8ocngsIHJ5ICsgaGVpZ2h0IC0gcmFkaXVzKTtcbiAgICAgICAgICAgIGNvbnRleHQucXVhZHJhdGljQ3VydmVUbyhyeCwgcnkgKyBoZWlnaHQsIHJ4ICsgcmFkaXVzLCByeSArIGhlaWdodCk7XG4gICAgICAgICAgICBjb250ZXh0LmxpbmVUbyhyeCArIHdpZHRoIC0gcmFkaXVzLCByeSArIGhlaWdodCk7XG4gICAgICAgICAgICBjb250ZXh0LnF1YWRyYXRpY0N1cnZlVG8ocnggKyB3aWR0aCwgcnkgKyBoZWlnaHQsIHJ4ICsgd2lkdGgsIHJ5ICsgaGVpZ2h0IC0gcmFkaXVzKTtcbiAgICAgICAgICAgIGNvbnRleHQubGluZVRvKHJ4ICsgd2lkdGgsIHJ5ICsgcmFkaXVzKTtcbiAgICAgICAgICAgIGNvbnRleHQucXVhZHJhdGljQ3VydmVUbyhyeCArIHdpZHRoLCByeSwgcnggKyB3aWR0aCAtIHJhZGl1cywgcnkpO1xuICAgICAgICAgICAgY29udGV4dC5saW5lVG8ocnggKyByYWRpdXMsIHJ5KTtcbiAgICAgICAgICAgIGNvbnRleHQucXVhZHJhdGljQ3VydmVUbyhyeCwgcnksIHJ4LCByeSArIHJhZGl1cyk7XG4gICAgICAgICAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuXG4gICAgICAgICAgICBpZiAoZGF0YS5maWxsQ29sb3IgfHwgZGF0YS5maWxsQ29sb3IgPT09IDApIHtcbiAgICAgICAgICAgICAgICBjb250ZXh0Lmdsb2JhbEFscGhhID0gZGF0YS5maWxsQWxwaGEgKiB3b3JsZEFscGhhO1xuICAgICAgICAgICAgICAgIGNvbnRleHQuZmlsbFN0eWxlID0gJyMnICsgKCcwMDAwMCcgKyAoIGZpbGxDb2xvciB8IDApLnRvU3RyaW5nKDE2KSkuc3Vic3RyKC02KTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LmZpbGwoKTtcblxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRhdGEubGluZVdpZHRoKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IGRhdGEubGluZUFscGhhICogd29ybGRBbHBoYTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZVN0eWxlID0gJyMnICsgKCcwMDAwMCcgKyAoIGxpbmVDb2xvciB8IDApLnRvU3RyaW5nKDE2KSkuc3Vic3RyKC02KTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufTtcblxuLypcbiAqIFJlbmRlcnMgYSBncmFwaGljcyBtYXNrXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSBncmFwaGljcyB7R3JhcGhpY3N9IHRoZSBncmFwaGljcyB3aGljaCB3aWxsIGJlIHVzZWQgYXMgYSBtYXNrXG4gKiBAcGFyYW0gY29udGV4dCB7Q2FudmFzUmVuZGVyaW5nQ29udGV4dDJEfSB0aGUgY29udGV4dCAyZCBtZXRob2Qgb2YgdGhlIGNhbnZhc1xuICovXG5DYW52YXNHcmFwaGljcy5yZW5kZXJHcmFwaGljc01hc2sgPSBmdW5jdGlvbiAoZ3JhcGhpY3MsIGNvbnRleHQpIHtcbiAgICB2YXIgbGVuID0gZ3JhcGhpY3MuZ3JhcGhpY3NEYXRhLmxlbmd0aDtcblxuICAgIGlmIChsZW4gPT09IDApIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnRleHQuYmVnaW5QYXRoKCk7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgIHZhciBkYXRhID0gZ3JhcGhpY3MuZ3JhcGhpY3NEYXRhW2ldO1xuICAgICAgICB2YXIgc2hhcGUgPSBkYXRhLnNoYXBlO1xuXG4gICAgICAgIGlmIChkYXRhLnR5cGUgPT09IENPTlNULlNIQVBFUy5QT0xZKSB7XG5cbiAgICAgICAgICAgIHZhciBwb2ludHMgPSBzaGFwZS5wb2ludHM7XG5cbiAgICAgICAgICAgIGNvbnRleHQubW92ZVRvKHBvaW50c1swXSwgcG9pbnRzWzFdKTtcblxuICAgICAgICAgICAgZm9yICh2YXIgaj0xOyBqIDwgcG9pbnRzLmxlbmd0aC8yOyBqKyspIHtcbiAgICAgICAgICAgICAgICBjb250ZXh0LmxpbmVUbyhwb2ludHNbaiAqIDJdLCBwb2ludHNbaiAqIDIgKyAxXSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIGlmIHRoZSBmaXJzdCBhbmQgbGFzdCBwb2ludCBhcmUgdGhlIHNhbWUgY2xvc2UgdGhlIHBhdGggLSBtdWNoIG5lYXRlciA6KVxuICAgICAgICAgICAgaWYgKHBvaW50c1swXSA9PT0gcG9pbnRzW3BvaW50cy5sZW5ndGgtMl0gJiYgcG9pbnRzWzFdID09PSBwb2ludHNbcG9pbnRzLmxlbmd0aC0xXSkge1xuICAgICAgICAgICAgICAgIGNvbnRleHQuY2xvc2VQYXRoKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChkYXRhLnR5cGUgPT09IENPTlNULlNIQVBFUy5SRUNUKSB7XG4gICAgICAgICAgICBjb250ZXh0LnJlY3Qoc2hhcGUueCwgc2hhcGUueSwgc2hhcGUud2lkdGgsIHNoYXBlLmhlaWdodCk7XG4gICAgICAgICAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLkNJUkMpIHtcbiAgICAgICAgICAgIC8vIFRPRE8gLSBuZWVkIHRvIGJlIFVuZGVmaW5lZCFcbiAgICAgICAgICAgIGNvbnRleHQuYXJjKHNoYXBlLngsIHNoYXBlLnksIHNoYXBlLnJhZGl1cywgMCwgMiAqIE1hdGguUEkpO1xuICAgICAgICAgICAgY29udGV4dC5jbG9zZVBhdGgoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChkYXRhLnR5cGUgPT09IENPTlNULlNIQVBFUy5FTElQKSB7XG5cbiAgICAgICAgICAgIC8vIGVsbGlwc2UgY29kZSB0YWtlbiBmcm9tOiBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzIxNzI3OTgvaG93LXRvLWRyYXctYW4tb3ZhbC1pbi1odG1sNS1jYW52YXNcblxuICAgICAgICAgICAgdmFyIHcgPSBzaGFwZS53aWR0aCAqIDI7XG4gICAgICAgICAgICB2YXIgaCA9IHNoYXBlLmhlaWdodCAqIDI7XG5cbiAgICAgICAgICAgIHZhciB4ID0gc2hhcGUueCAtIHcvMjtcbiAgICAgICAgICAgIHZhciB5ID0gc2hhcGUueSAtIGgvMjtcblxuICAgICAgICAgICAgdmFyIGthcHBhID0gMC41NTIyODQ4LFxuICAgICAgICAgICAgICAgIG94ID0gKHcgLyAyKSAqIGthcHBhLCAvLyBjb250cm9sIHBvaW50IG9mZnNldCBob3Jpem9udGFsXG4gICAgICAgICAgICAgICAgb3kgPSAoaCAvIDIpICoga2FwcGEsIC8vIGNvbnRyb2wgcG9pbnQgb2Zmc2V0IHZlcnRpY2FsXG4gICAgICAgICAgICAgICAgeGUgPSB4ICsgdywgICAgICAgICAgIC8vIHgtZW5kXG4gICAgICAgICAgICAgICAgeWUgPSB5ICsgaCwgICAgICAgICAgIC8vIHktZW5kXG4gICAgICAgICAgICAgICAgeG0gPSB4ICsgdyAvIDIsICAgICAgIC8vIHgtbWlkZGxlXG4gICAgICAgICAgICAgICAgeW0gPSB5ICsgaCAvIDI7ICAgICAgIC8vIHktbWlkZGxlXG5cbiAgICAgICAgICAgIGNvbnRleHQubW92ZVRvKHgsIHltKTtcbiAgICAgICAgICAgIGNvbnRleHQuYmV6aWVyQ3VydmVUbyh4LCB5bSAtIG95LCB4bSAtIG94LCB5LCB4bSwgeSk7XG4gICAgICAgICAgICBjb250ZXh0LmJlemllckN1cnZlVG8oeG0gKyBveCwgeSwgeGUsIHltIC0gb3ksIHhlLCB5bSk7XG4gICAgICAgICAgICBjb250ZXh0LmJlemllckN1cnZlVG8oeGUsIHltICsgb3ksIHhtICsgb3gsIHllLCB4bSwgeWUpO1xuICAgICAgICAgICAgY29udGV4dC5iZXppZXJDdXJ2ZVRvKHhtIC0gb3gsIHllLCB4LCB5bSArIG95LCB4LCB5bSk7XG4gICAgICAgICAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLlJSRUMpIHtcblxuICAgICAgICAgICAgdmFyIHJ4ID0gc2hhcGUueDtcbiAgICAgICAgICAgIHZhciByeSA9IHNoYXBlLnk7XG4gICAgICAgICAgICB2YXIgd2lkdGggPSBzaGFwZS53aWR0aDtcbiAgICAgICAgICAgIHZhciBoZWlnaHQgPSBzaGFwZS5oZWlnaHQ7XG4gICAgICAgICAgICB2YXIgcmFkaXVzID0gc2hhcGUucmFkaXVzO1xuXG4gICAgICAgICAgICB2YXIgbWF4UmFkaXVzID0gTWF0aC5taW4od2lkdGgsIGhlaWdodCkgLyAyIHwgMDtcbiAgICAgICAgICAgIHJhZGl1cyA9IHJhZGl1cyA+IG1heFJhZGl1cyA/IG1heFJhZGl1cyA6IHJhZGl1cztcblxuICAgICAgICAgICAgY29udGV4dC5tb3ZlVG8ocngsIHJ5ICsgcmFkaXVzKTtcbiAgICAgICAgICAgIGNvbnRleHQubGluZVRvKHJ4LCByeSArIGhlaWdodCAtIHJhZGl1cyk7XG4gICAgICAgICAgICBjb250ZXh0LnF1YWRyYXRpY0N1cnZlVG8ocngsIHJ5ICsgaGVpZ2h0LCByeCArIHJhZGl1cywgcnkgKyBoZWlnaHQpO1xuICAgICAgICAgICAgY29udGV4dC5saW5lVG8ocnggKyB3aWR0aCAtIHJhZGl1cywgcnkgKyBoZWlnaHQpO1xuICAgICAgICAgICAgY29udGV4dC5xdWFkcmF0aWNDdXJ2ZVRvKHJ4ICsgd2lkdGgsIHJ5ICsgaGVpZ2h0LCByeCArIHdpZHRoLCByeSArIGhlaWdodCAtIHJhZGl1cyk7XG4gICAgICAgICAgICBjb250ZXh0LmxpbmVUbyhyeCArIHdpZHRoLCByeSArIHJhZGl1cyk7XG4gICAgICAgICAgICBjb250ZXh0LnF1YWRyYXRpY0N1cnZlVG8ocnggKyB3aWR0aCwgcnksIHJ4ICsgd2lkdGggLSByYWRpdXMsIHJ5KTtcbiAgICAgICAgICAgIGNvbnRleHQubGluZVRvKHJ4ICsgcmFkaXVzLCByeSk7XG4gICAgICAgICAgICBjb250ZXh0LnF1YWRyYXRpY0N1cnZlVG8ocngsIHJ5LCByeCwgcnkgKyByYWRpdXMpO1xuICAgICAgICAgICAgY29udGV4dC5jbG9zZVBhdGgoKTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cbkNhbnZhc0dyYXBoaWNzLnVwZGF0ZUdyYXBoaWNzVGludCA9IGZ1bmN0aW9uIChncmFwaGljcykge1xuICAgIGlmIChncmFwaGljcy50aW50ID09PSAweEZGRkZGRikge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIHRpbnRSID0gKGdyYXBoaWNzLnRpbnQgPj4gMTYgJiAweEZGKSAvIDI1NTtcbiAgICB2YXIgdGludEcgPSAoZ3JhcGhpY3MudGludCA+PiA4ICYgMHhGRikgLyAyNTU7XG4gICAgdmFyIHRpbnRCID0gKGdyYXBoaWNzLnRpbnQgJiAweEZGKS8gMjU1O1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBncmFwaGljcy5ncmFwaGljc0RhdGEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGRhdGEgPSBncmFwaGljcy5ncmFwaGljc0RhdGFbaV07XG5cbiAgICAgICAgdmFyIGZpbGxDb2xvciA9IGRhdGEuZmlsbENvbG9yIHwgMDtcbiAgICAgICAgdmFyIGxpbmVDb2xvciA9IGRhdGEubGluZUNvbG9yIHwgMDtcblxuICAgICAgICAvKlxuICAgICAgICB2YXIgY29sb3JSID0gKGZpbGxDb2xvciA+PiAxNiAmIDB4RkYpIC8gMjU1O1xuICAgICAgICB2YXIgY29sb3JHID0gKGZpbGxDb2xvciA+PiA4ICYgMHhGRikgLyAyNTU7XG4gICAgICAgIHZhciBjb2xvckIgPSAoZmlsbENvbG9yICYgMHhGRikgLyAyNTU7XG5cbiAgICAgICAgY29sb3JSICo9IHRpbnRSO1xuICAgICAgICBjb2xvckcgKj0gdGludEc7XG4gICAgICAgIGNvbG9yQiAqPSB0aW50QjtcblxuICAgICAgICBmaWxsQ29sb3IgPSAoKGNvbG9yUioyNTUgPDwgMTYpICsgKGNvbG9yRyoyNTUgPDwgOCkgKyBjb2xvckIqMjU1KTtcblxuICAgICAgICBjb2xvclIgPSAobGluZUNvbG9yID4+IDE2ICYgMHhGRikgLyAyNTU7XG4gICAgICAgIGNvbG9yRyA9IChsaW5lQ29sb3IgPj4gOCAmIDB4RkYpIC8gMjU1O1xuICAgICAgICBjb2xvckIgPSAobGluZUNvbG9yICYgMHhGRikgLyAyNTU7XG5cbiAgICAgICAgY29sb3JSICo9IHRpbnRSO1xuICAgICAgICBjb2xvckcgKj0gdGludEc7XG4gICAgICAgIGNvbG9yQiAqPSB0aW50QjtcblxuICAgICAgICBsaW5lQ29sb3IgPSAoKGNvbG9yUioyNTUgPDwgMTYpICsgKGNvbG9yRyoyNTUgPDwgOCkgKyBjb2xvckIqMjU1KTtcbiAgICAgICAgKi9cblxuICAgICAgICAvLyBzdXBlciBpbmxpbmUgY29zIGltIGFuIG9wdGltaXphdGlvbiBOQVpJIDopXG4gICAgICAgIGRhdGEuX2ZpbGxUaW50ID0gKCgoZmlsbENvbG9yID4+IDE2ICYgMHhGRikgLyAyNTUgKiB0aW50UioyNTUgPDwgMTYpICsgKChmaWxsQ29sb3IgPj4gOCAmIDB4RkYpIC8gMjU1ICogdGludEcqMjU1IDw8IDgpICsgIChmaWxsQ29sb3IgJiAweEZGKSAvIDI1NSAqIHRpbnRCKjI1NSk7XG4gICAgICAgIGRhdGEuX2xpbmVUaW50ID0gKCgobGluZUNvbG9yID4+IDE2ICYgMHhGRikgLyAyNTUgKiB0aW50UioyNTUgPDwgMTYpICsgKChsaW5lQ29sb3IgPj4gOCAmIDB4RkYpIC8gMjU1ICogdGludEcqMjU1IDw8IDgpICsgIChsaW5lQ29sb3IgJiAweEZGKSAvIDI1NSAqIHRpbnRCKjI1NSk7XG5cbiAgICB9XG59O1xuXG4iLCJ2YXIgQ2FudmFzR3JhcGhpY3MgPSByZXF1aXJlKCcuL0NhbnZhc0dyYXBoaWNzJyk7XG5cbi8qKlxuICogQSBzZXQgb2YgZnVuY3Rpb25zIHVzZWQgdG8gaGFuZGxlIG1hc2tpbmcuXG4gKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gQ2FudmFzTWFza01hbmFnZXIoKSB7fVxuXG5DYW52YXNNYXNrTWFuYWdlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDYW52YXNNYXNrTWFuYWdlcjtcbm1vZHVsZS5leHBvcnRzID0gQ2FudmFzTWFza01hbmFnZXI7XG5cbi8qKlxuICogVGhpcyBtZXRob2QgYWRkcyBpdCB0byB0aGUgY3VycmVudCBzdGFjayBvZiBtYXNrcy5cbiAqXG4gKiBAcGFyYW0gbWFza0RhdGEge29iamVjdH0gdGhlIG1hc2tEYXRhIHRoYXQgd2lsbCBiZSBwdXNoZWRcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcnxDYW52YXNSZW5kZXJlcn0gVGhlIHJlbmRlcmVyIGNvbnRleHQgdG8gdXNlLlxuICovXG5DYW52YXNNYXNrTWFuYWdlci5wcm90b3R5cGUucHVzaE1hc2sgPSBmdW5jdGlvbiAobWFza0RhdGEsIHJlbmRlcmVyKSB7XG4gICAgcmVuZGVyZXIuY29udGV4dC5zYXZlKCk7XG5cbiAgICB2YXIgY2FjaGVBbHBoYSA9IG1hc2tEYXRhLmFscGhhO1xuICAgIHZhciB0cmFuc2Zvcm0gPSBtYXNrRGF0YS53b3JsZFRyYW5zZm9ybTtcbiAgICB2YXIgcmVzb2x1dGlvbiA9IHJlbmRlcmVyLnJlc29sdXRpb247XG5cbiAgICByZW5kZXJlci5jb250ZXh0LnNldFRyYW5zZm9ybShcbiAgICAgICAgdHJhbnNmb3JtLmEgKiByZXNvbHV0aW9uLFxuICAgICAgICB0cmFuc2Zvcm0uYiAqIHJlc29sdXRpb24sXG4gICAgICAgIHRyYW5zZm9ybS5jICogcmVzb2x1dGlvbixcbiAgICAgICAgdHJhbnNmb3JtLmQgKiByZXNvbHV0aW9uLFxuICAgICAgICB0cmFuc2Zvcm0udHggKiByZXNvbHV0aW9uLFxuICAgICAgICB0cmFuc2Zvcm0udHkgKiByZXNvbHV0aW9uXG4gICAgKTtcblxuICAgIENhbnZhc0dyYXBoaWNzLnJlbmRlckdyYXBoaWNzTWFzayhtYXNrRGF0YSwgcmVuZGVyZXIuY29udGV4dCk7XG5cbiAgICByZW5kZXJlci5jb250ZXh0LmNsaXAoKTtcblxuICAgIG1hc2tEYXRhLndvcmxkQWxwaGEgPSBjYWNoZUFscGhhO1xufTtcblxuLyoqXG4gKiBSZXN0b3JlcyB0aGUgY3VycmVudCBkcmF3aW5nIGNvbnRleHQgdG8gdGhlIHN0YXRlIGl0IHdhcyBiZWZvcmUgdGhlIG1hc2sgd2FzIGFwcGxpZWQuXG4gKlxuICogQHBhcmFtIHJlbmRlcmVyIHtXZWJHTFJlbmRlcmVyfENhbnZhc1JlbmRlcmVyfSBUaGUgcmVuZGVyZXIgY29udGV4dCB0byB1c2UuXG4gKi9cbkNhbnZhc01hc2tNYW5hZ2VyLnByb3RvdHlwZS5wb3BNYXNrID0gZnVuY3Rpb24gKHJlbmRlcmVyKSB7XG4gICAgcmVuZGVyZXIuY29udGV4dC5yZXN0b3JlKCk7XG59O1xuIiwidmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbHMnKTtcblxuLyoqXG4gKiBVdGlsaXR5IG1ldGhvZHMgZm9yIFNwcml0ZS9UZXh0dXJlIHRpbnRpbmcuXG4gKlxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbnZhciBDYW52YXNUaW50ZXIgPSBtb2R1bGUuZXhwb3J0cyA9IHt9O1xuXG4vKipcbiAqIEJhc2ljYWxseSB0aGlzIG1ldGhvZCBqdXN0IG5lZWRzIGEgc3ByaXRlIGFuZCBhIGNvbG9yIGFuZCB0aW50cyB0aGUgc3ByaXRlIHdpdGggdGhlIGdpdmVuIGNvbG9yLlxuICpcbiAqIEBwYXJhbSBzcHJpdGUge1Nwcml0ZX0gdGhlIHNwcml0ZSB0byB0aW50XG4gKiBAcGFyYW0gY29sb3Ige251bWJlcn0gdGhlIGNvbG9yIHRvIHVzZSB0byB0aW50IHRoZSBzcHJpdGUgd2l0aFxuICogQHJldHVybiB7SFRNTENhbnZhc0VsZW1lbnR9IFRoZSB0aW50ZWQgY2FudmFzXG4gKi9cbkNhbnZhc1RpbnRlci5nZXRUaW50ZWRUZXh0dXJlID0gZnVuY3Rpb24gKHNwcml0ZSwgY29sb3IpIHtcbiAgICB2YXIgdGV4dHVyZSA9IHNwcml0ZS50ZXh0dXJlO1xuXG4gICAgY29sb3IgPSBDYW52YXNUaW50ZXIucm91bmRDb2xvcihjb2xvcik7XG5cbiAgICB2YXIgc3RyaW5nQ29sb3IgPSAnIycgKyAoJzAwMDAwJyArICggY29sb3IgfCAwKS50b1N0cmluZygxNikpLnN1YnN0cigtNik7XG5cbiAgICB0ZXh0dXJlLnRpbnRDYWNoZSA9IHRleHR1cmUudGludENhY2hlIHx8IHt9O1xuXG4gICAgaWYgKHRleHR1cmUudGludENhY2hlW3N0cmluZ0NvbG9yXSkge1xuICAgICAgICByZXR1cm4gdGV4dHVyZS50aW50Q2FjaGVbc3RyaW5nQ29sb3JdO1xuICAgIH1cblxuICAgICAvLyBjbG9uZSB0ZXh0dXJlLi5cbiAgICB2YXIgY2FudmFzID0gQ2FudmFzVGludGVyLmNhbnZhcyB8fCBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcblxuICAgIC8vQ2FudmFzVGludGVyLnRpbnRXaXRoUGVyUGl4ZWwodGV4dHVyZSwgc3RyaW5nQ29sb3IsIGNhbnZhcyk7XG4gICAgQ2FudmFzVGludGVyLnRpbnRNZXRob2QodGV4dHVyZSwgY29sb3IsIGNhbnZhcyk7XG5cbiAgICBpZiAoQ2FudmFzVGludGVyLmNvbnZlcnRUaW50VG9JbWFnZSkge1xuICAgICAgICAvLyBpcyB0aGlzIGJldHRlcj9cbiAgICAgICAgdmFyIHRpbnRJbWFnZSA9IG5ldyBJbWFnZSgpO1xuICAgICAgICB0aW50SW1hZ2Uuc3JjID0gY2FudmFzLnRvRGF0YVVSTCgpO1xuXG4gICAgICAgIHRleHR1cmUudGludENhY2hlW3N0cmluZ0NvbG9yXSA9IHRpbnRJbWFnZTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHRleHR1cmUudGludENhY2hlW3N0cmluZ0NvbG9yXSA9IGNhbnZhcztcbiAgICAgICAgLy8gaWYgd2UgYXJlIG5vdCBjb252ZXJ0aW5nIHRoZSB0ZXh0dXJlIHRvIGFuIGltYWdlIHRoZW4gd2UgbmVlZCB0byBsb3NlIHRoZSByZWZlcmVuY2UgdG8gdGhlIGNhbnZhc1xuICAgICAgICBDYW52YXNUaW50ZXIuY2FudmFzID0gbnVsbDtcbiAgICB9XG5cbiAgICByZXR1cm4gY2FudmFzO1xufTtcblxuLyoqXG4gKiBUaW50IGEgdGV4dHVyZSB1c2luZyB0aGUgJ211bHRpcGx5JyBvcGVyYXRpb24uXG4gKlxuICogQHBhcmFtIHRleHR1cmUge1RleHR1cmV9IHRoZSB0ZXh0dXJlIHRvIHRpbnRcbiAqIEBwYXJhbSBjb2xvciB7bnVtYmVyfSB0aGUgY29sb3IgdG8gdXNlIHRvIHRpbnQgdGhlIHNwcml0ZSB3aXRoXG4gKiBAcGFyYW0gY2FudmFzIHtIVE1MQ2FudmFzRWxlbWVudH0gdGhlIGN1cnJlbnQgY2FudmFzXG4gKi9cbkNhbnZhc1RpbnRlci50aW50V2l0aE11bHRpcGx5ID0gZnVuY3Rpb24gKHRleHR1cmUsIGNvbG9yLCBjYW52YXMpIHtcbiAgICB2YXIgY29udGV4dCA9IGNhbnZhcy5nZXRDb250ZXh0KCAnMmQnICk7XG5cbiAgICB2YXIgY3JvcCA9IHRleHR1cmUuY3JvcDtcblxuICAgIGNhbnZhcy53aWR0aCA9IGNyb3Aud2lkdGg7XG4gICAgY2FudmFzLmhlaWdodCA9IGNyb3AuaGVpZ2h0O1xuXG4gICAgY29udGV4dC5maWxsU3R5bGUgPSAnIycgKyAoJzAwMDAwJyArICggY29sb3IgfCAwKS50b1N0cmluZygxNikpLnN1YnN0cigtNik7XG5cbiAgICBjb250ZXh0LmZpbGxSZWN0KDAsIDAsIGNyb3Aud2lkdGgsIGNyb3AuaGVpZ2h0KTtcblxuICAgIGNvbnRleHQuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uID0gJ211bHRpcGx5JztcblxuICAgIGNvbnRleHQuZHJhd0ltYWdlKFxuICAgICAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLnNvdXJjZSxcbiAgICAgICAgY3JvcC54LFxuICAgICAgICBjcm9wLnksXG4gICAgICAgIGNyb3Aud2lkdGgsXG4gICAgICAgIGNyb3AuaGVpZ2h0LFxuICAgICAgICAwLFxuICAgICAgICAwLFxuICAgICAgICBjcm9wLndpZHRoLFxuICAgICAgICBjcm9wLmhlaWdodFxuICAgICk7XG5cbiAgICBjb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9ICdkZXN0aW5hdGlvbi1hdG9wJztcblxuICAgIGNvbnRleHQuZHJhd0ltYWdlKFxuICAgICAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLnNvdXJjZSxcbiAgICAgICAgY3JvcC54LFxuICAgICAgICBjcm9wLnksXG4gICAgICAgIGNyb3Aud2lkdGgsXG4gICAgICAgIGNyb3AuaGVpZ2h0LFxuICAgICAgICAwLFxuICAgICAgICAwLFxuICAgICAgICBjcm9wLndpZHRoLFxuICAgICAgICBjcm9wLmhlaWdodFxuICAgICk7XG59O1xuXG4vKipcbiAqIFRpbnQgYSB0ZXh0dXJlIHVzaW5nIHRoZSAnb3ZlcmxheScgb3BlcmF0aW9uLlxuICpcbiAqIEBwYXJhbSB0ZXh0dXJlIHtUZXh0dXJlfSB0aGUgdGV4dHVyZSB0byB0aW50XG4gKiBAcGFyYW0gY29sb3Ige251bWJlcn0gdGhlIGNvbG9yIHRvIHVzZSB0byB0aW50IHRoZSBzcHJpdGUgd2l0aFxuICogQHBhcmFtIGNhbnZhcyB7SFRNTENhbnZhc0VsZW1lbnR9IHRoZSBjdXJyZW50IGNhbnZhc1xuICovXG5DYW52YXNUaW50ZXIudGludFdpdGhPdmVybGF5ID0gZnVuY3Rpb24gKHRleHR1cmUsIGNvbG9yLCBjYW52YXMpIHtcbiAgICB2YXIgY29udGV4dCA9IGNhbnZhcy5nZXRDb250ZXh0KCAnMmQnICk7XG5cbiAgICB2YXIgY3JvcCA9IHRleHR1cmUuY3JvcDtcblxuICAgIGNhbnZhcy53aWR0aCA9IGNyb3Aud2lkdGg7XG4gICAgY2FudmFzLmhlaWdodCA9IGNyb3AuaGVpZ2h0O1xuXG4gICAgY29udGV4dC5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb24gPSAnY29weSc7XG4gICAgY29udGV4dC5maWxsU3R5bGUgPSAnIycgKyAoJzAwMDAwJyArICggY29sb3IgfCAwKS50b1N0cmluZygxNikpLnN1YnN0cigtNik7XG4gICAgY29udGV4dC5maWxsUmVjdCgwLCAwLCBjcm9wLndpZHRoLCBjcm9wLmhlaWdodCk7XG5cbiAgICBjb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9ICdkZXN0aW5hdGlvbi1hdG9wJztcbiAgICBjb250ZXh0LmRyYXdJbWFnZShcbiAgICAgICAgdGV4dHVyZS5iYXNlVGV4dHVyZS5zb3VyY2UsXG4gICAgICAgIGNyb3AueCxcbiAgICAgICAgY3JvcC55LFxuICAgICAgICBjcm9wLndpZHRoLFxuICAgICAgICBjcm9wLmhlaWdodCxcbiAgICAgICAgMCxcbiAgICAgICAgMCxcbiAgICAgICAgY3JvcC53aWR0aCxcbiAgICAgICAgY3JvcC5oZWlnaHRcbiAgICApO1xuXG4gICAgLy8gY29udGV4dC5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb24gPSAnY29weSc7XG59O1xuXG4vKipcbiAqIFRpbnQgYSB0ZXh0dXJlIHBpeGVsIHBlciBwaXhlbC5cbiAqXG4gKiBAcGFyYW0gdGV4dHVyZSB7VGV4dHVyZX0gdGhlIHRleHR1cmUgdG8gdGludFxuICogQHBhcmFtIGNvbG9yIHtudW1iZXJ9IHRoZSBjb2xvciB0byB1c2UgdG8gdGludCB0aGUgc3ByaXRlIHdpdGhcbiAqIEBwYXJhbSBjYW52YXMge0hUTUxDYW52YXNFbGVtZW50fSB0aGUgY3VycmVudCBjYW52YXNcbiAqL1xuQ2FudmFzVGludGVyLnRpbnRXaXRoUGVyUGl4ZWwgPSBmdW5jdGlvbiAodGV4dHVyZSwgY29sb3IsIGNhbnZhcykge1xuICAgIHZhciBjb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoICcyZCcgKTtcblxuICAgIHZhciBjcm9wID0gdGV4dHVyZS5jcm9wO1xuXG4gICAgY2FudmFzLndpZHRoID0gY3JvcC53aWR0aDtcbiAgICBjYW52YXMuaGVpZ2h0ID0gY3JvcC5oZWlnaHQ7XG5cbiAgICBjb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9ICdjb3B5JztcbiAgICBjb250ZXh0LmRyYXdJbWFnZShcbiAgICAgICAgdGV4dHVyZS5iYXNlVGV4dHVyZS5zb3VyY2UsXG4gICAgICAgIGNyb3AueCxcbiAgICAgICAgY3JvcC55LFxuICAgICAgICBjcm9wLndpZHRoLFxuICAgICAgICBjcm9wLmhlaWdodCxcbiAgICAgICAgMCxcbiAgICAgICAgMCxcbiAgICAgICAgY3JvcC53aWR0aCxcbiAgICAgICAgY3JvcC5oZWlnaHRcbiAgICApO1xuXG4gICAgdmFyIHJnYlZhbHVlcyA9IHV0aWxzLmhleDJyZ2IoY29sb3IpO1xuICAgIHZhciByID0gcmdiVmFsdWVzWzBdLCBnID0gcmdiVmFsdWVzWzFdLCBiID0gcmdiVmFsdWVzWzJdO1xuXG4gICAgdmFyIHBpeGVsRGF0YSA9IGNvbnRleHQuZ2V0SW1hZ2VEYXRhKDAsIDAsIGNyb3Aud2lkdGgsIGNyb3AuaGVpZ2h0KTtcblxuICAgIHZhciBwaXhlbHMgPSBwaXhlbERhdGEuZGF0YTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcGl4ZWxzLmxlbmd0aDsgaSArPSA0KSB7XG4gICAgICAgIHBpeGVsc1tpKzBdICo9IHI7XG4gICAgICAgIHBpeGVsc1tpKzFdICo9IGc7XG4gICAgICAgIHBpeGVsc1tpKzJdICo9IGI7XG4gICAgfVxuXG4gICAgY29udGV4dC5wdXRJbWFnZURhdGEocGl4ZWxEYXRhLCAwLCAwKTtcbn07XG5cbi8qKlxuICogUm91bmRzIHRoZSBzcGVjaWZpZWQgY29sb3IgYWNjb3JkaW5nIHRvIHRoZSBDYW52YXNUaW50ZXIuY2FjaGVTdGVwc1BlckNvbG9yQ2hhbm5lbC5cbiAqXG4gKiBAcGFyYW0gY29sb3Ige251bWJlcn0gdGhlIGNvbG9yIHRvIHJvdW5kLCBzaG91bGQgYmUgYSBoZXggY29sb3JcbiAqL1xuQ2FudmFzVGludGVyLnJvdW5kQ29sb3IgPSBmdW5jdGlvbiAoY29sb3IpIHtcbiAgICB2YXIgc3RlcCA9IENhbnZhc1RpbnRlci5jYWNoZVN0ZXBzUGVyQ29sb3JDaGFubmVsO1xuXG4gICAgdmFyIHJnYlZhbHVlcyA9IHV0aWxzLmhleDJyZ2IoY29sb3IpO1xuXG4gICAgcmdiVmFsdWVzWzBdID0gTWF0aC5taW4oMjU1LCAocmdiVmFsdWVzWzBdIC8gc3RlcCkgKiBzdGVwKTtcbiAgICByZ2JWYWx1ZXNbMV0gPSBNYXRoLm1pbigyNTUsIChyZ2JWYWx1ZXNbMV0gLyBzdGVwKSAqIHN0ZXApO1xuICAgIHJnYlZhbHVlc1syXSA9IE1hdGgubWluKDI1NSwgKHJnYlZhbHVlc1syXSAvIHN0ZXApICogc3RlcCk7XG5cbiAgICByZXR1cm4gdXRpbHMucmdiMmhleChyZ2JWYWx1ZXMpO1xufTtcblxuLyoqXG4gKiBOdW1iZXIgb2Ygc3RlcHMgd2hpY2ggd2lsbCBiZSB1c2VkIGFzIGEgY2FwIHdoZW4gcm91bmRpbmcgY29sb3JzLlxuICpcbiAqIEBtZW1iZXJcbiAqL1xuQ2FudmFzVGludGVyLmNhY2hlU3RlcHNQZXJDb2xvckNoYW5uZWwgPSA4O1xuXG4vKipcbiAqIFRpbnQgY2FjaGUgYm9vbGVhbiBmbGFnLlxuICpcbiAqIEBtZW1iZXJcbiAqL1xuQ2FudmFzVGludGVyLmNvbnZlcnRUaW50VG9JbWFnZSA9IGZhbHNlO1xuXG4vKipcbiAqIFdoZXRoZXIgb3Igbm90IHRoZSBDYW52YXMgQmxlbmRNb2RlcyBhcmUgc3VwcG9ydGVkLCBjb25zZXF1ZW50bHkgdGhlIGFiaWxpdHkgdG8gdGludCB1c2luZyB0aGUgbXVsdGlwbHkgbWV0aG9kLlxuICpcbiAqIEBtZW1iZXJcbiAqL1xuQ2FudmFzVGludGVyLmNhblVzZU11bHRpcGx5ID0gdXRpbHMuY2FuVXNlTmV3Q2FudmFzQmxlbmRNb2RlcygpO1xuXG4vKipcbiAqIFRoZSB0aW50aW5nIG1ldGhvZCB0aGF0IHdpbGwgYmUgdXNlZC5cbiAqXG4gKi9cbkNhbnZhc1RpbnRlci50aW50TWV0aG9kID0gQ2FudmFzVGludGVyLmNhblVzZU11bHRpcGx5ID8gQ2FudmFzVGludGVyLnRpbnRXaXRoTXVsdGlwbHkgOiAgQ2FudmFzVGludGVyLnRpbnRXaXRoUGVyUGl4ZWw7XG4iLCJ2YXIgV2ViR0xTcHJpdGVCYXRjaCA9IHJlcXVpcmUoJy4vdXRpbHMvV2ViR0xTcHJpdGVCYXRjaCcpLFxuICAgIFdlYkdMRmFzdFNwcml0ZUJhdGNoID0gcmVxdWlyZSgnLi91dGlscy9XZWJHTEZhc3RTcHJpdGVCYXRjaCcpLFxuICAgIFdlYkdMU2hhZGVyTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvV2ViR0xTaGFkZXJNYW5hZ2VyJyksXG4gICAgV2ViR0xNYXNrTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvV2ViR0xNYXNrTWFuYWdlcicpLFxuICAgIFdlYkdMRmlsdGVyTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvV2ViR0xGaWx0ZXJNYW5hZ2VyJyksXG4gICAgV2ViR0xTdGVuY2lsTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvV2ViR0xTdGVuY2lsTWFuYWdlcicpLFxuICAgIFdlYkdMQmxlbmRNb2RlTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvV2ViR0xCbGVuZE1vZGVNYW5hZ2VyJyksXG4gICAgbWF0aCA9IHJlcXVpcmUoJy4uLy4uL21hdGgnKSxcbiAgICB1dGlscyA9IHJlcXVpcmUoJy4uLy4uL3V0aWxzJyksXG4gICAgQ09OU1QgPSByZXF1aXJlKCcuLi8uLi9jb25zdCcpO1xuXG4vKipcbiAqIFRoZSBXZWJHTFJlbmRlcmVyIGRyYXdzIHRoZSBzY2VuZSBhbmQgYWxsIGl0cyBjb250ZW50IG9udG8gYSB3ZWJHTCBlbmFibGVkIGNhbnZhcy4gVGhpcyByZW5kZXJlclxuICogc2hvdWxkIGJlIHVzZWQgZm9yIGJyb3dzZXJzIHRoYXQgc3VwcG9ydCB3ZWJHTC4gVGhpcyBSZW5kZXIgd29ya3MgYnkgYXV0b21hdGljYWxseSBtYW5hZ2luZyB3ZWJHTEJhdGNocy5cbiAqIFNvIG5vIG5lZWQgZm9yIFNwcml0ZSBCYXRjaGVzIG9yIFNwcml0ZSBDbG91ZHMuXG4gKiBEb24ndCBmb3JnZXQgdG8gYWRkIHRoZSB2aWV3IHRvIHlvdXIgRE9NIG9yIHlvdSB3aWxsIG5vdCBzZWUgYW55dGhpbmcgOilcbiAqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIFt3aWR0aD0wXSB7bnVtYmVyfSB0aGUgd2lkdGggb2YgdGhlIGNhbnZhcyB2aWV3XG4gKiBAcGFyYW0gW2hlaWdodD0wXSB7bnVtYmVyfSB0aGUgaGVpZ2h0IG9mIHRoZSBjYW52YXMgdmlld1xuICogQHBhcmFtIFtvcHRpb25zXSB7b2JqZWN0fSBUaGUgb3B0aW9uYWwgcmVuZGVyZXIgcGFyYW1ldGVyc1xuICogQHBhcmFtIFtvcHRpb25zLnZpZXddIHtIVE1MQ2FudmFzRWxlbWVudH0gdGhlIGNhbnZhcyB0byB1c2UgYXMgYSB2aWV3LCBvcHRpb25hbFxuICogQHBhcmFtIFtvcHRpb25zLnRyYW5zcGFyZW50PWZhbHNlXSB7Ym9vbGVhbn0gSWYgdGhlIHJlbmRlciB2aWV3IGlzIHRyYW5zcGFyZW50LCBkZWZhdWx0IGZhbHNlXG4gKiBAcGFyYW0gW29wdGlvbnMuYXV0b1Jlc2l6ZT1mYWxzZV0ge2Jvb2xlYW59IElmIHRoZSByZW5kZXIgdmlldyBpcyBhdXRvbWF0aWNhbGx5IHJlc2l6ZWQsIGRlZmF1bHQgZmFsc2VcbiAqIEBwYXJhbSBbb3B0aW9ucy5hbnRpYWxpYXM9ZmFsc2VdIHtib29sZWFufSBzZXRzIGFudGlhbGlhcyAob25seSBhcHBsaWNhYmxlIGluIGNocm9tZSBhdCB0aGUgbW9tZW50KVxuICogQHBhcmFtIFtvcHRpb25zLnByZXNlcnZlRHJhd2luZ0J1ZmZlcj1mYWxzZV0ge2Jvb2xlYW59IGVuYWJsZXMgZHJhd2luZyBidWZmZXIgcHJlc2VydmF0aW9uLCBlbmFibGUgdGhpcyBpZiB5b3UgbmVlZCB0byBjYWxsIHRvRGF0YVVybCBvbiB0aGUgd2ViZ2wgY29udGV4dFxuICogQHBhcmFtIFtvcHRpb25zLnJlc29sdXRpb249MV0ge251bWJlcn0gdGhlIHJlc29sdXRpb24gb2YgdGhlIHJlbmRlcmVyIHJldGluYSB3b3VsZCBiZSAyXG4gKi9cbmZ1bmN0aW9uIFdlYkdMUmVuZGVyZXIod2lkdGgsIGhlaWdodCwgb3B0aW9ucykge1xuICAgIHV0aWxzLnNheUhlbGxvKCd3ZWJHTCcpO1xuXG4gICAgaWYgKG9wdGlvbnMpIHtcbiAgICAgICAgZm9yICh2YXIgaSBpbiBDT05TVC5kZWZhdWx0UmVuZGVyT3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBvcHRpb25zW2ldID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIG9wdGlvbnNbaV0gPSBDT05TVC5kZWZhdWx0UmVuZGVyT3B0aW9uc1tpXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgb3B0aW9ucyA9IENPTlNULmRlZmF1bHRSZW5kZXJPcHRpb25zO1xuICAgIH1cblxuICAgIHRoaXMudXVpZCA9IHV0aWxzLnV1aWQoKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLnR5cGUgPSBDT05TVC5XRUJHTF9SRU5ERVJFUjtcblxuICAgIC8qKlxuICAgICAqIFRoZSByZXNvbHV0aW9uIG9mIHRoZSByZW5kZXJlclxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDFcbiAgICAgKi9cbiAgICB0aGlzLnJlc29sdXRpb24gPSBvcHRpb25zLnJlc29sdXRpb247XG5cbiAgICAvLyBkbyBhIGNhdGNoLi4gb25seSAxIHdlYkdMIHJlbmRlcmVyLi5cblxuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgdGhlIHJlbmRlciB2aWV3IGlzIHRyYW5zcGFyZW50XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMudHJhbnNwYXJlbnQgPSBvcHRpb25zLnRyYW5zcGFyZW50O1xuXG4gICAgLyoqXG4gICAgICogVGhlIGJhY2tncm91bmQgY29sb3IgYXMgYSBudW1iZXIuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl9iYWNrZ3JvdW5kQ29sb3IgPSAweDAwMDAwMDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBiYWNrZ3JvdW5kIGNvbG9yIGFzIGFuIFtSLCBHLCBCXSBhcnJheS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcltdfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fYmFja2dyb3VuZENvbG9yUmdiID0gWzAsIDAsIDBdO1xuXG4gICAgdGhpcy5iYWNrZ3JvdW5kQ29sb3IgPSBvcHRpb25zLmJhY2tncm91bmRDb2xvciB8fCB0aGlzLl9iYWNrZ3JvdW5kQ29sb3I7IC8vIHJ1biBiZyBjb2xvciBzZXR0ZXJcblxuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgdGhlIHJlbmRlciB2aWV3IHNob3VsZCBiZSByZXNpemVkIGF1dG9tYXRpY2FsbHlcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5hdXRvUmVzaXplID0gb3B0aW9ucy5hdXRvUmVzaXplIHx8IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHZhbHVlIG9mIHRoZSBwcmVzZXJ2ZURyYXdpbmdCdWZmZXIgZmxhZyBhZmZlY3RzIHdoZXRoZXIgb3Igbm90IHRoZSBjb250ZW50cyBvZiB0aGUgc3RlbmNpbCBidWZmZXIgaXMgcmV0YWluZWQgYWZ0ZXIgcmVuZGVyaW5nLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLnByZXNlcnZlRHJhd2luZ0J1ZmZlciA9IG9wdGlvbnMucHJlc2VydmVEcmF3aW5nQnVmZmVyO1xuXG4gICAgLyoqXG4gICAgICogVGhpcyBzZXRzIGlmIHRoZSBXZWJHTFJlbmRlcmVyIHdpbGwgY2xlYXIgdGhlIGNvbnRleHQgdGV4dHVyZSBvciBub3QgYmVmb3JlIHRoZSBuZXcgcmVuZGVyIHBhc3MuIElmIHRydWU6XG4gICAgICogSWYgdGhlIHJlbmRlcmVyIGlzIE5PVCB0cmFuc3BhcmVudCwgUGl4aSB3aWxsIGNsZWFyIHRvIGFscGhhICgwLCAwLCAwLCAwKS5cbiAgICAgKiBJZiB0aGUgcmVuZGVyZXIgaXMgdHJhbnNwYXJlbnQsIFBpeGkgd2lsbCBjbGVhciB0byB0aGUgdGFyZ2V0IFN0YWdlJ3MgYmFja2dyb3VuZCBjb2xvci5cbiAgICAgKiBEaXNhYmxlIHRoaXMgYnkgc2V0dGluZyB0aGlzIHRvIGZhbHNlLiBGb3IgZXhhbXBsZTogaWYgeW91ciBnYW1lIGhhcyBhIGNhbnZhcyBmaWxsaW5nIGJhY2tncm91bmQgaW1hZ2UsIHlvdSBvZnRlbiBkb24ndCBuZWVkIHRoaXMgc2V0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAZGVmYXVsdFxuICAgICAqL1xuICAgIHRoaXMuY2xlYXJCZWZvcmVSZW5kZXIgPSBvcHRpb25zLmNsZWFyQmVmb3JlUmVuZGVyO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHdpZHRoIG9mIHRoZSBjYW52YXMgdmlld1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDgwMFxuICAgICAqL1xuICAgIHRoaXMud2lkdGggPSB3aWR0aCB8fCA4MDA7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgaGVpZ2h0IG9mIHRoZSBjYW52YXMgdmlld1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDYwMFxuICAgICAqL1xuICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0IHx8IDYwMDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBjYW52YXMgZWxlbWVudCB0aGF0IGV2ZXJ5dGhpbmcgaXMgZHJhd24gdG9cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0hUTUxDYW52YXNFbGVtZW50fVxuICAgICAqL1xuICAgIHRoaXMudmlldyA9IG9wdGlvbnMudmlldyB8fCBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnY2FudmFzJyApO1xuXG4gICAgLy8gZGVhbCB3aXRoIGxvc2luZyBjb250ZXh0Li5cblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge0Z1bmN0aW9ufVxuICAgICAqL1xuICAgIHRoaXMuY29udGV4dExvc3RCb3VuZCA9IHRoaXMuaGFuZGxlQ29udGV4dExvc3QuYmluZCh0aGlzKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge0Z1bmN0aW9ufVxuICAgICAqL1xuICAgIHRoaXMuY29udGV4dFJlc3RvcmVkQm91bmQgPSB0aGlzLmhhbmRsZUNvbnRleHRSZXN0b3JlZC5iaW5kKHRoaXMpO1xuXG4gICAgdGhpcy52aWV3LmFkZEV2ZW50TGlzdGVuZXIoJ3dlYmdsY29udGV4dGxvc3QnLCB0aGlzLmNvbnRleHRMb3N0Qm91bmQsIGZhbHNlKTtcbiAgICB0aGlzLnZpZXcuYWRkRXZlbnRMaXN0ZW5lcignd2ViZ2xjb250ZXh0cmVzdG9yZWQnLCB0aGlzLmNvbnRleHRSZXN0b3JlZEJvdW5kLCBmYWxzZSk7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtvYmplY3R9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl9jb250ZXh0T3B0aW9ucyA9IHtcbiAgICAgICAgYWxwaGE6IHRoaXMudHJhbnNwYXJlbnQsXG4gICAgICAgIGFudGlhbGlhczogb3B0aW9ucy5hbnRpYWxpYXMsIC8vIFNQRUVEIFVQPz9cbiAgICAgICAgcHJlbXVsdGlwbGllZEFscGhhOnRoaXMudHJhbnNwYXJlbnQgJiYgdGhpcy50cmFuc3BhcmVudCAhPT0gJ25vdE11bHRpcGxpZWQnLFxuICAgICAgICBzdGVuY2lsOnRydWUsXG4gICAgICAgIHByZXNlcnZlRHJhd2luZ0J1ZmZlcjogb3B0aW9ucy5wcmVzZXJ2ZURyYXdpbmdCdWZmZXJcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICovXG4gICAgdGhpcy5wcm9qZWN0aW9uID0gbmV3IG1hdGguUG9pbnQoKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge1BvaW50fVxuICAgICAqL1xuICAgIHRoaXMub2Zmc2V0ID0gbmV3IG1hdGguUG9pbnQoMCwgMCk7XG5cbiAgICAvKipcbiAgICAgKiBDb3VudGVyIGZvciB0aGUgbnVtYmVyIG9mIGRyYXdzIG1hZGUgZWFjaCBmcmFtZVxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMuZHJhd0NvdW50ID0gMDtcblxuICAgIC8vIHRpbWUgdG8gY3JlYXRlIHRoZSByZW5kZXIgbWFuYWdlcnMhIGVhY2ggb25lIGZvY3VzZXMgb24gbWFuYWdpbmcgYSBzdGF0ZSBpbiB3ZWJHTFxuXG4gICAgLyoqXG4gICAgICogRGVhbHMgd2l0aCBtYW5hZ2luZyB0aGUgc2hhZGVyIHByb2dyYW1zIGFuZCB0aGVpciBhdHRyaWJzXG4gICAgICogQG1lbWJlciB7V2ViR0xTaGFkZXJNYW5hZ2VyfVxuICAgICAqL1xuICAgIHRoaXMuc2hhZGVyTWFuYWdlciA9IG5ldyBXZWJHTFNoYWRlck1hbmFnZXIodGhpcyk7XG5cbiAgICAvKipcbiAgICAgKiBNYW5hZ2VzIHRoZSByZW5kZXJpbmcgb2Ygc3ByaXRlc1xuICAgICAqIEBtZW1iZXIge1dlYkdMU3ByaXRlQmF0Y2h9XG4gICAgICovXG4gICAgdGhpcy5zcHJpdGVCYXRjaCA9IG5ldyBXZWJHTFNwcml0ZUJhdGNoKHRoaXMpO1xuXG4gICAgLyoqXG4gICAgICogTWFuYWdlcyB0aGUgcmVuZGVyaW5nIG9mIHNwcml0ZXNcbiAgICAgKiBAbWVtYmVyIHtXZWJHTEZhc3RTcHJpdGVCYXRjaH1cbiAgICAgKi9cbiAgICB0aGlzLmZhc3RTcHJpdGVCYXRjaCA9IG5ldyBXZWJHTEZhc3RTcHJpdGVCYXRjaCh0aGlzKTtcblxuICAgIC8qKlxuICAgICAqIE1hbmFnZXMgdGhlIG1hc2tzIHVzaW5nIHRoZSBzdGVuY2lsIGJ1ZmZlclxuICAgICAqIEBtZW1iZXIge1dlYkdMTWFza01hbmFnZXJ9XG4gICAgICovXG4gICAgdGhpcy5tYXNrTWFuYWdlciA9IG5ldyBXZWJHTE1hc2tNYW5hZ2VyKHRoaXMpO1xuXG4gICAgLyoqXG4gICAgICogTWFuYWdlcyB0aGUgZmlsdGVyc1xuICAgICAqIEBtZW1iZXIge1dlYkdMRmlsdGVyTWFuYWdlcn1cbiAgICAgKi9cbiAgICB0aGlzLmZpbHRlck1hbmFnZXIgPSBuZXcgV2ViR0xGaWx0ZXJNYW5hZ2VyKHRoaXMpO1xuXG4gICAgLyoqXG4gICAgICogTWFuYWdlcyB0aGUgc3RlbmNpbCBidWZmZXJcbiAgICAgKiBAbWVtYmVyIHtXZWJHTFN0ZW5jaWxNYW5hZ2VyfVxuICAgICAqL1xuICAgIHRoaXMuc3RlbmNpbE1hbmFnZXIgPSBuZXcgV2ViR0xTdGVuY2lsTWFuYWdlcih0aGlzKTtcblxuICAgIC8qKlxuICAgICAqIE1hbmFnZXMgdGhlIGJsZW5kTW9kZXNcbiAgICAgKiBAbWVtYmVyIHtXZWJHTEJsZW5kTW9kZU1hbmFnZXJ9XG4gICAgICovXG4gICAgdGhpcy5ibGVuZE1vZGVNYW5hZ2VyID0gbmV3IFdlYkdMQmxlbmRNb2RlTWFuYWdlcih0aGlzKTtcblxuICAgIHRoaXMuYmxlbmRNb2RlcyA9IG51bGw7XG5cbiAgICB0aGlzLl9ib3VuZFVwZGF0ZVRleHR1cmUgPSB0aGlzLnVwZGF0ZVRleHR1cmUuYmluZCh0aGlzKTtcbiAgICB0aGlzLl9ib3VuZERlc3Ryb3lUZXh0dXJlID0gdGhpcy5kZXN0cm95VGV4dHVyZS5iaW5kKHRoaXMpO1xuXG4gICAgLy8gdGltZSBpbml0IHRoZSBjb250ZXh0Li5cbiAgICB0aGlzLl9pbml0Q29udGV4dCgpO1xuXG4gICAgLy8gbWFwIHNvbWUgd2ViR0wgYmxlbmQgbW9kZXMuLlxuICAgIHRoaXMuX21hcEJsZW5kTW9kZXMoKTtcbn1cblxuLy8gY29uc3RydWN0b3JcbldlYkdMUmVuZGVyZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gV2ViR0xSZW5kZXJlcjtcbm1vZHVsZS5leHBvcnRzID0gV2ViR0xSZW5kZXJlcjtcblxudXRpbHMuZXZlbnRUYXJnZXQubWl4aW4oV2ViR0xSZW5kZXJlci5wcm90b3R5cGUpO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhXZWJHTFJlbmRlcmVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSBiYWNrZ3JvdW5kIGNvbG9yIHRvIGZpbGwgaWYgbm90IHRyYW5zcGFyZW50XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIFdlYkdMUmVuZGVyZXIjXG4gICAgICovXG4gICAgYmFja2dyb3VuZENvbG9yOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2JhY2tncm91bmRDb2xvcjtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsKSB7XG4gICAgICAgICAgICB0aGlzLl9iYWNrZ3JvdW5kQ29sb3IgPSB2YWw7XG4gICAgICAgICAgICB1dGlscy5oZXgycmdiKHZhbCwgdGhpcy5fYmFja2dyb3VuZENvbG9yUmdiKTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG4vKipcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5XZWJHTFJlbmRlcmVyLnByb3RvdHlwZS5faW5pdENvbnRleHQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGdsID0gdGhpcy52aWV3LmdldENvbnRleHQoJ3dlYmdsJywgdGhpcy5fY29udGV4dE9wdGlvbnMpIHx8IHRoaXMudmlldy5nZXRDb250ZXh0KCdleHBlcmltZW50YWwtd2ViZ2wnLCB0aGlzLl9jb250ZXh0T3B0aW9ucyk7XG4gICAgdGhpcy5nbCA9IGdsO1xuXG4gICAgaWYgKCFnbCkge1xuICAgICAgICAvLyBmYWlsLCBub3QgYWJsZSB0byBnZXQgYSBjb250ZXh0XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVGhpcyBicm93c2VyIGRvZXMgbm90IHN1cHBvcnQgd2ViR0wuIFRyeSB1c2luZyB0aGUgY2FudmFzIHJlbmRlcmVyJyk7XG4gICAgfVxuXG4gICAgdGhpcy5nbENvbnRleHRJZCA9IFdlYkdMUmVuZGVyZXIuZ2xDb250ZXh0SWQrKztcbiAgICBnbC5pZCA9IHRoaXMuZ2xDb250ZXh0SWQ7XG4gICAgZ2wucmVuZGVyZXIgPSB0aGlzO1xuXG4gICAgLy8gc2V0IHVwIHRoZSBkZWZhdWx0IHBpeGkgc2V0dGluZ3MuLlxuICAgIGdsLmRpc2FibGUoZ2wuREVQVEhfVEVTVCk7XG4gICAgZ2wuZGlzYWJsZShnbC5DVUxMX0ZBQ0UpO1xuICAgIGdsLmVuYWJsZShnbC5CTEVORCk7XG5cbiAgICB0aGlzLmVtaXQoJ2NvbnRleHQnLCBnbCk7XG5cbiAgICAvLyBub3cgcmVzaXplIGFuZCB3ZSBhcmUgZ29vZCB0byBnbyFcbiAgICB0aGlzLnJlc2l6ZSh0aGlzLndpZHRoLCB0aGlzLmhlaWdodCk7XG59O1xuXG4vKipcbiAqIFJlbmRlcnMgdGhlIG9iamVjdCB0byBpdHMgd2ViR0wgdmlld1xuICpcbiAqIEBwYXJhbSBvYmplY3Qge0Rpc3BsYXlPYmplY3R9IHRoZSBvYmplY3QgdG8gYmUgcmVuZGVyZWRcbiAqL1xuV2ViR0xSZW5kZXJlci5wcm90b3R5cGUucmVuZGVyID0gZnVuY3Rpb24gKG9iamVjdCkge1xuICAgIC8vIG5vIHBvaW50IHJlbmRlcmluZyBpZiBvdXIgY29udGV4dCBoYXMgYmVlbiBibG93biB1cCFcbiAgICBpZiAodGhpcy5nbC5pc0NvbnRleHRMb3N0KCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIHVwZGF0ZSB0aGUgc2NlbmUgZ3JhcGhcbiAgICBvYmplY3QudXBkYXRlVHJhbnNmb3JtKCk7XG5cbiAgICB2YXIgZ2wgPSB0aGlzLmdsO1xuXG4gICAgLy8gLS0gRG9lcyB0aGlzIG5lZWQgdG8gYmUgc2V0IGV2ZXJ5IGZyYW1lPyAtLSAvL1xuICAgIGdsLnZpZXdwb3J0KDAsIDAsIHRoaXMud2lkdGgsIHRoaXMuaGVpZ2h0KTtcblxuICAgIC8vIG1ha2Ugc3VyZSB3ZSBhcmUgYm91bmQgdG8gdGhlIG1haW4gZnJhbWUgYnVmZmVyXG4gICAgZ2wuYmluZEZyYW1lYnVmZmVyKGdsLkZSQU1FQlVGRkVSLCBudWxsKTtcblxuICAgIGlmICh0aGlzLmNsZWFyQmVmb3JlUmVuZGVyKSB7XG4gICAgICAgIGlmICh0aGlzLnRyYW5zcGFyZW50KSB7XG4gICAgICAgICAgICBnbC5jbGVhckNvbG9yKDAsIDAsIDAsIDApO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZ2wuY2xlYXJDb2xvcih0aGlzLl9iYWNrZ3JvdW5kQ29sb3JSZ2JbMF0sIHRoaXMuX2JhY2tncm91bmRDb2xvclJnYlsxXSwgdGhpcy5fYmFja2dyb3VuZENvbG9yUmdiWzJdLCAxKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGdsLmNsZWFyKGdsLkNPTE9SX0JVRkZFUl9CSVQpO1xuICAgIH1cblxuICAgIHRoaXMucmVuZGVyRGlzcGxheU9iamVjdChvYmplY3QsIHRoaXMucHJvamVjdGlvbik7XG59O1xuXG4vKipcbiAqIFJlbmRlcnMgYSBEaXNwbGF5IE9iamVjdC5cbiAqXG4gKiBAcGFyYW0gZGlzcGxheU9iamVjdCB7RGlzcGxheU9iamVjdH0gVGhlIERpc3BsYXlPYmplY3QgdG8gcmVuZGVyXG4gKiBAcGFyYW0gcHJvamVjdGlvbiB7UG9pbnR9IFRoZSBwcm9qZWN0aW9uXG4gKiBAcGFyYW0gYnVmZmVyIHtBcnJheX0gYSBzdGFuZGFyZCBXZWJHTCBidWZmZXJcbiAqL1xuV2ViR0xSZW5kZXJlci5wcm90b3R5cGUucmVuZGVyRGlzcGxheU9iamVjdCA9IGZ1bmN0aW9uIChkaXNwbGF5T2JqZWN0LCBwcm9qZWN0aW9uLCBidWZmZXIpIHtcbiAgICB0aGlzLmJsZW5kTW9kZU1hbmFnZXIuc2V0QmxlbmRNb2RlKENPTlNULmJsZW5kTW9kZXMuTk9STUFMKTtcblxuICAgIC8vIHJlc2V0IHRoZSByZW5kZXIgc2Vzc2lvbiBkYXRhLi5cbiAgICB0aGlzLmRyYXdDb3VudCA9IDA7XG5cbiAgICAvLyBtYWtlIHN1cmUgdG8gZmxpcCB0aGUgWSBpZiB1c2luZyBhIHJlbmRlciB0ZXh0dXJlLi5cbiAgICB0aGlzLmZsaXBZID0gYnVmZmVyID8gLTEgOiAxO1xuXG4gICAgLy8gc2V0IHRoZSBkZWZhdWx0IHByb2plY3Rpb25cbiAgICB0aGlzLnByb2plY3Rpb24gPSBwcm9qZWN0aW9uO1xuXG4gICAgLy9zZXQgdGhlIGRlZmF1bHQgb2Zmc2V0XG4gICAgdGhpcy5vZmZzZXQgPSB0aGlzLm9mZnNldDtcblxuICAgIC8vIHN0YXJ0IHRoZSBzcHJpdGUgYmF0Y2hcbiAgICB0aGlzLnNwcml0ZUJhdGNoLmJlZ2luKCk7XG5cbiAgICAvLyBzdGFydCB0aGUgZmlsdGVyIG1hbmFnZXJcbiAgICB0aGlzLmZpbHRlck1hbmFnZXIuYmVnaW4oYnVmZmVyKTtcblxuICAgIC8vIHJlbmRlciB0aGUgc2NlbmUhXG4gICAgZGlzcGxheU9iamVjdC5yZW5kZXJXZWJHTCh0aGlzKTtcblxuICAgIC8vIGZpbmlzaCB0aGUgc3ByaXRlIGJhdGNoXG4gICAgdGhpcy5zcHJpdGVCYXRjaC5lbmQoKTtcbn07XG5cbi8qKlxuICogUmVzaXplcyB0aGUgd2ViR0wgdmlldyB0byB0aGUgc3BlY2lmaWVkIHdpZHRoIGFuZCBoZWlnaHQuXG4gKlxuICogQHBhcmFtIHdpZHRoIHtudW1iZXJ9IHRoZSBuZXcgd2lkdGggb2YgdGhlIHdlYkdMIHZpZXdcbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gdGhlIG5ldyBoZWlnaHQgb2YgdGhlIHdlYkdMIHZpZXdcbiAqL1xuV2ViR0xSZW5kZXJlci5wcm90b3R5cGUucmVzaXplID0gZnVuY3Rpb24gKHdpZHRoLCBoZWlnaHQpIHtcbiAgICB0aGlzLndpZHRoID0gd2lkdGggKiB0aGlzLnJlc29sdXRpb247XG4gICAgdGhpcy5oZWlnaHQgPSBoZWlnaHQgKiB0aGlzLnJlc29sdXRpb247XG5cbiAgICB0aGlzLnZpZXcud2lkdGggPSB0aGlzLndpZHRoO1xuICAgIHRoaXMudmlldy5oZWlnaHQgPSB0aGlzLmhlaWdodDtcblxuICAgIGlmICh0aGlzLmF1dG9SZXNpemUpIHtcbiAgICAgICAgdGhpcy52aWV3LnN0eWxlLndpZHRoID0gdGhpcy53aWR0aCAvIHRoaXMucmVzb2x1dGlvbiArICdweCc7XG4gICAgICAgIHRoaXMudmlldy5zdHlsZS5oZWlnaHQgPSB0aGlzLmhlaWdodCAvIHRoaXMucmVzb2x1dGlvbiArICdweCc7XG4gICAgfVxuXG4gICAgdGhpcy5nbC52aWV3cG9ydCgwLCAwLCB0aGlzLndpZHRoLCB0aGlzLmhlaWdodCk7XG5cbiAgICB0aGlzLnByb2plY3Rpb24ueCA9ICB0aGlzLndpZHRoIC8gMiAvIHRoaXMucmVzb2x1dGlvbjtcbiAgICB0aGlzLnByb2plY3Rpb24ueSA9ICAtdGhpcy5oZWlnaHQgLyAyIC8gdGhpcy5yZXNvbHV0aW9uO1xufTtcblxuLyoqXG4gKiBVcGRhdGVzIGFuZC9vciBDcmVhdGVzIGEgV2ViR0wgdGV4dHVyZSBmb3IgdGhlIHJlbmRlcmVyJ3MgY29udGV4dC5cbiAqXG4gKiBAcGFyYW0gdGV4dHVyZSB7QmFzZVRleHR1cmV8VGV4dHVyZX0gdGhlIHRleHR1cmUgdG8gdXBkYXRlXG4gKi9cbldlYkdMUmVuZGVyZXIucHJvdG90eXBlLnVwZGF0ZVRleHR1cmUgPSBmdW5jdGlvbiAodGV4dHVyZSkge1xuICAgIHRleHR1cmUgPSB0ZXh0dXJlLmJhc2VUZXh0dXJlIHx8IHRleHR1cmU7XG5cbiAgICBpZiAoIXRleHR1cmUuaGFzTG9hZGVkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgZ2wgPSB0aGlzLmdsO1xuXG4gICAgaWYgKCF0ZXh0dXJlLl9nbFRleHR1cmVzW2dsLmlkXSkge1xuICAgICAgICB0ZXh0dXJlLl9nbFRleHR1cmVzW2dsLmlkXSA9IGdsLmNyZWF0ZVRleHR1cmUoKTtcbiAgICAgICAgdGV4dHVyZS5vbigndXBkYXRlJywgdGhpcy5fYm91bmRVcGRhdGVUZXh0dXJlKTtcbiAgICAgICAgdGV4dHVyZS5vbignZGlzcG9zZScsIHRoaXMuX2JvdW5kRGVzdHJveVRleHR1cmUpO1xuICAgIH1cblxuICAgIGdsLmJpbmRUZXh0dXJlKGdsLlRFWFRVUkVfMkQsIHRleHR1cmUuX2dsVGV4dHVyZXNbZ2wuaWRdKTtcblxuICAgIGdsLnBpeGVsU3RvcmVpKGdsLlVOUEFDS19QUkVNVUxUSVBMWV9BTFBIQV9XRUJHTCwgdGV4dHVyZS5wcmVtdWx0aXBsaWVkQWxwaGEpO1xuICAgIGdsLnRleEltYWdlMkQoZ2wuVEVYVFVSRV8yRCwgMCwgZ2wuUkdCQSwgZ2wuUkdCQSwgZ2wuVU5TSUdORURfQllURSwgdGV4dHVyZS5zb3VyY2UpO1xuXG4gICAgZ2wudGV4UGFyYW1ldGVyaShnbC5URVhUVVJFXzJELCBnbC5URVhUVVJFX01BR19GSUxURVIsIHRleHR1cmUuc2NhbGVNb2RlID09PSBDT05TVC5zY2FsZU1vZGVzLkxJTkVBUiA/IGdsLkxJTkVBUiA6IGdsLk5FQVJFU1QpO1xuXG5cbiAgICBpZiAodGV4dHVyZS5taXBtYXAgJiYgdXRpbHMuaXNQb3dlck9mVHdvKHRleHR1cmUud2lkdGgsIHRleHR1cmUuaGVpZ2h0KSkge1xuICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfTUlOX0ZJTFRFUiwgdGV4dHVyZS5zY2FsZU1vZGUgPT09IENPTlNULnNjYWxlTW9kZXMuTElORUFSID8gZ2wuTElORUFSX01JUE1BUF9MSU5FQVIgOiBnbC5ORUFSRVNUX01JUE1BUF9ORUFSRVNUKTtcbiAgICAgICAgZ2wuZ2VuZXJhdGVNaXBtYXAoZ2wuVEVYVFVSRV8yRCk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfTUlOX0ZJTFRFUiwgdGV4dHVyZS5zY2FsZU1vZGUgPT09IENPTlNULnNjYWxlTW9kZXMuTElORUFSID8gZ2wuTElORUFSIDogZ2wuTkVBUkVTVCk7XG4gICAgfVxuXG4gICAgaWYgKCF0ZXh0dXJlLl9wb3dlck9mMikge1xuICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfV1JBUF9TLCBnbC5DTEFNUF9UT19FREdFKTtcbiAgICAgICAgZ2wudGV4UGFyYW1ldGVyaShnbC5URVhUVVJFXzJELCBnbC5URVhUVVJFX1dSQVBfVCwgZ2wuQ0xBTVBfVE9fRURHRSk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfV1JBUF9TLCBnbC5SRVBFQVQpO1xuICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfV1JBUF9ULCBnbC5SRVBFQVQpO1xuICAgIH1cblxuICAgIHJldHVybiAgdGV4dHVyZS5fZ2xUZXh0dXJlc1tnbC5pZF07XG59O1xuXG5XZWJHTFJlbmRlcmVyLnByb3RvdHlwZS5kZXN0cm95VGV4dHVyZSA9IGZ1bmN0aW9uICh0ZXh0dXJlKSB7XG4gICAgdGV4dHVyZSA9IHRleHR1cmUuYmFzZVRleHR1cmUgfHwgdGV4dHVyZTtcblxuICAgIGlmICghdGV4dHVyZS5oYXNMb2FkZWQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0ZXh0dXJlLl9nbFRleHR1cmVzW3RoaXMuZ2wuaWRdKSB7XG4gICAgICAgIHRoaXMuZ2wuZGVsZXRlVGV4dHVyZSh0ZXh0dXJlLl9nbFRleHR1cmVzW3RoaXMuZ2wuaWRdKTtcbiAgICB9XG59O1xuXG4vKipcbiAqIEhhbmRsZXMgYSBsb3N0IHdlYmdsIGNvbnRleHRcbiAqXG4gKiBAcGFyYW0gZXZlbnQge0V2ZW50fVxuICogQHByaXZhdGVcbiAqL1xuV2ViR0xSZW5kZXJlci5wcm90b3R5cGUuaGFuZGxlQ29udGV4dExvc3QgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xufTtcblxuLyoqXG4gKiBIYW5kbGVzIGEgcmVzdG9yZWQgd2ViZ2wgY29udGV4dFxuICpcbiAqIEBwYXJhbSBldmVudCB7RXZlbnR9XG4gKiBAcHJpdmF0ZVxuICovXG5XZWJHTFJlbmRlcmVyLnByb3RvdHlwZS5oYW5kbGVDb250ZXh0UmVzdG9yZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5faW5pdENvbnRleHQoKTtcblxuICAgIC8vIGVtcHR5IGFsbCB0aGUgb2wgZ2wgdGV4dHVyZXMgYXMgdGhleSBhcmUgdXNlbGVzcyBub3dcbiAgICBmb3IgKHZhciBrZXkgaW4gdXRpbHMuVGV4dHVyZUNhY2hlKSB7XG4gICAgICAgIHZhciB0ZXh0dXJlID0gdXRpbHMuVGV4dHVyZUNhY2hlW2tleV0uYmFzZVRleHR1cmU7XG4gICAgICAgIHRleHR1cmUuX2dsVGV4dHVyZXMgPSBbXTtcbiAgICB9XG59O1xuXG4vKipcbiAqIFJlbW92ZXMgZXZlcnl0aGluZyBmcm9tIHRoZSByZW5kZXJlciAoZXZlbnQgbGlzdGVuZXJzLCBzcHJpdGViYXRjaCwgZXRjLi4uKVxuICpcbiAqIEBwYXJhbSBbcmVtb3ZlVmlldz1mYWxzZV0ge2Jvb2xlYW59IFJlbW92ZXMgdGhlIENhbnZhcyBlbGVtZW50IGZyb20gdGhlIERPTS5cbiAqL1xuV2ViR0xSZW5kZXJlci5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uIChyZW1vdmVWaWV3KSB7XG4gICAgaWYgKHJlbW92ZVZpZXcgJiYgdGhpcy52aWV3LnBhcmVudCkge1xuICAgICAgICB0aGlzLnZpZXcucGFyZW50LnJlbW92ZUNoaWxkKHRoaXMudmlldyk7XG4gICAgfVxuXG4gICAgLy8gcmVtb3ZlIGxpc3RlbmVyc1xuICAgIHRoaXMudmlldy5yZW1vdmVFdmVudExpc3RlbmVyKCd3ZWJnbGNvbnRleHRsb3N0JywgdGhpcy5jb250ZXh0TG9zdEJvdW5kKTtcbiAgICB0aGlzLnZpZXcucmVtb3ZlRXZlbnRMaXN0ZW5lcignd2ViZ2xjb250ZXh0cmVzdG9yZWQnLCB0aGlzLmNvbnRleHRSZXN0b3JlZEJvdW5kKTtcblxuICAgIC8vIHRpbWUgdG8gY3JlYXRlIHRoZSByZW5kZXIgbWFuYWdlcnMhIGVhY2ggb25lIGZvY3VzZXMgb24gbWFuYWdpbmUgYSBzdGF0ZSBpbiB3ZWJHTFxuICAgIHRoaXMuc2hhZGVyTWFuYWdlci5kZXN0cm95KCk7XG4gICAgdGhpcy5zcHJpdGVCYXRjaC5kZXN0cm95KCk7XG4gICAgdGhpcy5tYXNrTWFuYWdlci5kZXN0cm95KCk7XG4gICAgdGhpcy5maWx0ZXJNYW5hZ2VyLmRlc3Ryb3koKTtcblxuXG4gICAgLy8gdGhpcy51dWlkID0gdXRpbHMudXVpZCgpO1xuICAgIC8vIHRoaXMudHlwZSA9IENPTlNULldFQkdMX1JFTkRFUkVSO1xuXG4gICAgLy8gdGhpcy5yZXNvbHV0aW9uID0gb3B0aW9ucy5yZXNvbHV0aW9uO1xuICAgIC8vIHRoaXMudHJhbnNwYXJlbnQgPSBvcHRpb25zLnRyYW5zcGFyZW50O1xuXG4gICAgdGhpcy5fYmFja2dyb3VuZENvbG9yID0gMHgwMDAwMDA7XG4gICAgdGhpcy5fYmFja2dyb3VuZENvbG9yUmdiID0gbnVsbDtcblxuICAgIC8vIHRoaXMuYmFja2dyb3VuZENvbG9yID0gbnVsbDtcbiAgICAvLyB0aGlzLmF1dG9SZXNpemUgPSBvcHRpb25zLmF1dG9SZXNpemUgfHwgZmFsc2U7XG4gICAgLy8gdGhpcy5wcmVzZXJ2ZURyYXdpbmdCdWZmZXIgPSBvcHRpb25zLnByZXNlcnZlRHJhd2luZ0J1ZmZlcjtcbiAgICAvLyB0aGlzLmNsZWFyQmVmb3JlUmVuZGVyID0gb3B0aW9ucy5jbGVhckJlZm9yZVJlbmRlcjtcbiAgICAvLyB0aGlzLndpZHRoID0gd2lkdGggfHwgODAwO1xuICAgIC8vIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0IHx8IDYwMDtcblxuICAgIHRoaXMudmlldyA9IG51bGw7XG5cbiAgICB0aGlzLmNvbnRleHRMb3N0Qm91bmQgPSBudWxsO1xuICAgIHRoaXMuY29udGV4dFJlc3RvcmVkQm91bmQgPSBudWxsO1xuXG4gICAgdGhpcy5fY29udGV4dE9wdGlvbnMgPSBudWxsO1xuXG4gICAgdGhpcy5wcm9qZWN0aW9uID0gbnVsbDtcbiAgICB0aGlzLm9mZnNldCA9IG51bGw7XG4gICAgdGhpcy5kcmF3Q291bnQgPSAwO1xuXG4gICAgdGhpcy5zaGFkZXJNYW5hZ2VyID0gbnVsbDtcbiAgICB0aGlzLnNwcml0ZUJhdGNoID0gbnVsbDtcbiAgICB0aGlzLm1hc2tNYW5hZ2VyID0gbnVsbDtcbiAgICB0aGlzLmZpbHRlck1hbmFnZXIgPSBudWxsO1xuICAgIHRoaXMuc3RlbmNpbE1hbmFnZXIgPSBudWxsO1xuICAgIHRoaXMuYmxlbmRNb2RlTWFuYWdlciA9IG51bGw7XG5cbiAgICB0aGlzLmJsZW5kTW9kZXMgPSBudWxsO1xuXG4gICAgdGhpcy5nbCA9IG51bGw7XG4gICAgdGhpcy5ibGVuZE1vZGVzID0gbnVsbDtcbn07XG5cbi8qKlxuICogTWFwcyBQaXhpIGJsZW5kIG1vZGVzIHRvIFdlYkdMIGJsZW5kIG1vZGVzLlxuICpcbiAqIEBwcml2YXRlXG4gKi9cbldlYkdMUmVuZGVyZXIucHJvdG90eXBlLl9tYXBCbGVuZE1vZGVzID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBnbCA9IHRoaXMuZ2w7XG5cbiAgICBpZiAoIXRoaXMuYmxlbmRNb2Rlcykge1xuICAgICAgICB0aGlzLmJsZW5kTW9kZXMgPSB7fTtcblxuICAgICAgICB0aGlzLmJsZW5kTW9kZXNbQ09OU1QuYmxlbmRNb2Rlcy5OT1JNQUxdICAgICAgICA9IFtnbC5PTkUsICAgICAgIGdsLk9ORV9NSU5VU19TUkNfQUxQSEFdO1xuICAgICAgICB0aGlzLmJsZW5kTW9kZXNbQ09OU1QuYmxlbmRNb2Rlcy5BRERdICAgICAgICAgICA9IFtnbC5TUkNfQUxQSEEsIGdsLkRTVF9BTFBIQV07XG4gICAgICAgIHRoaXMuYmxlbmRNb2Rlc1tDT05TVC5ibGVuZE1vZGVzLk1VTFRJUExZXSAgICAgID0gW2dsLkRTVF9DT0xPUiwgZ2wuT05FX01JTlVTX1NSQ19BTFBIQV07XG4gICAgICAgIHRoaXMuYmxlbmRNb2Rlc1tDT05TVC5ibGVuZE1vZGVzLlNDUkVFTl0gICAgICAgID0gW2dsLlNSQ19BTFBIQSwgZ2wuT05FXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuT1ZFUkxBWV0gICAgICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuREFSS0VOXSAgICAgICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTElHSFRFTl0gICAgICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JfRE9ER0VdICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JfQlVSTl0gICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuSEFSRF9MSUdIVF0gICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuU09GVF9MSUdIVF0gICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuRElGRkVSRU5DRV0gICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuRVhDTFVTSU9OXSAgICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuSFVFXSAgICAgICAgICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuU0FUVVJBVElPTl0gICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JdICAgICAgICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTFVNSU5PU0lUWV0gICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICB9XG59O1xuXG5XZWJHTFJlbmRlcmVyLmdsQ29udGV4dElkID0gMDtcbiIsInZhciBXZWJHTE1hbmFnZXIgPSByZXF1aXJlKCcuL1dlYkdMTWFuYWdlcicpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9IFRoZSByZW5kZXJlciB0aGlzIG1hbmFnZXIgd29ya3MgZm9yLlxuICovXG5mdW5jdGlvbiBXZWJHTEJsZW5kTW9kZU1hbmFnZXIocmVuZGVyZXIpIHtcbiAgICBXZWJHTE1hbmFnZXIuY2FsbCh0aGlzLCByZW5kZXJlcik7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5jdXJyZW50QmxlbmRNb2RlID0gOTk5OTk7XG59XG5cbldlYkdMQmxlbmRNb2RlTWFuYWdlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKFdlYkdMTWFuYWdlci5wcm90b3R5cGUpO1xuV2ViR0xCbGVuZE1vZGVNYW5hZ2VyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFdlYkdMQmxlbmRNb2RlTWFuYWdlcjtcbm1vZHVsZS5leHBvcnRzID0gV2ViR0xCbGVuZE1vZGVNYW5hZ2VyO1xuXG4vKipcbiAqIFNldHMtdXAgdGhlIGdpdmVuIGJsZW5kTW9kZSBmcm9tIFdlYkdMJ3MgcG9pbnQgb2Ygdmlldy5cbiAqXG4gKiBAcGFyYW0gYmxlbmRNb2RlIHtudW1iZXJ9IHRoZSBibGVuZE1vZGUsIHNob3VsZCBiZSBhIFBpeGkgY29uc3QsIHN1Y2ggYXMgQmxlbmRNb2Rlcy5BRERcbiAqL1xuV2ViR0xCbGVuZE1vZGVNYW5hZ2VyLnByb3RvdHlwZS5zZXRCbGVuZE1vZGUgPSBmdW5jdGlvbiAoYmxlbmRNb2RlKSB7XG4gICAgaWYgKHRoaXMuY3VycmVudEJsZW5kTW9kZSA9PT0gYmxlbmRNb2RlKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICB0aGlzLmN1cnJlbnRCbGVuZE1vZGUgPSBibGVuZE1vZGU7XG5cbiAgICB2YXIgbW9kZSA9IHRoaXMucmVuZGVyZXIuYmxlbmRNb2Rlc1t0aGlzLmN1cnJlbnRCbGVuZE1vZGVdO1xuICAgIHRoaXMucmVuZGVyZXIuZ2wuYmxlbmRGdW5jKG1vZGVbMF0sIG1vZGVbMV0pO1xuXG4gICAgcmV0dXJuIHRydWU7XG59O1xuIiwidmFyIFdlYkdMTWFuYWdlciA9IHJlcXVpcmUoJy4vV2ViR0xNYW5hZ2VyJyksXG4gICAgRmlsdGVyVGV4dHVyZSA9IHJlcXVpcmUoJy4uL3V0aWxzL0ZpbHRlclRleHR1cmUnKSxcbiAgICBTaGFkZXIgPSByZXF1aXJlKCcuLi9zaGFkZXJzL1NoYWRlcicpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9IFRoZSByZW5kZXJlciB0aGlzIG1hbmFnZXIgd29ya3MgZm9yLlxuICovXG5mdW5jdGlvbiBXZWJHTEZpbHRlck1hbmFnZXIocmVuZGVyZXIpIHtcbiAgICBXZWJHTE1hbmFnZXIuY2FsbCh0aGlzLCByZW5kZXJlcik7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHthbnlbXX1cbiAgICAgKi9cbiAgICB0aGlzLmZpbHRlclN0YWNrID0gW107XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHthbnlbXV19XG4gICAgICovXG4gICAgdGhpcy50ZXh0dXJlUG9vbCA9IFtdO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMub2Zmc2V0WCA9IDA7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5vZmZzZXRZID0gMDtcblxuICAgIC8vIGxpc3RlbiBmb3IgY29udGV4dCBhbmQgdXBkYXRlIG5lY2Vzc2FyeSBidWZmZXJzXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHRoaXMucmVuZGVyZXIub24oJ2NvbnRleHQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHNlbGYudGV4dHVyZVBvb2wubGVuZ3RoID0gMDtcbiAgICAgICAgc2VsZi5pbml0U2hhZGVyQnVmZmVycygpO1xuICAgIH0pO1xufVxuXG5XZWJHTEZpbHRlck1hbmFnZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShXZWJHTE1hbmFnZXIucHJvdG90eXBlKTtcbldlYkdMRmlsdGVyTWFuYWdlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBXZWJHTEZpbHRlck1hbmFnZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFdlYkdMRmlsdGVyTWFuYWdlcjtcblxuLyoqXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9XG4gKiBAcGFyYW0gYnVmZmVyIHtBcnJheUJ1ZmZlcn1cbiAqL1xuV2ViR0xGaWx0ZXJNYW5hZ2VyLnByb3RvdHlwZS5iZWdpbiA9IGZ1bmN0aW9uIChidWZmZXIpIHtcbiAgICB0aGlzLmRlZmF1bHRTaGFkZXIgPSB0aGlzLnJlbmRlcmVyLnNoYWRlck1hbmFnZXIuZGVmYXVsdFNoYWRlcjtcblxuICAgIHRoaXMud2lkdGggPSB0aGlzLnJlbmRlcmVyLnByb2plY3Rpb24ueCAqIDI7XG4gICAgdGhpcy5oZWlnaHQgPSAtdGhpcy5yZW5kZXJlci5wcm9qZWN0aW9uLnkgKiAyO1xuXG4gICAgdGhpcy5idWZmZXIgPSBidWZmZXI7XG59O1xuXG4vKipcbiAqIEFwcGxpZXMgdGhlIGZpbHRlciBhbmQgYWRkcyBpdCB0byB0aGUgY3VycmVudCBmaWx0ZXIgc3RhY2suXG4gKlxuICogQHBhcmFtIGZpbHRlckJsb2NrIHtvYmplY3R9IHRoZSBmaWx0ZXIgdGhhdCB3aWxsIGJlIHB1c2hlZCB0byB0aGUgY3VycmVudCBmaWx0ZXIgc3RhY2tcbiAqL1xuV2ViR0xGaWx0ZXJNYW5hZ2VyLnByb3RvdHlwZS5wdXNoRmlsdGVyID0gZnVuY3Rpb24gKGZpbHRlckJsb2NrKSB7XG4gICAgdmFyIGdsID0gdGhpcy5yZW5kZXJlci5nbDtcblxuICAgIHZhciBwcm9qZWN0aW9uID0gdGhpcy5yZW5kZXJlci5wcm9qZWN0aW9uO1xuICAgIHZhciBvZmZzZXQgPSB0aGlzLnJlbmRlcmVyLm9mZnNldDtcblxuICAgIGZpbHRlckJsb2NrLl9maWx0ZXJBcmVhID0gZmlsdGVyQmxvY2sudGFyZ2V0LmZpbHRlckFyZWEgfHwgZmlsdGVyQmxvY2sudGFyZ2V0LmdldEJvdW5kcygpO1xuXG4gICAgLy8gZmlsdGVyIHByb2dyYW1cbiAgICAvLyBPUFRJTUlTQVRJT04gLSB0aGUgZmlyc3QgZmlsdGVyIGlzIGZyZWUgaWYgaXRzIGEgc2ltcGxlIGNvbG9yIGNoYW5nZT9cbiAgICB0aGlzLmZpbHRlclN0YWNrLnB1c2goZmlsdGVyQmxvY2spO1xuXG4gICAgdmFyIGZpbHRlciA9IGZpbHRlckJsb2NrLmZpbHRlclBhc3Nlc1swXTtcblxuICAgIHRoaXMub2Zmc2V0WCArPSBmaWx0ZXJCbG9jay5fZmlsdGVyQXJlYS54O1xuICAgIHRoaXMub2Zmc2V0WSArPSBmaWx0ZXJCbG9jay5fZmlsdGVyQXJlYS55O1xuXG4gICAgdmFyIHRleHR1cmUgPSB0aGlzLnRleHR1cmVQb29sLnBvcCgpO1xuICAgIGlmICghdGV4dHVyZSkge1xuICAgICAgICB0ZXh0dXJlID0gbmV3IEZpbHRlclRleHR1cmUodGhpcy5yZW5kZXJlci5nbCwgdGhpcy53aWR0aCwgdGhpcy5oZWlnaHQpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdGV4dHVyZS5yZXNpemUodGhpcy53aWR0aCwgdGhpcy5oZWlnaHQpO1xuICAgIH1cblxuICAgIGdsLmJpbmRUZXh0dXJlKGdsLlRFWFRVUkVfMkQsICB0ZXh0dXJlLnRleHR1cmUpO1xuXG4gICAgdmFyIGZpbHRlckFyZWEgPSBmaWx0ZXJCbG9jay5fZmlsdGVyQXJlYTsvLyBmaWx0ZXJCbG9jay50YXJnZXQuZ2V0Qm91bmRzKCk7Ly8vZmlsdGVyQmxvY2sudGFyZ2V0LmZpbHRlckFyZWE7XG5cbiAgICB2YXIgcGFkZGluZyA9IGZpbHRlci5wYWRkaW5nO1xuICAgIGZpbHRlckFyZWEueCAtPSBwYWRkaW5nO1xuICAgIGZpbHRlckFyZWEueSAtPSBwYWRkaW5nO1xuICAgIGZpbHRlckFyZWEud2lkdGggKz0gcGFkZGluZyAqIDI7XG4gICAgZmlsdGVyQXJlYS5oZWlnaHQgKz0gcGFkZGluZyAqIDI7XG5cbiAgICB2YXIgbG9jYWxYID0gZmlsdGVyQXJlYS54LFxuICAgICAgICBsb2NhbFkgPSBmaWx0ZXJBcmVhLnk7XG5cbiAgICBpZiAoZmlsdGVyQXJlYS54IDwgMCkge1xuICAgICAgICBmaWx0ZXJBcmVhLndpZHRoICs9IGZpbHRlckFyZWEueDtcbiAgICAgICAgZmlsdGVyQXJlYS54ID0gMDtcbiAgICB9XG5cbiAgICBpZiAoZmlsdGVyQXJlYS55IDwgMCkge1xuICAgICAgICBmaWx0ZXJBcmVhLmhlaWdodCArPSBmaWx0ZXJBcmVhLnk7XG4gICAgICAgIGZpbHRlckFyZWEueSA9IDA7XG4gICAgfVxuXG4gICAgaWYgKGxvY2FsWCArIGZpbHRlckFyZWEud2lkdGggPiB0aGlzLndpZHRoKSB7XG4gICAgICAgIGZpbHRlckFyZWEud2lkdGggPSB0aGlzLndpZHRoIC0gbG9jYWxYO1xuICAgIH1cblxuICAgIGlmIChsb2NhbFkgKyBmaWx0ZXJBcmVhLmhlaWdodCA+IHRoaXMuaGVpZ2h0KSB7XG4gICAgICAgIGZpbHRlckFyZWEuaGVpZ2h0ID0gdGhpcy5oZWlnaHQgLSBsb2NhbFk7XG4gICAgfVxuXG4gICAgaWYgKGZpbHRlckFyZWEud2lkdGggPCAwKSB7XG4gICAgICAgIGZpbHRlckFyZWEud2lkdGggPSAwO1xuICAgIH1cblxuICAgIGlmIChmaWx0ZXJBcmVhLmhlaWdodCA8IDApIHtcbiAgICAgICAgZmlsdGVyQXJlYS5oZWlnaHQgPSAwO1xuICAgIH1cblxuICAgIC8vZ2wudGV4SW1hZ2UyRChnbC5URVhUVVJFXzJELCAwLCBnbC5SR0JBLCAgZmlsdGVyQXJlYS53aWR0aCwgZmlsdGVyQXJlYS5oZWlnaHQsIDAsIGdsLlJHQkEsIGdsLlVOU0lHTkVEX0JZVEUsIG51bGwpO1xuICAgIGdsLmJpbmRGcmFtZWJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgdGV4dHVyZS5mcmFtZUJ1ZmZlcik7XG5cbiAgICAvLyBzZXQgdmlldyBwb3J0XG4gICAgZ2wudmlld3BvcnQoMCwgMCwgZmlsdGVyQXJlYS53aWR0aCwgZmlsdGVyQXJlYS5oZWlnaHQpO1xuXG4gICAgcHJvamVjdGlvbi54ID0gZmlsdGVyQXJlYS53aWR0aC8yO1xuICAgIHByb2plY3Rpb24ueSA9IC1maWx0ZXJBcmVhLmhlaWdodC8yO1xuXG4gICAgb2Zmc2V0LnggPSAtZmlsdGVyQXJlYS54O1xuICAgIG9mZnNldC55ID0gLWZpbHRlckFyZWEueTtcblxuICAgIC8vIHVwZGF0ZSBwcm9qZWN0aW9uXG4gICAgLy8gbm93IHJlc3RvcmUgdGhlIHJlZ3VsYXIgc2hhZGVyLi5cbiAgICAvLyB0aGlzLnJlbmRlcmVyLnNoYWRlck1hbmFnZXIuc2V0U2hhZGVyKHRoaXMuZGVmYXVsdFNoYWRlcik7XG4gICAgLy9nbC51bmlmb3JtMmYodGhpcy5kZWZhdWx0U2hhZGVyLnByb2plY3Rpb25WZWN0b3IsIGZpbHRlckFyZWEud2lkdGgvMiwgLWZpbHRlckFyZWEuaGVpZ2h0LzIpO1xuICAgIC8vZ2wudW5pZm9ybTJmKHRoaXMuZGVmYXVsdFNoYWRlci5vZmZzZXRWZWN0b3IsIC1maWx0ZXJBcmVhLngsIC1maWx0ZXJBcmVhLnkpO1xuXG4gICAgZ2wuY29sb3JNYXNrKHRydWUsIHRydWUsIHRydWUsIHRydWUpO1xuICAgIGdsLmNsZWFyQ29sb3IoMCwwLDAsIDApO1xuICAgIGdsLmNsZWFyKGdsLkNPTE9SX0JVRkZFUl9CSVQpO1xuXG4gICAgZmlsdGVyQmxvY2suX2dsRmlsdGVyVGV4dHVyZSA9IHRleHR1cmU7XG5cbn07XG5cbi8qKlxuICogUmVtb3ZlcyB0aGUgbGFzdCBmaWx0ZXIgZnJvbSB0aGUgZmlsdGVyIHN0YWNrIGFuZCBkb2Vzbid0IHJldHVybiBpdC5cbiAqXG4gKi9cbldlYkdMRmlsdGVyTWFuYWdlci5wcm90b3R5cGUucG9wRmlsdGVyID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBnbCA9IHRoaXMucmVuZGVyZXIuZ2w7XG5cbiAgICB2YXIgZmlsdGVyQmxvY2sgPSB0aGlzLmZpbHRlclN0YWNrLnBvcCgpO1xuICAgIHZhciBmaWx0ZXJBcmVhID0gZmlsdGVyQmxvY2suX2ZpbHRlckFyZWE7XG4gICAgdmFyIHRleHR1cmUgPSBmaWx0ZXJCbG9jay5fZ2xGaWx0ZXJUZXh0dXJlO1xuICAgIHZhciBwcm9qZWN0aW9uID0gdGhpcy5yZW5kZXJlci5wcm9qZWN0aW9uO1xuICAgIHZhciBvZmZzZXQgPSB0aGlzLnJlbmRlcmVyLm9mZnNldDtcblxuICAgIGlmIChmaWx0ZXJCbG9jay5maWx0ZXJQYXNzZXMubGVuZ3RoID4gMSkge1xuICAgICAgICBnbC52aWV3cG9ydCgwLCAwLCBmaWx0ZXJBcmVhLndpZHRoLCBmaWx0ZXJBcmVhLmhlaWdodCk7XG5cbiAgICAgICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMudmVydGV4QnVmZmVyKTtcblxuICAgICAgICB0aGlzLnZlcnRleEFycmF5WzBdID0gMDtcbiAgICAgICAgdGhpcy52ZXJ0ZXhBcnJheVsxXSA9IGZpbHRlckFyZWEuaGVpZ2h0O1xuXG4gICAgICAgIHRoaXMudmVydGV4QXJyYXlbMl0gPSBmaWx0ZXJBcmVhLndpZHRoO1xuICAgICAgICB0aGlzLnZlcnRleEFycmF5WzNdID0gZmlsdGVyQXJlYS5oZWlnaHQ7XG5cbiAgICAgICAgdGhpcy52ZXJ0ZXhBcnJheVs0XSA9IDA7XG4gICAgICAgIHRoaXMudmVydGV4QXJyYXlbNV0gPSAwO1xuXG4gICAgICAgIHRoaXMudmVydGV4QXJyYXlbNl0gPSBmaWx0ZXJBcmVhLndpZHRoO1xuICAgICAgICB0aGlzLnZlcnRleEFycmF5WzddID0gMDtcblxuICAgICAgICBnbC5idWZmZXJTdWJEYXRhKGdsLkFSUkFZX0JVRkZFUiwgMCwgdGhpcy52ZXJ0ZXhBcnJheSk7XG5cbiAgICAgICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMudXZCdWZmZXIpO1xuICAgICAgICAvLyBub3cgc2V0IHRoZSB1dnMuLlxuICAgICAgICB0aGlzLnV2QXJyYXlbMl0gPSBmaWx0ZXJBcmVhLndpZHRoL3RoaXMud2lkdGg7XG4gICAgICAgIHRoaXMudXZBcnJheVs1XSA9IGZpbHRlckFyZWEuaGVpZ2h0L3RoaXMuaGVpZ2h0O1xuICAgICAgICB0aGlzLnV2QXJyYXlbNl0gPSBmaWx0ZXJBcmVhLndpZHRoL3RoaXMud2lkdGg7XG4gICAgICAgIHRoaXMudXZBcnJheVs3XSA9IGZpbHRlckFyZWEuaGVpZ2h0L3RoaXMuaGVpZ2h0O1xuXG4gICAgICAgIGdsLmJ1ZmZlclN1YkRhdGEoZ2wuQVJSQVlfQlVGRkVSLCAwLCB0aGlzLnV2QXJyYXkpO1xuXG4gICAgICAgIHZhciBpbnB1dFRleHR1cmUgPSB0ZXh0dXJlO1xuICAgICAgICB2YXIgb3V0cHV0VGV4dHVyZSA9IHRoaXMudGV4dHVyZVBvb2wucG9wKCk7XG4gICAgICAgIGlmICghb3V0cHV0VGV4dHVyZSkge1xuICAgICAgICAgICAgb3V0cHV0VGV4dHVyZSA9IG5ldyBGaWx0ZXJUZXh0dXJlKHRoaXMucmVuZGVyZXIuZ2wsIHRoaXMud2lkdGgsIHRoaXMuaGVpZ2h0KTtcbiAgICAgICAgfVxuICAgICAgICBvdXRwdXRUZXh0dXJlLnJlc2l6ZSh0aGlzLndpZHRoLCB0aGlzLmhlaWdodCk7XG5cbiAgICAgICAgLy8gbmVlZCB0byBjbGVhciB0aGlzIEZCTyBhcyBpdCBtYXkgaGF2ZSBzb21lIGxlZnQgb3ZlciBlbGVtZW50cyBmcm9tIGEgcHJldmlvdXMgZmlsdGVyLlxuICAgICAgICBnbC5iaW5kRnJhbWVidWZmZXIoZ2wuRlJBTUVCVUZGRVIsIG91dHB1dFRleHR1cmUuZnJhbWVCdWZmZXIgKTtcbiAgICAgICAgZ2wuY2xlYXIoZ2wuQ09MT1JfQlVGRkVSX0JJVCk7XG5cbiAgICAgICAgZ2wuZGlzYWJsZShnbC5CTEVORCk7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBmaWx0ZXJCbG9jay5maWx0ZXJQYXNzZXMubGVuZ3RoLTE7IGkrKykge1xuICAgICAgICAgICAgdmFyIGZpbHRlclBhc3MgPSBmaWx0ZXJCbG9jay5maWx0ZXJQYXNzZXNbaV07XG5cbiAgICAgICAgICAgIGdsLmJpbmRGcmFtZWJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgb3V0cHV0VGV4dHVyZS5mcmFtZUJ1ZmZlciApO1xuXG4gICAgICAgICAgICAvLyBzZXQgdGV4dHVyZVxuICAgICAgICAgICAgZ2wuYWN0aXZlVGV4dHVyZShnbC5URVhUVVJFMCk7XG4gICAgICAgICAgICBnbC5iaW5kVGV4dHVyZShnbC5URVhUVVJFXzJELCBpbnB1dFRleHR1cmUudGV4dHVyZSk7XG5cbiAgICAgICAgICAgIC8vIGRyYXcgdGV4dHVyZS4uXG4gICAgICAgICAgICAvL2ZpbHRlclBhc3MuYXBwbHlGaWx0ZXJQYXNzKGZpbHRlckFyZWEud2lkdGgsIGZpbHRlckFyZWEuaGVpZ2h0KTtcbiAgICAgICAgICAgIHRoaXMuYXBwbHlGaWx0ZXJQYXNzKGZpbHRlclBhc3MsIGZpbHRlckFyZWEsIGZpbHRlckFyZWEud2lkdGgsIGZpbHRlckFyZWEuaGVpZ2h0KTtcblxuICAgICAgICAgICAgLy8gc3dhcCB0aGUgdGV4dHVyZXMuLlxuICAgICAgICAgICAgdmFyIHRlbXAgPSBpbnB1dFRleHR1cmU7XG4gICAgICAgICAgICBpbnB1dFRleHR1cmUgPSBvdXRwdXRUZXh0dXJlO1xuICAgICAgICAgICAgb3V0cHV0VGV4dHVyZSA9IHRlbXA7XG4gICAgICAgIH1cblxuICAgICAgICBnbC5lbmFibGUoZ2wuQkxFTkQpO1xuXG4gICAgICAgIHRleHR1cmUgPSBpbnB1dFRleHR1cmU7XG4gICAgICAgIHRoaXMudGV4dHVyZVBvb2wucHVzaChvdXRwdXRUZXh0dXJlKTtcbiAgICB9XG5cbiAgICB2YXIgZmlsdGVyID0gZmlsdGVyQmxvY2suZmlsdGVyUGFzc2VzW2ZpbHRlckJsb2NrLmZpbHRlclBhc3Nlcy5sZW5ndGgtMV07XG5cbiAgICB0aGlzLm9mZnNldFggLT0gZmlsdGVyQXJlYS54O1xuICAgIHRoaXMub2Zmc2V0WSAtPSBmaWx0ZXJBcmVhLnk7XG5cbiAgICB2YXIgc2l6ZVggPSB0aGlzLndpZHRoO1xuICAgIHZhciBzaXplWSA9IHRoaXMuaGVpZ2h0O1xuXG4gICAgdmFyIG9mZnNldFggPSAwO1xuICAgIHZhciBvZmZzZXRZID0gMDtcblxuICAgIHZhciBidWZmZXIgPSB0aGlzLmJ1ZmZlcjtcblxuICAgIC8vIHRpbWUgdG8gcmVuZGVyIHRoZSBmaWx0ZXJzIHRleHR1cmUgdG8gdGhlIHByZXZpb3VzIHNjZW5lXG4gICAgaWYgKHRoaXMuZmlsdGVyU3RhY2subGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGdsLmNvbG9yTWFzayh0cnVlLCB0cnVlLCB0cnVlLCB0cnVlKTsvL3RoaXMudHJhbnNwYXJlbnQpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdmFyIGN1cnJlbnRGaWx0ZXIgPSB0aGlzLmZpbHRlclN0YWNrW3RoaXMuZmlsdGVyU3RhY2subGVuZ3RoLTFdO1xuICAgICAgICBmaWx0ZXJBcmVhID0gY3VycmVudEZpbHRlci5fZmlsdGVyQXJlYTtcblxuICAgICAgICBzaXplWCA9IGZpbHRlckFyZWEud2lkdGg7XG4gICAgICAgIHNpemVZID0gZmlsdGVyQXJlYS5oZWlnaHQ7XG5cbiAgICAgICAgb2Zmc2V0WCA9IGZpbHRlckFyZWEueDtcbiAgICAgICAgb2Zmc2V0WSA9IGZpbHRlckFyZWEueTtcblxuICAgICAgICBidWZmZXIgPSAgY3VycmVudEZpbHRlci5fZ2xGaWx0ZXJUZXh0dXJlLmZyYW1lQnVmZmVyO1xuICAgIH1cblxuICAgIC8vIFRPRE8gbmVlZCB0byByZW1vdmUgdGhlc2UgZ2xvYmFsIGVsZW1lbnRzLi5cbiAgICBwcm9qZWN0aW9uLnggPSBzaXplWC8yO1xuICAgIHByb2plY3Rpb24ueSA9IC1zaXplWS8yO1xuXG4gICAgb2Zmc2V0LnggPSBvZmZzZXRYO1xuICAgIG9mZnNldC55ID0gb2Zmc2V0WTtcblxuICAgIGZpbHRlckFyZWEgPSBmaWx0ZXJCbG9jay5fZmlsdGVyQXJlYTtcblxuICAgIHZhciB4ID0gZmlsdGVyQXJlYS54LW9mZnNldFg7XG4gICAgdmFyIHkgPSBmaWx0ZXJBcmVhLnktb2Zmc2V0WTtcblxuICAgIC8vIHVwZGF0ZSB0aGUgYnVmZmVycy4uXG4gICAgLy8gbWFrZSBzdXJlIHRvIGZsaXAgdGhlIHkhXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMudmVydGV4QnVmZmVyKTtcblxuICAgIHRoaXMudmVydGV4QXJyYXlbMF0gPSB4O1xuICAgIHRoaXMudmVydGV4QXJyYXlbMV0gPSB5ICsgZmlsdGVyQXJlYS5oZWlnaHQ7XG5cbiAgICB0aGlzLnZlcnRleEFycmF5WzJdID0geCArIGZpbHRlckFyZWEud2lkdGg7XG4gICAgdGhpcy52ZXJ0ZXhBcnJheVszXSA9IHkgKyBmaWx0ZXJBcmVhLmhlaWdodDtcblxuICAgIHRoaXMudmVydGV4QXJyYXlbNF0gPSB4O1xuICAgIHRoaXMudmVydGV4QXJyYXlbNV0gPSB5O1xuXG4gICAgdGhpcy52ZXJ0ZXhBcnJheVs2XSA9IHggKyBmaWx0ZXJBcmVhLndpZHRoO1xuICAgIHRoaXMudmVydGV4QXJyYXlbN10gPSB5O1xuXG4gICAgZ2wuYnVmZmVyU3ViRGF0YShnbC5BUlJBWV9CVUZGRVIsIDAsIHRoaXMudmVydGV4QXJyYXkpO1xuXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMudXZCdWZmZXIpO1xuXG4gICAgdGhpcy51dkFycmF5WzJdID0gZmlsdGVyQXJlYS53aWR0aC90aGlzLndpZHRoO1xuICAgIHRoaXMudXZBcnJheVs1XSA9IGZpbHRlckFyZWEuaGVpZ2h0L3RoaXMuaGVpZ2h0O1xuICAgIHRoaXMudXZBcnJheVs2XSA9IGZpbHRlckFyZWEud2lkdGgvdGhpcy53aWR0aDtcbiAgICB0aGlzLnV2QXJyYXlbN10gPSBmaWx0ZXJBcmVhLmhlaWdodC90aGlzLmhlaWdodDtcblxuICAgIGdsLmJ1ZmZlclN1YkRhdGEoZ2wuQVJSQVlfQlVGRkVSLCAwLCB0aGlzLnV2QXJyYXkpO1xuXG4gICAgZ2wudmlld3BvcnQoMCwgMCwgc2l6ZVgsIHNpemVZKTtcblxuICAgIC8vIGJpbmQgdGhlIGJ1ZmZlclxuICAgIGdsLmJpbmRGcmFtZWJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgYnVmZmVyICk7XG5cbiAgICAvLyBzZXQgdGhlIGJsZW5kIG1vZGUhXG4gICAgLy9nbC5ibGVuZEZ1bmMoZ2wuT05FLCBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBKVxuXG4gICAgLy8gc2V0IHRleHR1cmVcbiAgICBnbC5hY3RpdmVUZXh0dXJlKGdsLlRFWFRVUkUwKTtcbiAgICBnbC5iaW5kVGV4dHVyZShnbC5URVhUVVJFXzJELCB0ZXh0dXJlLnRleHR1cmUpO1xuXG4gICAgLy8gYXBwbHkhXG4gICAgdGhpcy5hcHBseUZpbHRlclBhc3MoZmlsdGVyLCBmaWx0ZXJBcmVhLCBzaXplWCwgc2l6ZVkpO1xuXG4gICAgLy8gbm93IHJlc3RvcmUgdGhlIHJlZ3VsYXIgc2hhZGVyLi4gc2hvdWxkIGhhcHBlbiBhdXRvbWF0aWNhbGx5IG5vdy4uXG4gICAgLy8gdGhpcy5yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLnNldFNoYWRlcih0aGlzLmRlZmF1bHRTaGFkZXIpO1xuICAgIC8vIGdsLnVuaWZvcm0yZih0aGlzLmRlZmF1bHRTaGFkZXIucHJvamVjdGlvblZlY3Rvciwgc2l6ZVgvMiwgLXNpemVZLzIpO1xuICAgIC8vIGdsLnVuaWZvcm0yZih0aGlzLmRlZmF1bHRTaGFkZXIub2Zmc2V0VmVjdG9yLCAtb2Zmc2V0WCwgLW9mZnNldFkpO1xuXG4gICAgLy8gcmV0dXJuIHRoZSB0ZXh0dXJlIHRvIHRoZSBwb29sXG4gICAgdGhpcy50ZXh0dXJlUG9vbC5wdXNoKHRleHR1cmUpO1xuICAgIGZpbHRlckJsb2NrLl9nbEZpbHRlclRleHR1cmUgPSBudWxsO1xufTtcblxuXG4vKipcbiAqIEFwcGxpZXMgdGhlIGZpbHRlciB0byB0aGUgc3BlY2lmaWVkIGFyZWEuXG4gKlxuICogQHBhcmFtIGZpbHRlciB7QWJzdHJhY3RGaWx0ZXJ9IHRoZSBmaWx0ZXIgdGhhdCBuZWVkcyB0byBiZSBhcHBsaWVkXG4gKiBAcGFyYW0gZmlsdGVyQXJlYSB7VGV4dHVyZX0gVE9ETyAtIG1pZ2h0IG5lZWQgYW4gdXBkYXRlXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gdGhlIGhvcml6b250YWwgcmFuZ2Ugb2YgdGhlIGZpbHRlclxuICogQHBhcmFtIGhlaWdodCB7bnVtYmVyfSB0aGUgdmVydGljYWwgcmFuZ2Ugb2YgdGhlIGZpbHRlclxuICovXG5XZWJHTEZpbHRlck1hbmFnZXIucHJvdG90eXBlLmFwcGx5RmlsdGVyUGFzcyA9IGZ1bmN0aW9uIChmaWx0ZXIsIGZpbHRlckFyZWEsIHdpZHRoLCBoZWlnaHQpIHtcbiAgICAvLyB1c2UgcHJvZ3JhbVxuICAgIHZhciBnbCA9IHRoaXMucmVuZGVyZXIuZ2w7XG5cbiAgICB2YXIgc2hhZGVyID0gZmlsdGVyLnNoYWRlcnNbZ2wuaWRdO1xuXG4gICAgaWYgKCFzaGFkZXIpIHtcbiAgICAgICAgc2hhZGVyID0gbmV3IFNoYWRlcihnbCk7XG5cbiAgICAgICAgc2hhZGVyLmZyYWdtZW50U3JjID0gZmlsdGVyLmZyYWdtZW50U3JjO1xuICAgICAgICBzaGFkZXIudW5pZm9ybXMgPSBmaWx0ZXIudW5pZm9ybXM7XG4gICAgICAgIHNoYWRlci5pbml0KCk7XG5cbiAgICAgICAgZmlsdGVyLnNoYWRlcnNbZ2wuaWRdID0gc2hhZGVyO1xuICAgIH1cblxuICAgIC8vIHNldCB0aGUgc2hhZGVyXG4gICAgdGhpcy5yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLnNldFNoYWRlcihzaGFkZXIpO1xuXG4vLyAgICBnbC51c2VQcm9ncmFtKHNoYWRlci5wcm9ncmFtKTtcblxuICAgIGdsLnVuaWZvcm0yZihzaGFkZXIucHJvamVjdGlvblZlY3Rvciwgd2lkdGgvMiwgLWhlaWdodC8yKTtcbiAgICBnbC51bmlmb3JtMmYoc2hhZGVyLm9mZnNldFZlY3RvciwgMCwwKTtcblxuICAgIGlmIChmaWx0ZXIudW5pZm9ybXMuZGltZW5zaW9ucykge1xuICAgICAgICBmaWx0ZXIudW5pZm9ybXMuZGltZW5zaW9ucy52YWx1ZVswXSA9IHRoaXMud2lkdGg7Ly93aWR0aDtcbiAgICAgICAgZmlsdGVyLnVuaWZvcm1zLmRpbWVuc2lvbnMudmFsdWVbMV0gPSB0aGlzLmhlaWdodDsvL2hlaWdodDtcbiAgICAgICAgZmlsdGVyLnVuaWZvcm1zLmRpbWVuc2lvbnMudmFsdWVbMl0gPSB0aGlzLnZlcnRleEFycmF5WzBdO1xuICAgICAgICBmaWx0ZXIudW5pZm9ybXMuZGltZW5zaW9ucy52YWx1ZVszXSA9IHRoaXMudmVydGV4QXJyYXlbNV07Ly9maWx0ZXJBcmVhLmhlaWdodDtcbiAgICB9XG5cbiAgICBzaGFkZXIuc3luY1VuaWZvcm1zKCk7XG5cbiAgICBnbC5iaW5kQnVmZmVyKGdsLkFSUkFZX0JVRkZFUiwgdGhpcy52ZXJ0ZXhCdWZmZXIpO1xuICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIoc2hhZGVyLmFWZXJ0ZXhQb3NpdGlvbiwgMiwgZ2wuRkxPQVQsIGZhbHNlLCAwLCAwKTtcblxuICAgIGdsLmJpbmRCdWZmZXIoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLnV2QnVmZmVyKTtcbiAgICBnbC52ZXJ0ZXhBdHRyaWJQb2ludGVyKHNoYWRlci5hVGV4dHVyZUNvb3JkLCAyLCBnbC5GTE9BVCwgZmFsc2UsIDAsIDApO1xuXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMuY29sb3JCdWZmZXIpO1xuICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIoc2hhZGVyLmFDb2xvciwgMiwgZ2wuRkxPQVQsIGZhbHNlLCAwLCAwKTtcblxuICAgIGdsLmJpbmRCdWZmZXIoZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIsIHRoaXMuaW5kZXhCdWZmZXIpO1xuXG4gICAgLy8gZHJhdyB0aGUgZmlsdGVyLi4uXG4gICAgZ2wuZHJhd0VsZW1lbnRzKGdsLlRSSUFOR0xFUywgNiwgZ2wuVU5TSUdORURfU0hPUlQsIDAgKTtcblxuICAgIHRoaXMucmVuZGVyZXIuZHJhd0NvdW50Kys7XG59O1xuXG4vKipcbiAqIEluaXRpYWxpc2VzIHRoZSBzaGFkZXIgYnVmZmVycy5cbiAqXG4gKi9cbldlYkdMRmlsdGVyTWFuYWdlci5wcm90b3R5cGUuaW5pdFNoYWRlckJ1ZmZlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGdsID0gdGhpcy5yZW5kZXJlci5nbDtcblxuICAgIC8vIGNyZWF0ZSBzb21lIGJ1ZmZlcnNcbiAgICB0aGlzLnZlcnRleEJ1ZmZlciA9IGdsLmNyZWF0ZUJ1ZmZlcigpO1xuICAgIHRoaXMudXZCdWZmZXIgPSBnbC5jcmVhdGVCdWZmZXIoKTtcbiAgICB0aGlzLmNvbG9yQnVmZmVyID0gZ2wuY3JlYXRlQnVmZmVyKCk7XG4gICAgdGhpcy5pbmRleEJ1ZmZlciA9IGdsLmNyZWF0ZUJ1ZmZlcigpO1xuXG4gICAgLy8gYmluZCBhbmQgdXBsb2FkIHRoZSB2ZXJ0ZXhzLi5cbiAgICAvLyBrZWVwIGEgcmVmZXJlbmNlIHRvIHRoZSB2ZXJ0ZXhGbG9hdERhdGEuLlxuICAgIHRoaXMudmVydGV4QXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KFswLjAsIDAuMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMS4wLCAwLjAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAuMCwgMS4wLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLjAsIDEuMF0pO1xuXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMudmVydGV4QnVmZmVyKTtcbiAgICBnbC5idWZmZXJEYXRhKGdsLkFSUkFZX0JVRkZFUiwgdGhpcy52ZXJ0ZXhBcnJheSwgZ2wuU1RBVElDX0RSQVcpO1xuXG4gICAgLy8gYmluZCBhbmQgdXBsb2FkIHRoZSB1diBidWZmZXJcbiAgICB0aGlzLnV2QXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KFswLjAsIDAuMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLjAsIDAuMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLjAsIDEuMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLjAsIDEuMF0pO1xuXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMudXZCdWZmZXIpO1xuICAgIGdsLmJ1ZmZlckRhdGEoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLnV2QXJyYXksIGdsLlNUQVRJQ19EUkFXKTtcblxuICAgIHRoaXMuY29sb3JBcnJheSA9IG5ldyBGbG9hdDMyQXJyYXkoWzEuMCwgMHhGRkZGRkYsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMS4wLCAweEZGRkZGRixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLjAsIDB4RkZGRkZGLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEuMCwgMHhGRkZGRkZdKTtcblxuICAgIGdsLmJpbmRCdWZmZXIoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLmNvbG9yQnVmZmVyKTtcbiAgICBnbC5idWZmZXJEYXRhKGdsLkFSUkFZX0JVRkZFUiwgdGhpcy5jb2xvckFycmF5LCBnbC5TVEFUSUNfRFJBVyk7XG5cbiAgICAvLyBiaW5kIGFuZCB1cGxvYWQgdGhlIGluZGV4XG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5FTEVNRU5UX0FSUkFZX0JVRkZFUiwgdGhpcy5pbmRleEJ1ZmZlcik7XG4gICAgZ2wuYnVmZmVyRGF0YShnbC5FTEVNRU5UX0FSUkFZX0JVRkZFUiwgbmV3IFVpbnQxNkFycmF5KFswLCAxLCAyLCAxLCAzLCAyXSksIGdsLlNUQVRJQ19EUkFXKTtcblxufTtcblxuLyoqXG4gKiBEZXN0cm95cyB0aGUgZmlsdGVyIGFuZCByZW1vdmVzIGl0IGZyb20gdGhlIGZpbHRlciBzdGFjay5cbiAqXG4gKi9cbldlYkdMRmlsdGVyTWFuYWdlci5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuXG4gICAgdGhpcy5maWx0ZXJTdGFjayA9IG51bGw7XG5cbiAgICB0aGlzLm9mZnNldFggPSAwO1xuICAgIHRoaXMub2Zmc2V0WSA9IDA7XG5cbiAgICAvLyBkZXN0cm95IHRleHR1cmVzXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnRleHR1cmVQb29sLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHRoaXMudGV4dHVyZVBvb2xbaV0uZGVzdHJveSgpO1xuICAgIH1cblxuICAgIHRoaXMudGV4dHVyZVBvb2wgPSBudWxsO1xuXG4gICAgLy9kZXN0cm95IGJ1ZmZlcnMuLlxuICAgIGdsLmRlbGV0ZUJ1ZmZlcih0aGlzLnZlcnRleEJ1ZmZlcik7XG4gICAgZ2wuZGVsZXRlQnVmZmVyKHRoaXMudXZCdWZmZXIpO1xuICAgIGdsLmRlbGV0ZUJ1ZmZlcih0aGlzLmNvbG9yQnVmZmVyKTtcbiAgICBnbC5kZWxldGVCdWZmZXIodGhpcy5pbmRleEJ1ZmZlcik7XG5cbiAgICB0aGlzLnJlbmRlcmVyID0gbnVsbDtcbn07XG4iLCIvKipcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9IFRoZSByZW5kZXJlciB0aGlzIG1hbmFnZXIgd29ya3MgZm9yLlxuICovXG5mdW5jdGlvbiBXZWJHTE1hbmFnZXIocmVuZGVyZXIpIHtcbiAgICAvKipcbiAgICAgKiBUaGUgcmVuZGVyZXIgdGhpcyBtYW5hZ2VyIHdvcmtzIGZvci5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1dlYkdMUmVuZGVyZXJ9XG4gICAgICovXG4gICAgdGhpcy5yZW5kZXJlciA9IHJlbmRlcmVyO1xufVxuXG5XZWJHTE1hbmFnZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gV2ViR0xNYW5hZ2VyO1xubW9kdWxlLmV4cG9ydHMgPSBXZWJHTE1hbmFnZXI7XG5cbldlYkdMTWFuYWdlci5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnJlbmRlcmVyID0gbnVsbDtcbn07XG4iLCJ2YXIgV2ViR0xNYW5hZ2VyID0gcmVxdWlyZSgnLi9XZWJHTE1hbmFnZXInKSxcbiAgICBXZWJHTEdyYXBoaWNzID0gcmVxdWlyZSgnLi4vdXRpbHMvV2ViR0xHcmFwaGljcycpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9IFRoZSByZW5kZXJlciB0aGlzIG1hbmFnZXIgd29ya3MgZm9yLlxuICovXG5mdW5jdGlvbiBXZWJHTE1hc2tNYW5hZ2VyKHJlbmRlcmVyKSB7XG4gICAgV2ViR0xNYW5hZ2VyLmNhbGwodGhpcywgcmVuZGVyZXIpO1xufVxuXG5XZWJHTE1hc2tNYW5hZ2VyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoV2ViR0xNYW5hZ2VyLnByb3RvdHlwZSk7XG5XZWJHTE1hc2tNYW5hZ2VyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFdlYkdMTWFza01hbmFnZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFdlYkdMTWFza01hbmFnZXI7XG5cbi8qKlxuICogQXBwbGllcyB0aGUgTWFzayBhbmQgYWRkcyBpdCB0byB0aGUgY3VycmVudCBmaWx0ZXIgc3RhY2suXG4gKlxuICogQHBhcmFtIG1hc2tEYXRhIHthbnlbXX1cbiAqL1xuV2ViR0xNYXNrTWFuYWdlci5wcm90b3R5cGUucHVzaE1hc2sgPSBmdW5jdGlvbiAobWFza0RhdGEpIHtcbiAgICBpZiAobWFza0RhdGEuZGlydHkpIHtcbiAgICAgICAgV2ViR0xHcmFwaGljcy51cGRhdGVHcmFwaGljcyhtYXNrRGF0YSwgdGhpcy5yZW5kZXJlci5nbCk7XG4gICAgfVxuXG4gICAgaWYgKCFtYXNrRGF0YS5fd2ViR0xbdGhpcy5yZW5kZXJlci5nbC5pZF0uZGF0YS5sZW5ndGgpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMucmVuZGVyZXIuc3RlbmNpbE1hbmFnZXIucHVzaFN0ZW5jaWwobWFza0RhdGEsIG1hc2tEYXRhLl93ZWJHTFt0aGlzLnJlbmRlcmVyLmdsLmlkXS5kYXRhWzBdLCB0aGlzLnJlbmRlcmVyKTtcbn07XG5cbi8qKlxuICogUmVtb3ZlcyB0aGUgbGFzdCBmaWx0ZXIgZnJvbSB0aGUgZmlsdGVyIHN0YWNrIGFuZCBkb2Vzbid0IHJldHVybiBpdC5cbiAqXG4gKiBAcGFyYW0gbWFza0RhdGEge2FueVtdfVxuICovXG5XZWJHTE1hc2tNYW5hZ2VyLnByb3RvdHlwZS5wb3BNYXNrID0gZnVuY3Rpb24gKG1hc2tEYXRhKSB7XG4gICAgdGhpcy5yZW5kZXJlci5zdGVuY2lsTWFuYWdlci5wb3BTdGVuY2lsKG1hc2tEYXRhLCBtYXNrRGF0YS5fd2ViR0xbdGhpcy5yZW5kZXJlci5nbC5pZF0uZGF0YVswXSwgdGhpcy5yZW5kZXJlcik7XG59O1xuIiwidmFyIFdlYkdMTWFuYWdlciA9IHJlcXVpcmUoJy4vV2ViR0xNYW5hZ2VyJyksXG4gICAgUHJpbWl0aXZlU2hhZGVyID0gcmVxdWlyZSgnLi4vc2hhZGVycy9QcmltaXRpdmVTaGFkZXInKSxcbiAgICBDb21wbGV4UHJpbWl0aXZlU2hhZGVyID0gcmVxdWlyZSgnLi4vc2hhZGVycy9Db21wbGV4UHJpbWl0aXZlU2hhZGVyJyksXG4gICAgU2hhZGVyID0gcmVxdWlyZSgnLi4vc2hhZGVycy9TaGFkZXInKSxcbiAgICBGYXN0U2hhZGVyID0gcmVxdWlyZSgnLi4vc2hhZGVycy9GYXN0U2hhZGVyJyksXG4gICAgU3RyaXBTaGFkZXIgPSByZXF1aXJlKCcuLi9zaGFkZXJzL1N0cmlwU2hhZGVyJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcn0gVGhlIHJlbmRlcmVyIHRoaXMgbWFuYWdlciB3b3JrcyBmb3IuXG4gKi9cbmZ1bmN0aW9uIFdlYkdMU2hhZGVyTWFuYWdlcihyZW5kZXJlcikge1xuICAgIFdlYkdMTWFuYWdlci5jYWxsKHRoaXMsIHJlbmRlcmVyKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLm1heEF0dGlicyA9IDEwO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7YW55W119XG4gICAgICovXG4gICAgdGhpcy5hdHRyaWJTdGF0ZSA9IFtdO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7YW55W119XG4gICAgICovXG4gICAgdGhpcy50ZW1wQXR0cmliU3RhdGUgPSBbXTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5tYXhBdHRpYnM7IGkrKykge1xuICAgICAgICB0aGlzLmF0dHJpYlN0YXRlW2ldID0gZmFsc2U7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7YW55W119XG4gICAgICovXG4gICAgdGhpcy5zdGFjayA9IFtdO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fY3VycmVudElkID0gLTE7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtTaGFkZXJ9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLmN1cnJlbnRTaGFkZXIgPSBudWxsO1xuXG4gICAgLy8gdGhpcyBzaGFkZXIgaXMgdXNlZCBmb3IgcmVuZGVyaW5nIHByaW1pdGl2ZXNcbiAgICB0aGlzLnByaW1pdGl2ZVNoYWRlciA9IG51bGw7XG5cbiAgICAvLyB0aGlzIHNoYWRlciBpcyB1c2VkIGZvciByZW5kZXJpbmcgdHJpYW5nbGUgc3RyaXBzXG4gICAgdGhpcy5jb21wbGV4UHJpbWl0aXZlU2hhZGVyID0gbnVsbDtcblxuICAgIC8vIHRoaXMgc2hhZGVyIGlzIHVzZWQgZm9yIHRoZSBkZWZhdWx0IHNwcml0ZSByZW5kZXJpbmdcbiAgICB0aGlzLmRlZmF1bHRTaGFkZXIgPSBudWxsO1xuXG4gICAgLy8gdGhpcyBzaGFkZXIgaXMgdXNlZCBmb3IgdGhlIGZhc3Qgc3ByaXRlIHJlbmRlcmluZ1xuICAgIHRoaXMuZmFzdFNoYWRlciA9IG51bGw7XG5cbiAgICAvLyB0aGUgbmV4dCBvbmUgaXMgdXNlZCBmb3IgcmVuZGVyaW5nIHRyaWFuZ2xlIHN0cmlwc1xuICAgIHRoaXMuc3RyaXBTaGFkZXIgPSBudWxsO1xuXG4gICAgLy8gbGlzdGVuIGZvciBjb250ZXh0IGFuZCB1cGRhdGUgbmVjZXNzYXJ5IHNoYWRlcnNcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy5yZW5kZXJlci5vbignY29udGV4dCcsIGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICB2YXIgZ2wgPSBldmVudC5kYXRhO1xuXG4gICAgICAgIC8vIHRoaXMgc2hhZGVyIGlzIHVzZWQgZm9yIHJlbmRlcmluZyBwcmltaXRpdmVzXG4gICAgICAgIHNlbGYucHJpbWl0aXZlU2hhZGVyID0gbmV3IFByaW1pdGl2ZVNoYWRlcihnbCk7XG5cbiAgICAgICAgLy8gdGhpcyBzaGFkZXIgaXMgdXNlZCBmb3IgcmVuZGVyaW5nIHRyaWFuZ2xlIHN0cmlwc1xuICAgICAgICBzZWxmLmNvbXBsZXhQcmltaXRpdmVTaGFkZXIgPSBuZXcgQ29tcGxleFByaW1pdGl2ZVNoYWRlcihnbCk7XG5cbiAgICAgICAgLy8gdGhpcyBzaGFkZXIgaXMgdXNlZCBmb3IgdGhlIGRlZmF1bHQgc3ByaXRlIHJlbmRlcmluZ1xuICAgICAgICBzZWxmLmRlZmF1bHRTaGFkZXIgPSBuZXcgU2hhZGVyKGdsKTtcblxuICAgICAgICAvLyB0aGlzIHNoYWRlciBpcyB1c2VkIGZvciB0aGUgZmFzdCBzcHJpdGUgcmVuZGVyaW5nXG4gICAgICAgIHNlbGYuZmFzdFNoYWRlciA9IG5ldyBGYXN0U2hhZGVyKGdsKTtcblxuICAgICAgICAvLyB0aGUgbmV4dCBvbmUgaXMgdXNlZCBmb3IgcmVuZGVyaW5nIHRyaWFuZ2xlIHN0cmlwc1xuICAgICAgICBzZWxmLnN0cmlwU2hhZGVyID0gbmV3IFN0cmlwU2hhZGVyKGdsKTtcblxuICAgICAgICBzZWxmLnNldFNoYWRlcihzZWxmLmRlZmF1bHRTaGFkZXIpO1xuICAgIH0pO1xufVxuXG5XZWJHTFNoYWRlck1hbmFnZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShXZWJHTE1hbmFnZXIucHJvdG90eXBlKTtcbldlYkdMU2hhZGVyTWFuYWdlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBXZWJHTFNoYWRlck1hbmFnZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFdlYkdMU2hhZGVyTWFuYWdlcjtcblxuLyoqXG4gKiBUYWtlcyB0aGUgYXR0cmlidXRlcyBnaXZlbiBpbiBwYXJhbWV0ZXJzLlxuICpcbiAqIEBwYXJhbSBhdHRyaWJzIHtBcnJheX0gYXR0cmlic1xuICovXG5XZWJHTFNoYWRlck1hbmFnZXIucHJvdG90eXBlLnNldEF0dHJpYnMgPSBmdW5jdGlvbiAoYXR0cmlicykge1xuICAgIC8vIHJlc2V0IHRlbXAgc3RhdGVcbiAgICB2YXIgaTtcblxuICAgIGZvciAoaSA9IDA7IGkgPCB0aGlzLnRlbXBBdHRyaWJTdGF0ZS5sZW5ndGg7IGkrKykge1xuICAgICAgICB0aGlzLnRlbXBBdHRyaWJTdGF0ZVtpXSA9IGZhbHNlO1xuICAgIH1cblxuICAgIC8vIHNldCB0aGUgbmV3IGF0dHJpYnNcbiAgICBmb3IgKHZhciBhIGluIGF0dHJpYnMpIHtcbiAgICAgICAgdGhpcy50ZW1wQXR0cmliU3RhdGVbYXR0cmlic1thXV0gPSB0cnVlO1xuICAgIH1cblxuICAgIHZhciBnbCA9IHRoaXMucmVuZGVyZXIuZ2w7XG5cbiAgICBmb3IgKGkgPSAwOyBpIDwgdGhpcy5hdHRyaWJTdGF0ZS5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAodGhpcy5hdHRyaWJTdGF0ZVtpXSAhPT0gdGhpcy50ZW1wQXR0cmliU3RhdGVbaV0pIHtcbiAgICAgICAgICAgIHRoaXMuYXR0cmliU3RhdGVbaV0gPSB0aGlzLnRlbXBBdHRyaWJTdGF0ZVtpXTtcblxuICAgICAgICAgICAgaWYgKHRoaXMuYXR0cmliU3RhdGVbaV0pIHtcbiAgICAgICAgICAgICAgICBnbC5lbmFibGVWZXJ0ZXhBdHRyaWJBcnJheShpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGdsLmRpc2FibGVWZXJ0ZXhBdHRyaWJBcnJheShpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn07XG5cbi8qKlxuICogU2V0cyB0aGUgY3VycmVudCBzaGFkZXIuXG4gKlxuICogQHBhcmFtIHNoYWRlciB7QW55fVxuICovXG5XZWJHTFNoYWRlck1hbmFnZXIucHJvdG90eXBlLnNldFNoYWRlciA9IGZ1bmN0aW9uIChzaGFkZXIpIHtcbiAgICBpZiAodGhpcy5fY3VycmVudElkID09PSBzaGFkZXIudXVpZCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgdGhpcy5fY3VycmVudElkID0gc2hhZGVyLnV1aWQ7XG5cbiAgICB0aGlzLmN1cnJlbnRTaGFkZXIgPSBzaGFkZXI7XG5cbiAgICB0aGlzLnJlbmRlcmVyLmdsLnVzZVByb2dyYW0oc2hhZGVyLnByb2dyYW0pO1xuICAgIHRoaXMuc2V0QXR0cmlicyhzaGFkZXIuYXR0cmlidXRlcyk7XG5cbiAgICByZXR1cm4gdHJ1ZTtcbn07XG5cbi8qKlxuICogRGVzdHJveXMgdGhpcyBvYmplY3QuXG4gKlxuICovXG5XZWJHTFNoYWRlck1hbmFnZXIucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5hdHRyaWJTdGF0ZSA9IG51bGw7XG5cbiAgICB0aGlzLnRlbXBBdHRyaWJTdGF0ZSA9IG51bGw7XG5cbiAgICB0aGlzLnByaW1pdGl2ZVNoYWRlci5kZXN0cm95KCk7XG4gICAgdGhpcy5wcmltaXRpdmVTaGFkZXIgPSBudWxsO1xuXG4gICAgdGhpcy5jb21wbGV4UHJpbWl0aXZlU2hhZGVyLmRlc3Ryb3koKTtcbiAgICB0aGlzLmNvbXBsZXhQcmltaXRpdmVTaGFkZXIgPSBudWxsO1xuXG4gICAgdGhpcy5kZWZhdWx0U2hhZGVyLmRlc3Ryb3koKTtcbiAgICB0aGlzLmRlZmF1bHRTaGFkZXIgPSBudWxsO1xuXG4gICAgdGhpcy5mYXN0U2hhZGVyLmRlc3Ryb3koKTtcbiAgICB0aGlzLmZhc3RTaGFkZXIgPSBudWxsO1xuXG4gICAgdGhpcy5zdHJpcFNoYWRlci5kZXN0cm95KCk7XG4gICAgdGhpcy5zdHJpcFNoYWRlciA9IG51bGw7XG5cbiAgICB0aGlzLnJlbmRlcmVyID0gbnVsbDtcbn07XG4iLCJ2YXIgV2ViR0xNYW5hZ2VyID0gcmVxdWlyZSgnLi9XZWJHTE1hbmFnZXInKSxcbiAgICB1dGlscyA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWxzJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcn0gVGhlIHJlbmRlcmVyIHRoaXMgbWFuYWdlciB3b3JrcyBmb3IuXG4gKi9cbmZ1bmN0aW9uIFdlYkdMU3RlbmNpbE1hbmFnZXIocmVuZGVyZXIpIHtcbiAgICBXZWJHTE1hbmFnZXIuY2FsbCh0aGlzLCByZW5kZXJlcik7XG5cbiAgICB0aGlzLnN0ZW5jaWxTdGFjayA9IFtdO1xuICAgIHRoaXMucmV2ZXJzZSA9IHRydWU7XG4gICAgdGhpcy5jb3VudCA9IDA7XG59XG5cbldlYkdMU3RlbmNpbE1hbmFnZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShXZWJHTE1hbmFnZXIucHJvdG90eXBlKTtcbldlYkdMU3RlbmNpbE1hbmFnZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gV2ViR0xTdGVuY2lsTWFuYWdlcjtcbm1vZHVsZS5leHBvcnRzID0gV2ViR0xTdGVuY2lsTWFuYWdlcjtcblxuLyoqXG4gKiBBcHBsaWVzIHRoZSBNYXNrIGFuZCBhZGRzIGl0IHRvIHRoZSBjdXJyZW50IGZpbHRlciBzdGFjay5cbiAqXG4gKiBAcGFyYW0gZ3JhcGhpY3Mge0dyYXBoaWNzfVxuICogQHBhcmFtIHdlYkdMRGF0YSB7YW55W119XG4gKi9cbldlYkdMU3RlbmNpbE1hbmFnZXIucHJvdG90eXBlLnB1c2hTdGVuY2lsID0gZnVuY3Rpb24gKGdyYXBoaWNzLCB3ZWJHTERhdGEpIHtcbiAgICB2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuXG4gICAgdGhpcy5iaW5kR3JhcGhpY3MoZ3JhcGhpY3MsIHdlYkdMRGF0YSwgdGhpcy5yZW5kZXJlcik7XG5cbiAgICBpZiAodGhpcy5zdGVuY2lsU3RhY2subGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGdsLmVuYWJsZShnbC5TVEVOQ0lMX1RFU1QpO1xuICAgICAgICBnbC5jbGVhcihnbC5TVEVOQ0lMX0JVRkZFUl9CSVQpO1xuICAgICAgICB0aGlzLnJldmVyc2UgPSB0cnVlO1xuICAgICAgICB0aGlzLmNvdW50ID0gMDtcbiAgICB9XG5cbiAgICB0aGlzLnN0ZW5jaWxTdGFjay5wdXNoKHdlYkdMRGF0YSk7XG5cbiAgICB2YXIgbGV2ZWwgPSB0aGlzLmNvdW50O1xuXG4gICAgZ2wuY29sb3JNYXNrKGZhbHNlLCBmYWxzZSwgZmFsc2UsIGZhbHNlKTtcblxuICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkFMV0FZUywwLDB4RkYpO1xuICAgIGdsLnN0ZW5jaWxPcChnbC5LRUVQLGdsLktFRVAsZ2wuSU5WRVJUKTtcblxuICAgIC8vIGRyYXcgdGhlIHRyaWFuZ2xlIHN0cmlwIVxuXG4gICAgaWYgKHdlYkdMRGF0YS5tb2RlID09PSAxKSB7XG4gICAgICAgIGdsLmRyYXdFbGVtZW50cyhnbC5UUklBTkdMRV9GQU4sICB3ZWJHTERhdGEuaW5kaWNlcy5sZW5ndGggLSA0LCBnbC5VTlNJR05FRF9TSE9SVCwgMCApO1xuXG4gICAgICAgIGlmICh0aGlzLnJldmVyc2UpIHtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLCAweEZGIC0gbGV2ZWwsIDB4RkYpO1xuICAgICAgICAgICAgZ2wuc3RlbmNpbE9wKGdsLktFRVAsZ2wuS0VFUCxnbC5ERUNSKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLGxldmVsLCAweEZGKTtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxPcChnbC5LRUVQLGdsLktFRVAsZ2wuSU5DUik7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkcmF3IGEgcXVhZCB0byBpbmNyZW1lbnQuLlxuICAgICAgICBnbC5kcmF3RWxlbWVudHMoZ2wuVFJJQU5HTEVfRkFOLCA0LCBnbC5VTlNJR05FRF9TSE9SVCwgKCB3ZWJHTERhdGEuaW5kaWNlcy5sZW5ndGggLSA0ICkgKiAyICk7XG5cbiAgICAgICAgaWYgKHRoaXMucmV2ZXJzZSkge1xuICAgICAgICAgICAgZ2wuc3RlbmNpbEZ1bmMoZ2wuRVFVQUwsMHhGRi0obGV2ZWwrMSksIDB4RkYpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZ2wuc3RlbmNpbEZ1bmMoZ2wuRVFVQUwsbGV2ZWwrMSwgMHhGRik7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnJldmVyc2UgPSAhdGhpcy5yZXZlcnNlO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgaWYgKCF0aGlzLnJldmVyc2UpIHtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLCAweEZGIC0gbGV2ZWwsIDB4RkYpO1xuICAgICAgICAgICAgZ2wuc3RlbmNpbE9wKGdsLktFRVAsZ2wuS0VFUCxnbC5ERUNSKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLGxldmVsLCAweEZGKTtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxPcChnbC5LRUVQLGdsLktFRVAsZ2wuSU5DUik7XG4gICAgICAgIH1cblxuICAgICAgICBnbC5kcmF3RWxlbWVudHMoZ2wuVFJJQU5HTEVfU1RSSVAsICB3ZWJHTERhdGEuaW5kaWNlcy5sZW5ndGgsIGdsLlVOU0lHTkVEX1NIT1JULCAwICk7XG5cbiAgICAgICAgaWYgKCF0aGlzLnJldmVyc2UpIHtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLDB4RkYtKGxldmVsKzEpLCAweEZGKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLGxldmVsKzEsIDB4RkYpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZ2wuY29sb3JNYXNrKHRydWUsIHRydWUsIHRydWUsIHRydWUpO1xuICAgIGdsLnN0ZW5jaWxPcChnbC5LRUVQLGdsLktFRVAsZ2wuS0VFUCk7XG5cbiAgICB0aGlzLmNvdW50Kys7XG59O1xuXG4vKipcbiAqIFRPRE8gdGhpcyBkb2VzIG5vdCBiZWxvbmcgaGVyZSFcbiAqXG4gKiBAcGFyYW0gZ3JhcGhpY3Mge0dyYXBoaWNzfVxuICogQHBhcmFtIHdlYkdMRGF0YSB7QXJyYXl9XG4gKi9cbldlYkdMU3RlbmNpbE1hbmFnZXIucHJvdG90eXBlLmJpbmRHcmFwaGljcyA9IGZ1bmN0aW9uIChncmFwaGljcywgd2ViR0xEYXRhKSB7XG4gICAgLy9pZiAodGhpcy5fY3VycmVudEdyYXBoaWNzID09PSBncmFwaGljcylyZXR1cm47XG4gICAgdGhpcy5fY3VycmVudEdyYXBoaWNzID0gZ3JhcGhpY3M7XG5cbiAgICB2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuXG4gICAgIC8vIGJpbmQgdGhlIGdyYXBoaWNzIG9iamVjdC4uXG4gICAgdmFyIHByb2plY3Rpb24gPSB0aGlzLnJlbmRlcmVyLnByb2plY3Rpb24sXG4gICAgICAgIG9mZnNldCA9IHRoaXMucmVuZGVyZXIub2Zmc2V0LFxuICAgICAgICBzaGFkZXI7Ly8gPSB0aGlzLnJlbmRlcmVyLnNoYWRlck1hbmFnZXIucHJpbWl0aXZlU2hhZGVyO1xuXG4gICAgaWYgKHdlYkdMRGF0YS5tb2RlID09PSAxKSB7XG4gICAgICAgIHNoYWRlciA9IHRoaXMucmVuZGVyZXIuc2hhZGVyTWFuYWdlci5jb21wbGV4UHJpbWl0aXZlU2hhZGVyO1xuXG4gICAgICAgIHRoaXMucmVuZGVyZXIuc2hhZGVyTWFuYWdlci5zZXRTaGFkZXIoc2hhZGVyKTtcblxuICAgICAgICBnbC51bmlmb3JtMWYoc2hhZGVyLmZsaXBZLCB0aGlzLnJlbmRlcmVyLmZsaXBZKTtcblxuICAgICAgICBnbC51bmlmb3JtTWF0cml4M2Z2KHNoYWRlci50cmFuc2xhdGlvbk1hdHJpeCwgZmFsc2UsIGdyYXBoaWNzLndvcmxkVHJhbnNmb3JtLnRvQXJyYXkodHJ1ZSkpO1xuXG4gICAgICAgIGdsLnVuaWZvcm0yZihzaGFkZXIucHJvamVjdGlvblZlY3RvciwgcHJvamVjdGlvbi54LCAtcHJvamVjdGlvbi55KTtcbiAgICAgICAgZ2wudW5pZm9ybTJmKHNoYWRlci5vZmZzZXRWZWN0b3IsIC1vZmZzZXQueCwgLW9mZnNldC55KTtcblxuICAgICAgICBnbC51bmlmb3JtM2Z2KHNoYWRlci50aW50Q29sb3IsIHV0aWxzLmhleDJyZ2IoZ3JhcGhpY3MudGludCkpO1xuICAgICAgICBnbC51bmlmb3JtM2Z2KHNoYWRlci5jb2xvciwgd2ViR0xEYXRhLmNvbG9yKTtcblxuICAgICAgICBnbC51bmlmb3JtMWYoc2hhZGVyLmFscGhhLCBncmFwaGljcy53b3JsZEFscGhhICogd2ViR0xEYXRhLmFscGhhKTtcblxuICAgICAgICBnbC5iaW5kQnVmZmVyKGdsLkFSUkFZX0JVRkZFUiwgd2ViR0xEYXRhLmJ1ZmZlcik7XG5cbiAgICAgICAgZ2wudmVydGV4QXR0cmliUG9pbnRlcihzaGFkZXIuYVZlcnRleFBvc2l0aW9uLCAyLCBnbC5GTE9BVCwgZmFsc2UsIDQgKiAyLCAwKTtcblxuXG4gICAgICAgIC8vIG5vdyBkbyB0aGUgcmVzdC4uXG4gICAgICAgIC8vIHNldCB0aGUgaW5kZXggYnVmZmVyIVxuICAgICAgICBnbC5iaW5kQnVmZmVyKGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCB3ZWJHTERhdGEuaW5kZXhCdWZmZXIpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgLy90aGlzLnJlbmRlcmVyLnNoYWRlck1hbmFnZXIuYWN0aXZhdGVQcmltaXRpdmVTaGFkZXIoKTtcbiAgICAgICAgc2hhZGVyID0gdGhpcy5yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLnByaW1pdGl2ZVNoYWRlcjtcbiAgICAgICAgdGhpcy5yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLnNldFNoYWRlciggc2hhZGVyICk7XG5cbiAgICAgICAgZ2wudW5pZm9ybU1hdHJpeDNmdihzaGFkZXIudHJhbnNsYXRpb25NYXRyaXgsIGZhbHNlLCBncmFwaGljcy53b3JsZFRyYW5zZm9ybS50b0FycmF5KHRydWUpKTtcblxuICAgICAgICBnbC51bmlmb3JtMWYoc2hhZGVyLmZsaXBZLCB0aGlzLnJlbmRlcmVyLmZsaXBZKTtcbiAgICAgICAgZ2wudW5pZm9ybTJmKHNoYWRlci5wcm9qZWN0aW9uVmVjdG9yLCBwcm9qZWN0aW9uLngsIC1wcm9qZWN0aW9uLnkpO1xuICAgICAgICBnbC51bmlmb3JtMmYoc2hhZGVyLm9mZnNldFZlY3RvciwgLW9mZnNldC54LCAtb2Zmc2V0LnkpO1xuXG4gICAgICAgIGdsLnVuaWZvcm0zZnYoc2hhZGVyLnRpbnRDb2xvciwgdXRpbHMuaGV4MnJnYihncmFwaGljcy50aW50KSk7XG5cbiAgICAgICAgZ2wudW5pZm9ybTFmKHNoYWRlci5hbHBoYSwgZ3JhcGhpY3Mud29ybGRBbHBoYSk7XG5cbiAgICAgICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHdlYkdMRGF0YS5idWZmZXIpO1xuXG4gICAgICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIoc2hhZGVyLmFWZXJ0ZXhQb3NpdGlvbiwgMiwgZ2wuRkxPQVQsIGZhbHNlLCA0ICogNiwgMCk7XG4gICAgICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIoc2hhZGVyLmFDb2xvciwgNCwgZ2wuRkxPQVQsIGZhbHNlLDQgKiA2LCAyICogNCk7XG5cbiAgICAgICAgLy8gc2V0IHRoZSBpbmRleCBidWZmZXIhXG4gICAgICAgIGdsLmJpbmRCdWZmZXIoZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIsIHdlYkdMRGF0YS5pbmRleEJ1ZmZlcik7XG4gICAgfVxufTtcblxuLyoqXG4gKiBAcGFyYW0gZ3JhcGhpY3Mge0dyYXBoaWNzfVxuICogQHBhcmFtIHdlYkdMRGF0YSB7QXJyYXl9XG4gKi9cbldlYkdMU3RlbmNpbE1hbmFnZXIucHJvdG90eXBlLnBvcFN0ZW5jaWwgPSBmdW5jdGlvbiAoZ3JhcGhpY3MsIHdlYkdMRGF0YSkge1xuXHR2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuXG4gICAgdGhpcy5zdGVuY2lsU3RhY2sucG9wKCk7XG5cbiAgICB0aGlzLmNvdW50LS07XG5cbiAgICBpZiAodGhpcy5zdGVuY2lsU3RhY2subGVuZ3RoID09PSAwKSB7XG4gICAgICAgIC8vIHRoZSBzdGFjayBpcyBlbXB0eSFcbiAgICAgICAgZ2wuZGlzYWJsZShnbC5TVEVOQ0lMX1RFU1QpO1xuXG4gICAgfVxuICAgIGVsc2Uge1xuXG4gICAgICAgIHZhciBsZXZlbCA9IHRoaXMuY291bnQ7XG5cbiAgICAgICAgdGhpcy5iaW5kR3JhcGhpY3MoZ3JhcGhpY3MsIHdlYkdMRGF0YSwgdGhpcy5yZW5kZXJlcik7XG5cbiAgICAgICAgZ2wuY29sb3JNYXNrKGZhbHNlLCBmYWxzZSwgZmFsc2UsIGZhbHNlKTtcblxuICAgICAgICBpZiAod2ViR0xEYXRhLm1vZGUgPT09IDEpIHtcbiAgICAgICAgICAgIHRoaXMucmV2ZXJzZSA9ICF0aGlzLnJldmVyc2U7XG5cbiAgICAgICAgICAgIGlmICh0aGlzLnJldmVyc2UpIHtcbiAgICAgICAgICAgICAgICBnbC5zdGVuY2lsRnVuYyhnbC5FUVVBTCwgMHhGRiAtIChsZXZlbCsxKSwgMHhGRik7XG4gICAgICAgICAgICAgICAgZ2wuc3RlbmNpbE9wKGdsLktFRVAsZ2wuS0VFUCxnbC5JTkNSKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLGxldmVsKzEsIDB4RkYpO1xuICAgICAgICAgICAgICAgIGdsLnN0ZW5jaWxPcChnbC5LRUVQLGdsLktFRVAsZ2wuREVDUik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIGRyYXcgYSBxdWFkIHRvIGluY3JlbWVudC4uXG4gICAgICAgICAgICBnbC5kcmF3RWxlbWVudHMoZ2wuVFJJQU5HTEVfRkFOLCA0LCBnbC5VTlNJR05FRF9TSE9SVCwgKCB3ZWJHTERhdGEuaW5kaWNlcy5sZW5ndGggLSA0ICkgKiAyICk7XG5cbiAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkFMV0FZUywwLDB4RkYpO1xuICAgICAgICAgICAgZ2wuc3RlbmNpbE9wKGdsLktFRVAsZ2wuS0VFUCxnbC5JTlZFUlQpO1xuXG4gICAgICAgICAgICAvLyBkcmF3IHRoZSB0cmlhbmdsZSBzdHJpcCFcbiAgICAgICAgICAgIGdsLmRyYXdFbGVtZW50cyhnbC5UUklBTkdMRV9GQU4sICB3ZWJHTERhdGEuaW5kaWNlcy5sZW5ndGggLSA0LCBnbC5VTlNJR05FRF9TSE9SVCwgMCApO1xuXG4gICAgICAgICAgICBpZiAoIXRoaXMucmV2ZXJzZSkge1xuICAgICAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLDB4RkYtKGxldmVsKSwgMHhGRik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBnbC5zdGVuY2lsRnVuYyhnbC5FUVVBTCxsZXZlbCwgMHhGRik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAvLyAgY29uc29sZS5sb2coXCI8PD4+XCIpXG4gICAgICAgICAgICBpZiAoIXRoaXMucmV2ZXJzZSkge1xuICAgICAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLCAweEZGIC0gKGxldmVsKzEpLCAweEZGKTtcbiAgICAgICAgICAgICAgICBnbC5zdGVuY2lsT3AoZ2wuS0VFUCxnbC5LRUVQLGdsLklOQ1IpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgZ2wuc3RlbmNpbEZ1bmMoZ2wuRVFVQUwsbGV2ZWwrMSwgMHhGRik7XG4gICAgICAgICAgICAgICAgZ2wuc3RlbmNpbE9wKGdsLktFRVAsZ2wuS0VFUCxnbC5ERUNSKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZ2wuZHJhd0VsZW1lbnRzKGdsLlRSSUFOR0xFX1NUUklQLCAgd2ViR0xEYXRhLmluZGljZXMubGVuZ3RoLCBnbC5VTlNJR05FRF9TSE9SVCwgMCApO1xuXG4gICAgICAgICAgICBpZiAoIXRoaXMucmV2ZXJzZSkge1xuICAgICAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLDB4RkYtKGxldmVsKSwgMHhGRik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBnbC5zdGVuY2lsRnVuYyhnbC5FUVVBTCxsZXZlbCwgMHhGRik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBnbC5jb2xvck1hc2sodHJ1ZSwgdHJ1ZSwgdHJ1ZSwgdHJ1ZSk7XG4gICAgICAgIGdsLnN0ZW5jaWxPcChnbC5LRUVQLGdsLktFRVAsZ2wuS0VFUCk7XG5cblxuICAgIH1cbn07XG5cbi8qKlxuICogRGVzdHJveXMgdGhlIG1hc2sgc3RhY2suXG4gKlxuICovXG5XZWJHTFN0ZW5jaWxNYW5hZ2VyLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMucmVuZGVyZXIgPSBudWxsO1xuICAgIHRoaXMuc3RlbmNpbFN0YWNrID0gbnVsbDtcbn07XG4iLCJ2YXIgU2hhZGVyID0gcmVxdWlyZSgnLi9TaGFkZXInKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIGdsIHtXZWJHTENvbnRleHR9IHRoZSBjdXJyZW50IFdlYkdMIGRyYXdpbmcgY29udGV4dFxuICovXG5mdW5jdGlvbiBDb21wbGV4UHJpbWl0aXZlU2hhZGVyKGdsKSB7XG4gICAgU2hhZGVyLmNhbGwodGhpcyxcbiAgICAgICAgZ2wsXG4gICAgICAgIC8vIHZlcnRleCBzaGFkZXJcbiAgICAgICAgW1xuICAgICAgICAgICAgJ2F0dHJpYnV0ZSB2ZWMyIGFWZXJ0ZXhQb3NpdGlvbjsnLFxuICAgICAgICAgICAgLy8gJ2F0dHJpYnV0ZSB2ZWMyIGFUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgICAgIC8vICdhdHRyaWJ1dGUgdmVjNCBhQ29sb3I7JyxcblxuICAgICAgICAgICAgJ3VuaWZvcm0gbWF0MyB0cmFuc2xhdGlvbk1hdHJpeDsnLFxuICAgICAgICAgICAgJ3VuaWZvcm0gdmVjMiBwcm9qZWN0aW9uVmVjdG9yOycsXG4gICAgICAgICAgICAndW5pZm9ybSB2ZWMyIG9mZnNldFZlY3RvcjsnLFxuXG4gICAgICAgICAgICAndW5pZm9ybSB2ZWMzIHRpbnQ7JyxcbiAgICAgICAgICAgICd1bmlmb3JtIGZsb2F0IGFscGhhOycsXG4gICAgICAgICAgICAndW5pZm9ybSB2ZWMzIGNvbG9yOycsXG4gICAgICAgICAgICAndW5pZm9ybSBmbG9hdCBmbGlwWTsnLFxuICAgICAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAgICAgJ3ZvaWQgbWFpbih2b2lkKSB7JyxcbiAgICAgICAgICAgICcgICB2ZWMzIHYgPSB0cmFuc2xhdGlvbk1hdHJpeCAqIHZlYzMoYVZlcnRleFBvc2l0aW9uICwgMS4wKTsnLFxuICAgICAgICAgICAgJyAgIHYgLT0gb2Zmc2V0VmVjdG9yLnh5eDsnLFxuICAgICAgICAgICAgJyAgIGdsX1Bvc2l0aW9uID0gdmVjNCggdi54IC8gcHJvamVjdGlvblZlY3Rvci54IC0xLjAsICh2LnkgLyBwcm9qZWN0aW9uVmVjdG9yLnkgKiAtZmxpcFkpICsgZmxpcFkgLCAwLjAsIDEuMCk7JyxcbiAgICAgICAgICAgICcgICB2Q29sb3IgPSB2ZWM0KGNvbG9yICogYWxwaGEgKiB0aW50LCBhbHBoYSk7JywvL1wiICogdmVjNCh0aW50ICogYWxwaGEsIGFscGhhKTsnLFxuICAgICAgICAgICAgJ30nXG4gICAgICAgIF0uam9pbignXFxuJyksXG4gICAgICAgIC8vIGZyYWdtZW50IHNoYWRlclxuICAgICAgICBbXG4gICAgICAgICAgICAncHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7JyxcblxuICAgICAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAgICAgJ3ZvaWQgbWFpbih2b2lkKSB7JyxcbiAgICAgICAgICAgICcgICBnbF9GcmFnQ29sb3IgPSB2Q29sb3I7JyxcbiAgICAgICAgICAgICd9J1xuICAgICAgICBdLmpvaW4oJ1xcbicpLFxuICAgICAgICAvLyBjdXN0b20gdW5pZm9ybXNcbiAgICAgICAge1xuICAgICAgICAgICAgdGludDogICB7IHR5cGU6ICczZicsIHZhbHVlOiBbMCwgMCwgMF0gfSxcbiAgICAgICAgICAgIGZsaXBZOiAgeyB0eXBlOiAnMWYnLCB2YWx1ZTogMCB9LFxuICAgICAgICAgICAgYWxwaGE6ICB7IHR5cGU6ICcxZicsIHZhbHVlOiAwIH0sXG4gICAgICAgICAgICB0cmFuc2xhdGlvbk1hdHJpeDogeyB0eXBlOiAnbWF0MycsIHZhbHVlOiBuZXcgRmxvYXQzMkFycmF5KDkpIH1cbiAgICAgICAgfVxuICAgICk7XG59XG5cbkNvbXBsZXhQcmltaXRpdmVTaGFkZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShTaGFkZXIucHJvdG90eXBlKTtcbkNvbXBsZXhQcmltaXRpdmVTaGFkZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQ29tcGxleFByaW1pdGl2ZVNoYWRlcjtcbm1vZHVsZS5leHBvcnRzID0gQ29tcGxleFByaW1pdGl2ZVNoYWRlcjtcbiIsInZhciBTaGFkZXIgPSByZXF1aXJlKCcuL1NoYWRlcicpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgU2hhZGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSBnbCB7V2ViR0xDb250ZXh0fSB0aGUgY3VycmVudCBXZWJHTCBkcmF3aW5nIGNvbnRleHRcbiAqL1xuZnVuY3Rpb24gRmFzdFNoYWRlcihnbCkge1xuICAgIFNoYWRlci5jYWxsKHRoaXMsXG4gICAgICAgIGdsLFxuICAgICAgICAvLyB2ZXJ0ZXggc2hhZGVyXG4gICAgICAgIFtcbiAgICAgICAgICAgICdhdHRyaWJ1dGUgdmVjMiBhVmVydGV4UG9zaXRpb247JyxcbiAgICAgICAgICAgICdhdHRyaWJ1dGUgdmVjMiBhVGV4dHVyZUNvb3JkOycsXG4gICAgICAgICAgICAnYXR0cmlidXRlIHZlYzQgYUNvbG9yOycsXG5cbiAgICAgICAgICAgICdhdHRyaWJ1dGUgdmVjMiBhUG9zaXRpb25Db29yZDsnLFxuICAgICAgICAgICAgJ2F0dHJpYnV0ZSB2ZWMyIGFTY2FsZTsnLFxuICAgICAgICAgICAgJ2F0dHJpYnV0ZSBmbG9hdCBhUm90YXRpb247JyxcblxuICAgICAgICAgICAgJ3VuaWZvcm0gdmVjMiBwcm9qZWN0aW9uVmVjdG9yOycsXG4gICAgICAgICAgICAndW5pZm9ybSB2ZWMyIG9mZnNldFZlY3RvcjsnLFxuICAgICAgICAgICAgJ3VuaWZvcm0gbWF0MyB1TWF0cml4OycsXG5cbiAgICAgICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAgICAgJ2NvbnN0IHZlYzIgY2VudGVyID0gdmVjMigtMS4wLCAxLjApOycsXG5cbiAgICAgICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICAgICAnICAgdmVjMiB2OycsXG4gICAgICAgICAgICAnICAgdmVjMiBzdiA9IGFWZXJ0ZXhQb3NpdGlvbiAqIGFTY2FsZTsnLFxuICAgICAgICAgICAgJyAgIHYueCA9IChzdi54KSAqIGNvcyhhUm90YXRpb24pIC0gKHN2LnkpICogc2luKGFSb3RhdGlvbik7JyxcbiAgICAgICAgICAgICcgICB2LnkgPSAoc3YueCkgKiBzaW4oYVJvdGF0aW9uKSArIChzdi55KSAqIGNvcyhhUm90YXRpb24pOycsXG4gICAgICAgICAgICAnICAgdiA9ICggdU1hdHJpeCAqIHZlYzModiArIGFQb3NpdGlvbkNvb3JkICwgMS4wKSApLnh5IDsnLFxuICAgICAgICAgICAgJyAgIGdsX1Bvc2l0aW9uID0gdmVjNCggKCB2IC8gcHJvamVjdGlvblZlY3RvcikgKyBjZW50ZXIgLCAwLjAsIDEuMCk7JyxcbiAgICAgICAgICAgICcgICB2VGV4dHVyZUNvb3JkID0gYVRleHR1cmVDb29yZDsnLFxuICAgICAgICAgIC8vICAnICAgdmVjMyBjb2xvciA9IG1vZCh2ZWMzKGFDb2xvci55LzY1NTM2LjAsIGFDb2xvci55LzI1Ni4wLCBhQ29sb3IueSksIDI1Ni4wKSAvIDI1Ni4wOycsXG4gICAgICAgICAgICAnICAgdkNvbG9yID0gYUNvbG9yOycsXG4gICAgICAgICAgICAnfSdcbiAgICAgICAgXS5qb2luKCdcXG4nKSxcbiAgICAgICAgLy8gZnJhZ21lbnQgc2hhZGVyLCB1c2UgZGVmYXVsdFxuICAgICAgICBudWxsLFxuICAgICAgICAvLyBjdXN0b20gdW5pZm9ybXNcbiAgICAgICAge1xuICAgICAgICAgICAgdU1hdHJpeDogeyB0eXBlOiAnbWF0MycsIHZhbHVlOiBuZXcgRmxvYXQzMkFycmF5KDkpIH1cbiAgICAgICAgfSxcbiAgICAgICAgLy8gY3VzdG9tIGF0dHJpYnV0ZXNcbiAgICAgICAge1xuICAgICAgICAgICAgYVBvc2l0aW9uQ29vcmQ6IDAsXG4gICAgICAgICAgICBhUm90YXRpb246ICAgICAgMCxcbiAgICAgICAgICAgIGFTY2FsZTogICAgICAgICAwXG4gICAgICAgIH1cbiAgICApO1xufVxuXG5GYXN0U2hhZGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoU2hhZGVyLnByb3RvdHlwZSk7XG5GYXN0U2hhZGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEZhc3RTaGFkZXI7XG5tb2R1bGUuZXhwb3J0cyA9IEZhc3RTaGFkZXI7XG4iLCJ2YXIgU2hhZGVyID0gcmVxdWlyZSgnLi9TaGFkZXInKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIGdsIHtXZWJHTENvbnRleHR9IHRoZSBjdXJyZW50IFdlYkdMIGRyYXdpbmcgY29udGV4dFxuICovXG5mdW5jdGlvbiBQcmltaXRpdmVTaGFkZXIoZ2wpIHtcbiAgICBTaGFkZXIuY2FsbCh0aGlzLFxuICAgICAgICBnbCxcbiAgICAgICAgLy8gdmVydGV4IHNoYWRlclxuICAgICAgICBbXG4gICAgICAgICAgICAnYXR0cmlidXRlIHZlYzIgYVZlcnRleFBvc2l0aW9uOycsXG4gICAgICAgICAgICAvLyAnYXR0cmlidXRlIHZlYzIgYVRleHR1cmVDb29yZDsnLFxuICAgICAgICAgICAgJ2F0dHJpYnV0ZSB2ZWM0IGFDb2xvcjsnLFxuXG4gICAgICAgICAgICAndW5pZm9ybSBtYXQzIHRyYW5zbGF0aW9uTWF0cml4OycsXG4gICAgICAgICAgICAndW5pZm9ybSB2ZWMyIHByb2plY3Rpb25WZWN0b3I7JyxcbiAgICAgICAgICAgICd1bmlmb3JtIHZlYzIgb2Zmc2V0VmVjdG9yOycsXG4gICAgICAgICAgICAndW5pZm9ybSBmbG9hdCBhbHBoYTsnLFxuICAgICAgICAgICAgJ3VuaWZvcm0gZmxvYXQgZmxpcFk7JyxcbiAgICAgICAgICAgICd1bmlmb3JtIHZlYzMgdGludDsnLFxuXG4gICAgICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAgICAgJyAgIHZlYzMgdiA9IHRyYW5zbGF0aW9uTWF0cml4ICogdmVjMyhhVmVydGV4UG9zaXRpb24gLCAxLjApOycsXG4gICAgICAgICAgICAnICAgdiAtPSBvZmZzZXRWZWN0b3IueHl4OycsXG4gICAgICAgICAgICAnICAgZ2xfUG9zaXRpb24gPSB2ZWM0KCB2LnggLyBwcm9qZWN0aW9uVmVjdG9yLnggLTEuMCwgKHYueSAvIHByb2plY3Rpb25WZWN0b3IueSAqIC1mbGlwWSkgKyBmbGlwWSAsIDAuMCwgMS4wKTsnLFxuICAgICAgICAgICAgJyAgIHZDb2xvciA9IGFDb2xvciAqIHZlYzQodGludCAqIGFscGhhLCBhbHBoYSk7JyxcbiAgICAgICAgICAgICd9J1xuICAgICAgICBdLmpvaW4oJ1xcbicpLFxuICAgICAgICAvLyBmcmFnbWVudCBzaGFkZXJcbiAgICAgICAgW1xuICAgICAgICAgICAgJ3ByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OycsXG5cbiAgICAgICAgICAgICd2YXJ5aW5nIHZlYzQgdkNvbG9yOycsXG5cbiAgICAgICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gdkNvbG9yOycsXG4gICAgICAgICAgICAnfSdcbiAgICAgICAgXS5qb2luKCdcXG4nKSxcbiAgICAgICAgLy8gY3VzdG9tIHVuaWZvcm1zXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRpbnQ6ICAgeyB0eXBlOiAnM2YnLCB2YWx1ZTogWzAsIDAsIDBdIH0sXG4gICAgICAgICAgICBmbGlwWTogIHsgdHlwZTogJzFmJywgdmFsdWU6IDAgfSxcbiAgICAgICAgICAgIGFscGhhOiAgeyB0eXBlOiAnMWYnLCB2YWx1ZTogMCB9LFxuICAgICAgICAgICAgdHJhbnNsYXRpb25NYXRyaXg6IHsgdHlwZTogJ21hdDMnLCB2YWx1ZTogbmV3IEZsb2F0MzJBcnJheSg5KSB9XG4gICAgICAgIH1cbiAgICApO1xufVxuXG5QcmltaXRpdmVTaGFkZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShTaGFkZXIucHJvdG90eXBlKTtcblByaW1pdGl2ZVNoYWRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBQcmltaXRpdmVTaGFkZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFByaW1pdGl2ZVNoYWRlcjtcbiIsInZhciB1dGlscyA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWxzJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSBbZnJhZ21lbnRTcmNdIHtzdHJpbmd9IFRoZSBzb3VyY2Ugb2YgdGhlIGZyYWdtZW50IHNoYWRlci5cbiAqIEBwYXJhbSBbdmVydGV4U3JjXSB7c3RyaW5nfSBUaGUgc291cmNlIG9mIHRoZSB2ZXJ0ZXggc2hhZGVyLlxuICovXG5mdW5jdGlvbiBTaGFkZXIoZ2wsIHZlcnRleFNyYywgZnJhZ21lbnRTcmMsIGN1c3RvbVVuaWZvcm1zLCBjdXN0b21BdHRyaWJ1dGVzKSB7XG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEByZWFkb25seVxuICAgICAqL1xuICAgIHRoaXMudXVpZCA9IHV0aWxzLnV1aWQoKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge1dlYkdMQ29udGV4dH1cbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKi9cbiAgICB0aGlzLmdsID0gZ2w7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgV2ViR0wgcHJvZ3JhbS5cbiAgICAgKiBAbWVtYmVyIHtXZWJHTFByb2dyYW19XG4gICAgICogQHJlYWRvbmx5XG4gICAgICovXG4gICAgdGhpcy5wcm9ncmFtID0gbnVsbDtcblxuICAgIHRoaXMudW5pZm9ybXMgPSB7XG4gICAgICAgIHVTYW1wbGVyOiAgICAgICAgICAgeyB0eXBlOiAnc2FtcGxlcjJEJywgdmFsdWU6IDAgfSxcbiAgICAgICAgcHJvamVjdGlvblZlY3RvcjogICB7IHR5cGU6ICcyZicsIHZhbHVlOiB7IHg6IDAsIHk6IDAgfSB9LFxuICAgICAgICBvZmZzZXRWZWN0b3I6ICAgICAgIHsgdHlwZTogJzJmJywgdmFsdWU6IHsgeDogMCwgeTogMCB9IH0sXG4gICAgICAgIGRpbWVuc2lvbnM6ICAgICAgICAgeyB0eXBlOiAnNGYnLCB2YWx1ZTogbmV3IEZsb2F0MzJBcnJheSg0KSB9XG4gICAgfTtcblxuICAgIGZvciAodmFyIHUgaW4gY3VzdG9tVW5pZm9ybXMpIHtcbiAgICAgICAgdGhpcy51bmlmb3Jtc1t1XSA9IGN1c3RvbVVuaWZvcm1zW3VdO1xuICAgIH1cblxuICAgIHRoaXMuYXR0cmlidXRlcyA9IHtcbiAgICAgICAgYVZlcnRleFBvc2l0aW9uOiAgICAwLFxuICAgICAgICBhVGV4dHVyZUNvb3JkOiAgICAgIDAsXG4gICAgICAgIGFDb2xvcjogICAgICAgICAgICAgMFxuICAgIH07XG5cbiAgICBmb3IgKHZhciBhIGluIGN1c3RvbUF0dHJpYnV0ZXMpIHtcbiAgICAgICAgdGhpcy5hdHRyaWJ1dGVzW2FdID0gY3VzdG9tQXR0cmlidXRlc1thXTtcbiAgICB9XG5cbiAgICB0aGlzLnRleHR1cmVDb3VudCA9IDA7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdmVydGV4IHNoYWRlci5cbiAgICAgKiBAbWVtYmVyIHtBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLnZlcnRleFNyYyA9IHZlcnRleFNyYyB8fCBbXG4gICAgICAgICdhdHRyaWJ1dGUgdmVjMiBhVmVydGV4UG9zaXRpb247JyxcbiAgICAgICAgJ2F0dHJpYnV0ZSB2ZWMyIGFUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgJ2F0dHJpYnV0ZSB2ZWM0IGFDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIHZlYzIgcHJvamVjdGlvblZlY3RvcjsnLFxuICAgICAgICAndW5pZm9ybSB2ZWMyIG9mZnNldFZlY3RvcjsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICdjb25zdCB2ZWMyIGNlbnRlciA9IHZlYzIoLTEuMCwgMS4wKTsnLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICBnbF9Qb3NpdGlvbiA9IHZlYzQoICgoYVZlcnRleFBvc2l0aW9uICsgb2Zmc2V0VmVjdG9yKSAvIHByb2plY3Rpb25WZWN0b3IpICsgY2VudGVyICwgMC4wLCAxLjApOycsXG4gICAgICAgICcgICB2VGV4dHVyZUNvb3JkID0gYVRleHR1cmVDb29yZDsnLFxuICAgICAgICAnICAgdkNvbG9yID0gdmVjNChhQ29sb3IucmdiICogYUNvbG9yLmEsIGFDb2xvci5hKTsnLFxuICAgICAgICAnfSdcbiAgICBdLmpvaW4oJ1xcbicpO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGZyYWdtZW50IHNoYWRlci5cbiAgICAgKiBAbWVtYmVyIHtBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLmZyYWdtZW50U3JjID0gZnJhZ21lbnRTcmMgfHwgW1xuICAgICAgICAncHJlY2lzaW9uIGxvd3AgZmxvYXQ7JyxcblxuICAgICAgICAndmFyeWluZyB2ZWMyIHZUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAndW5pZm9ybSBzYW1wbGVyMkQgdVNhbXBsZXI7JyxcblxuICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkKSAqIHZDb2xvciA7JyxcbiAgICAgICAgJ30nXG4gICAgXS5qb2luKCdcXG4nKTtcblxuICAgIHRoaXMuaW5pdCgpO1xufVxuXG5TaGFkZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gU2hhZGVyO1xubW9kdWxlLmV4cG9ydHMgPSBTaGFkZXI7XG5cblNoYWRlci5wcm90b3R5cGUuaW5pdCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmNvbXBpbGUoKTtcblxuICAgIHRoaXMuZ2wudXNlUHJvZ3JhbSh0aGlzLnByb2dyYW0pO1xuXG4gICAgdGhpcy5jYWNoZVVuaWZvcm1Mb2NhdGlvbnMoT2JqZWN0LmtleXModGhpcy51bmlmb3JtcykpO1xuICAgIHRoaXMuY2FjaGVBdHRyaWJ1dGVMb2NhdGlvbnMoT2JqZWN0LmtleXModGhpcy5hdHRyaWJ1dGVzKSk7XG59O1xuXG5TaGFkZXIucHJvdG90eXBlLmNhY2hlVW5pZm9ybUxvY2F0aW9ucyA9IGZ1bmN0aW9uIChrZXlzKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgKytpKSB7XG4gICAgICAgIHRoaXMudW5pZm9ybXNba2V5c1tpXV0uX2xvY2F0aW9uID0gdGhpcy5nbC5nZXRVbmlmb3JtTG9jYXRpb24odGhpcy5wcm9ncmFtLCBrZXlzW2ldKTtcbiAgICB9XG59O1xuXG5TaGFkZXIucHJvdG90eXBlLmNhY2hlQXR0cmlidXRlTG9jYXRpb25zID0gZnVuY3Rpb24gKGtleXMpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGtleXMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgdGhpcy5hdHRyaWJ1dGVzW2tleXNbaV1dID0gdGhpcy5nbC5nZXRBdHRyaWJMb2NhdGlvbih0aGlzLnByb2dyYW0sIGtleXNbaV0pO1xuICAgIH1cblxuICAgIC8vIFRPRE86IENoZWNrIGlmIHRoaXMgaXMgbmVlZGVkIGFueW1vcmUuLi5cblxuICAgIC8vIEJlZ2luIHdvcnN0IGhhY2sgZXZhIC8vXG5cbiAgICAvLyBXSFk/Pz8gT05MWSBvbiBteSBjaHJvbWUgcGl4ZWwgdGhlIGxpbmUgYWJvdmUgcmV0dXJucyAtMSB3aGVuIHVzaW5nIGZpbHRlcnM/XG4gICAgLy8gbWF5YmUgaXRzIHNvbWV0aGluZyB0byBkbyB3aXRoIHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBnbCBjb250ZXh0LlxuICAgIC8vIEknbSBjb252aW5jZWQgdGhpcyBpcyBhIGJ1ZyBpbiB0aGUgY2hyb21lIGJyb3dzZXIgYXMgdGhlcmUgaXMgTk8gcmVhc29uIHdoeSB0aGlzIHNob3VsZCBiZSByZXR1cm5pbmcgLTEgZXNwZWNpYWxseSBhcyBpdCBvbmx5IG1hbmlmZXN0cyBvbiBteSBjaHJvbWUgcGl4ZWxcbiAgICAvLyBJZiB0aGVyZXMgYW55IHdlYkdMIHBlb3BsZSB0aGF0IGtub3cgd2h5IGNvdWxkIGhhcHBlbiBwbGVhc2UgaGVscCA6KVxuICAgIC8vIGlmICh0aGlzLmF0dHJpYnV0ZXMuYUNvbG9yID09PSAtMSkge1xuICAgIC8vICAgICB0aGlzLmF0dHJpYnV0ZXMuYUNvbG9yID0gMjtcbiAgICAvLyB9XG5cbiAgICAvLyBFbmQgd29yc3QgaGFjayBldmEgLy9cbn07XG5cblNoYWRlci5wcm90b3R5cGUuY29tcGlsZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZ2wgPSB0aGlzLmdsO1xuXG4gICAgdmFyIGdsVmVydFNoYWRlciA9IHRoaXMuX2dsQ29tcGlsZShnbC5WRVJURVhfU0hBREVSLCB0aGlzLnZlcnRleFNyYyk7XG4gICAgdmFyIGdsRnJhZ1NoYWRlciA9IHRoaXMuX2dsQ29tcGlsZShnbC5GUkFHTUVOVF9TSEFERVIsIHRoaXMuZnJhZ21lbnRTcmMpO1xuXG4gICAgdmFyIHByb2dyYW0gPSBnbC5jcmVhdGVQcm9ncmFtKCk7XG5cbiAgICBnbC5hdHRhY2hTaGFkZXIocHJvZ3JhbSwgZ2xWZXJ0U2hhZGVyKTtcbiAgICBnbC5hdHRhY2hTaGFkZXIocHJvZ3JhbSwgZ2xGcmFnU2hhZGVyKTtcbiAgICBnbC5saW5rUHJvZ3JhbShwcm9ncmFtKTtcblxuICAgIC8vIGlmIGxpbmtpbmcgZmFpbHMsIHRoZW4gbG9nIGFuZCBjbGVhbnVwXG4gICAgaWYgKCFnbC5nZXRQcm9ncmFtUGFyYW1ldGVyKHByb2dyYW0sIGdsLkxJTktfU1RBVFVTKSkge1xuICAgICAgICB3aW5kb3cuY29uc29sZS5lcnJvcignUGl4aS5qcyBFcnJvcjogQ291bGQgbm90IGluaXRpYWxpemUgc2hhZGVyLicpO1xuICAgICAgICB3aW5kb3cuY29uc29sZS5lcnJvcignZ2wuVkFMSURBVEVfU1RBVFVTJywgZ2wuZ2V0UHJvZ3JhbVBhcmFtZXRlcihwcm9ncmFtLCBnbC5WQUxJREFURV9TVEFUVVMpKTtcbiAgICAgICAgd2luZG93LmNvbnNvbGUuZXJyb3IoJ2dsLmdldEVycm9yKCknLCBnbC5nZXRFcnJvcigpKTtcblxuICAgICAgICAvLyBpZiB0aGVyZSBpcyBhIHByb2dyYW0gaW5mbyBsb2csIGxvZyBpdFxuICAgICAgICBpZiAoZ2wuZ2V0UHJvZ3JhbUluZm9Mb2cocHJvZ3JhbSkgIT09ICcnKSB7XG4gICAgICAgICAgICB3aW5kb3cuY29uc29sZS53YXJuKCdQaXhpLmpzIFdhcm5pbmc6IGdsLmdldFByb2dyYW1JbmZvTG9nKCknLCBnbC5nZXRQcm9ncmFtSW5mb0xvZyhwcm9ncmFtKSk7XG4gICAgICAgIH1cblxuICAgICAgICBnbC5kZWxldGVQcm9ncmFtKHByb2dyYW0pO1xuICAgICAgICBwcm9ncmFtID0gbnVsbDtcbiAgICB9XG5cbiAgICAvLyBjbGVhbiB1cCBzb21lIHNoYWRlcnNcbiAgICBnbC5kZWxldGVTaGFkZXIoZ2xWZXJ0U2hhZGVyKTtcbiAgICBnbC5kZWxldGVTaGFkZXIoZ2xGcmFnU2hhZGVyKTtcblxuICAgIHJldHVybiAodGhpcy5wcm9ncmFtID0gcHJvZ3JhbSk7XG59O1xuXG5TaGFkZXIucHJvdG90eXBlLnN5bmNVbmlmb3JtcyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZ2wgPSB0aGlzLmdsO1xuXG4gICAgdGhpcy50ZXh0dXJlQ291bnQgPSAxO1xuXG4gICAgZm9yICh2YXIga2V5IGluIHRoaXMudW5pZm9ybXMpIHtcbiAgICAgICAgdmFyIHVuaWZvcm0gPSB0aGlzLnVuaWZvcm1zW2tleV0sXG4gICAgICAgICAgICBsb2NhdGlvbiA9IHVuaWZvcm0uX2xvY2F0aW9uLFxuICAgICAgICAgICAgdmFsdWUgPSB1bmlmb3JtLnZhbHVlLFxuICAgICAgICAgICAgaSwgaWw7XG5cbiAgICAgICAgc3dpdGNoICh1bmlmb3JtLnR5cGUpIHtcbiAgICAgICAgICAgIGNhc2UgJ2knOlxuICAgICAgICAgICAgY2FzZSAnMWknOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0xaShsb2NhdGlvbiwgdmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICBjYXNlICdmJzpcbiAgICAgICAgICAgIGNhc2UgJzFmJzpcbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtMWYobG9jYXRpb24sIHZhbHVlKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSAnMmYnOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0yZihsb2NhdGlvbiwgdmFsdWVbMF0sIHZhbHVlWzFdKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSAnM2YnOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0zZihsb2NhdGlvbiwgdmFsdWVbMF0sIHZhbHVlWzFdLCB2YWx1ZVsyXSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIGNhc2UgJzRmJzpcbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtNGYobG9jYXRpb24sIHZhbHVlWzBdLCB2YWx1ZVsxXSwgdmFsdWVbMl0sIHZhbHVlWzNdKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgLy8gYSAyRCBQb2ludCBvYmplY3RcbiAgICAgICAgICAgIGNhc2UgJ3YyJzpcbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtMmYobG9jYXRpb24sIHZhbHVlLngsIHZhbHVlLnkpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAvLyBhIDNEIFBvaW50IG9iamVjdFxuICAgICAgICAgICAgY2FzZSAndjMnOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0zZihsb2NhdGlvbiwgdmFsdWUueCwgdmFsdWUueSwgdmFsdWUueik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIC8vIGEgNEQgUG9pbnQgb2JqZWN0XG4gICAgICAgICAgICBjYXNlICd2NCc6XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTRmKGxvY2F0aW9uLCB2YWx1ZS54LCB2YWx1ZS55LCB2YWx1ZS56LCB2YWx1ZS53KTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSAnMWl2JzpcbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtMWl2KGxvY2F0aW9uLCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIGNhc2UgJzNpdic6XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTNpdihsb2NhdGlvbiwgdmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICBjYXNlICcxZnYnOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0xZnYobG9jYXRpb24sIHZhbHVlKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSAnMmZ2JzpcbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtMmZ2KGxvY2F0aW9uLCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIGNhc2UgJzNmdic6XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTNmdihsb2NhdGlvbiwgdmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICBjYXNlICc0ZnYnOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm00ZnYobG9jYXRpb24sIHZhbHVlKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSAnbTInOlxuICAgICAgICAgICAgY2FzZSAnbWF0Mic6XG4gICAgICAgICAgICBjYXNlICdNYXRyaXgyZnYnOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm1NYXRyaXgyZnYobG9jYXRpb24sIHVuaWZvcm0udHJhbnNwb3NlLCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIGNhc2UgJ20zJzpcbiAgICAgICAgICAgIGNhc2UgJ21hdDMnOlxuICAgICAgICAgICAgY2FzZSAnTWF0cml4M2Z2JzpcbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtTWF0cml4M2Z2KGxvY2F0aW9uLCB1bmlmb3JtLnRyYW5zcG9zZSwgdmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICBjYXNlICdtNCc6XG4gICAgICAgICAgICBjYXNlICdtYXQ0JzpcbiAgICAgICAgICAgIGNhc2UgJ01hdHJpeDRmdic6XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybU1hdHJpeDRmdihsb2NhdGlvbiwgdW5pZm9ybS50cmFuc3Bvc2UsIHZhbHVlKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgLy8gYSBDb2xvciBWYWx1ZVxuICAgICAgICAgICAgY2FzZSAnYyc6XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB1dGlscy5oZXgycmdiKHZhbHVlKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtM2YobG9jYXRpb24sIHZhbHVlWzBdLCB2YWx1ZVsxXSwgdmFsdWVbMl0pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAvLyBmbGF0IGFycmF5IG9mIGludGVnZXJzIChKUyBvciB0eXBlZCBhcnJheSlcbiAgICAgICAgICAgIGNhc2UgJ2l2MSc6XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTFpdihsb2NhdGlvbiwgdmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAvLyBmbGF0IGFycmF5IG9mIGludGVnZXJzIHdpdGggMyB4IE4gc2l6ZSAoSlMgb3IgdHlwZWQgYXJyYXkpXG4gICAgICAgICAgICBjYXNlICdpdic6XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTNpdihsb2NhdGlvbiwgdmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAvLyBmbGF0IGFycmF5IG9mIGZsb2F0cyAoSlMgb3IgdHlwZWQgYXJyYXkpXG4gICAgICAgICAgICBjYXNlICdmdjEnOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0xZnYobG9jYXRpb24sIHZhbHVlKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgLy8gZmxhdCBhcnJheSBvZiBmbG9hdHMgd2l0aCAzIHggTiBzaXplIChKUyBvciB0eXBlZCBhcnJheSlcbiAgICAgICAgICAgIGNhc2UgJ2Z2JzpcbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtM2Z2KGxvY2F0aW9uLCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIC8vIGFycmF5IG9mIDJEIFBvaW50IG9iamVjdHNcbiAgICAgICAgICAgIGNhc2UgJ3Yydic6XG4gICAgICAgICAgICAgICAgaWYgKCF1bmlmb3JtLl9hcnJheSkge1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheSA9IG5ldyBGbG9hdDMyQXJyYXkoMiAqIHZhbHVlLmxlbmd0aCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgZm9yIChpID0gMCwgaWwgPSB2YWx1ZS5sZW5ndGg7IGkgPCBpbDsgKytpKSB7XG4gICAgICAgICAgICAgICAgICAgIHVuaWZvcm0uX2FycmF5W2kgKiAyXSAgICAgICA9IHZhbHVlW2ldLng7XG4gICAgICAgICAgICAgICAgICAgIHVuaWZvcm0uX2FycmF5W2kgKiAyICsgMV0gICA9IHZhbHVlW2ldLnk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTJmdihsb2NhdGlvbiwgdW5pZm9ybS5fYXJyYXkpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAvLyBhcnJheSBvZiAzRCBQb2ludCBvYmplY3RzXG4gICAgICAgICAgICBjYXNlICd2M3YnOlxuICAgICAgICAgICAgICAgIGlmICghdW5pZm9ybS5fYXJyYXkpIHtcbiAgICAgICAgICAgICAgICAgICAgdW5pZm9ybS5fYXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KDMgKiB2YWx1ZS5sZW5ndGgpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGZvciAoaSA9IDAsIGlsID0gdmFsdWUubGVuZ3RoOyBpIDwgaWw7ICsraSkge1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheVtpICogM10gICAgICAgPSB2YWx1ZVtpXS54O1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheVtpICogMyArIDFdICAgPSB2YWx1ZVtpXS55O1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheVtpICogMyArIDJdICAgPSB2YWx1ZVtpXS56O1xuXG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTNmdihsb2NhdGlvbiwgdW5pZm9ybS5fYXJyYXkpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAvLyBhcnJheSBvZiA0RCBQb2ludCBvYmplY3RzXG4gICAgICAgICAgICBjYXNlICd2NHYnOlxuICAgICAgICAgICAgICAgIGlmICghdW5pZm9ybS5fYXJyYXkpIHtcbiAgICAgICAgICAgICAgICAgICAgdW5pZm9ybS5fYXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KDQgKiB2YWx1ZS5sZW5ndGgpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGZvciAoaSA9IDAsIGlsID0gdmFsdWUubGVuZ3RoOyBpIDwgaWw7ICsraSkge1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheVtpICogNF0gICAgICAgPSB2YWx1ZVtpXS54O1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheVtpICogNCArIDFdICAgPSB2YWx1ZVtpXS55O1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheVtpICogNCArIDJdICAgPSB2YWx1ZVtpXS56O1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheVtpICogNCArIDNdICAgPSB2YWx1ZVtpXS53O1xuXG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTRmdihsb2NhdGlvbiwgdW5pZm9ybS5fYXJyYXkpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICBjYXNlICd0JzpcbiAgICAgICAgICAgIGNhc2UgJ3NhbXBsZXIyRCc6XG4gICAgICAgICAgICAgICAgaWYgKCF1bmlmb3JtLnZhbHVlIHx8ICF1bmlmb3JtLnZhbHVlLmJhc2VUZXh0dXJlIHx8ICF1bmlmb3JtLnZhbHVlLmJhc2VUZXh0dXJlLmhhc0xvYWRlZCkge1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBhY3RpdmF0ZSB0aGlzIHRleHR1cmVcbiAgICAgICAgICAgICAgICBnbC5hY3RpdmVUZXh0dXJlKGdsWydURVhUVVJFJyArIHRoaXMudGV4dHVyZUNvdW50XSk7XG5cbiAgICAgICAgICAgICAgICAvLyBiaW5kIHRoZSB0ZXh0dXJlXG4gICAgICAgICAgICAgICAgZ2wuYmluZFRleHR1cmUoZ2wuVEVYVFVSRV8yRCwgdW5pZm9ybS52YWx1ZS5iYXNlVGV4dHVyZS5fZ2xUZXh0dXJlc1tnbC5pZF0pO1xuXG4gICAgICAgICAgICAgICAgLy8gc2V0IHVuaWZvcm0gdG8gdGV4dHVyZSBpbmRleFxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0xaSh1bmlmb3JtLl9sb2NhdGlvbiwgdGhpcy50ZXh0dXJlQ291bnQpO1xuXG4gICAgICAgICAgICAgICAgLy8gaW5jcmVtZW50IG5leHQgdGV4dHVyZSBpZFxuICAgICAgICAgICAgICAgIHRoaXMudGV4dHVyZUNvdW50Kys7XG5cbiAgICAgICAgICAgICAgICAvLyBpbml0aWFsaXplIHRoZSB0ZXh0dXJlIGlmIHdlIGhhdmVuJ3QgeWV0XG4gICAgICAgICAgICAgICAgaWYgKCF1bmlmb3JtLl9pbml0KSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaW5pdFNhbXBsZXIyRCh1bmlmb3JtKTtcblxuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9pbml0ID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgd2luZG93LmNvbnNvbGUud2FybignUGl4aS5qcyBTaGFkZXIgV2FybmluZzogVW5rbm93biB1bmlmb3JtIHR5cGU6ICcgKyB1bmlmb3JtLnR5cGUpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuXG4vKipcbiAqIEluaXRpYWxpc2VzIGEgU2FtcGxlcjJEIHVuaWZvcm0gKHdoaWNoIG1heSBvbmx5IGJlIGF2YWlsYWJsZSBsYXRlciBvbiBhZnRlciBpbml0VW5pZm9ybXMgb25jZSB0aGUgdGV4dHVyZSBoYXMgbG9hZGVkKVxuICpcbiAqL1xuU2hhZGVyLnByb3RvdHlwZS5pbml0U2FtcGxlcjJEID0gZnVuY3Rpb24gKHVuaWZvcm0pIHtcbiAgICB2YXIgZ2wgPSB0aGlzLmdsO1xuXG4gICAgLy8gIEV4dGVuZGVkIHRleHR1cmUgZGF0YVxuICAgIGlmICh1bmlmb3JtLnRleHR1cmVEYXRhKSB7XG4gICAgICAgIHZhciBkYXRhID0gdW5pZm9ybS50ZXh0dXJlRGF0YTtcblxuICAgICAgICAvLyBHTFRleHR1cmUgPSBtYWcgbGluZWFyLCBtaW4gbGluZWFyX21pcG1hcF9saW5lYXIsIHdyYXAgcmVwZWF0ICsgZ2wuZ2VuZXJhdGVNaXBtYXAoZ2wuVEVYVFVSRV8yRCk7XG4gICAgICAgIC8vIEdMVGV4dHVyZUxpbmVhciA9IG1hZy9taW4gbGluZWFyLCB3cmFwIGNsYW1wXG4gICAgICAgIC8vIEdMVGV4dHVyZU5lYXJlc3RSZXBlYXQgPSBtYWcvbWluIE5FQVJFU1QsIHdyYXAgcmVwZWF0XG4gICAgICAgIC8vIEdMVGV4dHVyZU5lYXJlc3QgPSBtYWcvbWluIG5lYXJlc3QsIHdyYXAgY2xhbXBcbiAgICAgICAgLy8gQXVkaW9UZXh0dXJlID0gd2hhdGV2ZXIgKyBsdW1pbmFuY2UgKyB3aWR0aCA1MTIsIGhlaWdodCAyLCBib3JkZXIgMFxuICAgICAgICAvLyBLZXlUZXh0dXJlID0gd2hhdGV2ZXIgKyBsdW1pbmFuY2UgKyB3aWR0aCAyNTYsIGhlaWdodCAyLCBib3JkZXIgMFxuXG4gICAgICAgIC8vICBtYWdGaWx0ZXIgY2FuIGJlOiBnbC5MSU5FQVIsIGdsLkxJTkVBUl9NSVBNQVBfTElORUFSIG9yIGdsLk5FQVJFU1RcbiAgICAgICAgLy8gIHdyYXBTL1QgY2FuIGJlOiBnbC5DTEFNUF9UT19FREdFIG9yIGdsLlJFUEVBVFxuXG4gICAgICAgIHZhciBtYWdGaWx0ZXIgPSAoZGF0YS5tYWdGaWx0ZXIpID8gZGF0YS5tYWdGaWx0ZXIgOiBnbC5MSU5FQVI7XG4gICAgICAgIHZhciBtaW5GaWx0ZXIgPSAoZGF0YS5taW5GaWx0ZXIpID8gZGF0YS5taW5GaWx0ZXIgOiBnbC5MSU5FQVI7XG4gICAgICAgIHZhciB3cmFwUyA9IChkYXRhLndyYXBTKSA/IGRhdGEud3JhcFMgOiBnbC5DTEFNUF9UT19FREdFO1xuICAgICAgICB2YXIgd3JhcFQgPSAoZGF0YS53cmFwVCkgPyBkYXRhLndyYXBUIDogZ2wuQ0xBTVBfVE9fRURHRTtcbiAgICAgICAgdmFyIGZvcm1hdCA9IChkYXRhLmx1bWluYW5jZSkgPyBnbC5MVU1JTkFOQ0UgOiBnbC5SR0JBO1xuXG4gICAgICAgIGlmIChkYXRhLnJlcGVhdCkge1xuICAgICAgICAgICAgd3JhcFMgPSBnbC5SRVBFQVQ7XG4gICAgICAgICAgICB3cmFwVCA9IGdsLlJFUEVBVDtcbiAgICAgICAgfVxuXG4gICAgICAgIGdsLnBpeGVsU3RvcmVpKGdsLlVOUEFDS19GTElQX1lfV0VCR0wsICEhZGF0YS5mbGlwWSk7XG5cbiAgICAgICAgaWYgKGRhdGEud2lkdGgpIHtcbiAgICAgICAgICAgIHZhciB3aWR0aCA9IChkYXRhLndpZHRoKSA/IGRhdGEud2lkdGggOiA1MTI7XG4gICAgICAgICAgICB2YXIgaGVpZ2h0ID0gKGRhdGEuaGVpZ2h0KSA/IGRhdGEuaGVpZ2h0IDogMjtcbiAgICAgICAgICAgIHZhciBib3JkZXIgPSAoZGF0YS5ib3JkZXIpID8gZGF0YS5ib3JkZXIgOiAwO1xuXG4gICAgICAgICAgICAvLyB2b2lkIHRleEltYWdlMkQoR0xlbnVtIHRhcmdldCwgR0xpbnQgbGV2ZWwsIEdMZW51bSBpbnRlcm5hbGZvcm1hdCwgR0xzaXplaSB3aWR0aCwgR0xzaXplaSBoZWlnaHQsIEdMaW50IGJvcmRlciwgR0xlbnVtIGZvcm1hdCwgR0xlbnVtIHR5cGUsIEFycmF5QnVmZmVyVmlldz8gcGl4ZWxzKTtcbiAgICAgICAgICAgIGdsLnRleEltYWdlMkQoZ2wuVEVYVFVSRV8yRCwgMCwgZm9ybWF0LCB3aWR0aCwgaGVpZ2h0LCBib3JkZXIsIGZvcm1hdCwgZ2wuVU5TSUdORURfQllURSwgbnVsbCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyAgdm9pZCB0ZXhJbWFnZTJEKEdMZW51bSB0YXJnZXQsIEdMaW50IGxldmVsLCBHTGVudW0gaW50ZXJuYWxmb3JtYXQsIEdMZW51bSBmb3JtYXQsIEdMZW51bSB0eXBlLCBJbWFnZURhdGE/IHBpeGVscyk7XG4gICAgICAgICAgICBnbC50ZXhJbWFnZTJEKGdsLlRFWFRVUkVfMkQsIDAsIGZvcm1hdCwgZ2wuUkdCQSwgZ2wuVU5TSUdORURfQllURSwgdW5pZm9ybS52YWx1ZS5iYXNlVGV4dHVyZS5zb3VyY2UpO1xuICAgICAgICB9XG5cbiAgICAgICAgZ2wudGV4UGFyYW1ldGVyaShnbC5URVhUVVJFXzJELCBnbC5URVhUVVJFX01BR19GSUxURVIsIG1hZ0ZpbHRlcik7XG4gICAgICAgIGdsLnRleFBhcmFtZXRlcmkoZ2wuVEVYVFVSRV8yRCwgZ2wuVEVYVFVSRV9NSU5fRklMVEVSLCBtaW5GaWx0ZXIpO1xuICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfV1JBUF9TLCB3cmFwUyk7XG4gICAgICAgIGdsLnRleFBhcmFtZXRlcmkoZ2wuVEVYVFVSRV8yRCwgZ2wuVEVYVFVSRV9XUkFQX1QsIHdyYXBUKTtcbiAgICB9XG59O1xuXG4vKipcbiAqIERlc3Ryb3lzIHRoZSBzaGFkZXIuXG4gKlxuICovXG5TaGFkZXIucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5nbC5kZWxldGVQcm9ncmFtKHRoaXMucHJvZ3JhbSk7XG5cbiAgICB0aGlzLmdsID0gbnVsbDtcbiAgICB0aGlzLnVuaWZvcm1zID0gbnVsbDtcbiAgICB0aGlzLmF0dHJpYnV0ZXMgPSBudWxsO1xuXG4gICAgdGhpcy52ZXJ0ZXhTcmMgPSBudWxsO1xuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBudWxsO1xufTtcblxuU2hhZGVyLnByb3RvdHlwZS5fZ2xDb21waWxlID0gZnVuY3Rpb24gKHR5cGUsIHNyYykge1xuICAgIHZhciBzaGFkZXIgPSB0aGlzLmdsLmNyZWF0ZVNoYWRlcih0eXBlKTtcblxuICAgIGlmIChBcnJheS5pc0FycmF5KHNyYykpIHtcbiAgICAgICAgZGVidWdnZXI7XG4gICAgfVxuXG4gICAgdGhpcy5nbC5zaGFkZXJTb3VyY2Uoc2hhZGVyLCBzcmMpO1xuICAgIHRoaXMuZ2wuY29tcGlsZVNoYWRlcihzaGFkZXIpO1xuXG4gICAgaWYgKCF0aGlzLmdsLmdldFNoYWRlclBhcmFtZXRlcihzaGFkZXIsIHRoaXMuZ2wuQ09NUElMRV9TVEFUVVMpKSB7XG4gICAgICAgIHdpbmRvdy5jb25zb2xlLmxvZyh0aGlzLmdsLmdldFNoYWRlckluZm9Mb2coc2hhZGVyKSk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHJldHVybiBzaGFkZXI7XG59O1xuIiwidmFyIFNoYWRlciA9IHJlcXVpcmUoJy4vU2hhZGVyJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSBnbCB7V2ViR0xDb250ZXh0fSB0aGUgY3VycmVudCBXZWJHTCBkcmF3aW5nIGNvbnRleHRcbiAqL1xuZnVuY3Rpb24gU3RyaXBTaGFkZXIoZ2wpIHtcbiAgICBTaGFkZXIuY2FsbCh0aGlzLFxuICAgICAgICBnbCxcbiAgICAgICAgLy8gdmVydGV4IHNoYWRlclxuICAgICAgICBbXG4gICAgICAgICAgICAnYXR0cmlidXRlIHZlYzIgYVZlcnRleFBvc2l0aW9uOycsXG4gICAgICAgICAgICAnYXR0cmlidXRlIHZlYzIgYVRleHR1cmVDb29yZDsnLFxuICAgICAgICAgICAgLy8gJ2F0dHJpYnV0ZSB2ZWM0IGFDb2xvcjsnLFxuXG4gICAgICAgICAgICAndW5pZm9ybSBtYXQzIHRyYW5zbGF0aW9uTWF0cml4OycsXG4gICAgICAgICAgICAndW5pZm9ybSB2ZWMyIHByb2plY3Rpb25WZWN0b3I7JyxcbiAgICAgICAgICAgICd1bmlmb3JtIHZlYzIgb2Zmc2V0VmVjdG9yOycsXG5cbiAgICAgICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuXG4gICAgICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAgICAgJyAgIHZlYzMgdiA9IHRyYW5zbGF0aW9uTWF0cml4ICogdmVjMyhhVmVydGV4UG9zaXRpb24gLCAxLjApOycsXG4gICAgICAgICAgICAnICAgdiAtPSBvZmZzZXRWZWN0b3IueHl4OycsXG4gICAgICAgICAgICAnICAgZ2xfUG9zaXRpb24gPSB2ZWM0KCB2LnggLyBwcm9qZWN0aW9uVmVjdG9yLnggLTEuMCwgdi55IC8gLXByb2plY3Rpb25WZWN0b3IueSArIDEuMCAsIDAuMCwgMS4wKTsnLFxuICAgICAgICAgICAgJyAgIHZUZXh0dXJlQ29vcmQgPSBhVGV4dHVyZUNvb3JkOycsXG4gICAgICAgICAgICAnfSdcbiAgICAgICAgXS5qb2luKCdcXG4nKSxcbiAgICAgICAgLy8gZnJhZ21lbnQgc2hhZGVyXG4gICAgICAgIFtcbiAgICAgICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICAgICAndW5pZm9ybSBmbG9hdCBhbHBoYTsnLFxuICAgICAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG5cbiAgICAgICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuXG4gICAgICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAgICAgJyAgIGdsX0ZyYWdDb2xvciA9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLngsIHZUZXh0dXJlQ29vcmQueSkpICogYWxwaGE7JyxcbiAgICAgICAgICAgICd9J1xuICAgICAgICBdLmpvaW4oJ1xcbicpLFxuICAgICAgICAvLyBjdXN0b20gdW5pZm9ybXNcbiAgICAgICAge1xuICAgICAgICAgICAgYWxwaGE6ICB7IHR5cGU6ICcxZicsIHZhbHVlOiAwIH0sXG4gICAgICAgICAgICB0cmFuc2xhdGlvbk1hdHJpeDogeyB0eXBlOiAnbWF0MycsIHZhbHVlOiBuZXcgRmxvYXQzMkFycmF5KDkpIH1cbiAgICAgICAgfVxuICAgICk7XG59XG5cblN0cmlwU2hhZGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoU2hhZGVyLnByb3RvdHlwZSk7XG5TdHJpcFNoYWRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBTdHJpcFNoYWRlcjtcbm1vZHVsZS5leHBvcnRzID0gU3RyaXBTaGFkZXI7XG4iLCJ2YXIgQ09OU1QgPSByZXF1aXJlKCcuLi8uLi8uLi9jb25zdCcpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gZ2wge1dlYkdMQ29udGV4dH0gdGhlIGN1cnJlbnQgV2ViR0wgZHJhd2luZyBjb250ZXh0XG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gdGhlIGhvcml6b250YWwgcmFuZ2Ugb2YgdGhlIGZpbHRlclxuICogQHBhcmFtIGhlaWdodCB7bnVtYmVyfSB0aGUgdmVydGljYWwgcmFuZ2Ugb2YgdGhlIGZpbHRlclxuICogQHBhcmFtIHNjYWxlTW9kZSB7bnVtYmVyfSBTZWUge3sjY3Jvc3NMaW5rIFwiUElYSS9zY2FsZU1vZGVzOnByb3BlcnR5XCJ9fXNjYWxlTW9kZXN7ey9jcm9zc0xpbmt9fSBmb3IgcG9zc2libGUgdmFsdWVzXG4gKi9cbmZ1bmN0aW9uIEZpbHRlclRleHR1cmUoZ2wsIHdpZHRoLCBoZWlnaHQsIHNjYWxlTW9kZSkge1xuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge1dlYkdMQ29udGV4dH1cbiAgICAgKi9cbiAgICB0aGlzLmdsID0gZ2w7XG5cbiAgICAvLyBuZXh0IHRpbWUgdG8gY3JlYXRlIGEgZnJhbWUgYnVmZmVyIGFuZCB0ZXh0dXJlXG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtBbnl9XG4gICAgICovXG4gICAgdGhpcy5mcmFtZUJ1ZmZlciA9IGdsLmNyZWF0ZUZyYW1lYnVmZmVyKCk7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtBbnl9XG4gICAgICovXG4gICAgdGhpcy50ZXh0dXJlID0gZ2wuY3JlYXRlVGV4dHVyZSgpO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHNjYWxlTW9kZSA9IHNjYWxlTW9kZSB8fCBDT05TVC5zY2FsZU1vZGVzLkRFRkFVTFQ7XG5cbiAgICBnbC5iaW5kVGV4dHVyZShnbC5URVhUVVJFXzJELCAgdGhpcy50ZXh0dXJlKTtcbiAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfTUFHX0ZJTFRFUiwgc2NhbGVNb2RlID09PSBDT05TVC5zY2FsZU1vZGVzLkxJTkVBUiA/IGdsLkxJTkVBUiA6IGdsLk5FQVJFU1QpO1xuICAgIGdsLnRleFBhcmFtZXRlcmkoZ2wuVEVYVFVSRV8yRCwgZ2wuVEVYVFVSRV9NSU5fRklMVEVSLCBzY2FsZU1vZGUgPT09IENPTlNULnNjYWxlTW9kZXMuTElORUFSID8gZ2wuTElORUFSIDogZ2wuTkVBUkVTVCk7XG4gICAgZ2wudGV4UGFyYW1ldGVyaShnbC5URVhUVVJFXzJELCBnbC5URVhUVVJFX1dSQVBfUywgZ2wuQ0xBTVBfVE9fRURHRSk7XG4gICAgZ2wudGV4UGFyYW1ldGVyaShnbC5URVhUVVJFXzJELCBnbC5URVhUVVJFX1dSQVBfVCwgZ2wuQ0xBTVBfVE9fRURHRSk7XG4gICAgZ2wuYmluZEZyYW1lYnVmZmVyKGdsLkZSQU1FQlVGRkVSLCB0aGlzLmZyYW1lQnVmZmVyICk7XG5cbiAgICBnbC5iaW5kRnJhbWVidWZmZXIoZ2wuRlJBTUVCVUZGRVIsIHRoaXMuZnJhbWVCdWZmZXIgKTtcbiAgICBnbC5mcmFtZWJ1ZmZlclRleHR1cmUyRChnbC5GUkFNRUJVRkZFUiwgZ2wuQ09MT1JfQVRUQUNITUVOVDAsIGdsLlRFWFRVUkVfMkQsIHRoaXMudGV4dHVyZSwgMCk7XG5cbiAgICAvLyByZXF1aXJlZCBmb3IgbWFza2luZyBhIG1hc2s/P1xuICAgIHRoaXMucmVuZGVyQnVmZmVyID0gZ2wuY3JlYXRlUmVuZGVyYnVmZmVyKCk7XG4gICAgZ2wuYmluZFJlbmRlcmJ1ZmZlcihnbC5SRU5ERVJCVUZGRVIsIHRoaXMucmVuZGVyQnVmZmVyKTtcbiAgICBnbC5mcmFtZWJ1ZmZlclJlbmRlcmJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgZ2wuREVQVEhfU1RFTkNJTF9BVFRBQ0hNRU5ULCBnbC5SRU5ERVJCVUZGRVIsIHRoaXMucmVuZGVyQnVmZmVyKTtcblxuICAgIC8vIHJlc2V0IHJlbmRlciBidWZmZXJcbiAgICBnbC5iaW5kUmVuZGVyYnVmZmVyKGdsLlJFTkRFUkJVRkZFUiwgbnVsbCk7XG5cbiAgICB0aGlzLnJlc2l6ZSh3aWR0aCwgaGVpZ2h0KTtcbn1cblxuRmlsdGVyVGV4dHVyZS5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBGaWx0ZXJUZXh0dXJlO1xubW9kdWxlLmV4cG9ydHMgPSBGaWx0ZXJUZXh0dXJlO1xuXG4vKipcbiAqIENsZWFycyB0aGUgZmlsdGVyIHRleHR1cmUuXG4gKlxuICovXG5GaWx0ZXJUZXh0dXJlLnByb3RvdHlwZS5jbGVhciA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZ2wgPSB0aGlzLmdsO1xuXG4gICAgZ2wuY2xlYXJDb2xvcigwLDAsMCwgMCk7XG4gICAgZ2wuY2xlYXIoZ2wuQ09MT1JfQlVGRkVSX0JJVCk7XG59O1xuXG4vKipcbiAqIFJlc2l6ZXMgdGhlIHRleHR1cmUgdG8gdGhlIHNwZWNpZmllZCB3aWR0aCBhbmQgaGVpZ2h0XG4gKlxuICogQHBhcmFtIHdpZHRoIHtudW1iZXJ9IHRoZSBuZXcgd2lkdGggb2YgdGhlIHRleHR1cmVcbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gdGhlIG5ldyBoZWlnaHQgb2YgdGhlIHRleHR1cmVcbiAqL1xuRmlsdGVyVGV4dHVyZS5wcm90b3R5cGUucmVzaXplID0gZnVuY3Rpb24gKHdpZHRoLCBoZWlnaHQpIHtcbiAgICBpZiAodGhpcy53aWR0aCA9PT0gd2lkdGggJiYgdGhpcy5oZWlnaHQgPT09IGhlaWdodCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy53aWR0aCA9IHdpZHRoO1xuICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xuXG4gICAgdmFyIGdsID0gdGhpcy5nbDtcblxuICAgIGdsLmJpbmRUZXh0dXJlKGdsLlRFWFRVUkVfMkQsICB0aGlzLnRleHR1cmUpO1xuICAgIGdsLnRleEltYWdlMkQoZ2wuVEVYVFVSRV8yRCwgMCwgZ2wuUkdCQSwgIHdpZHRoICwgaGVpZ2h0ICwgMCwgZ2wuUkdCQSwgZ2wuVU5TSUdORURfQllURSwgbnVsbCk7XG4gICAgLy8gdXBkYXRlIHRoZSBzdGVuY2lsIGJ1ZmZlciB3aWR0aCBhbmQgaGVpZ2h0XG4gICAgZ2wuYmluZFJlbmRlcmJ1ZmZlcihnbC5SRU5ERVJCVUZGRVIsIHRoaXMucmVuZGVyQnVmZmVyKTtcbiAgICBnbC5yZW5kZXJidWZmZXJTdG9yYWdlKGdsLlJFTkRFUkJVRkZFUiwgZ2wuREVQVEhfU1RFTkNJTCwgd2lkdGggLCBoZWlnaHQpO1xuXG4gICAgLy8gcmVzZXQgcmVuZGVyIGJ1ZmZlclxuICAgIGdsLmJpbmRSZW5kZXJidWZmZXIoZ2wuUkVOREVSQlVGRkVSLCBudWxsKTtcbn07XG5cbi8qKlxuICogRGVzdHJveXMgdGhlIGZpbHRlciB0ZXh0dXJlLlxuICpcbiAqL1xuRmlsdGVyVGV4dHVyZS5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZ2wgPSB0aGlzLmdsO1xuICAgIGdsLmRlbGV0ZUZyYW1lYnVmZmVyKCB0aGlzLmZyYW1lQnVmZmVyICk7XG4gICAgZ2wuZGVsZXRlVGV4dHVyZSggdGhpcy50ZXh0dXJlICk7XG5cbiAgICB0aGlzLmZyYW1lQnVmZmVyID0gbnVsbDtcbiAgICB0aGlzLnRleHR1cmUgPSBudWxsO1xufTtcbiIsIi8qKlxuICogQGF1dGhvciBNYXQgR3JvdmVzXG4gKlxuICogQmlnIHRoYW5rcyB0byB0aGUgdmVyeSBjbGV2ZXIgTWF0dCBEZXNMYXVyaWVycyA8bWF0dGRlc2w+IGh0dHBzOi8vZ2l0aHViLmNvbS9tYXR0ZGVzbC9cbiAqIGZvciBjcmVhdGluZyB0aGUgb3JpZ2luYWwgcGl4aSB2ZXJzaW9uIVxuICpcbiAqIEhlYXZpbHkgaW5zcGlyZWQgYnkgTGliR0RYJ3MgV2ViR0xTcHJpdGVCYXRjaDpcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9saWJnZHgvbGliZ2R4L2Jsb2IvbWFzdGVyL2dkeC9zcmMvY29tL2JhZGxvZ2ljL2dkeC9ncmFwaGljcy9nMmQvV2ViR0xTcHJpdGVCYXRjaC5qYXZhXG4gKi9cblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBwcml2YXRlXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcn0gVGhlIHJlbmRlcmVyIHRoaXMgc3ByaXRlIGJhdGNoIHdvcmtzIGZvci5cbiAqL1xuZnVuY3Rpb24gV2ViR0xGYXN0U3ByaXRlQmF0Y2gocmVuZGVyZXIpIHtcbiAgICAvKipcbiAgICAgKiBUaGUgcmVuZGVyZXIgaW5zdGFuY2UgdGhpcyBzcHJpdGUgYmF0Y2ggb3BlcmF0ZXMgb24uXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtXZWJHTFJlbmRlcmVyfVxuICAgICAqL1xuICAgIHRoaXMucmVuZGVyZXIgPSByZW5kZXJlcjtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy52ZXJ0U2l6ZSA9IDEwO1xuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLm1heFNpemUgPSA2MDAwOy8vTWF0aC5wb3coMiwgMTYpIC8gIHRoaXMudmVydFNpemU7XG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMuc2l6ZSA9IHRoaXMubWF4U2l6ZTtcblxuICAgIC8vdGhlIHRvdGFsIG51bWJlciBvZiBmbG9hdHMgaW4gb3VyIGJhdGNoXG4gICAgdmFyIG51bVZlcnRzID0gdGhpcy5zaXplICogNCAqICB0aGlzLnZlcnRTaXplO1xuXG4gICAgLy90aGUgdG90YWwgbnVtYmVyIG9mIGluZGljZXMgaW4gb3VyIGJhdGNoXG4gICAgdmFyIG51bUluZGljZXMgPSB0aGlzLm1heFNpemUgKiA2O1xuXG4gICAgLyoqXG4gICAgICogVmVydGV4IGRhdGFcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0Zsb2F0MzJBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLnZlcnRpY2VzID0gbmV3IEZsb2F0MzJBcnJheShudW1WZXJ0cyk7XG5cbiAgICAvKipcbiAgICAgKiBJbmRleCBkYXRhXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtVaW50MTZBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLmluZGljZXMgPSBuZXcgVWludDE2QXJyYXkobnVtSW5kaWNlcyk7XG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqXG4gICAgICogQG1lbWJlciB7b2JqZWN0fVxuICAgICAqL1xuICAgIHRoaXMudmVydGV4QnVmZmVyID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtvYmplY3R9XG4gICAgICovXG4gICAgdGhpcy5pbmRleEJ1ZmZlciA9IG51bGw7XG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMubGFzdEluZGV4Q291bnQgPSAwO1xuXG4gICAgZm9yICh2YXIgaT0wLCBqPTA7IGkgPCBudW1JbmRpY2VzOyBpICs9IDYsIGogKz0gNCkge1xuICAgICAgICB0aGlzLmluZGljZXNbaSArIDBdID0gaiArIDA7XG4gICAgICAgIHRoaXMuaW5kaWNlc1tpICsgMV0gPSBqICsgMTtcbiAgICAgICAgdGhpcy5pbmRpY2VzW2kgKyAyXSA9IGogKyAyO1xuICAgICAgICB0aGlzLmluZGljZXNbaSArIDNdID0gaiArIDA7XG4gICAgICAgIHRoaXMuaW5kaWNlc1tpICsgNF0gPSBqICsgMjtcbiAgICAgICAgdGhpcy5pbmRpY2VzW2kgKyA1XSA9IGogKyAzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMuZHJhd2luZyA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLmN1cnJlbnRCYXRjaFNpemUgPSAwO1xuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0Jhc2VUZXh0dXJlfVxuICAgICAqL1xuICAgIHRoaXMuY3VycmVudEJhc2VUZXh0dXJlID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5jdXJyZW50QmxlbmRNb2RlID0gMDtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtvYmplY3R9XG4gICAgICovXG4gICAgdGhpcy5zaGFkZXIgPSBudWxsO1xuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge01hdHJpeH1cbiAgICAgKi9cbiAgICB0aGlzLm1hdHJpeCA9IG51bGw7XG5cbiAgICAvLyBsaXN0ZW4gZm9yIGNvbnRleHQgYW5kIHVwZGF0ZSBuZWNlc3NhcnkgYnVmZmVyc1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB0aGlzLnJlbmRlcmVyLm9uKCdjb250ZXh0JywgZnVuY3Rpb24gKCkge1xuICAgICAgICBzZWxmLnNldHVwQ29udGV4dCgpO1xuICAgIH0pO1xufVxuXG5XZWJHTEZhc3RTcHJpdGVCYXRjaC5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBXZWJHTEZhc3RTcHJpdGVCYXRjaDtcbm1vZHVsZS5leHBvcnRzID0gV2ViR0xGYXN0U3ByaXRlQmF0Y2g7XG5cbi8qKlxuICogU2V0cyB0aGUgV2ViR0wgQ29udGV4dC5cbiAqXG4gKiBAcGFyYW0gZ2wge1dlYkdMQ29udGV4dH0gdGhlIGN1cnJlbnQgV2ViR0wgZHJhd2luZyBjb250ZXh0XG4gKi9cbldlYkdMRmFzdFNwcml0ZUJhdGNoLnByb3RvdHlwZS5zZXR1cENvbnRleHQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGdsID0gdGhpcy5yZW5kZXJlci5nbDtcblxuICAgIC8vIGNyZWF0ZSBhIGNvdXBsZSBvZiBidWZmZXJzXG4gICAgdGhpcy52ZXJ0ZXhCdWZmZXIgPSBnbC5jcmVhdGVCdWZmZXIoKTtcbiAgICB0aGlzLmluZGV4QnVmZmVyID0gZ2wuY3JlYXRlQnVmZmVyKCk7XG5cbiAgICAvLyA2NTUzNSBpcyBtYXggaW5kZXgsIHNvIDY1NTM1IC8gNiA9IDEwOTIyLlxuXG4gICAgLy91cGxvYWQgdGhlIGluZGV4IGRhdGFcbiAgICBnbC5iaW5kQnVmZmVyKGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCB0aGlzLmluZGV4QnVmZmVyKTtcbiAgICBnbC5idWZmZXJEYXRhKGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCB0aGlzLmluZGljZXMsIGdsLlNUQVRJQ19EUkFXKTtcblxuICAgIGdsLmJpbmRCdWZmZXIoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLnZlcnRleEJ1ZmZlcik7XG4gICAgZ2wuYnVmZmVyRGF0YShnbC5BUlJBWV9CVUZGRVIsIHRoaXMudmVydGljZXMsIGdsLkRZTkFNSUNfRFJBVyk7XG59O1xuXG4vKipcbiAqIEBwYXJhbSBzcHJpdGVCYXRjaCB7U3ByaXRlQmF0Y2h9IFRoZSBTcHJpdGVCYXRjaCBjb250YWluZXIgdG8gcHJlcGFyZSBmb3IuXG4gKi9cbldlYkdMRmFzdFNwcml0ZUJhdGNoLnByb3RvdHlwZS5iZWdpbiA9IGZ1bmN0aW9uIChzcHJpdGVCYXRjaCkge1xuICAgIHRoaXMuc2hhZGVyID0gdGhpcy5yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLmZhc3RTaGFkZXI7XG5cbiAgICB0aGlzLm1hdHJpeCA9IHNwcml0ZUJhdGNoLndvcmxkVHJhbnNmb3JtLnRvQXJyYXkodHJ1ZSk7XG5cbiAgICB0aGlzLnN0YXJ0KCk7XG59O1xuXG4vKipcbiAqL1xuV2ViR0xGYXN0U3ByaXRlQmF0Y2gucHJvdG90eXBlLmVuZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmZsdXNoKCk7XG59O1xuXG4vKipcbiAqIEBwYXJhbSBzcHJpdGVCYXRjaCB7U3ByaXRlQmF0Y2h9IFRoZSBTcHJpdGVCYXRjaCBjb250YWluZXIgdG8gcmVuZGVyLlxuICovXG5XZWJHTEZhc3RTcHJpdGVCYXRjaC5wcm90b3R5cGUucmVuZGVyID0gZnVuY3Rpb24gKHNwcml0ZUJhdGNoKSB7XG4gICAgdmFyIGNoaWxkcmVuID0gc3ByaXRlQmF0Y2guY2hpbGRyZW47XG4gICAgdmFyIHNwcml0ZSA9IGNoaWxkcmVuWzBdO1xuXG4gICAgLy8gaWYgdGhlIHV2cyBoYXZlIG5vdCB1cGRhdGVkIHRoZW4gbm8gcG9pbnQgcmVuZGVyaW5nIGp1c3QgeWV0IVxuXG4gICAgLy8gY2hlY2sgdGV4dHVyZS5cbiAgICBpZiAoIXNwcml0ZS50ZXh0dXJlLl91dnMpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuY3VycmVudEJhc2VUZXh0dXJlID0gc3ByaXRlLnRleHR1cmUuYmFzZVRleHR1cmU7XG5cbiAgICAvLyBjaGVjayBibGVuZCBtb2RlXG4gICAgaWYgKHNwcml0ZS5ibGVuZE1vZGUgIT09IHRoaXMucmVuZGVyZXIuYmxlbmRNb2RlTWFuYWdlci5jdXJyZW50QmxlbmRNb2RlKSB7XG4gICAgICAgIHRoaXMuZmx1c2goKTtcbiAgICAgICAgdGhpcy5yZW5kZXJlci5ibGVuZE1vZGVNYW5hZ2VyLnNldEJsZW5kTW9kZShzcHJpdGUuYmxlbmRNb2RlKTtcbiAgICB9XG5cbiAgICBmb3IgKHZhciBpPTAsaj0gY2hpbGRyZW4ubGVuZ3RoOyBpPGo7IGkrKykge1xuICAgICAgICB0aGlzLnJlbmRlclNwcml0ZShjaGlsZHJlbltpXSk7XG4gICAgfVxuXG4gICAgdGhpcy5mbHVzaCgpO1xufTtcblxuLyoqXG4gKiBAcGFyYW0gc3ByaXRlIHtTcHJpdGV9IFRoZSBTcHJpdGUgdG8gcmVuZGVyLlxuICovXG5XZWJHTEZhc3RTcHJpdGVCYXRjaC5wcm90b3R5cGUucmVuZGVyU3ByaXRlID0gZnVuY3Rpb24gKHNwcml0ZSkge1xuICAgIC8vc3ByaXRlID0gY2hpbGRyZW5baV07XG4gICAgaWYgKCFzcHJpdGUudmlzaWJsZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gVE9ETyB0cmltPz9cbiAgICBpZiAoc3ByaXRlLnRleHR1cmUuYmFzZVRleHR1cmUgIT09IHRoaXMuY3VycmVudEJhc2VUZXh0dXJlKSB7XG4gICAgICAgIHRoaXMuZmx1c2goKTtcbiAgICAgICAgdGhpcy5jdXJyZW50QmFzZVRleHR1cmUgPSBzcHJpdGUudGV4dHVyZS5iYXNlVGV4dHVyZTtcblxuICAgICAgICBpZiAoIXNwcml0ZS50ZXh0dXJlLl91dnMpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHZhciB1dnMsIHZlcnRpY2VzID0gdGhpcy52ZXJ0aWNlcywgd2lkdGgsIGhlaWdodCwgdzAsIHcxLCBoMCwgaDEsIGluZGV4O1xuXG4gICAgdXZzID0gc3ByaXRlLnRleHR1cmUuX3V2cztcblxuICAgIHdpZHRoID0gc3ByaXRlLnRleHR1cmUuZnJhbWUud2lkdGg7XG4gICAgaGVpZ2h0ID0gc3ByaXRlLnRleHR1cmUuZnJhbWUuaGVpZ2h0O1xuXG4gICAgaWYgKHNwcml0ZS50ZXh0dXJlLnRyaW0pIHtcbiAgICAgICAgLy8gaWYgdGhlIHNwcml0ZSBpcyB0cmltbWVkIHRoZW4gd2UgbmVlZCB0byBhZGQgdGhlIGV4dHJhIHNwYWNlIGJlZm9yZSB0cmFuc2Zvcm1pbmcgdGhlIHNwcml0ZSBjb29yZHMuLlxuICAgICAgICB2YXIgdHJpbSA9IHNwcml0ZS50ZXh0dXJlLnRyaW07XG5cbiAgICAgICAgdzEgPSB0cmltLnggLSBzcHJpdGUuYW5jaG9yLnggKiB0cmltLndpZHRoO1xuICAgICAgICB3MCA9IHcxICsgc3ByaXRlLnRleHR1cmUuY3JvcC53aWR0aDtcblxuICAgICAgICBoMSA9IHRyaW0ueSAtIHNwcml0ZS5hbmNob3IueSAqIHRyaW0uaGVpZ2h0O1xuICAgICAgICBoMCA9IGgxICsgc3ByaXRlLnRleHR1cmUuY3JvcC5oZWlnaHQ7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB3MCA9IChzcHJpdGUudGV4dHVyZS5mcmFtZS53aWR0aCApICogKDEtc3ByaXRlLmFuY2hvci54KTtcbiAgICAgICAgdzEgPSAoc3ByaXRlLnRleHR1cmUuZnJhbWUud2lkdGggKSAqIC1zcHJpdGUuYW5jaG9yLng7XG5cbiAgICAgICAgaDAgPSBzcHJpdGUudGV4dHVyZS5mcmFtZS5oZWlnaHQgKiAoMS1zcHJpdGUuYW5jaG9yLnkpO1xuICAgICAgICBoMSA9IHNwcml0ZS50ZXh0dXJlLmZyYW1lLmhlaWdodCAqIC1zcHJpdGUuYW5jaG9yLnk7XG4gICAgfVxuXG4gICAgaW5kZXggPSB0aGlzLmN1cnJlbnRCYXRjaFNpemUgKiA0ICogdGhpcy52ZXJ0U2l6ZTtcblxuICAgIC8vIHh5XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB3MTtcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IGgxO1xuXG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUucG9zaXRpb24ueDtcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5wb3NpdGlvbi55O1xuXG4gICAgLy9zY2FsZVxuICAgIHZlcnRpY2VzW2luZGV4KytdID0gc3ByaXRlLnNjYWxlLng7XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUuc2NhbGUueTtcblxuICAgIC8vcm90YXRpb25cbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5yb3RhdGlvbjtcblxuICAgIC8vIHV2XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB1dnMueDA7XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB1dnMueTE7XG4gICAgLy8gY29sb3JcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5hbHBoYTtcblxuXG4gICAgLy8geHlcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHcwO1xuICAgIHZlcnRpY2VzW2luZGV4KytdID0gaDE7XG5cbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5wb3NpdGlvbi54O1xuICAgIHZlcnRpY2VzW2luZGV4KytdID0gc3ByaXRlLnBvc2l0aW9uLnk7XG5cbiAgICAvL3NjYWxlXG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUuc2NhbGUueDtcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5zY2FsZS55O1xuXG4gICAgIC8vcm90YXRpb25cbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5yb3RhdGlvbjtcblxuICAgIC8vIHV2XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB1dnMueDE7XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB1dnMueTE7XG4gICAgLy8gY29sb3JcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5hbHBoYTtcblxuXG4gICAgLy8geHlcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHcwO1xuICAgIHZlcnRpY2VzW2luZGV4KytdID0gaDA7XG5cbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5wb3NpdGlvbi54O1xuICAgIHZlcnRpY2VzW2luZGV4KytdID0gc3ByaXRlLnBvc2l0aW9uLnk7XG5cbiAgICAvL3NjYWxlXG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUuc2NhbGUueDtcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5zY2FsZS55O1xuXG4gICAgIC8vcm90YXRpb25cbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5yb3RhdGlvbjtcblxuICAgIC8vIHV2XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB1dnMueDI7XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB1dnMueTI7XG4gICAgLy8gY29sb3JcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5hbHBoYTtcblxuXG5cblxuICAgIC8vIHh5XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB3MTtcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IGgwO1xuXG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUucG9zaXRpb24ueDtcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5wb3NpdGlvbi55O1xuXG4gICAgLy9zY2FsZVxuICAgIHZlcnRpY2VzW2luZGV4KytdID0gc3ByaXRlLnNjYWxlLng7XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUuc2NhbGUueTtcblxuICAgICAvL3JvdGF0aW9uXG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUucm90YXRpb247XG5cbiAgICAvLyB1dlxuICAgIHZlcnRpY2VzW2luZGV4KytdID0gdXZzLngzO1xuICAgIHZlcnRpY2VzW2luZGV4KytdID0gdXZzLnkzO1xuICAgIC8vIGNvbG9yXG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUuYWxwaGE7XG5cbiAgICAvLyBpbmNyZW1lbnQgdGhlIGJhdGNoc1xuICAgIHRoaXMuY3VycmVudEJhdGNoU2l6ZSsrO1xuXG4gICAgaWYgKHRoaXMuY3VycmVudEJhdGNoU2l6ZSA+PSB0aGlzLnNpemUpIHtcbiAgICAgICAgdGhpcy5mbHVzaCgpO1xuICAgIH1cbn07XG5cbi8qKlxuICpcbiAqL1xuV2ViR0xGYXN0U3ByaXRlQmF0Y2gucHJvdG90eXBlLmZsdXNoID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIElmIHRoZSBiYXRjaCBpcyBsZW5ndGggMCB0aGVuIHJldHVybiBhcyB0aGVyZSBpcyBub3RoaW5nIHRvIGRyYXdcbiAgICBpZiAodGhpcy5jdXJyZW50QmF0Y2hTaXplID09PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuXG4gICAgLy8gYmluZCB0aGUgY3VycmVudCB0ZXh0dXJlXG4gICAgaWYgKCF0aGlzLmN1cnJlbnRCYXNlVGV4dHVyZS5fZ2xUZXh0dXJlc1tnbC5pZF0pIHtcbiAgICAgICAgdGhpcy5yZW5kZXJlci51cGRhdGVUZXh0dXJlKHRoaXMuY3VycmVudEJhc2VUZXh0dXJlLCBnbCk7XG4gICAgfVxuICAgIC8vVE9ETy1TSE9VRCBUSElTIEJFIEVMU0U/PyE/IT8hXG4gICAgZWxzZSB7XG4gICAgICAgIGdsLmJpbmRUZXh0dXJlKGdsLlRFWFRVUkVfMkQsIHRoaXMuY3VycmVudEJhc2VUZXh0dXJlLl9nbFRleHR1cmVzW2dsLmlkXSk7XG4gICAgfVxuXG4gICAgLy8gdXBsb2FkIHRoZSB2ZXJ0cyB0byB0aGUgYnVmZmVyXG5cbiAgICBpZiAodGhpcy5jdXJyZW50QmF0Y2hTaXplID4gKCB0aGlzLnNpemUgKiAwLjUgKSApIHtcbiAgICAgICAgZ2wuYnVmZmVyU3ViRGF0YShnbC5BUlJBWV9CVUZGRVIsIDAsIHRoaXMudmVydGljZXMpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdmFyIHZpZXcgPSB0aGlzLnZlcnRpY2VzLnN1YmFycmF5KDAsIHRoaXMuY3VycmVudEJhdGNoU2l6ZSAqIDQgKiB0aGlzLnZlcnRTaXplKTtcblxuICAgICAgICBnbC5idWZmZXJTdWJEYXRhKGdsLkFSUkFZX0JVRkZFUiwgMCwgdmlldyk7XG4gICAgfVxuXG4gICAgLy8gbm93IGRyYXcgdGhvc2Ugc3Vja2FzIVxuICAgIGdsLmRyYXdFbGVtZW50cyhnbC5UUklBTkdMRVMsIHRoaXMuY3VycmVudEJhdGNoU2l6ZSAqIDYsIGdsLlVOU0lHTkVEX1NIT1JULCAwKTtcblxuICAgIC8vIHRoZW4gcmVzZXQgdGhlIGJhdGNoIVxuICAgIHRoaXMuY3VycmVudEJhdGNoU2l6ZSA9IDA7XG5cbiAgICAvLyBpbmNyZW1lbnQgdGhlIGRyYXcgY291bnRcbiAgICB0aGlzLnJlbmRlcmVyLmRyYXdDb3VudCsrO1xufTtcblxuXG4vKipcbiAqIEVuZHMgdGhlIGJhdGNoIGFuZCBmbHVzaGVzXG4gKlxuICovXG5XZWJHTEZhc3RTcHJpdGVCYXRjaC5wcm90b3R5cGUuc3RvcCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmZsdXNoKCk7XG59O1xuXG4vKipcbiAqXG4gKi9cbldlYkdMRmFzdFNwcml0ZUJhdGNoLnByb3RvdHlwZS5zdGFydCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuXG4gICAgLy8gYmluZCB0aGUgbWFpbiB0ZXh0dXJlXG4gICAgZ2wuYWN0aXZlVGV4dHVyZShnbC5URVhUVVJFMCk7XG5cbiAgICAvLyBiaW5kIHRoZSBidWZmZXJzXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMudmVydGV4QnVmZmVyKTtcbiAgICBnbC5iaW5kQnVmZmVyKGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCB0aGlzLmluZGV4QnVmZmVyKTtcblxuICAgIC8vIHNldCB0aGUgcHJvamVjdGlvblxuICAgIHZhciBwcm9qZWN0aW9uID0gdGhpcy5yZW5kZXJlci5wcm9qZWN0aW9uO1xuICAgIGdsLnVuaWZvcm0yZih0aGlzLnNoYWRlci5wcm9qZWN0aW9uVmVjdG9yLCBwcm9qZWN0aW9uLngsIHByb2plY3Rpb24ueSk7XG5cbiAgICAvLyBzZXQgdGhlIG1hdHJpeFxuICAgIGdsLnVuaWZvcm1NYXRyaXgzZnYodGhpcy5zaGFkZXIudU1hdHJpeCwgZmFsc2UsIHRoaXMubWF0cml4KTtcblxuICAgIC8vIHNldCB0aGUgcG9pbnRlcnNcbiAgICB2YXIgc3RyaWRlID0gIHRoaXMudmVydFNpemUgKiA0O1xuXG4gICAgZ2wudmVydGV4QXR0cmliUG9pbnRlcih0aGlzLnNoYWRlci5hdHRyaWJ1dGVzLmFWZXJ0ZXhQb3NpdGlvbiwgMiwgZ2wuRkxPQVQsIGZhbHNlLCBzdHJpZGUsIDApO1xuICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIodGhpcy5zaGFkZXIuYXR0cmlidXRlcy5hUG9zaXRpb25Db29yZCwgMiwgZ2wuRkxPQVQsIGZhbHNlLCBzdHJpZGUsIDIgKiA0KTtcbiAgICBnbC52ZXJ0ZXhBdHRyaWJQb2ludGVyKHRoaXMuc2hhZGVyLmF0dHJpYnV0ZXMuYVNjYWxlLCAyLCBnbC5GTE9BVCwgZmFsc2UsIHN0cmlkZSwgNCAqIDQpO1xuICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIodGhpcy5zaGFkZXIuYXR0cmlidXRlcy5hUm90YXRpb24sIDEsIGdsLkZMT0FULCBmYWxzZSwgc3RyaWRlLCA2ICogNCk7XG4gICAgZ2wudmVydGV4QXR0cmliUG9pbnRlcih0aGlzLnNoYWRlci5hdHRyaWJ1dGVzLmFUZXh0dXJlQ29vcmQsIDIsIGdsLkZMT0FULCBmYWxzZSwgc3RyaWRlLCA3ICogNCk7XG4gICAgZ2wudmVydGV4QXR0cmliUG9pbnRlcih0aGlzLnNoYWRlci5hdHRyaWJ1dGVzLmFDb2xvciwgMSwgZ2wuRkxPQVQsIGZhbHNlLCBzdHJpZGUsIDkgKiA0KTtcbn07XG4iLCJ2YXIgdXRpbHMgPSByZXF1aXJlKCcuLi8uLi8uLi91dGlscycpLFxuICAgIG1hdGggPSByZXF1aXJlKCcuLi8uLi8uLi9tYXRoJyksXG4gICAgQ09OU1QgPSByZXF1aXJlKCcuLi8uLi8uLi9jb25zdCcpLFxuICAgIFdlYkdMR3JhcGhpY3NEYXRhID0gcmVxdWlyZSgnLi9XZWJHTEdyYXBoaWNzRGF0YScpO1xuXG4vKipcbiAqIEEgc2V0IG9mIGZ1bmN0aW9ucyB1c2VkIGJ5IHRoZSB3ZWJHTCByZW5kZXJlciB0byBkcmF3IHRoZSBwcmltaXRpdmUgZ3JhcGhpY3MgZGF0YVxuICpcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHByaXZhdGVcbiAqL1xudmFyIFdlYkdMR3JhcGhpY3MgPSBtb2R1bGUuZXhwb3J0cyA9IHt9O1xuXG4vKipcbiAqIFJlbmRlcnMgdGhlIGdyYXBoaWNzIG9iamVjdFxuICpcbiAqIEBzdGF0aWNcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0gZ3JhcGhpY3Mge0dyYXBoaWNzfVxuICogQHBhcmFtIHJlbmRlcmVyIHtXZWJHTFJlbmRlcmVyfVxuICovXG5XZWJHTEdyYXBoaWNzLnJlbmRlckdyYXBoaWNzID0gZnVuY3Rpb24gKGdyYXBoaWNzLCByZW5kZXJlcikgey8vcHJvamVjdGlvbiwgb2Zmc2V0KSB7XG4gICAgdmFyIGdsID0gcmVuZGVyZXIuZ2w7XG5cbiAgICB2YXIgcHJvamVjdGlvbiA9IHJlbmRlcmVyLnByb2plY3Rpb24sXG4gICAgICAgIG9mZnNldCA9IHJlbmRlcmVyLm9mZnNldCxcbiAgICAgICAgc2hhZGVyID0gcmVuZGVyZXIuc2hhZGVyTWFuYWdlci5wcmltaXRpdmVTaGFkZXIsXG4gICAgICAgIHdlYkdMRGF0YTtcblxuICAgIGlmIChncmFwaGljcy5kaXJ0eSkge1xuICAgICAgICBXZWJHTEdyYXBoaWNzLnVwZGF0ZUdyYXBoaWNzKGdyYXBoaWNzLCBnbCk7XG4gICAgfVxuXG4gICAgdmFyIHdlYkdMID0gZ3JhcGhpY3MuX3dlYkdMW2dsLmlkXTtcblxuICAgIC8vIFRoaXMgIGNvdWxkIGJlIHNwZWVkZWQgdXAgZm9yIHN1cmUhXG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHdlYkdMLmRhdGEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaWYgKHdlYkdMLmRhdGFbaV0ubW9kZSA9PT0gMSkge1xuICAgICAgICAgICAgd2ViR0xEYXRhID0gd2ViR0wuZGF0YVtpXTtcblxuICAgICAgICAgICAgcmVuZGVyZXIuc3RlbmNpbE1hbmFnZXIucHVzaFN0ZW5jaWwoZ3JhcGhpY3MsIHdlYkdMRGF0YSwgcmVuZGVyZXIpO1xuXG4gICAgICAgICAgICAvLyByZW5kZXIgcXVhZC4uXG4gICAgICAgICAgICBnbC5kcmF3RWxlbWVudHMoZ2wuVFJJQU5HTEVfRkFOLCA0LCBnbC5VTlNJR05FRF9TSE9SVCwgKCB3ZWJHTERhdGEuaW5kaWNlcy5sZW5ndGggLSA0ICkgKiAyICk7XG5cbiAgICAgICAgICAgIHJlbmRlcmVyLnN0ZW5jaWxNYW5hZ2VyLnBvcFN0ZW5jaWwoZ3JhcGhpY3MsIHdlYkdMRGF0YSwgcmVuZGVyZXIpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgd2ViR0xEYXRhID0gd2ViR0wuZGF0YVtpXTtcblxuXG4gICAgICAgICAgICByZW5kZXJlci5zaGFkZXJNYW5hZ2VyLnNldFNoYWRlciggc2hhZGVyICk7Ly9hY3RpdmF0ZVByaW1pdGl2ZVNoYWRlcigpO1xuICAgICAgICAgICAgc2hhZGVyID0gcmVuZGVyZXIuc2hhZGVyTWFuYWdlci5wcmltaXRpdmVTaGFkZXI7XG4gICAgICAgICAgICBnbC51bmlmb3JtTWF0cml4M2Z2KHNoYWRlci50cmFuc2xhdGlvbk1hdHJpeCwgZmFsc2UsIGdyYXBoaWNzLndvcmxkVHJhbnNmb3JtLnRvQXJyYXkodHJ1ZSkpO1xuXG4gICAgICAgICAgICBnbC51bmlmb3JtMWYoc2hhZGVyLmZsaXBZLCAxKTtcblxuICAgICAgICAgICAgZ2wudW5pZm9ybTJmKHNoYWRlci5wcm9qZWN0aW9uVmVjdG9yLCBwcm9qZWN0aW9uLngsIC1wcm9qZWN0aW9uLnkpO1xuICAgICAgICAgICAgZ2wudW5pZm9ybTJmKHNoYWRlci5vZmZzZXRWZWN0b3IsIC1vZmZzZXQueCwgLW9mZnNldC55KTtcblxuICAgICAgICAgICAgZ2wudW5pZm9ybTNmdihzaGFkZXIudGludENvbG9yLCB1dGlscy5oZXgycmdiKGdyYXBoaWNzLnRpbnQpKTtcblxuICAgICAgICAgICAgZ2wudW5pZm9ybTFmKHNoYWRlci5hbHBoYSwgZ3JhcGhpY3Mud29ybGRBbHBoYSk7XG5cblxuICAgICAgICAgICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHdlYkdMRGF0YS5idWZmZXIpO1xuXG4gICAgICAgICAgICBnbC52ZXJ0ZXhBdHRyaWJQb2ludGVyKHNoYWRlci5hVmVydGV4UG9zaXRpb24sIDIsIGdsLkZMT0FULCBmYWxzZSwgNCAqIDYsIDApO1xuICAgICAgICAgICAgZ2wudmVydGV4QXR0cmliUG9pbnRlcihzaGFkZXIuYUNvbG9yLCA0LCBnbC5GTE9BVCwgZmFsc2UsNCAqIDYsIDIgKiA0KTtcblxuICAgICAgICAgICAgLy8gc2V0IHRoZSBpbmRleCBidWZmZXIhXG4gICAgICAgICAgICBnbC5iaW5kQnVmZmVyKGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCB3ZWJHTERhdGEuaW5kZXhCdWZmZXIpO1xuICAgICAgICAgICAgZ2wuZHJhd0VsZW1lbnRzKGdsLlRSSUFOR0xFX1NUUklQLCAgd2ViR0xEYXRhLmluZGljZXMubGVuZ3RoLCBnbC5VTlNJR05FRF9TSE9SVCwgMCApO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuLyoqXG4gKiBVcGRhdGVzIHRoZSBncmFwaGljcyBvYmplY3RcbiAqXG4gKiBAc3RhdGljXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIGdyYXBoaWNzRGF0YSB7R3JhcGhpY3N9IFRoZSBncmFwaGljcyBvYmplY3QgdG8gdXBkYXRlXG4gKiBAcGFyYW0gZ2wge1dlYkdMQ29udGV4dH0gdGhlIGN1cnJlbnQgV2ViR0wgZHJhd2luZyBjb250ZXh0XG4gKi9cbldlYkdMR3JhcGhpY3MudXBkYXRlR3JhcGhpY3MgPSBmdW5jdGlvbiAoZ3JhcGhpY3MsIGdsKSB7XG4gICAgLy8gZ2V0IHRoZSBjb250ZXh0cyBncmFwaGljcyBvYmplY3RcbiAgICB2YXIgd2ViR0wgPSBncmFwaGljcy5fd2ViR0xbZ2wuaWRdO1xuXG4gICAgLy8gaWYgdGhlIGdyYXBoaWNzIG9iamVjdCBkb2VzIG5vdCBleGlzdCBpbiB0aGUgd2ViR0wgY29udGV4dCB0aW1lIHRvIGNyZWF0ZSBpdCFcbiAgICBpZiAoIXdlYkdMKSB7XG4gICAgICAgIHdlYkdMID0gZ3JhcGhpY3MuX3dlYkdMW2dsLmlkXSA9IHtsYXN0SW5kZXg6MCwgZGF0YTpbXSwgZ2w6Z2x9O1xuICAgIH1cblxuICAgIC8vIGZsYWcgdGhlIGdyYXBoaWNzIGFzIG5vdCBkaXJ0eSBhcyB3ZSBhcmUgYWJvdXQgdG8gdXBkYXRlIGl0Li4uXG4gICAgZ3JhcGhpY3MuZGlydHkgPSBmYWxzZTtcblxuICAgIHZhciBpO1xuXG4gICAgLy8gaWYgdGhlIHVzZXIgY2xlYXJlZCB0aGUgZ3JhcGhpY3Mgb2JqZWN0IHdlIHdpbGwgbmVlZCB0byBjbGVhciBldmVyeSBvYmplY3RcbiAgICBpZiAoZ3JhcGhpY3MuY2xlYXJEaXJ0eSkge1xuICAgICAgICBncmFwaGljcy5jbGVhckRpcnR5ID0gZmFsc2U7XG5cbiAgICAgICAgLy8gbG9wIHRocm91Z2ggYW5kIHJldHVybiBhbGwgdGhlIHdlYkdMRGF0YXMgdG8gdGhlIG9iamVjdCBwb29sIHNvIHRoYW4gY2FuIGJlIHJldXNlZCBsYXRlciBvblxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgd2ViR0wuZGF0YS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIGdyYXBoaWNzRGF0YSA9IHdlYkdMLmRhdGFbaV07XG4gICAgICAgICAgICBncmFwaGljc0RhdGEucmVzZXQoKTtcbiAgICAgICAgICAgIFdlYkdMR3JhcGhpY3MuZ3JhcGhpY3NEYXRhUG9vbC5wdXNoKCBncmFwaGljc0RhdGEgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGNsZWFyIHRoZSBhcnJheSBhbmQgcmVzZXQgdGhlIGluZGV4Li5cbiAgICAgICAgd2ViR0wuZGF0YSA9IFtdO1xuICAgICAgICB3ZWJHTC5sYXN0SW5kZXggPSAwO1xuICAgIH1cblxuICAgIHZhciB3ZWJHTERhdGE7XG5cbiAgICAvLyBsb29wIHRocm91Z2ggdGhlIGdyYXBoaWNzIGRhdGFzIGFuZCBjb25zdHJ1Y3QgZWFjaCBvbmUuLlxuICAgIC8vIGlmIHRoZSBvYmplY3QgaXMgYSBjb21wbGV4IGZpbGwgdGhlbiB0aGUgbmV3IHN0ZW5jaWwgYnVmZmVyIHRlY2huaXF1ZSB3aWxsIGJlIHVzZWRcbiAgICAvLyBvdGhlciB3aXNlIGdyYXBoaWNzIG9iamVjdHMgd2lsbCBiZSBwdXNoZWQgaW50byBhIGJhdGNoLi5cbiAgICBmb3IgKGkgPSB3ZWJHTC5sYXN0SW5kZXg7IGkgPCBncmFwaGljcy5ncmFwaGljc0RhdGEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGRhdGEgPSBncmFwaGljcy5ncmFwaGljc0RhdGFbaV07XG5cbiAgICAgICAgaWYgKGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLlBPTFkpIHtcbiAgICAgICAgICAgIC8vIG5lZWQgdG8gYWRkIHRoZSBwb2ludHMgdGhlIHRoZSBncmFwaGljcyBvYmplY3QuLlxuICAgICAgICAgICAgZGF0YS5wb2ludHMgPSBkYXRhLnNoYXBlLnBvaW50cy5zbGljZSgpO1xuICAgICAgICAgICAgaWYgKGRhdGEuc2hhcGUuY2xvc2VkKSB7XG4gICAgICAgICAgICAgICAgLy8gY2xvc2UgdGhlIHBvbHkgaWYgdGhlIHZhbHVlIGlzIHRydWUhXG4gICAgICAgICAgICAgICAgaWYgKGRhdGEucG9pbnRzWzBdICE9PSBkYXRhLnBvaW50c1tkYXRhLnBvaW50cy5sZW5ndGgtMl0gfHwgZGF0YS5wb2ludHNbMV0gIT09IGRhdGEucG9pbnRzW2RhdGEucG9pbnRzLmxlbmd0aC0xXSkge1xuICAgICAgICAgICAgICAgICAgICBkYXRhLnBvaW50cy5wdXNoKGRhdGEucG9pbnRzWzBdLCBkYXRhLnBvaW50c1sxXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBNQUtFIFNVUkUgV0UgSEFWRSBUSEUgQ09SUkVDVCBUWVBFLi5cbiAgICAgICAgICAgIGlmIChkYXRhLmZpbGwpIHtcbiAgICAgICAgICAgICAgICBpZiAoZGF0YS5wb2ludHMubGVuZ3RoID49IDYpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGRhdGEucG9pbnRzLmxlbmd0aCA8IDYgKiAyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB3ZWJHTERhdGEgPSBXZWJHTEdyYXBoaWNzLnN3aXRjaE1vZGUod2ViR0wsIDApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgY2FuRHJhd1VzaW5nU2ltcGxlID0gV2ViR0xHcmFwaGljcy5idWlsZFBvbHkoZGF0YSwgd2ViR0xEYXRhKTtcbiAgICAgICAgICAgICAgICAgICAvLyAgICAgY29uc29sZS5sb2coY2FuRHJhd1VzaW5nU2ltcGxlKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFjYW5EcmF3VXNpbmdTaW1wbGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgIGNvbnNvbGUubG9nKFwiPD4+PlwiKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdlYkdMRGF0YSA9IFdlYkdMR3JhcGhpY3Muc3dpdGNoTW9kZSh3ZWJHTCwgMSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgV2ViR0xHcmFwaGljcy5idWlsZENvbXBsZXhQb2x5KGRhdGEsIHdlYkdMRGF0YSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdlYkdMRGF0YSA9IFdlYkdMR3JhcGhpY3Muc3dpdGNoTW9kZSh3ZWJHTCwgMSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBXZWJHTEdyYXBoaWNzLmJ1aWxkQ29tcGxleFBvbHkoZGF0YSwgd2ViR0xEYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGRhdGEubGluZVdpZHRoID4gMCkge1xuICAgICAgICAgICAgICAgIHdlYkdMRGF0YSA9IFdlYkdMR3JhcGhpY3Muc3dpdGNoTW9kZSh3ZWJHTCwgMCk7XG4gICAgICAgICAgICAgICAgV2ViR0xHcmFwaGljcy5idWlsZExpbmUoZGF0YSwgd2ViR0xEYXRhKTtcblxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgd2ViR0xEYXRhID0gV2ViR0xHcmFwaGljcy5zd2l0Y2hNb2RlKHdlYkdMLCAwKTtcblxuICAgICAgICAgICAgaWYgKGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLlJFQ1QpIHtcbiAgICAgICAgICAgICAgICBXZWJHTEdyYXBoaWNzLmJ1aWxkUmVjdGFuZ2xlKGRhdGEsIHdlYkdMRGF0YSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChkYXRhLnR5cGUgPT09IENPTlNULlNIQVBFUy5DSVJDIHx8IGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLkVMSVApIHtcbiAgICAgICAgICAgICAgICBXZWJHTEdyYXBoaWNzLmJ1aWxkQ2lyY2xlKGRhdGEsIHdlYkdMRGF0YSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChkYXRhLnR5cGUgPT09IENPTlNULlNIQVBFUy5SUkVDKSB7XG4gICAgICAgICAgICAgICAgV2ViR0xHcmFwaGljcy5idWlsZFJvdW5kZWRSZWN0YW5nbGUoZGF0YSwgd2ViR0xEYXRhKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHdlYkdMLmxhc3RJbmRleCsrO1xuICAgIH1cblxuICAgIC8vIHVwbG9hZCBhbGwgdGhlIGRpcnR5IGRhdGEuLi5cbiAgICBmb3IgKGkgPSAwOyBpIDwgd2ViR0wuZGF0YS5sZW5ndGg7IGkrKykge1xuICAgICAgICB3ZWJHTERhdGEgPSB3ZWJHTC5kYXRhW2ldO1xuXG4gICAgICAgIGlmICh3ZWJHTERhdGEuZGlydHkpIHtcbiAgICAgICAgICAgIHdlYkdMRGF0YS51cGxvYWQoKTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cbi8qKlxuICogQHN0YXRpY1xuICogQHByaXZhdGVcbiAqIEBwYXJhbSB3ZWJHTCB7V2ViR0xDb250ZXh0fVxuICogQHBhcmFtIHR5cGUge251bWJlcn1cbiAqL1xuV2ViR0xHcmFwaGljcy5zd2l0Y2hNb2RlID0gZnVuY3Rpb24gKHdlYkdMLCB0eXBlKSB7XG4gICAgdmFyIHdlYkdMRGF0YTtcblxuICAgIGlmICghd2ViR0wuZGF0YS5sZW5ndGgpIHtcbiAgICAgICAgd2ViR0xEYXRhID0gV2ViR0xHcmFwaGljcy5ncmFwaGljc0RhdGFQb29sLnBvcCgpIHx8IG5ldyBXZWJHTEdyYXBoaWNzRGF0YSh3ZWJHTC5nbCk7XG4gICAgICAgIHdlYkdMRGF0YS5tb2RlID0gdHlwZTtcbiAgICAgICAgd2ViR0wuZGF0YS5wdXNoKHdlYkdMRGF0YSk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB3ZWJHTERhdGEgPSB3ZWJHTC5kYXRhW3dlYkdMLmRhdGEubGVuZ3RoLTFdO1xuXG4gICAgICAgIGlmICh3ZWJHTERhdGEubW9kZSAhPT0gdHlwZSB8fCB0eXBlID09PSAxKSB7XG4gICAgICAgICAgICB3ZWJHTERhdGEgPSBXZWJHTEdyYXBoaWNzLmdyYXBoaWNzRGF0YVBvb2wucG9wKCkgfHwgbmV3IFdlYkdMR3JhcGhpY3NEYXRhKHdlYkdMLmdsKTtcbiAgICAgICAgICAgIHdlYkdMRGF0YS5tb2RlID0gdHlwZTtcbiAgICAgICAgICAgIHdlYkdMLmRhdGEucHVzaCh3ZWJHTERhdGEpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgd2ViR0xEYXRhLmRpcnR5ID0gdHJ1ZTtcblxuICAgIHJldHVybiB3ZWJHTERhdGE7XG59O1xuXG4vKipcbiAqIEJ1aWxkcyBhIHJlY3RhbmdsZSB0byBkcmF3XG4gKlxuICogQHN0YXRpY1xuICogQHByaXZhdGVcbiAqIEBwYXJhbSBncmFwaGljc0RhdGEge0dyYXBoaWNzfSBUaGUgZ3JhcGhpY3Mgb2JqZWN0IGNvbnRhaW5pbmcgYWxsIHRoZSBuZWNlc3NhcnkgcHJvcGVydGllc1xuICogQHBhcmFtIHdlYkdMRGF0YSB7b2JqZWN0fVxuICovXG5XZWJHTEdyYXBoaWNzLmJ1aWxkUmVjdGFuZ2xlID0gZnVuY3Rpb24gKGdyYXBoaWNzRGF0YSwgd2ViR0xEYXRhKSB7XG4gICAgLy8gLS0tIC8vXG4gICAgLy8gbmVlZCB0byBjb252ZXJ0IHBvaW50cyB0byBhIG5pY2UgcmVndWxhciBkYXRhXG4gICAgLy9cbiAgICB2YXIgcmVjdERhdGEgPSBncmFwaGljc0RhdGEuc2hhcGU7XG4gICAgdmFyIHggPSByZWN0RGF0YS54O1xuICAgIHZhciB5ID0gcmVjdERhdGEueTtcbiAgICB2YXIgd2lkdGggPSByZWN0RGF0YS53aWR0aDtcbiAgICB2YXIgaGVpZ2h0ID0gcmVjdERhdGEuaGVpZ2h0O1xuXG4gICAgaWYgKGdyYXBoaWNzRGF0YS5maWxsKSB7XG4gICAgICAgIHZhciBjb2xvciA9IHV0aWxzLmhleDJyZ2IoZ3JhcGhpY3NEYXRhLmZpbGxDb2xvcik7XG4gICAgICAgIHZhciBhbHBoYSA9IGdyYXBoaWNzRGF0YS5maWxsQWxwaGE7XG5cbiAgICAgICAgdmFyIHIgPSBjb2xvclswXSAqIGFscGhhO1xuICAgICAgICB2YXIgZyA9IGNvbG9yWzFdICogYWxwaGE7XG4gICAgICAgIHZhciBiID0gY29sb3JbMl0gKiBhbHBoYTtcblxuICAgICAgICB2YXIgdmVydHMgPSB3ZWJHTERhdGEucG9pbnRzO1xuICAgICAgICB2YXIgaW5kaWNlcyA9IHdlYkdMRGF0YS5pbmRpY2VzO1xuXG4gICAgICAgIHZhciB2ZXJ0UG9zID0gdmVydHMubGVuZ3RoLzY7XG5cbiAgICAgICAgLy8gc3RhcnRcbiAgICAgICAgdmVydHMucHVzaCh4LCB5KTtcbiAgICAgICAgdmVydHMucHVzaChyLCBnLCBiLCBhbHBoYSk7XG5cbiAgICAgICAgdmVydHMucHVzaCh4ICsgd2lkdGgsIHkpO1xuICAgICAgICB2ZXJ0cy5wdXNoKHIsIGcsIGIsIGFscGhhKTtcblxuICAgICAgICB2ZXJ0cy5wdXNoKHggLCB5ICsgaGVpZ2h0KTtcbiAgICAgICAgdmVydHMucHVzaChyLCBnLCBiLCBhbHBoYSk7XG5cbiAgICAgICAgdmVydHMucHVzaCh4ICsgd2lkdGgsIHkgKyBoZWlnaHQpO1xuICAgICAgICB2ZXJ0cy5wdXNoKHIsIGcsIGIsIGFscGhhKTtcblxuICAgICAgICAvLyBpbnNlcnQgMiBkZWFkIHRyaWFuZ2xlcy4uXG4gICAgICAgIGluZGljZXMucHVzaCh2ZXJ0UG9zLCB2ZXJ0UG9zLCB2ZXJ0UG9zKzEsIHZlcnRQb3MrMiwgdmVydFBvcyszLCB2ZXJ0UG9zKzMpO1xuICAgIH1cblxuICAgIGlmIChncmFwaGljc0RhdGEubGluZVdpZHRoKSB7XG4gICAgICAgIHZhciB0ZW1wUG9pbnRzID0gZ3JhcGhpY3NEYXRhLnBvaW50cztcblxuICAgICAgICBncmFwaGljc0RhdGEucG9pbnRzID0gW3gsIHksXG4gICAgICAgICAgICAgICAgICB4ICsgd2lkdGgsIHksXG4gICAgICAgICAgICAgICAgICB4ICsgd2lkdGgsIHkgKyBoZWlnaHQsXG4gICAgICAgICAgICAgICAgICB4LCB5ICsgaGVpZ2h0LFxuICAgICAgICAgICAgICAgICAgeCwgeV07XG5cblxuICAgICAgICBXZWJHTEdyYXBoaWNzLmJ1aWxkTGluZShncmFwaGljc0RhdGEsIHdlYkdMRGF0YSk7XG5cbiAgICAgICAgZ3JhcGhpY3NEYXRhLnBvaW50cyA9IHRlbXBQb2ludHM7XG4gICAgfVxufTtcblxuLyoqXG4gKiBCdWlsZHMgYSByb3VuZGVkIHJlY3RhbmdsZSB0byBkcmF3XG4gKlxuICogQHN0YXRpY1xuICogQHByaXZhdGVcbiAqIEBwYXJhbSBncmFwaGljc0RhdGEge0dyYXBoaWNzfSBUaGUgZ3JhcGhpY3Mgb2JqZWN0IGNvbnRhaW5pbmcgYWxsIHRoZSBuZWNlc3NhcnkgcHJvcGVydGllc1xuICogQHBhcmFtIHdlYkdMRGF0YSB7b2JqZWN0fVxuICovXG5XZWJHTEdyYXBoaWNzLmJ1aWxkUm91bmRlZFJlY3RhbmdsZSA9IGZ1bmN0aW9uIChncmFwaGljc0RhdGEsIHdlYkdMRGF0YSkge1xuICAgIHZhciBycmVjdERhdGEgPSBncmFwaGljc0RhdGEuc2hhcGU7XG4gICAgdmFyIHggPSBycmVjdERhdGEueDtcbiAgICB2YXIgeSA9IHJyZWN0RGF0YS55O1xuICAgIHZhciB3aWR0aCA9IHJyZWN0RGF0YS53aWR0aDtcbiAgICB2YXIgaGVpZ2h0ID0gcnJlY3REYXRhLmhlaWdodDtcblxuICAgIHZhciByYWRpdXMgPSBycmVjdERhdGEucmFkaXVzO1xuXG4gICAgdmFyIHJlY1BvaW50cyA9IFtdO1xuICAgIHJlY1BvaW50cy5wdXNoKHgsIHkgKyByYWRpdXMpO1xuICAgIHJlY1BvaW50cyA9IHJlY1BvaW50cy5jb25jYXQoV2ViR0xHcmFwaGljcy5xdWFkcmF0aWNCZXppZXJDdXJ2ZSh4LCB5ICsgaGVpZ2h0IC0gcmFkaXVzLCB4LCB5ICsgaGVpZ2h0LCB4ICsgcmFkaXVzLCB5ICsgaGVpZ2h0KSk7XG4gICAgcmVjUG9pbnRzID0gcmVjUG9pbnRzLmNvbmNhdChXZWJHTEdyYXBoaWNzLnF1YWRyYXRpY0JlemllckN1cnZlKHggKyB3aWR0aCAtIHJhZGl1cywgeSArIGhlaWdodCwgeCArIHdpZHRoLCB5ICsgaGVpZ2h0LCB4ICsgd2lkdGgsIHkgKyBoZWlnaHQgLSByYWRpdXMpKTtcbiAgICByZWNQb2ludHMgPSByZWNQb2ludHMuY29uY2F0KFdlYkdMR3JhcGhpY3MucXVhZHJhdGljQmV6aWVyQ3VydmUoeCArIHdpZHRoLCB5ICsgcmFkaXVzLCB4ICsgd2lkdGgsIHksIHggKyB3aWR0aCAtIHJhZGl1cywgeSkpO1xuICAgIHJlY1BvaW50cyA9IHJlY1BvaW50cy5jb25jYXQoV2ViR0xHcmFwaGljcy5xdWFkcmF0aWNCZXppZXJDdXJ2ZSh4ICsgcmFkaXVzLCB5LCB4LCB5LCB4LCB5ICsgcmFkaXVzKSk7XG5cbiAgICBpZiAoZ3JhcGhpY3NEYXRhLmZpbGwpIHtcbiAgICAgICAgdmFyIGNvbG9yID0gdXRpbHMuaGV4MnJnYihncmFwaGljc0RhdGEuZmlsbENvbG9yKTtcbiAgICAgICAgdmFyIGFscGhhID0gZ3JhcGhpY3NEYXRhLmZpbGxBbHBoYTtcblxuICAgICAgICB2YXIgciA9IGNvbG9yWzBdICogYWxwaGE7XG4gICAgICAgIHZhciBnID0gY29sb3JbMV0gKiBhbHBoYTtcbiAgICAgICAgdmFyIGIgPSBjb2xvclsyXSAqIGFscGhhO1xuXG4gICAgICAgIHZhciB2ZXJ0cyA9IHdlYkdMRGF0YS5wb2ludHM7XG4gICAgICAgIHZhciBpbmRpY2VzID0gd2ViR0xEYXRhLmluZGljZXM7XG5cbiAgICAgICAgdmFyIHZlY1BvcyA9IHZlcnRzLmxlbmd0aC82O1xuXG4gICAgICAgIHZhciB0cmlhbmdsZXMgPSB1dGlscy5Qb2x5Sy5Ucmlhbmd1bGF0ZShyZWNQb2ludHMpO1xuXG4gICAgICAgIC8vXG5cbiAgICAgICAgdmFyIGkgPSAwO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdHJpYW5nbGVzLmxlbmd0aDsgaSs9Mykge1xuICAgICAgICAgICAgaW5kaWNlcy5wdXNoKHRyaWFuZ2xlc1tpXSArIHZlY1Bvcyk7XG4gICAgICAgICAgICBpbmRpY2VzLnB1c2godHJpYW5nbGVzW2ldICsgdmVjUG9zKTtcbiAgICAgICAgICAgIGluZGljZXMucHVzaCh0cmlhbmdsZXNbaSsxXSArIHZlY1Bvcyk7XG4gICAgICAgICAgICBpbmRpY2VzLnB1c2godHJpYW5nbGVzW2krMl0gKyB2ZWNQb3MpO1xuICAgICAgICAgICAgaW5kaWNlcy5wdXNoKHRyaWFuZ2xlc1tpKzJdICsgdmVjUG9zKTtcbiAgICAgICAgfVxuXG5cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHJlY1BvaW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmVydHMucHVzaChyZWNQb2ludHNbaV0sIHJlY1BvaW50c1srK2ldLCByLCBnLCBiLCBhbHBoYSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoZ3JhcGhpY3NEYXRhLmxpbmVXaWR0aCkge1xuICAgICAgICB2YXIgdGVtcFBvaW50cyA9IGdyYXBoaWNzRGF0YS5wb2ludHM7XG5cbiAgICAgICAgZ3JhcGhpY3NEYXRhLnBvaW50cyA9IHJlY1BvaW50cztcblxuICAgICAgICBXZWJHTEdyYXBoaWNzLmJ1aWxkTGluZShncmFwaGljc0RhdGEsIHdlYkdMRGF0YSk7XG5cbiAgICAgICAgZ3JhcGhpY3NEYXRhLnBvaW50cyA9IHRlbXBQb2ludHM7XG4gICAgfVxufTtcblxuLyoqXG4gKiBDYWxjdWxhdGUgdGhlIHBvaW50cyBmb3IgYSBxdWFkcmF0aWMgYmV6aWVyIGN1cnZlLiAoaGVscGVyIGZ1bmN0aW9uLi4pXG4gKiBCYXNlZCBvbjogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNzg1MDk3L2hvdy1kby1pLWltcGxlbWVudC1hLWJlemllci1jdXJ2ZS1pbi1jXG4gKlxuICogQHN0YXRpY1xuICogQHByaXZhdGVcbiAqIEBwYXJhbSBmcm9tWCB7bnVtYmVyfSBPcmlnaW4gcG9pbnQgeFxuICogQHBhcmFtIGZyb21ZIHtudW1iZXJ9IE9yaWdpbiBwb2ludCB4XG4gKiBAcGFyYW0gY3BYIHtudW1iZXJ9IENvbnRyb2wgcG9pbnQgeFxuICogQHBhcmFtIGNwWSB7bnVtYmVyfSBDb250cm9sIHBvaW50IHlcbiAqIEBwYXJhbSB0b1gge251bWJlcn0gRGVzdGluYXRpb24gcG9pbnQgeFxuICogQHBhcmFtIHRvWSB7bnVtYmVyfSBEZXN0aW5hdGlvbiBwb2ludCB5XG4gKiBAcmV0dXJuIHtudW1iZXJbXX1cbiAqL1xuV2ViR0xHcmFwaGljcy5xdWFkcmF0aWNCZXppZXJDdXJ2ZSA9IGZ1bmN0aW9uIChmcm9tWCwgZnJvbVksIGNwWCwgY3BZLCB0b1gsIHRvWSkge1xuXG4gICAgdmFyIHhhLFxuICAgICAgICB5YSxcbiAgICAgICAgeGIsXG4gICAgICAgIHliLFxuICAgICAgICB4LFxuICAgICAgICB5LFxuICAgICAgICBuID0gMjAsXG4gICAgICAgIHBvaW50cyA9IFtdO1xuXG4gICAgZnVuY3Rpb24gZ2V0UHQobjEgLCBuMiwgcGVyYykge1xuICAgICAgICB2YXIgZGlmZiA9IG4yIC0gbjE7XG5cbiAgICAgICAgcmV0dXJuIG4xICsgKCBkaWZmICogcGVyYyApO1xuICAgIH1cblxuICAgIHZhciBqID0gMDtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8PSBuOyBpKysgKSB7XG4gICAgICAgIGogPSBpIC8gbjtcblxuICAgICAgICAvLyBUaGUgR3JlZW4gTGluZVxuICAgICAgICB4YSA9IGdldFB0KCBmcm9tWCAsIGNwWCAsIGogKTtcbiAgICAgICAgeWEgPSBnZXRQdCggZnJvbVkgLCBjcFkgLCBqICk7XG4gICAgICAgIHhiID0gZ2V0UHQoIGNwWCAsIHRvWCAsIGogKTtcbiAgICAgICAgeWIgPSBnZXRQdCggY3BZICwgdG9ZICwgaiApO1xuXG4gICAgICAgIC8vIFRoZSBCbGFjayBEb3RcbiAgICAgICAgeCA9IGdldFB0KCB4YSAsIHhiICwgaiApO1xuICAgICAgICB5ID0gZ2V0UHQoIHlhICwgeWIgLCBqICk7XG5cbiAgICAgICAgcG9pbnRzLnB1c2goeCwgeSk7XG4gICAgfVxuICAgIHJldHVybiBwb2ludHM7XG59O1xuXG4vKipcbiAqIEJ1aWxkcyBhIGNpcmNsZSB0byBkcmF3XG4gKlxuICogQHN0YXRpY1xuICogQHByaXZhdGVcbiAqIEBwYXJhbSBncmFwaGljc0RhdGEge0dyYXBoaWNzfSBUaGUgZ3JhcGhpY3Mgb2JqZWN0IHRvIGRyYXdcbiAqIEBwYXJhbSB3ZWJHTERhdGEge29iamVjdH1cbiAqL1xuV2ViR0xHcmFwaGljcy5idWlsZENpcmNsZSA9IGZ1bmN0aW9uIChncmFwaGljc0RhdGEsIHdlYkdMRGF0YSkge1xuICAgIC8vIG5lZWQgdG8gY29udmVydCBwb2ludHMgdG8gYSBuaWNlIHJlZ3VsYXIgZGF0YVxuICAgIHZhciBjaXJjbGVEYXRhID0gZ3JhcGhpY3NEYXRhLnNoYXBlO1xuICAgIHZhciB4ID0gY2lyY2xlRGF0YS54O1xuICAgIHZhciB5ID0gY2lyY2xlRGF0YS55O1xuICAgIHZhciB3aWR0aDtcbiAgICB2YXIgaGVpZ2h0O1xuXG4gICAgLy8gVE9ETyAtIGJpdCBoYWNreT8/XG4gICAgaWYgKGdyYXBoaWNzRGF0YS50eXBlID09PSBDT05TVC5TSEFQRVMuQ0lSQykge1xuICAgICAgICB3aWR0aCA9IGNpcmNsZURhdGEucmFkaXVzO1xuICAgICAgICBoZWlnaHQgPSBjaXJjbGVEYXRhLnJhZGl1cztcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHdpZHRoID0gY2lyY2xlRGF0YS53aWR0aDtcbiAgICAgICAgaGVpZ2h0ID0gY2lyY2xlRGF0YS5oZWlnaHQ7XG4gICAgfVxuXG4gICAgdmFyIHRvdGFsU2VncyA9IDQwO1xuICAgIHZhciBzZWcgPSAoTWF0aC5QSSAqIDIpIC8gdG90YWxTZWdzIDtcblxuICAgIHZhciBpID0gMDtcblxuICAgIGlmIChncmFwaGljc0RhdGEuZmlsbCkge1xuICAgICAgICB2YXIgY29sb3IgPSB1dGlscy5oZXgycmdiKGdyYXBoaWNzRGF0YS5maWxsQ29sb3IpO1xuICAgICAgICB2YXIgYWxwaGEgPSBncmFwaGljc0RhdGEuZmlsbEFscGhhO1xuXG4gICAgICAgIHZhciByID0gY29sb3JbMF0gKiBhbHBoYTtcbiAgICAgICAgdmFyIGcgPSBjb2xvclsxXSAqIGFscGhhO1xuICAgICAgICB2YXIgYiA9IGNvbG9yWzJdICogYWxwaGE7XG5cbiAgICAgICAgdmFyIHZlcnRzID0gd2ViR0xEYXRhLnBvaW50cztcbiAgICAgICAgdmFyIGluZGljZXMgPSB3ZWJHTERhdGEuaW5kaWNlcztcblxuICAgICAgICB2YXIgdmVjUG9zID0gdmVydHMubGVuZ3RoLzY7XG5cbiAgICAgICAgaW5kaWNlcy5wdXNoKHZlY1Bvcyk7XG5cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHRvdGFsU2VncyArIDEgOyBpKyspIHtcbiAgICAgICAgICAgIHZlcnRzLnB1c2goeCx5LCByLCBnLCBiLCBhbHBoYSk7XG5cbiAgICAgICAgICAgIHZlcnRzLnB1c2goeCArIE1hdGguc2luKHNlZyAqIGkpICogd2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgIHkgKyBNYXRoLmNvcyhzZWcgKiBpKSAqIGhlaWdodCxcbiAgICAgICAgICAgICAgICAgICAgICAgciwgZywgYiwgYWxwaGEpO1xuXG4gICAgICAgICAgICBpbmRpY2VzLnB1c2godmVjUG9zKyssIHZlY1BvcysrKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGluZGljZXMucHVzaCh2ZWNQb3MtMSk7XG4gICAgfVxuXG4gICAgaWYgKGdyYXBoaWNzRGF0YS5saW5lV2lkdGgpIHtcbiAgICAgICAgdmFyIHRlbXBQb2ludHMgPSBncmFwaGljc0RhdGEucG9pbnRzO1xuXG4gICAgICAgIGdyYXBoaWNzRGF0YS5wb2ludHMgPSBbXTtcblxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdG90YWxTZWdzICsgMTsgaSsrKSB7XG4gICAgICAgICAgICBncmFwaGljc0RhdGEucG9pbnRzLnB1c2goeCArIE1hdGguc2luKHNlZyAqIGkpICogd2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSArIE1hdGguY29zKHNlZyAqIGkpICogaGVpZ2h0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIFdlYkdMR3JhcGhpY3MuYnVpbGRMaW5lKGdyYXBoaWNzRGF0YSwgd2ViR0xEYXRhKTtcblxuICAgICAgICBncmFwaGljc0RhdGEucG9pbnRzID0gdGVtcFBvaW50cztcbiAgICB9XG59O1xuXG4vKipcbiAqIEJ1aWxkcyBhIGxpbmUgdG8gZHJhd1xuICpcbiAqIEBzdGF0aWNcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0gZ3JhcGhpY3NEYXRhIHtHcmFwaGljc30gVGhlIGdyYXBoaWNzIG9iamVjdCBjb250YWluaW5nIGFsbCB0aGUgbmVjZXNzYXJ5IHByb3BlcnRpZXNcbiAqIEBwYXJhbSB3ZWJHTERhdGEge29iamVjdH1cbiAqL1xuV2ViR0xHcmFwaGljcy5idWlsZExpbmUgPSBmdW5jdGlvbiAoZ3JhcGhpY3NEYXRhLCB3ZWJHTERhdGEpIHtcbiAgICAvLyBUT0RPIE9QVElNSVNFIVxuICAgIHZhciBpID0gMDtcbiAgICB2YXIgcG9pbnRzID0gZ3JhcGhpY3NEYXRhLnBvaW50cztcblxuICAgIGlmIChwb2ludHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBpZiB0aGUgbGluZSB3aWR0aCBpcyBhbiBvZGQgbnVtYmVyIGFkZCAwLjUgdG8gYWxpZ24gdG8gYSB3aG9sZSBwaXhlbFxuICAgIGlmIChncmFwaGljc0RhdGEubGluZVdpZHRoJTIpIHtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHBvaW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgcG9pbnRzW2ldICs9IDAuNTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIGdldCBmaXJzdCBhbmQgbGFzdCBwb2ludC4uIGZpZ3VyZSBvdXQgdGhlIG1pZGRsZSFcbiAgICB2YXIgZmlyc3RQb2ludCA9IG5ldyBtYXRoLlBvaW50KHBvaW50c1swXSwgcG9pbnRzWzFdKTtcbiAgICB2YXIgbGFzdFBvaW50ID0gbmV3IG1hdGguUG9pbnQocG9pbnRzW3BvaW50cy5sZW5ndGggLSAyXSwgcG9pbnRzW3BvaW50cy5sZW5ndGggLSAxXSk7XG5cbiAgICAvLyBpZiB0aGUgZmlyc3QgcG9pbnQgaXMgdGhlIGxhc3QgcG9pbnQgLSBnb25uYSBoYXZlIGlzc3VlcyA6KVxuICAgIGlmIChmaXJzdFBvaW50LnggPT09IGxhc3RQb2ludC54ICYmIGZpcnN0UG9pbnQueSA9PT0gbGFzdFBvaW50LnkpIHtcbiAgICAgICAgLy8gbmVlZCB0byBjbG9uZSBhcyB3ZSBhcmUgZ29pbmcgdG8gc2xpZ2h0bHkgbW9kaWZ5IHRoZSBzaGFwZS4uXG4gICAgICAgIHBvaW50cyA9IHBvaW50cy5zbGljZSgpO1xuXG4gICAgICAgIHBvaW50cy5wb3AoKTtcbiAgICAgICAgcG9pbnRzLnBvcCgpO1xuXG4gICAgICAgIGxhc3RQb2ludCA9IG5ldyBtYXRoLlBvaW50KHBvaW50c1twb2ludHMubGVuZ3RoIC0gMl0sIHBvaW50c1twb2ludHMubGVuZ3RoIC0gMV0pO1xuXG4gICAgICAgIHZhciBtaWRQb2ludFggPSBsYXN0UG9pbnQueCArIChmaXJzdFBvaW50LnggLSBsYXN0UG9pbnQueCkgKjAuNTtcbiAgICAgICAgdmFyIG1pZFBvaW50WSA9IGxhc3RQb2ludC55ICsgKGZpcnN0UG9pbnQueSAtIGxhc3RQb2ludC55KSAqMC41O1xuXG4gICAgICAgIHBvaW50cy51bnNoaWZ0KG1pZFBvaW50WCwgbWlkUG9pbnRZKTtcbiAgICAgICAgcG9pbnRzLnB1c2gobWlkUG9pbnRYLCBtaWRQb2ludFkpO1xuICAgIH1cblxuICAgIHZhciB2ZXJ0cyA9IHdlYkdMRGF0YS5wb2ludHM7XG4gICAgdmFyIGluZGljZXMgPSB3ZWJHTERhdGEuaW5kaWNlcztcbiAgICB2YXIgbGVuZ3RoID0gcG9pbnRzLmxlbmd0aCAvIDI7XG4gICAgdmFyIGluZGV4Q291bnQgPSBwb2ludHMubGVuZ3RoO1xuICAgIHZhciBpbmRleFN0YXJ0ID0gdmVydHMubGVuZ3RoLzY7XG5cbiAgICAvLyBEUkFXIHRoZSBMaW5lXG4gICAgdmFyIHdpZHRoID0gZ3JhcGhpY3NEYXRhLmxpbmVXaWR0aCAvIDI7XG5cbiAgICAvLyBzb3J0IGNvbG9yXG4gICAgdmFyIGNvbG9yID0gdXRpbHMuaGV4MnJnYihncmFwaGljc0RhdGEubGluZUNvbG9yKTtcbiAgICB2YXIgYWxwaGEgPSBncmFwaGljc0RhdGEubGluZUFscGhhO1xuICAgIHZhciByID0gY29sb3JbMF0gKiBhbHBoYTtcbiAgICB2YXIgZyA9IGNvbG9yWzFdICogYWxwaGE7XG4gICAgdmFyIGIgPSBjb2xvclsyXSAqIGFscGhhO1xuXG4gICAgdmFyIHB4LCBweSwgcDF4LCBwMXksIHAyeCwgcDJ5LCBwM3gsIHAzeTtcbiAgICB2YXIgcGVycHgsIHBlcnB5LCBwZXJwMngsIHBlcnAyeSwgcGVycDN4LCBwZXJwM3k7XG4gICAgdmFyIGExLCBiMSwgYzEsIGEyLCBiMiwgYzI7XG4gICAgdmFyIGRlbm9tLCBwZGlzdCwgZGlzdDtcblxuICAgIHAxeCA9IHBvaW50c1swXTtcbiAgICBwMXkgPSBwb2ludHNbMV07XG5cbiAgICBwMnggPSBwb2ludHNbMl07XG4gICAgcDJ5ID0gcG9pbnRzWzNdO1xuXG4gICAgcGVycHggPSAtKHAxeSAtIHAyeSk7XG4gICAgcGVycHkgPSAgcDF4IC0gcDJ4O1xuXG4gICAgZGlzdCA9IE1hdGguc3FydChwZXJweCpwZXJweCArIHBlcnB5KnBlcnB5KTtcblxuICAgIHBlcnB4IC89IGRpc3Q7XG4gICAgcGVycHkgLz0gZGlzdDtcbiAgICBwZXJweCAqPSB3aWR0aDtcbiAgICBwZXJweSAqPSB3aWR0aDtcblxuICAgIC8vIHN0YXJ0XG4gICAgdmVydHMucHVzaChwMXggLSBwZXJweCAsIHAxeSAtIHBlcnB5LFxuICAgICAgICAgICAgICAgIHIsIGcsIGIsIGFscGhhKTtcblxuICAgIHZlcnRzLnB1c2gocDF4ICsgcGVycHggLCBwMXkgKyBwZXJweSxcbiAgICAgICAgICAgICAgICByLCBnLCBiLCBhbHBoYSk7XG5cbiAgICBmb3IgKGkgPSAxOyBpIDwgbGVuZ3RoLTE7IGkrKykge1xuICAgICAgICBwMXggPSBwb2ludHNbKGktMSkqMl07XG4gICAgICAgIHAxeSA9IHBvaW50c1soaS0xKSoyICsgMV07XG5cbiAgICAgICAgcDJ4ID0gcG9pbnRzWyhpKSoyXTtcbiAgICAgICAgcDJ5ID0gcG9pbnRzWyhpKSoyICsgMV07XG5cbiAgICAgICAgcDN4ID0gcG9pbnRzWyhpKzEpKjJdO1xuICAgICAgICBwM3kgPSBwb2ludHNbKGkrMSkqMiArIDFdO1xuXG4gICAgICAgIHBlcnB4ID0gLShwMXkgLSBwMnkpO1xuICAgICAgICBwZXJweSA9IHAxeCAtIHAyeDtcblxuICAgICAgICBkaXN0ID0gTWF0aC5zcXJ0KHBlcnB4KnBlcnB4ICsgcGVycHkqcGVycHkpO1xuICAgICAgICBwZXJweCAvPSBkaXN0O1xuICAgICAgICBwZXJweSAvPSBkaXN0O1xuICAgICAgICBwZXJweCAqPSB3aWR0aDtcbiAgICAgICAgcGVycHkgKj0gd2lkdGg7XG5cbiAgICAgICAgcGVycDJ4ID0gLShwMnkgLSBwM3kpO1xuICAgICAgICBwZXJwMnkgPSBwMnggLSBwM3g7XG5cbiAgICAgICAgZGlzdCA9IE1hdGguc3FydChwZXJwMngqcGVycDJ4ICsgcGVycDJ5KnBlcnAyeSk7XG4gICAgICAgIHBlcnAyeCAvPSBkaXN0O1xuICAgICAgICBwZXJwMnkgLz0gZGlzdDtcbiAgICAgICAgcGVycDJ4ICo9IHdpZHRoO1xuICAgICAgICBwZXJwMnkgKj0gd2lkdGg7XG5cbiAgICAgICAgYTEgPSAoLXBlcnB5ICsgcDF5KSAtICgtcGVycHkgKyBwMnkpO1xuICAgICAgICBiMSA9ICgtcGVycHggKyBwMngpIC0gKC1wZXJweCArIHAxeCk7XG4gICAgICAgIGMxID0gKC1wZXJweCArIHAxeCkgKiAoLXBlcnB5ICsgcDJ5KSAtICgtcGVycHggKyBwMngpICogKC1wZXJweSArIHAxeSk7XG4gICAgICAgIGEyID0gKC1wZXJwMnkgKyBwM3kpIC0gKC1wZXJwMnkgKyBwMnkpO1xuICAgICAgICBiMiA9ICgtcGVycDJ4ICsgcDJ4KSAtICgtcGVycDJ4ICsgcDN4KTtcbiAgICAgICAgYzIgPSAoLXBlcnAyeCArIHAzeCkgKiAoLXBlcnAyeSArIHAyeSkgLSAoLXBlcnAyeCArIHAyeCkgKiAoLXBlcnAyeSArIHAzeSk7XG5cbiAgICAgICAgZGVub20gPSBhMSpiMiAtIGEyKmIxO1xuXG4gICAgICAgIGlmIChNYXRoLmFicyhkZW5vbSkgPCAwLjEgKSB7XG5cbiAgICAgICAgICAgIGRlbm9tKz0xMC4xO1xuICAgICAgICAgICAgdmVydHMucHVzaChwMnggLSBwZXJweCAsIHAyeSAtIHBlcnB5LFxuICAgICAgICAgICAgICAgIHIsIGcsIGIsIGFscGhhKTtcblxuICAgICAgICAgICAgdmVydHMucHVzaChwMnggKyBwZXJweCAsIHAyeSArIHBlcnB5LFxuICAgICAgICAgICAgICAgIHIsIGcsIGIsIGFscGhhKTtcblxuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBweCA9IChiMSpjMiAtIGIyKmMxKS9kZW5vbTtcbiAgICAgICAgcHkgPSAoYTIqYzEgLSBhMSpjMikvZGVub207XG5cblxuICAgICAgICBwZGlzdCA9IChweCAtcDJ4KSAqIChweCAtcDJ4KSArIChweSAtcDJ5KSArIChweSAtcDJ5KTtcblxuXG4gICAgICAgIGlmIChwZGlzdCA+IDE0MCAqIDE0MCkge1xuICAgICAgICAgICAgcGVycDN4ID0gcGVycHggLSBwZXJwMng7XG4gICAgICAgICAgICBwZXJwM3kgPSBwZXJweSAtIHBlcnAyeTtcblxuICAgICAgICAgICAgZGlzdCA9IE1hdGguc3FydChwZXJwM3gqcGVycDN4ICsgcGVycDN5KnBlcnAzeSk7XG4gICAgICAgICAgICBwZXJwM3ggLz0gZGlzdDtcbiAgICAgICAgICAgIHBlcnAzeSAvPSBkaXN0O1xuICAgICAgICAgICAgcGVycDN4ICo9IHdpZHRoO1xuICAgICAgICAgICAgcGVycDN5ICo9IHdpZHRoO1xuXG4gICAgICAgICAgICB2ZXJ0cy5wdXNoKHAyeCAtIHBlcnAzeCwgcDJ5IC1wZXJwM3kpO1xuICAgICAgICAgICAgdmVydHMucHVzaChyLCBnLCBiLCBhbHBoYSk7XG5cbiAgICAgICAgICAgIHZlcnRzLnB1c2gocDJ4ICsgcGVycDN4LCBwMnkgK3BlcnAzeSk7XG4gICAgICAgICAgICB2ZXJ0cy5wdXNoKHIsIGcsIGIsIGFscGhhKTtcblxuICAgICAgICAgICAgdmVydHMucHVzaChwMnggLSBwZXJwM3gsIHAyeSAtcGVycDN5KTtcbiAgICAgICAgICAgIHZlcnRzLnB1c2gociwgZywgYiwgYWxwaGEpO1xuXG4gICAgICAgICAgICBpbmRleENvdW50Kys7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG5cbiAgICAgICAgICAgIHZlcnRzLnB1c2gocHggLCBweSk7XG4gICAgICAgICAgICB2ZXJ0cy5wdXNoKHIsIGcsIGIsIGFscGhhKTtcblxuICAgICAgICAgICAgdmVydHMucHVzaChwMnggLSAocHgtcDJ4KSwgcDJ5IC0gKHB5IC0gcDJ5KSk7XG4gICAgICAgICAgICB2ZXJ0cy5wdXNoKHIsIGcsIGIsIGFscGhhKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHAxeCA9IHBvaW50c1sobGVuZ3RoLTIpKjJdO1xuICAgIHAxeSA9IHBvaW50c1sobGVuZ3RoLTIpKjIgKyAxXTtcblxuICAgIHAyeCA9IHBvaW50c1sobGVuZ3RoLTEpKjJdO1xuICAgIHAyeSA9IHBvaW50c1sobGVuZ3RoLTEpKjIgKyAxXTtcblxuICAgIHBlcnB4ID0gLShwMXkgLSBwMnkpO1xuICAgIHBlcnB5ID0gcDF4IC0gcDJ4O1xuXG4gICAgZGlzdCA9IE1hdGguc3FydChwZXJweCpwZXJweCArIHBlcnB5KnBlcnB5KTtcbiAgICBwZXJweCAvPSBkaXN0O1xuICAgIHBlcnB5IC89IGRpc3Q7XG4gICAgcGVycHggKj0gd2lkdGg7XG4gICAgcGVycHkgKj0gd2lkdGg7XG5cbiAgICB2ZXJ0cy5wdXNoKHAyeCAtIHBlcnB4ICwgcDJ5IC0gcGVycHkpO1xuICAgIHZlcnRzLnB1c2gociwgZywgYiwgYWxwaGEpO1xuXG4gICAgdmVydHMucHVzaChwMnggKyBwZXJweCAsIHAyeSArIHBlcnB5KTtcbiAgICB2ZXJ0cy5wdXNoKHIsIGcsIGIsIGFscGhhKTtcblxuICAgIGluZGljZXMucHVzaChpbmRleFN0YXJ0KTtcblxuICAgIGZvciAoaSA9IDA7IGkgPCBpbmRleENvdW50OyBpKyspIHtcbiAgICAgICAgaW5kaWNlcy5wdXNoKGluZGV4U3RhcnQrKyk7XG4gICAgfVxuXG4gICAgaW5kaWNlcy5wdXNoKGluZGV4U3RhcnQtMSk7XG59O1xuXG4vKipcbiAqIEJ1aWxkcyBhIGNvbXBsZXggcG9seWdvbiB0byBkcmF3XG4gKlxuICogQHN0YXRpY1xuICogQHByaXZhdGVcbiAqIEBwYXJhbSBncmFwaGljc0RhdGEge0dyYXBoaWNzfSBUaGUgZ3JhcGhpY3Mgb2JqZWN0IGNvbnRhaW5pbmcgYWxsIHRoZSBuZWNlc3NhcnkgcHJvcGVydGllc1xuICogQHBhcmFtIHdlYkdMRGF0YSB7b2JqZWN0fVxuICovXG5XZWJHTEdyYXBoaWNzLmJ1aWxkQ29tcGxleFBvbHkgPSBmdW5jdGlvbiAoZ3JhcGhpY3NEYXRhLCB3ZWJHTERhdGEpIHtcbiAgICAvL1RPRE8gLSBubyBuZWVkIHRvIGNvcHkgdGhpcyBhcyBpdCBnZXRzIHR1cm5lZCBpbnRvIGEgRkxvYXQzMkFycmF5IGFueXdheXMuLlxuICAgIHZhciBwb2ludHMgPSBncmFwaGljc0RhdGEucG9pbnRzLnNsaWNlKCk7XG5cbiAgICBpZiAocG9pbnRzLmxlbmd0aCA8IDYpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIGdldCBmaXJzdCBhbmQgbGFzdCBwb2ludC4uIGZpZ3VyZSBvdXQgdGhlIG1pZGRsZSFcbiAgICB2YXIgaW5kaWNlcyA9IHdlYkdMRGF0YS5pbmRpY2VzO1xuICAgIHdlYkdMRGF0YS5wb2ludHMgPSBwb2ludHM7XG4gICAgd2ViR0xEYXRhLmFscGhhID0gZ3JhcGhpY3NEYXRhLmZpbGxBbHBoYTtcbiAgICB3ZWJHTERhdGEuY29sb3IgPSB1dGlscy5oZXgycmdiKGdyYXBoaWNzRGF0YS5maWxsQ29sb3IpO1xuXG4gICAgLy8gY2FsY2xhdGUgdGhlIGJvdW5kcy4uXG4gICAgdmFyIG1pblggPSBJbmZpbml0eTtcbiAgICB2YXIgbWF4WCA9IC1JbmZpbml0eTtcblxuICAgIHZhciBtaW5ZID0gSW5maW5pdHk7XG4gICAgdmFyIG1heFkgPSAtSW5maW5pdHk7XG5cbiAgICB2YXIgeCx5O1xuXG4gICAgLy8gZ2V0IHNpemUuLlxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSs9Mikge1xuICAgICAgICB4ID0gcG9pbnRzW2ldO1xuICAgICAgICB5ID0gcG9pbnRzW2krMV07XG5cbiAgICAgICAgbWluWCA9IHggPCBtaW5YID8geCA6IG1pblg7XG4gICAgICAgIG1heFggPSB4ID4gbWF4WCA/IHggOiBtYXhYO1xuXG4gICAgICAgIG1pblkgPSB5IDwgbWluWSA/IHkgOiBtaW5ZO1xuICAgICAgICBtYXhZID0geSA+IG1heFkgPyB5IDogbWF4WTtcbiAgICB9XG5cbiAgICAvLyBhZGQgYSBxdWFkIHRvIHRoZSBlbmQgY29zIHRoZXJlIGlzIG5vIHBvaW50IG1ha2luZyBhbm90aGVyIGJ1ZmZlciFcbiAgICBwb2ludHMucHVzaChtaW5YLCBtaW5ZLFxuICAgICAgICAgICAgICAgIG1heFgsIG1pblksXG4gICAgICAgICAgICAgICAgbWF4WCwgbWF4WSxcbiAgICAgICAgICAgICAgICBtaW5YLCBtYXhZKTtcblxuICAgIC8vIHB1c2ggYSBxdWFkIG9udG8gdGhlIGVuZC4uXG5cbiAgICAvL1RPRE8gLSB0aGlzIGFpbnQgbmVlZGVkIVxuICAgIHZhciBsZW5ndGggPSBwb2ludHMubGVuZ3RoIC8gMjtcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaW5kaWNlcy5wdXNoKCBpICk7XG4gICAgfVxuXG59O1xuXG4vKipcbiAqIEJ1aWxkcyBhIHBvbHlnb24gdG8gZHJhd1xuICpcbiAqIEBzdGF0aWNcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0gZ3JhcGhpY3NEYXRhIHtHcmFwaGljc30gVGhlIGdyYXBoaWNzIG9iamVjdCBjb250YWluaW5nIGFsbCB0aGUgbmVjZXNzYXJ5IHByb3BlcnRpZXNcbiAqIEBwYXJhbSB3ZWJHTERhdGEge29iamVjdH1cbiAqL1xuV2ViR0xHcmFwaGljcy5idWlsZFBvbHkgPSBmdW5jdGlvbiAoZ3JhcGhpY3NEYXRhLCB3ZWJHTERhdGEpIHtcbiAgICB2YXIgcG9pbnRzID0gZ3JhcGhpY3NEYXRhLnBvaW50cztcblxuICAgIGlmIChwb2ludHMubGVuZ3RoIDwgNikge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIGdldCBmaXJzdCBhbmQgbGFzdCBwb2ludC4uIGZpZ3VyZSBvdXQgdGhlIG1pZGRsZSFcbiAgICB2YXIgdmVydHMgPSB3ZWJHTERhdGEucG9pbnRzO1xuICAgIHZhciBpbmRpY2VzID0gd2ViR0xEYXRhLmluZGljZXM7XG5cbiAgICB2YXIgbGVuZ3RoID0gcG9pbnRzLmxlbmd0aCAvIDI7XG5cbiAgICAvLyBzb3J0IGNvbG9yXG4gICAgdmFyIGNvbG9yID0gdXRpbHMuaGV4MnJnYihncmFwaGljc0RhdGEuZmlsbENvbG9yKTtcbiAgICB2YXIgYWxwaGEgPSBncmFwaGljc0RhdGEuZmlsbEFscGhhO1xuICAgIHZhciByID0gY29sb3JbMF0gKiBhbHBoYTtcbiAgICB2YXIgZyA9IGNvbG9yWzFdICogYWxwaGE7XG4gICAgdmFyIGIgPSBjb2xvclsyXSAqIGFscGhhO1xuXG4gICAgdmFyIHRyaWFuZ2xlcyA9IHV0aWxzLlBvbHlLLlRyaWFuZ3VsYXRlKHBvaW50cyk7XG5cbiAgICBpZiAoIXRyaWFuZ2xlcykge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgdmFyIHZlcnRQb3MgPSB2ZXJ0cy5sZW5ndGggLyA2O1xuXG4gICAgdmFyIGkgPSAwO1xuXG4gICAgZm9yIChpID0gMDsgaSA8IHRyaWFuZ2xlcy5sZW5ndGg7IGkrPTMpIHtcbiAgICAgICAgaW5kaWNlcy5wdXNoKHRyaWFuZ2xlc1tpXSArIHZlcnRQb3MpO1xuICAgICAgICBpbmRpY2VzLnB1c2godHJpYW5nbGVzW2ldICsgdmVydFBvcyk7XG4gICAgICAgIGluZGljZXMucHVzaCh0cmlhbmdsZXNbaSsxXSArIHZlcnRQb3MpO1xuICAgICAgICBpbmRpY2VzLnB1c2godHJpYW5nbGVzW2krMl0gK3ZlcnRQb3MpO1xuICAgICAgICBpbmRpY2VzLnB1c2godHJpYW5nbGVzW2krMl0gKyB2ZXJ0UG9zKTtcbiAgICB9XG5cbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmVydHMucHVzaChwb2ludHNbaSAqIDJdLCBwb2ludHNbaSAqIDIgKyAxXSxcbiAgICAgICAgICAgICAgICAgICByLCBnLCBiLCBhbHBoYSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG59O1xuXG5XZWJHTEdyYXBoaWNzLmdyYXBoaWNzRGF0YVBvb2wgPSBbXTtcbiIsIi8qKlxuICogQGNsYXNzXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBXZWJHTEdyYXBoaWNzRGF0YShnbCkge1xuICAgIHRoaXMuZ2wgPSBnbDtcblxuICAgIC8vVE9ETyBkb2VzIHRoaXMgbmVlZCB0byBiZSBzcGxpdCBiZWZvcmUgdXBsb2Rpbmc/P1xuICAgIHRoaXMuY29sb3IgPSBbMCwgMCwgMF07IC8vIGNvbG9yIHNwbGl0IVxuICAgIHRoaXMucG9pbnRzID0gW107XG4gICAgdGhpcy5pbmRpY2VzID0gW107XG4gICAgdGhpcy5idWZmZXIgPSBnbC5jcmVhdGVCdWZmZXIoKTtcbiAgICB0aGlzLmluZGV4QnVmZmVyID0gZ2wuY3JlYXRlQnVmZmVyKCk7XG4gICAgdGhpcy5tb2RlID0gMTtcbiAgICB0aGlzLmFscGhhID0gMTtcbiAgICB0aGlzLmRpcnR5ID0gdHJ1ZTtcbn1cblxuV2ViR0xHcmFwaGljc0RhdGEucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gV2ViR0xHcmFwaGljc0RhdGE7XG5tb2R1bGUuZXhwb3J0cyA9IFdlYkdMR3JhcGhpY3NEYXRhO1xuXG4vKipcbiAqXG4gKi9cbldlYkdMR3JhcGhpY3NEYXRhLnByb3RvdHlwZS5yZXNldCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnBvaW50cy5sZW5ndGggPSAwO1xuICAgIHRoaXMuaW5kaWNlcy5sZW5ndGggPSAwO1xufTtcblxuLyoqXG4gKlxuICovXG5XZWJHTEdyYXBoaWNzRGF0YS5wcm90b3R5cGUudXBsb2FkID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBnbCA9IHRoaXMuZ2w7XG5cbi8vICAgIHRoaXMubGFzdEluZGV4ID0gZ3JhcGhpY3MuZ3JhcGhpY3NEYXRhLmxlbmd0aDtcbiAgICB0aGlzLmdsUG9pbnRzID0gbmV3IEZsb2F0MzJBcnJheSh0aGlzLnBvaW50cyk7XG5cbiAgICBnbC5iaW5kQnVmZmVyKGdsLkFSUkFZX0JVRkZFUiwgdGhpcy5idWZmZXIpO1xuICAgIGdsLmJ1ZmZlckRhdGEoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLmdsUG9pbnRzLCBnbC5TVEFUSUNfRFJBVyk7XG5cbiAgICB0aGlzLmdsSW5kaWNpZXMgPSBuZXcgVWludDE2QXJyYXkodGhpcy5pbmRpY2VzKTtcblxuICAgIGdsLmJpbmRCdWZmZXIoZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIsIHRoaXMuaW5kZXhCdWZmZXIpO1xuICAgIGdsLmJ1ZmZlckRhdGEoZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIsIHRoaXMuZ2xJbmRpY2llcywgZ2wuU1RBVElDX0RSQVcpO1xuXG4gICAgdGhpcy5kaXJ0eSA9IGZhbHNlO1xufTtcbiIsInZhciBUZXh0dXJlVXZzID0gcmVxdWlyZSgnLi4vLi4vLi4vdGV4dHVyZXMvVGV4dHVyZVV2cycpLFxuICAgIFNoYWRlciA9IHJlcXVpcmUoJy4uL3NoYWRlcnMvU2hhZGVyJyk7XG5cbi8qKlxuICogQGF1dGhvciBNYXQgR3JvdmVzXG4gKlxuICogQmlnIHRoYW5rcyB0byB0aGUgdmVyeSBjbGV2ZXIgTWF0dCBEZXNMYXVyaWVycyA8bWF0dGRlc2w+IGh0dHBzOi8vZ2l0aHViLmNvbS9tYXR0ZGVzbC9cbiAqIGZvciBjcmVhdGluZyB0aGUgb3JpZ2luYWwgcGl4aSB2ZXJzaW9uIVxuICogQWxzbyBhIHRoYW5rcyB0byBodHRwczovL2dpdGh1Yi5jb20vYmNoZXZhbGllciBmb3IgdHdlYWtpbmcgdGhlIHRpbnQgYW5kIGFscGhhIHNvIHRoYXQgdGhleSBub3cgc2hhcmUgNCBieXRlcyBvbiB0aGUgdmVydGV4IGJ1ZmZlclxuICpcbiAqIEhlYXZpbHkgaW5zcGlyZWQgYnkgTGliR0RYJ3MgV2ViR0xTcHJpdGVCYXRjaDpcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9saWJnZHgvbGliZ2R4L2Jsb2IvbWFzdGVyL2dkeC9zcmMvY29tL2JhZGxvZ2ljL2dkeC9ncmFwaGljcy9nMmQvV2ViR0xTcHJpdGVCYXRjaC5qYXZhXG4gKi9cblxuLyoqXG4gKlxuICogQGNsYXNzXG4gKiBAcHJpdmF0ZVxuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9IFRoZSByZW5kZXJlciB0aGlzIHNwcml0ZSBiYXRjaCB3b3JrcyBmb3IuXG4gKi9cbmZ1bmN0aW9uIFdlYkdMU3ByaXRlQmF0Y2gocmVuZGVyZXIpIHtcbiAgICAvKipcbiAgICAgKlxuICAgICAqXG4gICAgICogQG1lbWJlciB7V2ViR0xSZW5kZXJlcn1cbiAgICAgKi9cbiAgICB0aGlzLnJlbmRlcmVyID0gcmVuZGVyZXI7XG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMudmVydFNpemUgPSA1O1xuXG4gICAgLyoqXG4gICAgICogVGhlIG51bWJlciBvZiBpbWFnZXMgaW4gdGhlIFNwcml0ZUJhdGNoIGJlZm9yZSBpdCBmbHVzaGVzLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMuc2l6ZSA9IDIwMDA7Ly9NYXRoLnBvdygyLCAxNikgLyAgdGhpcy52ZXJ0U2l6ZTtcblxuICAgIC8vIHRoZSB0b3RhbCBudW1iZXIgb2YgYnl0ZXMgaW4gb3VyIGJhdGNoXG4gICAgdmFyIG51bVZlcnRzID0gdGhpcy5zaXplICogNCAqIDQgKiB0aGlzLnZlcnRTaXplO1xuICAgIC8vIHRoZSB0b3RhbCBudW1iZXIgb2YgaW5kaWNlcyBpbiBvdXIgYmF0Y2hcbiAgICB2YXIgbnVtSW5kaWNlcyA9IHRoaXMuc2l6ZSAqIDY7XG5cbiAgICAvKipcbiAgICAgKiBIb2xkcyB0aGUgdmVydGljZXNcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0FycmF5QnVmZmVyfVxuICAgICAqL1xuICAgIHRoaXMudmVydGljZXMgPSBuZXcgQXJyYXlCdWZmZXIobnVtVmVydHMpO1xuXG4gICAgLyoqXG4gICAgICogVmlldyBvbiB0aGUgdmVydGljZXMgYXMgYSBGbG9hdDMyQXJyYXlcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0Zsb2F0MzJBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLnBvc2l0aW9ucyA9IG5ldyBGbG9hdDMyQXJyYXkodGhpcy52ZXJ0aWNlcyk7XG5cbiAgICAvKipcbiAgICAgKiBWaWV3IG9uIHRoZSB2ZXJ0aWNlcyBhcyBhIFVpbnQzMkFycmF5XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtVaW50MzJBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLmNvbG9ycyA9IG5ldyBVaW50MzJBcnJheSh0aGlzLnZlcnRpY2VzKTtcblxuICAgIC8qKlxuICAgICAqIEhvbGRzIHRoZSBpbmRpY2VzXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtVaW50MTZBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLmluZGljZXMgPSBuZXcgVWludDE2QXJyYXkobnVtSW5kaWNlcyk7XG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMubGFzdEluZGV4Q291bnQgPSAwO1xuXG4gICAgZm9yICh2YXIgaT0wLCBqPTA7IGkgPCBudW1JbmRpY2VzOyBpICs9IDYsIGogKz0gNCkge1xuICAgICAgICB0aGlzLmluZGljZXNbaSArIDBdID0gaiArIDA7XG4gICAgICAgIHRoaXMuaW5kaWNlc1tpICsgMV0gPSBqICsgMTtcbiAgICAgICAgdGhpcy5pbmRpY2VzW2kgKyAyXSA9IGogKyAyO1xuICAgICAgICB0aGlzLmluZGljZXNbaSArIDNdID0gaiArIDA7XG4gICAgICAgIHRoaXMuaW5kaWNlc1tpICsgNF0gPSBqICsgMjtcbiAgICAgICAgdGhpcy5pbmRpY2VzW2kgKyA1XSA9IGogKyAzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMuZHJhd2luZyA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLmN1cnJlbnRCYXRjaFNpemUgPSAwO1xuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0Jhc2VUZXh0dXJlfVxuICAgICAqL1xuICAgIHRoaXMuY3VycmVudEJhc2VUZXh0dXJlID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0FycmF5fVxuICAgICAqL1xuICAgIHRoaXMudGV4dHVyZXMgPSBbXTtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLmJsZW5kTW9kZXMgPSBbXTtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLnNoYWRlcnMgPSBbXTtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLnNwcml0ZXMgPSBbXTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBkZWZhdWx0IHNoYWRlciB0aGF0IGlzIHVzZWQgaWYgYSBzcHJpdGUgZG9lc24ndCBoYXZlIGEgbW9yZSBzcGVjaWZpYyBvbmUuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtTaGFkZXJ9XG4gICAgICovXG4gICAgdGhpcy5zaGFkZXIgPSBudWxsO1xuXG4gICAgLy8gbGlzdGVuIGZvciBjb250ZXh0IGFuZCB1cGRhdGUgbmVjZXNzYXJ5IGJ1ZmZlcnNcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy5yZW5kZXJlci5vbignY29udGV4dCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgc2VsZi5zZXR1cENvbnRleHQoKTtcbiAgICB9KTtcbn1cblxuV2ViR0xTcHJpdGVCYXRjaC5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBXZWJHTFNwcml0ZUJhdGNoO1xubW9kdWxlLmV4cG9ydHMgPSBXZWJHTFNwcml0ZUJhdGNoO1xuXG4vKipcbiAqIEBwYXJhbSBnbCB7V2ViR0xDb250ZXh0fSB0aGUgY3VycmVudCBXZWJHTCBkcmF3aW5nIGNvbnRleHRcbiAqL1xuV2ViR0xTcHJpdGVCYXRjaC5wcm90b3R5cGUuc2V0dXBDb250ZXh0ID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBnbCA9IHRoaXMucmVuZGVyZXIuZ2w7XG5cbiAgICAvLyBzZXR1cCBkZWZhdWx0IHNoYWRlclxuICAgIHRoaXMuc2hhZGVyID0gbmV3IFNoYWRlcihnbCk7XG5cbiAgICAvLyBjcmVhdGUgYSBjb3VwbGUgb2YgYnVmZmVyc1xuICAgIHRoaXMudmVydGV4QnVmZmVyID0gZ2wuY3JlYXRlQnVmZmVyKCk7XG4gICAgdGhpcy5pbmRleEJ1ZmZlciA9IGdsLmNyZWF0ZUJ1ZmZlcigpO1xuXG4gICAgLy8gNjU1MzUgaXMgbWF4IGluZGV4LCBzbyA2NTUzNSAvIDYgPSAxMDkyMi5cblxuICAgIC8vdXBsb2FkIHRoZSBpbmRleCBkYXRhXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5FTEVNRU5UX0FSUkFZX0JVRkZFUiwgdGhpcy5pbmRleEJ1ZmZlcik7XG4gICAgZ2wuYnVmZmVyRGF0YShnbC5FTEVNRU5UX0FSUkFZX0JVRkZFUiwgdGhpcy5pbmRpY2VzLCBnbC5TVEFUSUNfRFJBVyk7XG5cbiAgICBnbC5iaW5kQnVmZmVyKGdsLkFSUkFZX0JVRkZFUiwgdGhpcy52ZXJ0ZXhCdWZmZXIpO1xuICAgIGdsLmJ1ZmZlckRhdGEoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLnZlcnRpY2VzLCBnbC5EWU5BTUlDX0RSQVcpO1xuXG4gICAgdGhpcy5jdXJyZW50QmxlbmRNb2RlID0gOTk5OTk7XG59O1xuXG4vKipcbiAqXG4gKi9cbldlYkdMU3ByaXRlQmF0Y2gucHJvdG90eXBlLmJlZ2luID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIHRoaXMuc2hhZGVyID0gdGhpcy5yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLmRlZmF1bHRTaGFkZXI7XG5cbiAgICB0aGlzLnN0YXJ0KCk7XG59O1xuXG4vKipcbiAqL1xuV2ViR0xTcHJpdGVCYXRjaC5wcm90b3R5cGUuZW5kID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZmx1c2goKTtcbn07XG5cbi8qKlxuICogQHBhcmFtIHNwcml0ZSB7U3ByaXRlfSB0aGUgc3ByaXRlIHRvIHJlbmRlciB3aGVuIHVzaW5nIHRoaXMgc3ByaXRlYmF0Y2hcbiAqL1xuV2ViR0xTcHJpdGVCYXRjaC5wcm90b3R5cGUucmVuZGVyID0gZnVuY3Rpb24gKHNwcml0ZSkge1xuICAgIHZhciB0ZXh0dXJlID0gc3ByaXRlLnRleHR1cmU7XG5cbiAgICAvL1RPRE8gc2V0IGJsZW5kIG1vZGVzLi5cbiAgICAvLyBjaGVjayB0ZXh0dXJlLi5cbiAgICBpZiAodGhpcy5jdXJyZW50QmF0Y2hTaXplID49IHRoaXMuc2l6ZSkge1xuICAgICAgICB0aGlzLmZsdXNoKCk7XG4gICAgICAgIHRoaXMuY3VycmVudEJhc2VUZXh0dXJlID0gdGV4dHVyZS5iYXNlVGV4dHVyZTtcbiAgICB9XG5cbiAgICAvLyBnZXQgdGhlIHV2cyBmb3IgdGhlIHRleHR1cmVcbiAgICB2YXIgdXZzID0gdGV4dHVyZS5fdXZzO1xuXG4gICAgLy8gaWYgdGhlIHV2cyBoYXZlIG5vdCB1cGRhdGVkIHRoZW4gbm8gcG9pbnQgcmVuZGVyaW5nIGp1c3QgeWV0IVxuICAgIGlmICghdXZzKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBUT0RPIHRyaW0/P1xuICAgIHZhciBhWCA9IHNwcml0ZS5hbmNob3IueDtcbiAgICB2YXIgYVkgPSBzcHJpdGUuYW5jaG9yLnk7XG5cbiAgICB2YXIgdzAsIHcxLCBoMCwgaDE7XG5cbiAgICBpZiAodGV4dHVyZS50cmltKSB7XG4gICAgICAgIC8vIGlmIHRoZSBzcHJpdGUgaXMgdHJpbW1lZCB0aGVuIHdlIG5lZWQgdG8gYWRkIHRoZSBleHRyYSBzcGFjZSBiZWZvcmUgdHJhbnNmb3JtaW5nIHRoZSBzcHJpdGUgY29vcmRzLi5cbiAgICAgICAgdmFyIHRyaW0gPSB0ZXh0dXJlLnRyaW07XG5cbiAgICAgICAgdzEgPSB0cmltLnggLSBhWCAqIHRyaW0ud2lkdGg7XG4gICAgICAgIHcwID0gdzEgKyB0ZXh0dXJlLmNyb3Aud2lkdGg7XG5cbiAgICAgICAgaDEgPSB0cmltLnkgLSBhWSAqIHRyaW0uaGVpZ2h0O1xuICAgICAgICBoMCA9IGgxICsgdGV4dHVyZS5jcm9wLmhlaWdodDtcblxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdzAgPSAodGV4dHVyZS5mcmFtZS53aWR0aCApICogKDEtYVgpO1xuICAgICAgICB3MSA9ICh0ZXh0dXJlLmZyYW1lLndpZHRoICkgKiAtYVg7XG5cbiAgICAgICAgaDAgPSB0ZXh0dXJlLmZyYW1lLmhlaWdodCAqICgxLWFZKTtcbiAgICAgICAgaDEgPSB0ZXh0dXJlLmZyYW1lLmhlaWdodCAqIC1hWTtcbiAgICB9XG5cbiAgICB2YXIgaW5kZXggPSB0aGlzLmN1cnJlbnRCYXRjaFNpemUgKiA0ICogdGhpcy52ZXJ0U2l6ZTtcblxuICAgIHZhciByZXNvbHV0aW9uID0gdGV4dHVyZS5iYXNlVGV4dHVyZS5yZXNvbHV0aW9uO1xuXG4gICAgdmFyIHdvcmxkVHJhbnNmb3JtID0gc3ByaXRlLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgdmFyIGEgPSB3b3JsZFRyYW5zZm9ybS5hIC8gcmVzb2x1dGlvbjtcbiAgICB2YXIgYiA9IHdvcmxkVHJhbnNmb3JtLmIgLyByZXNvbHV0aW9uO1xuICAgIHZhciBjID0gd29ybGRUcmFuc2Zvcm0uYyAvIHJlc29sdXRpb247XG4gICAgdmFyIGQgPSB3b3JsZFRyYW5zZm9ybS5kIC8gcmVzb2x1dGlvbjtcbiAgICB2YXIgdHggPSB3b3JsZFRyYW5zZm9ybS50eDtcbiAgICB2YXIgdHkgPSB3b3JsZFRyYW5zZm9ybS50eTtcblxuICAgIHZhciBjb2xvcnMgPSB0aGlzLmNvbG9ycztcbiAgICB2YXIgcG9zaXRpb25zID0gdGhpcy5wb3NpdGlvbnM7XG5cbiAgICBpZiAodGhpcy5yZW5kZXJlci5yb3VuZFBpeGVscykge1xuICAgICAgICAvLyB4eVxuICAgICAgICBwb3NpdGlvbnNbaW5kZXhdID0gYSAqIHcxICsgYyAqIGgxICsgdHggfCAwO1xuICAgICAgICBwb3NpdGlvbnNbaW5kZXgrMV0gPSBkICogaDEgKyBiICogdzEgKyB0eSB8IDA7XG5cbiAgICAgICAgLy8geHlcbiAgICAgICAgcG9zaXRpb25zW2luZGV4KzVdID0gYSAqIHcwICsgYyAqIGgxICsgdHggfCAwO1xuICAgICAgICBwb3NpdGlvbnNbaW5kZXgrNl0gPSBkICogaDEgKyBiICogdzAgKyB0eSB8IDA7XG5cbiAgICAgICAgIC8vIHh5XG4gICAgICAgIHBvc2l0aW9uc1tpbmRleCsxMF0gPSBhICogdzAgKyBjICogaDAgKyB0eCB8IDA7XG4gICAgICAgIHBvc2l0aW9uc1tpbmRleCsxMV0gPSBkICogaDAgKyBiICogdzAgKyB0eSB8IDA7XG5cbiAgICAgICAgLy8geHlcbiAgICAgICAgcG9zaXRpb25zW2luZGV4KzE1XSA9IGEgKiB3MSArIGMgKiBoMCArIHR4IHwgMDtcbiAgICAgICAgcG9zaXRpb25zW2luZGV4KzE2XSA9IGQgKiBoMCArIGIgKiB3MSArIHR5IHwgMDtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIC8vIHh5XG4gICAgICAgIHBvc2l0aW9uc1tpbmRleF0gPSBhICogdzEgKyBjICogaDEgKyB0eDtcbiAgICAgICAgcG9zaXRpb25zW2luZGV4KzFdID0gZCAqIGgxICsgYiAqIHcxICsgdHk7XG5cbiAgICAgICAgLy8geHlcbiAgICAgICAgcG9zaXRpb25zW2luZGV4KzVdID0gYSAqIHcwICsgYyAqIGgxICsgdHg7XG4gICAgICAgIHBvc2l0aW9uc1tpbmRleCs2XSA9IGQgKiBoMSArIGIgKiB3MCArIHR5O1xuXG4gICAgICAgICAvLyB4eVxuICAgICAgICBwb3NpdGlvbnNbaW5kZXgrMTBdID0gYSAqIHcwICsgYyAqIGgwICsgdHg7XG4gICAgICAgIHBvc2l0aW9uc1tpbmRleCsxMV0gPSBkICogaDAgKyBiICogdzAgKyB0eTtcblxuICAgICAgICAvLyB4eVxuICAgICAgICBwb3NpdGlvbnNbaW5kZXgrMTVdID0gYSAqIHcxICsgYyAqIGgwICsgdHg7XG4gICAgICAgIHBvc2l0aW9uc1tpbmRleCsxNl0gPSBkICogaDAgKyBiICogdzEgKyB0eTtcbiAgICB9XG5cbiAgICAvLyB1dlxuICAgIHBvc2l0aW9uc1tpbmRleCsyXSA9IHV2cy54MDtcbiAgICBwb3NpdGlvbnNbaW5kZXgrM10gPSB1dnMueTA7XG5cbiAgICAvLyB1dlxuICAgIHBvc2l0aW9uc1tpbmRleCs3XSA9IHV2cy54MTtcbiAgICBwb3NpdGlvbnNbaW5kZXgrOF0gPSB1dnMueTE7XG5cbiAgICAgLy8gdXZcbiAgICBwb3NpdGlvbnNbaW5kZXgrMTJdID0gdXZzLngyO1xuICAgIHBvc2l0aW9uc1tpbmRleCsxM10gPSB1dnMueTI7XG5cbiAgICAvLyB1dlxuICAgIHBvc2l0aW9uc1tpbmRleCsxN10gPSB1dnMueDM7XG4gICAgcG9zaXRpb25zW2luZGV4KzE4XSA9IHV2cy55MztcblxuICAgIC8vIGNvbG9yIGFuZCBhbHBoYVxuICAgIHZhciB0aW50ID0gc3ByaXRlLnRpbnQ7XG4gICAgY29sb3JzW2luZGV4KzRdID0gY29sb3JzW2luZGV4KzldID0gY29sb3JzW2luZGV4KzE0XSA9IGNvbG9yc1tpbmRleCsxOV0gPSAodGludCA+PiAxNikgKyAodGludCAmIDB4ZmYwMCkgKyAoKHRpbnQgJiAweGZmKSA8PCAxNikgKyAoc3ByaXRlLndvcmxkQWxwaGEgKiAyNTUgPDwgMjQpO1xuXG4gICAgLy8gaW5jcmVtZW50IHRoZSBiYXRjaHNpemVcbiAgICB0aGlzLnNwcml0ZXNbdGhpcy5jdXJyZW50QmF0Y2hTaXplKytdID0gc3ByaXRlO1xuXG5cbn07XG5cbi8qKlxuICogUmVuZGVycyBhIFRpbGluZ1Nwcml0ZSB1c2luZyB0aGUgc3ByaXRlQmF0Y2guXG4gKlxuICogQHBhcmFtIHNwcml0ZSB7VGlsaW5nU3ByaXRlfSB0aGUgdGlsaW5nU3ByaXRlIHRvIHJlbmRlclxuICovXG5XZWJHTFNwcml0ZUJhdGNoLnByb3RvdHlwZS5yZW5kZXJUaWxpbmdTcHJpdGUgPSBmdW5jdGlvbiAodGlsaW5nU3ByaXRlKSB7XG4gICAgdmFyIHRleHR1cmUgPSB0aWxpbmdTcHJpdGUudGlsaW5nVGV4dHVyZTtcblxuICAgIC8vIGNoZWNrIHRleHR1cmUuLlxuICAgIGlmICh0aGlzLmN1cnJlbnRCYXRjaFNpemUgPj0gdGhpcy5zaXplKSB7XG4gICAgICAgIC8vcmV0dXJuO1xuICAgICAgICB0aGlzLmZsdXNoKCk7XG4gICAgICAgIHRoaXMuY3VycmVudEJhc2VUZXh0dXJlID0gdGV4dHVyZS5iYXNlVGV4dHVyZTtcbiAgICB9XG5cbiAgICAvLyBzZXQgdGhlIHRleHR1cmVzIHV2cyB0ZW1wb3JhcmlseVxuICAgIC8vIFRPRE8gY3JlYXRlIGEgc2VwYXJhdGUgdGV4dHVyZSBzbyB0aGF0IHdlIGNhbiB0aWxlIHBhcnQgb2YgYSB0ZXh0dXJlXG5cbiAgICBpZiAoIXRpbGluZ1Nwcml0ZS5fdXZzKSB7XG4gICAgICAgIHRpbGluZ1Nwcml0ZS5fdXZzID0gbmV3IFRleHR1cmVVdnMoKTtcbiAgICB9XG5cbiAgICB2YXIgdXZzID0gdGlsaW5nU3ByaXRlLl91dnM7XG5cbiAgICB0aWxpbmdTcHJpdGUudGlsZVBvc2l0aW9uLnggJT0gdGV4dHVyZS5iYXNlVGV4dHVyZS53aWR0aCAqIHRpbGluZ1Nwcml0ZS50aWxlU2NhbGVPZmZzZXQueDtcbiAgICB0aWxpbmdTcHJpdGUudGlsZVBvc2l0aW9uLnkgJT0gdGV4dHVyZS5iYXNlVGV4dHVyZS5oZWlnaHQgKiB0aWxpbmdTcHJpdGUudGlsZVNjYWxlT2Zmc2V0Lnk7XG5cbiAgICB2YXIgb2Zmc2V0WCA9ICB0aWxpbmdTcHJpdGUudGlsZVBvc2l0aW9uLngvKHRleHR1cmUuYmFzZVRleHR1cmUud2lkdGgqdGlsaW5nU3ByaXRlLnRpbGVTY2FsZU9mZnNldC54KTtcbiAgICB2YXIgb2Zmc2V0WSA9ICB0aWxpbmdTcHJpdGUudGlsZVBvc2l0aW9uLnkvKHRleHR1cmUuYmFzZVRleHR1cmUuaGVpZ2h0KnRpbGluZ1Nwcml0ZS50aWxlU2NhbGVPZmZzZXQueSk7XG5cbiAgICB2YXIgc2NhbGVYID0gICh0aWxpbmdTcHJpdGUud2lkdGggLyB0ZXh0dXJlLmJhc2VUZXh0dXJlLndpZHRoKSAgLyAodGlsaW5nU3ByaXRlLnRpbGVTY2FsZS54ICogdGlsaW5nU3ByaXRlLnRpbGVTY2FsZU9mZnNldC54KTtcbiAgICB2YXIgc2NhbGVZID0gICh0aWxpbmdTcHJpdGUuaGVpZ2h0IC8gdGV4dHVyZS5iYXNlVGV4dHVyZS5oZWlnaHQpIC8gKHRpbGluZ1Nwcml0ZS50aWxlU2NhbGUueSAqIHRpbGluZ1Nwcml0ZS50aWxlU2NhbGVPZmZzZXQueSk7XG5cbiAgICB1dnMueDAgPSAwIC0gb2Zmc2V0WDtcbiAgICB1dnMueTAgPSAwIC0gb2Zmc2V0WTtcblxuICAgIHV2cy54MSA9ICgxICogc2NhbGVYKSAtIG9mZnNldFg7XG4gICAgdXZzLnkxID0gMCAtIG9mZnNldFk7XG5cbiAgICB1dnMueDIgPSAoMSAqIHNjYWxlWCkgLSBvZmZzZXRYO1xuICAgIHV2cy55MiA9ICgxICogc2NhbGVZKSAtIG9mZnNldFk7XG5cbiAgICB1dnMueDMgPSAwIC0gb2Zmc2V0WDtcbiAgICB1dnMueTMgPSAoMSAqIHNjYWxlWSkgLSBvZmZzZXRZO1xuXG4gICAgLy8gZ2V0IHRoZSB0aWxpbmdTcHJpdGVzIGN1cnJlbnQgYWxwaGEgYW5kIHRpbnQgYW5kIGNvbWJpbmluZyB0aGVtIGludG8gYSBzaW5nbGUgY29sb3JcbiAgICB2YXIgdGludCA9IHRpbGluZ1Nwcml0ZS50aW50O1xuICAgIHZhciBjb2xvciA9ICh0aW50ID4+IDE2KSArICh0aW50ICYgMHhmZjAwKSArICgodGludCAmIDB4ZmYpIDw8IDE2KSArICh0aWxpbmdTcHJpdGUuYWxwaGEgKiAyNTUgPDwgMjQpO1xuXG4gICAgdmFyIHBvc2l0aW9ucyA9IHRoaXMucG9zaXRpb25zO1xuICAgIHZhciBjb2xvcnMgPSB0aGlzLmNvbG9ycztcblxuICAgIHZhciB3aWR0aCA9IHRpbGluZ1Nwcml0ZS53aWR0aDtcbiAgICB2YXIgaGVpZ2h0ID0gdGlsaW5nU3ByaXRlLmhlaWdodDtcblxuICAgIC8vIFRPRE8gdHJpbT8/XG4gICAgdmFyIGFYID0gdGlsaW5nU3ByaXRlLmFuY2hvci54O1xuICAgIHZhciBhWSA9IHRpbGluZ1Nwcml0ZS5hbmNob3IueTtcbiAgICB2YXIgdzAgPSB3aWR0aCAqICgxLWFYKTtcbiAgICB2YXIgdzEgPSB3aWR0aCAqIC1hWDtcblxuICAgIHZhciBoMCA9IGhlaWdodCAqICgxLWFZKTtcbiAgICB2YXIgaDEgPSBoZWlnaHQgKiAtYVk7XG5cbiAgICB2YXIgaW5kZXggPSB0aGlzLmN1cnJlbnRCYXRjaFNpemUgKiA0ICogdGhpcy52ZXJ0U2l6ZTtcblxuICAgIHZhciByZXNvbHV0aW9uID0gdGV4dHVyZS5iYXNlVGV4dHVyZS5yZXNvbHV0aW9uO1xuXG4gICAgdmFyIHdvcmxkVHJhbnNmb3JtID0gdGlsaW5nU3ByaXRlLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgdmFyIGEgPSB3b3JsZFRyYW5zZm9ybS5hIC8gcmVzb2x1dGlvbjsvL1swXTtcbiAgICB2YXIgYiA9IHdvcmxkVHJhbnNmb3JtLmIgLyByZXNvbHV0aW9uOy8vWzNdO1xuICAgIHZhciBjID0gd29ybGRUcmFuc2Zvcm0uYyAvIHJlc29sdXRpb247Ly9bMV07XG4gICAgdmFyIGQgPSB3b3JsZFRyYW5zZm9ybS5kIC8gcmVzb2x1dGlvbjsvL1s0XTtcbiAgICB2YXIgdHggPSB3b3JsZFRyYW5zZm9ybS50eDsvL1syXTtcbiAgICB2YXIgdHkgPSB3b3JsZFRyYW5zZm9ybS50eTsvL1s1XTtcblxuICAgIC8vIHh5XG4gICAgcG9zaXRpb25zW2luZGV4KytdID0gYSAqIHcxICsgYyAqIGgxICsgdHg7XG4gICAgcG9zaXRpb25zW2luZGV4KytdID0gZCAqIGgxICsgYiAqIHcxICsgdHk7XG4gICAgLy8gdXZcbiAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSB1dnMueDA7XG4gICAgcG9zaXRpb25zW2luZGV4KytdID0gdXZzLnkwO1xuICAgIC8vIGNvbG9yXG4gICAgY29sb3JzW2luZGV4KytdID0gY29sb3I7XG5cbiAgICAvLyB4eVxuICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IChhICogdzAgKyBjICogaDEgKyB0eCk7XG4gICAgcG9zaXRpb25zW2luZGV4KytdID0gZCAqIGgxICsgYiAqIHcwICsgdHk7XG4gICAgLy8gdXZcbiAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSB1dnMueDE7XG4gICAgcG9zaXRpb25zW2luZGV4KytdID0gdXZzLnkxO1xuICAgIC8vIGNvbG9yXG4gICAgY29sb3JzW2luZGV4KytdID0gY29sb3I7XG5cbiAgICAvLyB4eVxuICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IGEgKiB3MCArIGMgKiBoMCArIHR4O1xuICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IGQgKiBoMCArIGIgKiB3MCArIHR5O1xuICAgIC8vIHV2XG4gICAgcG9zaXRpb25zW2luZGV4KytdID0gdXZzLngyO1xuICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IHV2cy55MjtcbiAgICAvLyBjb2xvclxuICAgIGNvbG9yc1tpbmRleCsrXSA9IGNvbG9yO1xuXG4gICAgLy8geHlcbiAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSBhICogdzEgKyBjICogaDAgKyB0eDtcbiAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSBkICogaDAgKyBiICogdzEgKyB0eTtcbiAgICAvLyB1dlxuICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IHV2cy54MztcbiAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSB1dnMueTM7XG4gICAgLy8gY29sb3JcbiAgICBjb2xvcnNbaW5kZXgrK10gPSBjb2xvcjtcblxuICAgIC8vIGluY3JlbWVudCB0aGUgYmF0Y2hzaXplXG4gICAgdGhpcy5zcHJpdGVzW3RoaXMuY3VycmVudEJhdGNoU2l6ZSsrXSA9IHRpbGluZ1Nwcml0ZTtcbn07XG5cbi8qKlxuICogUmVuZGVycyB0aGUgY29udGVudCBhbmQgZW1wdGllcyB0aGUgY3VycmVudCBiYXRjaC5cbiAqXG4gKi9cbldlYkdMU3ByaXRlQmF0Y2gucHJvdG90eXBlLmZsdXNoID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIElmIHRoZSBiYXRjaCBpcyBsZW5ndGggMCB0aGVuIHJldHVybiBhcyB0aGVyZSBpcyBub3RoaW5nIHRvIGRyYXdcbiAgICBpZiAodGhpcy5jdXJyZW50QmF0Y2hTaXplID09PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuICAgIHZhciBzaGFkZXI7XG5cbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLmRpcnR5ID0gZmFsc2U7XG4gICAgICAgIC8vIGJpbmQgdGhlIG1haW4gdGV4dHVyZVxuICAgICAgICBnbC5hY3RpdmVUZXh0dXJlKGdsLlRFWFRVUkUwKTtcblxuICAgICAgICAvLyBiaW5kIHRoZSBidWZmZXJzXG4gICAgICAgIGdsLmJpbmRCdWZmZXIoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLnZlcnRleEJ1ZmZlcik7XG4gICAgICAgIGdsLmJpbmRCdWZmZXIoZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIsIHRoaXMuaW5kZXhCdWZmZXIpO1xuXG4gICAgICAgIC8vIHRoaXMgaXMgdGhlIHNhbWUgZm9yIGVhY2ggc2hhZGVyP1xuICAgICAgICB2YXIgc3RyaWRlID0gIHRoaXMudmVydFNpemUgKiA0O1xuICAgICAgICBnbC52ZXJ0ZXhBdHRyaWJQb2ludGVyKHRoaXMuc2hhZGVyLmF0dHJpYnV0ZXMuYVZlcnRleFBvc2l0aW9uLCAyLCBnbC5GTE9BVCwgZmFsc2UsIHN0cmlkZSwgMCk7XG4gICAgICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIodGhpcy5zaGFkZXIuYXR0cmlidXRlcy5hVGV4dHVyZUNvb3JkLCAyLCBnbC5GTE9BVCwgZmFsc2UsIHN0cmlkZSwgMiAqIDQpO1xuXG4gICAgICAgIC8vIGNvbG9yIGF0dHJpYnV0ZXMgd2lsbCBiZSBpbnRlcnByZXRlZCBhcyB1bnNpZ25lZCBieXRlcyBhbmQgbm9ybWFsaXplZFxuICAgICAgICBnbC52ZXJ0ZXhBdHRyaWJQb2ludGVyKHRoaXMuc2hhZGVyLmF0dHJpYnV0ZXMuYUNvbG9yLCA0LCBnbC5VTlNJR05FRF9CWVRFLCB0cnVlLCBzdHJpZGUsIDQgKiA0KTtcbiAgICB9XG5cbiAgICAvLyB1cGxvYWQgdGhlIHZlcnRzIHRvIHRoZSBidWZmZXJcbiAgICBpZiAodGhpcy5jdXJyZW50QmF0Y2hTaXplID4gKCB0aGlzLnNpemUgKiAwLjUgKSApIHtcbiAgICAgICAgZ2wuYnVmZmVyU3ViRGF0YShnbC5BUlJBWV9CVUZGRVIsIDAsIHRoaXMudmVydGljZXMpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdmFyIHZpZXcgPSB0aGlzLnBvc2l0aW9ucy5zdWJhcnJheSgwLCB0aGlzLmN1cnJlbnRCYXRjaFNpemUgKiA0ICogdGhpcy52ZXJ0U2l6ZSk7XG4gICAgICAgIGdsLmJ1ZmZlclN1YkRhdGEoZ2wuQVJSQVlfQlVGRkVSLCAwLCB2aWV3KTtcbiAgICB9XG5cbiAgICB2YXIgbmV4dFRleHR1cmUsIG5leHRCbGVuZE1vZGUsIG5leHRTaGFkZXI7XG4gICAgdmFyIGJhdGNoU2l6ZSA9IDA7XG4gICAgdmFyIHN0YXJ0ID0gMDtcblxuICAgIHZhciBjdXJyZW50QmFzZVRleHR1cmUgPSBudWxsO1xuICAgIHZhciBjdXJyZW50QmxlbmRNb2RlID0gdGhpcy5yZW5kZXJlci5ibGVuZE1vZGVNYW5hZ2VyLmN1cnJlbnRCbGVuZE1vZGU7XG4gICAgdmFyIGN1cnJlbnRTaGFkZXIgPSBudWxsO1xuXG4gICAgdmFyIGJsZW5kU3dhcCA9IGZhbHNlO1xuICAgIHZhciBzaGFkZXJTd2FwID0gZmFsc2U7XG4gICAgdmFyIHNwcml0ZTtcblxuICAgIGZvciAodmFyIGkgPSAwLCBqID0gdGhpcy5jdXJyZW50QmF0Y2hTaXplOyBpIDwgajsgaSsrKSB7XG5cbiAgICAgICAgc3ByaXRlID0gdGhpcy5zcHJpdGVzW2ldO1xuXG4gICAgICAgIG5leHRUZXh0dXJlID0gc3ByaXRlLnRleHR1cmUuYmFzZVRleHR1cmU7XG4gICAgICAgIG5leHRCbGVuZE1vZGUgPSBzcHJpdGUuYmxlbmRNb2RlO1xuICAgICAgICBuZXh0U2hhZGVyID0gc3ByaXRlLnNoYWRlciB8fCB0aGlzLnNoYWRlcjtcblxuICAgICAgICBibGVuZFN3YXAgPSBjdXJyZW50QmxlbmRNb2RlICE9PSBuZXh0QmxlbmRNb2RlO1xuICAgICAgICBzaGFkZXJTd2FwID0gY3VycmVudFNoYWRlciAhPT0gbmV4dFNoYWRlcjsgLy8gc2hvdWxkIEkgdXNlIHV1aWRTPz8/XG5cbiAgICAgICAgaWYgKGN1cnJlbnRCYXNlVGV4dHVyZSAhPT0gbmV4dFRleHR1cmUgfHwgYmxlbmRTd2FwIHx8IHNoYWRlclN3YXApIHtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyQmF0Y2goY3VycmVudEJhc2VUZXh0dXJlLCBiYXRjaFNpemUsIHN0YXJ0KTtcblxuICAgICAgICAgICAgc3RhcnQgPSBpO1xuICAgICAgICAgICAgYmF0Y2hTaXplID0gMDtcbiAgICAgICAgICAgIGN1cnJlbnRCYXNlVGV4dHVyZSA9IG5leHRUZXh0dXJlO1xuXG4gICAgICAgICAgICBpZiAoYmxlbmRTd2FwKSB7XG4gICAgICAgICAgICAgICAgY3VycmVudEJsZW5kTW9kZSA9IG5leHRCbGVuZE1vZGU7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5ibGVuZE1vZGVNYW5hZ2VyLnNldEJsZW5kTW9kZSggY3VycmVudEJsZW5kTW9kZSApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoc2hhZGVyU3dhcCkge1xuICAgICAgICAgICAgICAgIGN1cnJlbnRTaGFkZXIgPSBuZXh0U2hhZGVyO1xuXG4gICAgICAgICAgICAgICAgc2hhZGVyID0gY3VycmVudFNoYWRlci5zaGFkZXJzID8gY3VycmVudFNoYWRlci5zaGFkZXJzW2dsLmlkXSA6IGN1cnJlbnRTaGFkZXI7XG5cbiAgICAgICAgICAgICAgICBpZiAoIXNoYWRlcikge1xuICAgICAgICAgICAgICAgICAgICBzaGFkZXIgPSBuZXcgU2hhZGVyKGdsLCBudWxsLCBjdXJyZW50U2hhZGVyLmZyYWdtZW50U3JjLCBjdXJyZW50U2hhZGVyLnVuaWZvcm1zKTtcbiAgICAgICAgICAgICAgICAgICAgY3VycmVudFNoYWRlci5zaGFkZXJzW2dsLmlkXSA9IHNoYWRlcjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBzZXQgc2hhZGVyIGZ1bmN0aW9uPz8/XG4gICAgICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLnNldFNoYWRlcihzaGFkZXIpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHNoYWRlci5kaXJ0eSkge1xuICAgICAgICAgICAgICAgICAgICBzaGFkZXIuc3luY1VuaWZvcm1zKCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gYm90aCB0aGVhc2Ugb25seSBuZWVkIHRvIGJlIHNldCBpZiB0aGV5IGFyZSBjaGFuZ2luZy4uXG4gICAgICAgICAgICAgICAgLy8gc2V0IHRoZSBwcm9qZWN0aW9uXG4gICAgICAgICAgICAgICAgdmFyIHByb2plY3Rpb24gPSB0aGlzLnJlbmRlcmVyLnByb2plY3Rpb247XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTJmKHNoYWRlci51bmlmb3Jtcy5wcm9qZWN0aW9uVmVjdG9yLl9sb2NhdGlvbiwgcHJvamVjdGlvbi54LCBwcm9qZWN0aW9uLnkpO1xuXG4gICAgICAgICAgICAgICAgLy8gVE9ETyAtIHRoaXMgaXMgdGVtcHJvcmFyeSFcbiAgICAgICAgICAgICAgICB2YXIgb2Zmc2V0VmVjdG9yID0gdGhpcy5yZW5kZXJlci5vZmZzZXQ7XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTJmKHNoYWRlci51bmlmb3Jtcy5vZmZzZXRWZWN0b3IuX2xvY2F0aW9uLCBvZmZzZXRWZWN0b3IueCwgb2Zmc2V0VmVjdG9yLnkpO1xuXG4gICAgICAgICAgICAgICAgLy8gc2V0IHRoZSBwb2ludGVyc1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgYmF0Y2hTaXplKys7XG4gICAgfVxuXG4gICAgdGhpcy5yZW5kZXJCYXRjaChjdXJyZW50QmFzZVRleHR1cmUsIGJhdGNoU2l6ZSwgc3RhcnQpO1xuXG4gICAgLy8gdGhlbiByZXNldCB0aGUgYmF0Y2ghXG4gICAgdGhpcy5jdXJyZW50QmF0Y2hTaXplID0gMDtcbn07XG5cbi8qKlxuICogQHBhcmFtIHRleHR1cmUge1RleHR1cmV9XG4gKiBAcGFyYW0gc2l6ZSB7bnVtYmVyfVxuICogQHBhcmFtIHN0YXJ0SW5kZXgge251bWJlcn1cbiAqL1xuV2ViR0xTcHJpdGVCYXRjaC5wcm90b3R5cGUucmVuZGVyQmF0Y2ggPSBmdW5jdGlvbiAodGV4dHVyZSwgc2l6ZSwgc3RhcnRJbmRleCkge1xuICAgIGlmIChzaXplID09PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuXG4gICAgaWYgKCF0ZXh0dXJlLl9nbFRleHR1cmVzW2dsLmlkXSkge1xuICAgICAgICB0aGlzLnJlbmRlcmVyLnVwZGF0ZVRleHR1cmUodGV4dHVyZSk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICAvLyBiaW5kIHRoZSBjdXJyZW50IHRleHR1cmVcbiAgICAgICAgZ2wuYmluZFRleHR1cmUoZ2wuVEVYVFVSRV8yRCwgdGV4dHVyZS5fZ2xUZXh0dXJlc1tnbC5pZF0pO1xuICAgIH1cblxuICAgIC8vIG5vdyBkcmF3IHRob3NlIHN1Y2thcyFcbiAgICBnbC5kcmF3RWxlbWVudHMoZ2wuVFJJQU5HTEVTLCBzaXplICogNiwgZ2wuVU5TSUdORURfU0hPUlQsIHN0YXJ0SW5kZXggKiA2ICogMik7XG5cbiAgICAvLyBpbmNyZW1lbnQgdGhlIGRyYXcgY291bnRcbiAgICB0aGlzLnJlbmRlcmVyLmRyYXdDb3VudCsrO1xufTtcblxuLyoqXG4gKlxuICovXG5XZWJHTFNwcml0ZUJhdGNoLnByb3RvdHlwZS5zdG9wID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZmx1c2goKTtcbiAgICB0aGlzLmRpcnR5ID0gdHJ1ZTtcbn07XG5cbi8qKlxuICpcbiAqL1xuV2ViR0xTcHJpdGVCYXRjaC5wcm90b3R5cGUuc3RhcnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5kaXJ0eSA9IHRydWU7XG59O1xuXG4vKipcbiAqIERlc3Ryb3lzIHRoZSBTcHJpdGVCYXRjaC5cbiAqXG4gKi9cbldlYkdMU3ByaXRlQmF0Y2gucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5yZW5kZXJlci5nbC5kZWxldGVCdWZmZXIodGhpcy52ZXJ0ZXhCdWZmZXIpO1xuICAgIHRoaXMucmVuZGVyZXIuZ2wuZGVsZXRlQnVmZmVyKHRoaXMuaW5kZXhCdWZmZXIpO1xuXG4gICAgdGhpcy52ZXJ0aWNlcyA9IG51bGw7XG4gICAgdGhpcy5pbmRpY2VzID0gbnVsbDtcblxuICAgIHRoaXMudmVydGV4QnVmZmVyID0gbnVsbDtcbiAgICB0aGlzLmluZGV4QnVmZmVyID0gbnVsbDtcblxuICAgIHRoaXMuY3VycmVudEJhc2VUZXh0dXJlID0gbnVsbDtcblxuICAgIHRoaXMucmVuZGVyZXIgPSBudWxsO1xufTtcbiIsInZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzJyksXG4gICAgQ09OU1QgPSByZXF1aXJlKCcuLi9jb25zdCcpO1xuXG4vKipcbiAqIEEgdGV4dHVyZSBzdG9yZXMgdGhlIGluZm9ybWF0aW9uIHRoYXQgcmVwcmVzZW50cyBhbiBpbWFnZS4gQWxsIHRleHR1cmVzIGhhdmUgYSBiYXNlIHRleHR1cmUuXG4gKlxuICogQGNsYXNzXG4gKiBAbWl4ZXMgZXZlbnRUYXJnZXRcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHNvdXJjZSB7SW1hZ2V8Q2FudmFzfSB0aGUgc291cmNlIG9iamVjdCBvZiB0aGUgdGV4dHVyZS5cbiAqIEBwYXJhbSBbc2NhbGVNb2RlPXNjYWxlTW9kZXMuREVGQVVMVF0ge251bWJlcn0gU2VlIHtAbGluayBzY2FsZU1vZGVzfSBmb3IgcG9zc2libGUgdmFsdWVzXG4gKi9cbmZ1bmN0aW9uIEJhc2VUZXh0dXJlKHNvdXJjZSwgc2NhbGVNb2RlKSB7XG4gICAgdGhpcy51dWlkID0gdXRpbHMudXVpZCgpO1xuXG4gICAgLyoqXG4gICAgICogVGhlIFJlc29sdXRpb24gb2YgdGhlIHRleHR1cmUuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5yZXNvbHV0aW9uID0gMTtcblxuICAgIC8qKlxuICAgICAqIFRoZSB3aWR0aCBvZiB0aGUgYmFzZSB0ZXh0dXJlIHNldCB3aGVuIHRoZSBpbWFnZSBoYXMgbG9hZGVkXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQHJlYWRPbmx5XG4gICAgICovXG4gICAgdGhpcy53aWR0aCA9IDEwMDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBoZWlnaHQgb2YgdGhlIGJhc2UgdGV4dHVyZSBzZXQgd2hlbiB0aGUgaW1hZ2UgaGFzIGxvYWRlZFxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEByZWFkT25seVxuICAgICAqL1xuICAgIHRoaXMuaGVpZ2h0ID0gMTAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHNjYWxlIG1vZGUgdG8gYXBwbHkgd2hlbiBzY2FsaW5nIHRoaXMgdGV4dHVyZVxuICAgICAqXG4gICAgICogQG1lbWJlciB7e251bWJlcn19XG4gICAgICogQGRlZmF1bHQgc2NhbGVNb2Rlcy5MSU5FQVJcbiAgICAgKi9cbiAgICB0aGlzLnNjYWxlTW9kZSA9IHNjYWxlTW9kZSB8fCBDT05TVC5zY2FsZU1vZGVzLkRFRkFVTFQ7XG5cbiAgICAvKipcbiAgICAgKiBTZXQgdG8gdHJ1ZSBvbmNlIHRoZSBiYXNlIHRleHR1cmUgaGFzIHN1Y2Nlc3NmdWxseSBsb2FkZWQuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIG5ldmVyIHRydWUgaWYgdGhlIHVuZGVybHlpbmcgc291cmNlIGZhaWxzIHRvIGxvYWQgb3IgaGFzIG5vIHRleHR1cmUgZGF0YS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICogQHJlYWRPbmx5XG4gICAgICovXG4gICAgdGhpcy5oYXNMb2FkZWQgPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqIFNldCB0byB0cnVlIGlmIHRoZSBzb3VyY2UgaXMgY3VycmVudGx5IGxvYWRpbmcuXG4gICAgICpcbiAgICAgKiBJZiBhbiBJbWFnZSBzb3VyY2UgaXMgbG9hZGluZyB0aGUgJ2xvYWRlZCcgb3IgJ2Vycm9yJyBldmVudCB3aWxsIGJlXG4gICAgICogZGlzcGF0Y2hlZCB3aGVuIHRoZSBvcGVyYXRpb24gZW5kcy4gQW4gdW5kZXJ5bGluZyBzb3VyY2UgdGhhdCBpc1xuICAgICAqIGltbWVkaWF0ZWx5LWF2YWlsYWJsZSBieXBhc3NlcyBsb2FkaW5nIGVudGlyZWx5LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKi9cbiAgICB0aGlzLmlzTG9hZGluZyA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGltYWdlIHNvdXJjZSB0aGF0IGlzIHVzZWQgdG8gY3JlYXRlIHRoZSB0ZXh0dXJlLlxuICAgICAqXG4gICAgICogVE9ETzogTWFrZSB0aGlzIGEgc2V0dGVyIHRoYXQgY2FsbHMgbG9hZFNvdXJjZSgpO1xuICAgICAqXG4gICAgICogQG1lbWJlciB7SW1hZ2V8Q2FudmFzfVxuICAgICAqIEByZWFkb25seVxuICAgICAqL1xuICAgIHRoaXMuc291cmNlID0gbnVsbDsgLy8gc2V0IGluIGxvYWRTb3VyY2UsIGlmIGF0IGFsbFxuXG4gICAgLyoqXG4gICAgICogQ29udHJvbHMgaWYgUkdCIGNoYW5uZWxzIHNob3VsZCBiZSBwcmUtbXVsdGlwbGllZCBieSBBbHBoYSAgKFdlYkdMIG9ubHkpXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqIEBkZWZhdWx0IHRydWVcbiAgICAgKi9cbiAgICB0aGlzLnByZW11bHRpcGxpZWRBbHBoYSA9IHRydWU7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtzdHJpbmd9XG4gICAgICovXG4gICAgdGhpcy5pbWFnZVVybCA9IG51bGw7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fcG93ZXJPZjIgPSBmYWxzZTtcblxuICAgIC8vIHVzZWQgZm9yIHdlYkdMXG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqIFNldCB0aGlzIHRvIHRydWUgaWYgYSBtaXBtYXAgb2YgdGhpcyB0ZXh0dXJlIG5lZWRzIHRvIGJlIGdlbmVyYXRlZC4gVGhpcyB2YWx1ZSBuZWVkcyB0byBiZSBzZXQgYmVmb3JlIHRoZSB0ZXh0dXJlIGlzIHVzZWRcbiAgICAgKiBBbHNvIHRoZSB0ZXh0dXJlIG11c3QgYmUgYSBwb3dlciBvZiB0d28gc2l6ZSB0byB3b3JrXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMubWlwbWFwID0gZmFsc2U7XG5cbiAgICAvKipcbiAgICAgKiBBIG1hcCBvZiByZW5kZXJlciBJRHMgdG8gd2ViZ2wgdGV4dHVyZXNcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge29iamVjdDxudW1iZXIsIFdlYkdMVGV4dHVyZT59XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl9nbFRleHR1cmVzID0ge307XG5cbiAgICAvKipcbiAgICAgKiBEb2VzIHRoZSB0ZXh0dXJlIG9uIHRoZSBHUFUgbmVlZCB0byBiZSB1cGRhdGVkP1xuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuX25lZWRzVXBkYXRlID0gZmFsc2U7XG5cbiAgICAvLyBpZiBubyBzb3VyY2UgcGFzc2VkIGRvbid0IHRyeSB0byBsb2FkXG4gICAgaWYgKHNvdXJjZSkge1xuICAgICAgICB0aGlzLmxvYWRTb3VyY2Uoc291cmNlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBGaXJlZCB3aGVuIGEgbm90LWltbWVkaWF0ZWx5LWF2YWlsYWJsZSBzb3VyY2UgZmluaXNoZXMgbG9hZGluZy5cbiAgICAgKlxuICAgICAqIEBldmVudCBsb2FkZWRcbiAgICAgKiBAcHJvdGVjdGVkXG4gICAgICovXG5cbiAgICAvKipcbiAgICAgKiBGaXJlZCB3aGVuIGEgbm90LWltbWVkaWF0ZWx5LWF2YWlsYWJsZSBzb3VyY2UgZmFpbHMgdG8gbG9hZC5cbiAgICAgKlxuICAgICAqIEBldmVudCBlcnJvclxuICAgICAqIEBwcm90ZWN0ZWRcbiAgICAgKi9cbn1cblxuQmFzZVRleHR1cmUucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQmFzZVRleHR1cmU7XG5tb2R1bGUuZXhwb3J0cyA9IEJhc2VUZXh0dXJlO1xuXG51dGlscy5ldmVudFRhcmdldC5taXhpbihCYXNlVGV4dHVyZS5wcm90b3R5cGUpO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhCYXNlVGV4dHVyZS5wcm90b3R5cGUsIHtcbiAgICBuZWVkc1VwZGF0ZToge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9uZWVkc1VwZGF0ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsKSB7XG4gICAgICAgICAgICB0aGlzLl9uZWVkc1VwZGF0ZSA9IHZhbDtcblxuICAgICAgICAgICAgaWYgKHZhbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuZW1pdCgndXBkYXRlJywgdGhpcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59KTtcblxuLyoqXG4gKiBMb2FkIGEgc291cmNlLlxuICpcbiAqIElmIHRoZSBzb3VyY2UgaXMgbm90LWltbWVkaWF0ZWx5LWF2YWlsYWJsZSwgc3VjaCBhcyBhbiBpbWFnZSB0aGF0IG5lZWRzIHRvIGJlXG4gKiBkb3dubG9hZGVkLCB0aGVuIHRoZSAnbG9hZGVkJyBvciAnZXJyb3InIGV2ZW50IHdpbGwgYmUgZGlzcGF0Y2hlZCBpbiB0aGUgZnV0dXJlXG4gKiBhbmQgYGhhc0xvYWRlZGAgd2lsbCByZW1haW4gZmFsc2UgYWZ0ZXIgdGhpcyBjYWxsLlxuICpcbiAqIFRoZSBsb2dpYyBzdGF0ZSBhZnRlciBjYWxsaW5nIGBsb2FkU291cmNlYCBkaXJlY3RseSBvciBpbmRpcmVjdGx5IChlZy4gYGZyb21JbWFnZWAsIGBuZXcgQmFzZVRleHR1cmVgKSBpczpcbiAqXG4gKiAgICAgaWYgKHRleHR1cmUuaGFzTG9hZGVkKSB7XG4gKiAgICAgICAgLy8gdGV4dHVyZSByZWFkeSBmb3IgdXNlXG4gKiAgICAgfSBlbHNlIGlmICh0ZXh0dXJlLmlzTG9hZGluZykge1xuICogICAgICAgIC8vIGxpc3RlbiB0byAnbG9hZGVkJyBhbmQvb3IgJ2Vycm9yJyBldmVudHMgb24gdGV4dHVyZVxuICogICAgIH0gZWxzZSB7XG4gKiAgICAgICAgLy8gbm90IGxvYWRpbmcsIG5vdCBnb2luZyB0byBsb2FkIFVOTEVTUyB0aGUgc291cmNlIGlzIHJlbG9hZGVkXG4gKiAgICAgICAgLy8gKGl0IG1heSBzdGlsbCBtYWtlIHNlbnNlIHRvIGxpc3RlbiB0byB0aGUgZXZlbnRzKVxuICogICAgIH1cbiAqXG4gKiBAcHJvdGVjdGVkXG4gKiBAcGFyYW0gc291cmNlIHtJbWFnZXxDYW52YXN9IHRoZSBzb3VyY2Ugb2JqZWN0IG9mIHRoZSB0ZXh0dXJlLlxuICovXG5CYXNlVGV4dHVyZS5wcm90b3R5cGUubG9hZFNvdXJjZSA9IGZ1bmN0aW9uIChzb3VyY2UpIHtcbiAgICB2YXIgd2FzTG9hZGluZyA9IHRoaXMuaXNMb2FkaW5nO1xuICAgIHRoaXMuaGFzTG9hZGVkID0gZmFsc2U7XG4gICAgdGhpcy5pc0xvYWRpbmcgPSBmYWxzZTtcblxuICAgIGlmICh3YXNMb2FkaW5nICYmIHRoaXMuc291cmNlKSB7XG4gICAgICAgIHRoaXMuc291cmNlLm9ubG9hZCA9IG51bGw7XG4gICAgICAgIHRoaXMuc291cmNlLm9uZXJyb3IgPSBudWxsO1xuICAgIH1cblxuICAgIHRoaXMuc291cmNlID0gc291cmNlO1xuXG4gICAgLy8gQXBwbHkgc291cmNlIGlmIGxvYWRlZC4gT3RoZXJ3aXNlIHNldHVwIGFwcHJvcHJpYXRlIGxvYWRpbmcgbW9uaXRvcnMuXG4gICAgaWYgKCh0aGlzLnNvdXJjZS5jb21wbGV0ZSB8fCB0aGlzLnNvdXJjZS5nZXRDb250ZXh0KSAmJiB0aGlzLnNvdXJjZS53aWR0aCAmJiB0aGlzLnNvdXJjZS5oZWlnaHQpIHtcbiAgICAgICAgdGhpcy5fc291cmNlTG9hZGVkKCk7XG4gICAgfVxuICAgIGVsc2UgIGlmKCFzb3VyY2UuZ2V0Q29udGV4dCkge1xuICAgICAgICAvLyBJbWFnZSBmYWlsIC8gbm90IHJlYWR5XG4gICAgICAgIHRoaXMuaXNMb2FkaW5nID0gdHJ1ZTtcblxuICAgICAgICB2YXIgc2NvcGUgPSB0aGlzO1xuXG4gICAgICAgIHNvdXJjZS5vbmxvYWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBzb3VyY2Uub25sb2FkID0gbnVsbDtcbiAgICAgICAgICAgIHNvdXJjZS5vbmVycm9yID0gbnVsbDtcblxuICAgICAgICAgICAgaWYoIXNjb3BlLmlzTG9hZGluZykge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2NvcGUuaXNMb2FkaW5nID0gZmFsc2U7XG4gICAgICAgICAgICBzY29wZS5fc291cmNlTG9hZGVkKCk7XG5cbiAgICAgICAgICAgIHNjb3BlLmVtaXQoJ2xvYWRlZCcsIHNjb3BlKTtcbiAgICAgICAgfTtcblxuICAgICAgICBzb3VyY2Uub25lcnJvciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHNvdXJjZS5vbmxvYWQgPSBudWxsO1xuICAgICAgICAgICAgc291cmNlLm9uZXJyb3IgPSBudWxsO1xuXG4gICAgICAgICAgICBpZighc2NvcGUuaXNMb2FkaW5nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzY29wZS5pc0xvYWRpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgIHNjb3BlLmVtaXQoJ2Vycm9yJywgc2NvcGUpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFBlciBodHRwOi8vd3d3LnczLm9yZy9UUi9odG1sNS9lbWJlZGRlZC1jb250ZW50LTAuaHRtbCN0aGUtaW1nLWVsZW1lbnRcbiAgICAgICAgLy8gICBcIlRoZSB2YWx1ZSBvZiBgY29tcGxldGVgIGNhbiB0aHVzIGNoYW5nZSB3aGlsZSBhIHNjcmlwdCBpcyBleGVjdXRpbmcuXCJcbiAgICAgICAgLy8gU28gY29tcGxldGUgbmVlZHMgdG8gYmUgcmUtY2hlY2tlZCBhZnRlciB0aGUgY2FsbGJhY2tzIGhhdmUgYmVlbiBhZGRlZC4uXG4gICAgICAgIGlmIChzb3VyY2UuY29tcGxldGUpIHtcbiAgICAgICAgICAgIHRoaXMuaXNMb2FkaW5nID0gZmFsc2U7XG5cbiAgICAgICAgICAgIC8vIC4uYW5kIGlmIHdlJ3JlIGNvbXBsZXRlIG5vdywgbm8gbmVlZCBmb3IgY2FsbGJhY2tzXG4gICAgICAgICAgICBzb3VyY2Uub25sb2FkID0gbnVsbDtcbiAgICAgICAgICAgIHNvdXJjZS5vbmVycm9yID0gbnVsbDtcblxuICAgICAgICAgICAgaWYgKHNvdXJjZS53aWR0aCAmJiBzb3VyY2UuaGVpZ2h0KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fc291cmNlTG9hZGVkKCk7XG5cbiAgICAgICAgICAgICAgICAvLyBJZiBhbnkgcHJldmlvdXMgc3Vic2NyaWJlcnMgcG9zc2libGVcbiAgICAgICAgICAgICAgICBpZiAod2FzTG9hZGluZykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2xvYWRlZCcsIHRoaXMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIElmIGFueSBwcmV2aW91cyBzdWJzY3JpYmVycyBwb3NzaWJsZVxuICAgICAgICAgICAgICAgIGlmICh3YXNMb2FkaW5nKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZW1pdCgnZXJyb3InLCB0aGlzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4vKipcbiAqIFVzZWQgaW50ZXJuYWxseSB0byB1cGRhdGUgdGhlIHdpZHRoLCBoZWlnaHQsIGFuZCBzb21lIG90aGVyIHRyYWNraW5nIHZhcnMgb25jZVxuICogYSBzb3VyY2UgaGFzIHN1Y2Nlc3NmdWxseSBsb2FkZWQuXG4gKlxuICogQHByaXZhdGVcbiAqL1xuQmFzZVRleHR1cmUucHJvdG90eXBlLl9zb3VyY2VMb2FkZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5oYXNMb2FkZWQgPSB0cnVlO1xuXG4gICAgdGhpcy53aWR0aCA9IHRoaXMuc291cmNlLm5hdHVyYWxXaWR0aCB8fCB0aGlzLnNvdXJjZS53aWR0aDtcbiAgICB0aGlzLmhlaWdodCA9IHRoaXMuc291cmNlLm5hdHVyYWxIZWlnaHQgfHwgdGhpcy5zb3VyY2UuaGVpZ2h0O1xuXG4gICAgdGhpcy5uZWVkc1VwZGF0ZSA9IHRydWU7XG59O1xuXG4vKipcbiAqIERlc3Ryb3lzIHRoaXMgYmFzZSB0ZXh0dXJlXG4gKlxuICovXG5CYXNlVGV4dHVyZS5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5pbWFnZVVybCkge1xuICAgICAgICBkZWxldGUgdXRpbHMuQmFzZVRleHR1cmVDYWNoZVt0aGlzLmltYWdlVXJsXTtcbiAgICAgICAgZGVsZXRlIHV0aWxzLlRleHR1cmVDYWNoZVt0aGlzLmltYWdlVXJsXTtcbiAgICAgICAgdGhpcy5pbWFnZVVybCA9IG51bGw7XG4gICAgICAgIGlmICghbmF2aWdhdG9yLmlzQ29jb29uSlMpIHtcbiAgICAgICAgICAgIHRoaXMuc291cmNlLnNyYyA9ICcnO1xuICAgICAgICB9XG4gICAgfVxuICAgIGVsc2UgaWYgKHRoaXMuc291cmNlICYmIHRoaXMuc291cmNlLl9waXhpSWQpIHtcbiAgICAgICAgZGVsZXRlIHV0aWxzLkJhc2VUZXh0dXJlQ2FjaGVbdGhpcy5zb3VyY2UuX3BpeGlJZF07XG4gICAgfVxuICAgIHRoaXMuc291cmNlID0gbnVsbDtcblxuICAgIHRoaXMuZGlzcG9zZSgpO1xufTtcblxuLyoqXG4gKiBGcmVlcyB0aGUgdGV4dHVyZSBmcm9tIFdlYkdMIG1lbW9yeSB3aXRob3V0IGRlc3Ryb3lpbmcgdGhpcyB0ZXh0dXJlIG9iamVjdC5cbiAqIFRoaXMgbWVhbnMgeW91IGNhbiBzdGlsbCB1c2UgdGhlIHRleHR1cmUgbGF0ZXIgd2hpY2ggd2lsbCB1cGxvYWQgaXQgdG8gR1BVXG4gKiBtZW1vcnkgYWdhaW4uXG4gKlxuICovXG5CYXNlVGV4dHVyZS5wcm90b3R5cGUuZGlzcG9zZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmVtaXQoJ2Rpc3Bvc2UnLCB0aGlzKTtcbn07XG5cbi8qKlxuICogQ2hhbmdlcyB0aGUgc291cmNlIGltYWdlIG9mIHRoZSB0ZXh0dXJlLlxuICogVGhlIG9yaWdpbmFsIHNvdXJjZSBtdXN0IGJlIGFuIEltYWdlIGVsZW1lbnQuXG4gKlxuICogQHBhcmFtIG5ld1NyYyB7c3RyaW5nfSB0aGUgcGF0aCBvZiB0aGUgaW1hZ2VcbiAqL1xuQmFzZVRleHR1cmUucHJvdG90eXBlLnVwZGF0ZVNvdXJjZUltYWdlID0gZnVuY3Rpb24gKG5ld1NyYykge1xuICAgIHRoaXMuc291cmNlLnNyYyA9IG5ld1NyYztcbiAgICB0aGlzLmxvYWRTb3VyY2UodGhpcy5zb3VyY2UpO1xufTtcblxuLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdGhhdCBjcmVhdGVzIGEgYmFzZSB0ZXh0dXJlIGZyb20gdGhlIGdpdmVuIGltYWdlIHVybC5cbiAqIElmIHRoZSBpbWFnZSBpcyBub3QgaW4gdGhlIGJhc2UgdGV4dHVyZSBjYWNoZSBpdCB3aWxsIGJlIGNyZWF0ZWQgYW5kIGxvYWRlZC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAcGFyYW0gaW1hZ2VVcmwge3N0cmluZ30gVGhlIGltYWdlIHVybCBvZiB0aGUgdGV4dHVyZVxuICogQHBhcmFtIFtjcm9zc29yaWdpbj0oYXV0byldIHtib29sZWFufSBTaG91bGQgdXNlIGFub255bW91c2UgQ09SUz8gRGVmYXVsdHMgdG8gdHJ1ZSBpZiB0aGUgVVJMIGlzIG5vdCBhIGRhdGEtVVJJLlxuICogQHBhcmFtIFtzY2FsZU1vZGU9c2NhbGVNb2Rlcy5ERUZBVUxUXSB7bnVtYmVyfSBTZWUge0BsaW5rIHNjYWxlTW9kZXN9IGZvciBwb3NzaWJsZSB2YWx1ZXNcbiAqIEByZXR1cm4gQmFzZVRleHR1cmVcbiAqL1xuQmFzZVRleHR1cmUuZnJvbUltYWdlID0gZnVuY3Rpb24gKGltYWdlVXJsLCBjcm9zc29yaWdpbiwgc2NhbGVNb2RlKSB7XG4gICAgdmFyIGJhc2VUZXh0dXJlID0gdXRpbHMuQmFzZVRleHR1cmVDYWNoZVtpbWFnZVVybF07XG5cbiAgICBpZiAoY3Jvc3NvcmlnaW4gPT09IHVuZGVmaW5lZCAmJiBpbWFnZVVybC5pbmRleE9mKCdkYXRhOicpICE9PSAwKSB7XG4gICAgICAgIGNyb3Nzb3JpZ2luID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBpZiAoIWJhc2VUZXh0dXJlKSB7XG4gICAgICAgIC8vIG5ldyBJbWFnZSgpIGJyZWFrcyB0ZXggbG9hZGluZyBpbiBzb21lIHZlcnNpb25zIG9mIENocm9tZS5cbiAgICAgICAgLy8gU2VlIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD0yMzgwNzFcbiAgICAgICAgdmFyIGltYWdlID0gbmV3IEltYWdlKCk7Ly9kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpbWcnKTtcbiAgICAgICAgaWYgKGNyb3Nzb3JpZ2luKSB7XG4gICAgICAgICAgICBpbWFnZS5jcm9zc09yaWdpbiA9ICcnO1xuICAgICAgICB9XG5cbiAgICAgICAgaW1hZ2Uuc3JjID0gaW1hZ2VVcmw7XG4gICAgICAgIGJhc2VUZXh0dXJlID0gbmV3IEJhc2VUZXh0dXJlKGltYWdlLCBzY2FsZU1vZGUpO1xuICAgICAgICBiYXNlVGV4dHVyZS5pbWFnZVVybCA9IGltYWdlVXJsO1xuICAgICAgICB1dGlscy5CYXNlVGV4dHVyZUNhY2hlW2ltYWdlVXJsXSA9IGJhc2VUZXh0dXJlO1xuXG4gICAgICAgIC8vIGlmIHRoZXJlIGlzIGFuIEAyeCBhdCB0aGUgZW5kIG9mIHRoZSB1cmwgd2UgYXJlIGdvaW5nIHRvIGFzc3VtZSBpdHMgYSBoaWdocmVzIGltYWdlXG4gICAgICAgIGlmICggaW1hZ2VVcmwuaW5kZXhPZihDT05TVC5SRVRJTkFfUFJFRklYICsgJy4nKSAhPT0gLTEpIHtcbiAgICAgICAgICAgIGJhc2VUZXh0dXJlLnJlc29sdXRpb24gPSAyO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGJhc2VUZXh0dXJlO1xufTtcblxuLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdGhhdCBjcmVhdGVzIGEgYmFzZSB0ZXh0dXJlIGZyb20gdGhlIGdpdmVuIGNhbnZhcyBlbGVtZW50LlxuICpcbiAqIEBzdGF0aWNcbiAqIEBwYXJhbSBjYW52YXMge0NhbnZhc30gVGhlIGNhbnZhcyBlbGVtZW50IHNvdXJjZSBvZiB0aGUgdGV4dHVyZVxuICogQHBhcmFtIHNjYWxlTW9kZSB7bnVtYmVyfSBTZWUge3sjY3Jvc3NMaW5rIFwiUElYSS9zY2FsZU1vZGVzOnByb3BlcnR5XCJ9fXNjYWxlTW9kZXN7ey9jcm9zc0xpbmt9fSBmb3IgcG9zc2libGUgdmFsdWVzXG4gKiBAcmV0dXJuIEJhc2VUZXh0dXJlXG4gKi9cbkJhc2VUZXh0dXJlLmZyb21DYW52YXMgPSBmdW5jdGlvbiAoY2FudmFzLCBzY2FsZU1vZGUpIHtcbiAgICBpZiAoIWNhbnZhcy5fcGl4aUlkKSB7XG4gICAgICAgIGNhbnZhcy5fcGl4aUlkID0gJ2NhbnZhc18nICsgdXRpbHMudXVpZCgpO1xuICAgIH1cblxuICAgIHZhciBiYXNlVGV4dHVyZSA9IHV0aWxzLkJhc2VUZXh0dXJlQ2FjaGVbY2FudmFzLl9waXhpSWRdO1xuXG4gICAgaWYgKCFiYXNlVGV4dHVyZSkge1xuICAgICAgICBiYXNlVGV4dHVyZSA9IG5ldyBCYXNlVGV4dHVyZShjYW52YXMsIHNjYWxlTW9kZSk7XG4gICAgICAgIHV0aWxzLkJhc2VUZXh0dXJlQ2FjaGVbY2FudmFzLl9waXhpSWRdID0gYmFzZVRleHR1cmU7XG4gICAgfVxuXG4gICAgcmV0dXJuIGJhc2VUZXh0dXJlO1xufTtcbiIsInZhciBCYXNlVGV4dHVyZSA9IHJlcXVpcmUoJy4vQmFzZVRleHR1cmUnKSxcbiAgICBUZXh0dXJlID0gcmVxdWlyZSgnLi9UZXh0dXJlJyksXG4gICAgRmlsdGVyVGV4dHVyZSA9IHJlcXVpcmUoJy4uL3JlbmRlcmVycy93ZWJnbC91dGlscy9GaWx0ZXJUZXh0dXJlJyksXG4gICAgQ2FudmFzQnVmZmVyID0gcmVxdWlyZSgnLi4vcmVuZGVyZXJzL2NhbnZhcy91dGlscy9DYW52YXNCdWZmZXInKSxcbiAgICBtYXRoID0gcmVxdWlyZSgnLi4vbWF0aCcpLFxuICAgIENPTlNUID0gcmVxdWlyZSgnLi4vY29uc3QnKTtcblxuLyoqXG4gKiBBIFJlbmRlclRleHR1cmUgaXMgYSBzcGVjaWFsIHRleHR1cmUgdGhhdCBhbGxvd3MgYW55IFBpeGkgZGlzcGxheSBvYmplY3QgdG8gYmUgcmVuZGVyZWQgdG8gaXQuXG4gKlxuICogX19IaW50X186IEFsbCBEaXNwbGF5T2JqZWN0cyAoaS5lLiBTcHJpdGVzKSB0aGF0IHJlbmRlciB0byBhIFJlbmRlclRleHR1cmUgc2hvdWxkIGJlIHByZWxvYWRlZFxuICogb3RoZXJ3aXNlIGJsYWNrIHJlY3RhbmdsZXMgd2lsbCBiZSBkcmF3biBpbnN0ZWFkLlxuICpcbiAqIEEgUmVuZGVyVGV4dHVyZSB0YWtlcyBhIHNuYXBzaG90IG9mIGFueSBEaXNwbGF5IE9iamVjdCBnaXZlbiB0byBpdHMgcmVuZGVyIG1ldGhvZC4gVGhlIHBvc2l0aW9uXG4gKiBhbmQgcm90YXRpb24gb2YgdGhlIGdpdmVuIERpc3BsYXkgT2JqZWN0cyBpcyBpZ25vcmVkLiBGb3IgZXhhbXBsZTpcbiAqXG4gKiBgYGBqc1xuICogdmFyIHJlbmRlclRleHR1cmUgPSBuZXcgUElYSS5SZW5kZXJUZXh0dXJlKDgwMCwgNjAwKTtcbiAqIHZhciBzcHJpdGUgPSBQSVhJLlNwcml0ZS5mcm9tSW1hZ2UoXCJzcGluT2JqXzAxLnBuZ1wiKTtcbiAqXG4gKiBzcHJpdGUucG9zaXRpb24ueCA9IDgwMC8yO1xuICogc3ByaXRlLnBvc2l0aW9uLnkgPSA2MDAvMjtcbiAqIHNwcml0ZS5hbmNob3IueCA9IDAuNTtcbiAqIHNwcml0ZS5hbmNob3IueSA9IDAuNTtcbiAqXG4gKiByZW5kZXJUZXh0dXJlLnJlbmRlcihzcHJpdGUpO1xuICogYGBgXG4gKlxuICogVGhlIFNwcml0ZSBpbiB0aGlzIGNhc2Ugd2lsbCBiZSByZW5kZXJlZCB0byBhIHBvc2l0aW9uIG9mIDAsMC4gVG8gcmVuZGVyIHRoaXMgc3ByaXRlIGF0IGl0cyBhY3R1YWxcbiAqIHBvc2l0aW9uIGEgRGlzcGxheU9iamVjdENvbnRhaW5lciBzaG91bGQgYmUgdXNlZDpcbiAqXG4gKiBgYGBqc1xuICogdmFyIGRvYyA9IG5ldyBEaXNwbGF5T2JqZWN0Q29udGFpbmVyKCk7XG4gKlxuICogZG9jLmFkZENoaWxkKHNwcml0ZSk7XG4gKlxuICogcmVuZGVyVGV4dHVyZS5yZW5kZXIoZG9jKTsgIC8vIFJlbmRlcnMgdG8gY2VudGVyIG9mIHJlbmRlclRleHR1cmVcbiAqIGBgYFxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgVGV4dHVyZVxuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gcmVuZGVyZXIge0NhbnZhc1JlbmRlcmVyfFdlYkdMUmVuZGVyZXJ9IFRoZSByZW5kZXJlciB1c2VkIGZvciB0aGlzIFJlbmRlclRleHR1cmVcbiAqIEBwYXJhbSBbd2lkdGg9MTAwXSB7bnVtYmVyfSBUaGUgd2lkdGggb2YgdGhlIHJlbmRlciB0ZXh0dXJlXG4gKiBAcGFyYW0gW2hlaWdodD0xMDBdIHtudW1iZXJ9IFRoZSBoZWlnaHQgb2YgdGhlIHJlbmRlciB0ZXh0dXJlXG4gKiBAcGFyYW0gW3NjYWxlTW9kZV0ge251bWJlcn0gU2VlIHtAbGluayBzY2FsZU1vZGVzfSBmb3IgcG9zc2libGUgdmFsdWVzXG4gKiBAcGFyYW0gW3Jlc29sdXRpb249MV0ge251bWJlcn0gVGhlIHJlc29sdXRpb24gb2YgdGhlIHRleHR1cmUgYmVpbmcgZ2VuZXJhdGVkXG4gKi9cbmZ1bmN0aW9uIFJlbmRlclRleHR1cmUocmVuZGVyZXIsIHdpZHRoLCBoZWlnaHQsIHNjYWxlTW9kZSwgcmVzb2x1dGlvbikge1xuICAgIGlmICghcmVuZGVyZXIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbmFibGUgdG8gY3JlYXRlIFJlbmRlclRleHR1cmUsIHlvdSBtdXN0IHBhc3MgYSByZW5kZXJlciBpbnRvIHRoZSBjb25zdHJ1Y3Rvci4nKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgd2l0aCBvZiB0aGUgcmVuZGVyIHRleHR1cmVcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLndpZHRoID0gd2lkdGggfHwgMTAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGhlaWdodCBvZiB0aGUgcmVuZGVyIHRleHR1cmVcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLmhlaWdodCA9IGhlaWdodCB8fCAxMDA7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgUmVzb2x1dGlvbiBvZiB0aGUgdGV4dHVyZS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLnJlc29sdXRpb24gPSByZXNvbHV0aW9uIHx8IDE7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgZnJhbWluZyByZWN0YW5nbGUgb2YgdGhlIHJlbmRlciB0ZXh0dXJlXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtSZWN0YW5nbGV9XG4gICAgICovXG4gICAgdGhpcy5mcmFtZSA9IG5ldyBtYXRoLlJlY3RhbmdsZSgwLCAwLCB0aGlzLndpZHRoICogdGhpcy5yZXNvbHV0aW9uLCB0aGlzLmhlaWdodCAqIHRoaXMucmVzb2x1dGlvbik7XG5cbiAgICAvKipcbiAgICAgKiBUaGlzIGlzIHRoZSBhcmVhIG9mIHRoZSBCYXNlVGV4dHVyZSBpbWFnZSB0byBhY3R1YWxseSBjb3B5IHRvIHRoZSBDYW52YXMgLyBXZWJHTCB3aGVuIHJlbmRlcmluZyxcbiAgICAgKiBpcnJlc3BlY3RpdmUgb2YgdGhlIGFjdHVhbCBmcmFtZSBzaXplIG9yIHBsYWNlbWVudCAod2hpY2ggY2FuIGJlIGluZmx1ZW5jZWQgYnkgdHJpbW1lZCB0ZXh0dXJlIGF0bGFzZXMpXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtSZWN0YW5nbGV9XG4gICAgICovXG4gICAgdGhpcy5jcm9wID0gbmV3IG1hdGguUmVjdGFuZ2xlKDAsIDAsIHRoaXMud2lkdGggKiB0aGlzLnJlc29sdXRpb24sIHRoaXMuaGVpZ2h0ICogdGhpcy5yZXNvbHV0aW9uKTtcblxuICAgIC8qKlxuICAgICAqIERyYXcvcmVuZGVyIHRoZSBnaXZlbiBEaXNwbGF5T2JqZWN0IG9udG8gdGhlIHRleHR1cmUuXG4gICAgICpcbiAgICAgKiBUaGUgZGlzcGxheU9iamVjdCBhbmQgZGVzY2VuZGVudHMgYXJlIHRyYW5zZm9ybWVkIGR1cmluZyB0aGlzIG9wZXJhdGlvbi5cbiAgICAgKiBJZiBgcmVzdG9yZVdvcmxkVHJhbnNmb3JtYCBpcyB0cnVlIHRoZW4gdGhlIHRyYW5zZm9ybWF0aW9ucyB3aWxsIGJlIHJlc3RvcmVkIGJlZm9yZSB0aGVcbiAgICAgKiBtZXRob2QgcmV0dXJucy4gT3RoZXJ3aXNlIGl0IGlzIHVwIHRvIHRoZSBjYWxsaW5nIGNvZGUgdG8gY29ycmVjdGx5IHVzZSBvciByZXNldFxuICAgICAqIHRoZSB0cmFuc2Zvcm1lZCBkaXNwbGF5IG9iamVjdHMuXG4gICAgICpcbiAgICAgKiBUaGUgZGlzcGxheSBvYmplY3QgaXMgYWx3YXlzIHJlbmRlcmVkIHdpdGggYSB3b3JsZEFscGhhIHZhbHVlIG9mIDEuXG4gICAgICpcbiAgICAgKiBAbWV0aG9kXG4gICAgICogQHBhcmFtIGRpc3BsYXlPYmplY3Qge0Rpc3BsYXlPYmplY3R9IFRoZSBkaXNwbGF5IG9iamVjdCB0byByZW5kZXIgdGhpcyB0ZXh0dXJlIG9uXG4gICAgICogQHBhcmFtIFttYXRyaXhdIHtNYXRyaXh9IE9wdGlvbmFsIG1hdHJpeCB0byBhcHBseSB0byB0aGUgZGlzcGxheSBvYmplY3QgYmVmb3JlIHJlbmRlcmluZy5cbiAgICAgKiBAcGFyYW0gW2NsZWFyPWZhbHNlXSB7Ym9vbGVhbn0gSWYgdHJ1ZSB0aGUgdGV4dHVyZSB3aWxsIGJlIGNsZWFyZWQgYmVmb3JlIHRoZSBkaXNwbGF5T2JqZWN0IGlzIGRyYXduXG4gICAgICogQHBhcmFtIFtyZXN0b3JlV29ybGRUcmFuc2Zvcm09dHJ1ZV0ge2Jvb2xlYW59IElmIHRydWUgdGhlIGRpc3BsYXlPYmplY3QncyB3b3JsZFRyYW5zZm9ybS93b3JsZEFscGhhIGFuZCBhbGwgY2hpbGRyZW5cbiAgICAgKiAgdHJhbnNmb3JtYXRpb25zIHdpbGwgYmUgcmVzdG9yZWQuIE5vdCByZXN0b3JpbmcgdGhpcyBpbmZvcm1hdGlvbiB3aWxsIGJlIGEgbGl0dGxlIGZhc3Rlci5cbiAgICAgKi9cbiAgICB0aGlzLnJlbmRlciA9IG51bGw7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgYmFzZSB0ZXh0dXJlIG9iamVjdCB0aGF0IHRoaXMgdGV4dHVyZSB1c2VzXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtCYXNlVGV4dHVyZX1cbiAgICAgKi9cbiAgICB0aGlzLmJhc2VUZXh0dXJlID0gbmV3IEJhc2VUZXh0dXJlKCk7XG4gICAgdGhpcy5iYXNlVGV4dHVyZS53aWR0aCA9IHRoaXMud2lkdGggKiB0aGlzLnJlc29sdXRpb247XG4gICAgdGhpcy5iYXNlVGV4dHVyZS5oZWlnaHQgPSB0aGlzLmhlaWdodCAqIHRoaXMucmVzb2x1dGlvbjtcbiAgICB0aGlzLmJhc2VUZXh0dXJlLl9nbFRleHR1cmVzID0gW107XG4gICAgdGhpcy5iYXNlVGV4dHVyZS5yZXNvbHV0aW9uID0gdGhpcy5yZXNvbHV0aW9uO1xuXG4gICAgdGhpcy5iYXNlVGV4dHVyZS5zY2FsZU1vZGUgPSBzY2FsZU1vZGUgfHwgQ09OU1Quc2NhbGVNb2Rlcy5ERUZBVUxUO1xuXG4gICAgdGhpcy5iYXNlVGV4dHVyZS5oYXNMb2FkZWQgPSB0cnVlO1xuXG4gICAgVGV4dHVyZS5jYWxsKHRoaXMsXG4gICAgICAgIHRoaXMuYmFzZVRleHR1cmUsXG4gICAgICAgIG5ldyBtYXRoLlJlY3RhbmdsZSgwLCAwLCB0aGlzLndpZHRoLCB0aGlzLmhlaWdodClcbiAgICApO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHJlbmRlcmVyIHRoaXMgUmVuZGVyVGV4dHVyZSB1c2VzLiBBIFJlbmRlclRleHR1cmUgY2FuIG9ubHkgYmVsb25nIHRvIG9uZSByZW5kZXJlciBhdCB0aGUgbW9tZW50IGlmIGl0cyB3ZWJHTC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0NhbnZhc1JlbmRlcmVyfFdlYkdMUmVuZGVyZXJ9XG4gICAgICovXG4gICAgdGhpcy5yZW5kZXJlciA9IHJlbmRlcmVyO1xuXG4gICAgaWYgKHRoaXMucmVuZGVyZXIudHlwZSA9PT0gQ09OU1QuV0VCR0xfUkVOREVSRVIpIHtcbiAgICAgICAgdmFyIGdsID0gdGhpcy5yZW5kZXJlci5nbDtcblxuICAgICAgICB0aGlzLnRleHR1cmVCdWZmZXIgPSBuZXcgRmlsdGVyVGV4dHVyZShnbCwgdGhpcy53aWR0aCAqIHRoaXMucmVzb2x1dGlvbiwgdGhpcy5oZWlnaHQgKiB0aGlzLnJlc29sdXRpb24sIHRoaXMuYmFzZVRleHR1cmUuc2NhbGVNb2RlKTtcbiAgICAgICAgdGhpcy5iYXNlVGV4dHVyZS5fZ2xUZXh0dXJlc1tnbC5pZF0gPSAgdGhpcy50ZXh0dXJlQnVmZmVyLnRleHR1cmU7XG5cbiAgICAgICAgdGhpcy5yZW5kZXIgPSB0aGlzLnJlbmRlcldlYkdMO1xuICAgICAgICB0aGlzLnByb2plY3Rpb24gPSBuZXcgbWF0aC5Qb2ludCh0aGlzLndpZHRoKjAuNSwgLXRoaXMuaGVpZ2h0KjAuNSk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLnJlbmRlciA9IHRoaXMucmVuZGVyQ2FudmFzO1xuICAgICAgICB0aGlzLnRleHR1cmVCdWZmZXIgPSBuZXcgQ2FudmFzQnVmZmVyKHRoaXMud2lkdGgqIHRoaXMucmVzb2x1dGlvbiwgdGhpcy5oZWlnaHQqIHRoaXMucmVzb2x1dGlvbik7XG4gICAgICAgIHRoaXMuYmFzZVRleHR1cmUuc291cmNlID0gdGhpcy50ZXh0dXJlQnVmZmVyLmNhbnZhcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMudmFsaWQgPSB0cnVlO1xuXG4gICAgdGhpcy5fdXBkYXRlVXZzKCk7XG59XG5cblJlbmRlclRleHR1cmUucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShUZXh0dXJlLnByb3RvdHlwZSk7XG5SZW5kZXJUZXh0dXJlLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFJlbmRlclRleHR1cmU7XG5tb2R1bGUuZXhwb3J0cyA9IFJlbmRlclRleHR1cmU7XG5cbi8qKlxuICogUmVzaXplcyB0aGUgUmVuZGVyVGV4dHVyZS5cbiAqXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gVGhlIHdpZHRoIHRvIHJlc2l6ZSB0by5cbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gVGhlIGhlaWdodCB0byByZXNpemUgdG8uXG4gKiBAcGFyYW0gdXBkYXRlQmFzZSB7Ym9vbGVhbn0gU2hvdWxkIHRoZSBiYXNlVGV4dHVyZS53aWR0aCBhbmQgaGVpZ2h0IHZhbHVlcyBiZSByZXNpemVkIGFzIHdlbGw/XG4gKi9cblJlbmRlclRleHR1cmUucHJvdG90eXBlLnJlc2l6ZSA9IGZ1bmN0aW9uICh3aWR0aCwgaGVpZ2h0LCB1cGRhdGVCYXNlKSB7XG4gICAgaWYgKHdpZHRoID09PSB0aGlzLndpZHRoICYmIGhlaWdodCA9PT0gdGhpcy5oZWlnaHQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMudmFsaWQgPSAod2lkdGggPiAwICYmIGhlaWdodCA+IDApO1xuXG4gICAgdGhpcy53aWR0aCA9IHRoaXMuZnJhbWUud2lkdGggPSB0aGlzLmNyb3Aud2lkdGggPSB3aWR0aDtcbiAgICB0aGlzLmhlaWdodCA9ICB0aGlzLmZyYW1lLmhlaWdodCA9IHRoaXMuY3JvcC5oZWlnaHQgPSBoZWlnaHQ7XG5cbiAgICBpZiAodXBkYXRlQmFzZSkge1xuICAgICAgICB0aGlzLmJhc2VUZXh0dXJlLndpZHRoID0gdGhpcy53aWR0aDtcbiAgICAgICAgdGhpcy5iYXNlVGV4dHVyZS5oZWlnaHQgPSB0aGlzLmhlaWdodDtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5yZW5kZXJlci50eXBlID09PSBDT05TVC5XRUJHTF9SRU5ERVJFUikge1xuICAgICAgICB0aGlzLnByb2plY3Rpb24ueCA9IHRoaXMud2lkdGggLyAyO1xuICAgICAgICB0aGlzLnByb2plY3Rpb24ueSA9IC10aGlzLmhlaWdodCAvIDI7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLnZhbGlkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnRleHR1cmVCdWZmZXIucmVzaXplKHRoaXMud2lkdGggKiB0aGlzLnJlc29sdXRpb24sIHRoaXMuaGVpZ2h0ICogdGhpcy5yZXNvbHV0aW9uKTtcbn07XG5cbi8qKlxuICogQ2xlYXJzIHRoZSBSZW5kZXJUZXh0dXJlLlxuICpcbiAqL1xuUmVuZGVyVGV4dHVyZS5wcm90b3R5cGUuY2xlYXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKCF0aGlzLnZhbGlkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5yZW5kZXJlci50eXBlID09PSBDT05TVC5XRUJHTF9SRU5ERVJFUikge1xuICAgICAgICB0aGlzLnJlbmRlcmVyLmdsLmJpbmRGcmFtZWJ1ZmZlcih0aGlzLnJlbmRlcmVyLmdsLkZSQU1FQlVGRkVSLCB0aGlzLnRleHR1cmVCdWZmZXIuZnJhbWVCdWZmZXIpO1xuICAgIH1cblxuICAgIHRoaXMudGV4dHVyZUJ1ZmZlci5jbGVhcigpO1xufTtcblxuLyoqXG4gKiBJbnRlcm5hbCBtZXRob2QgYXNzaWduZWQgdG8gdGhlIGByZW5kZXJgIHByb3BlcnR5IGlmIHVzaW5nIGEgQ2FudmFzUmVuZGVyZXIuXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSBkaXNwbGF5T2JqZWN0IHtEaXNwbGF5T2JqZWN0fSBUaGUgZGlzcGxheSBvYmplY3QgdG8gcmVuZGVyIHRoaXMgdGV4dHVyZSBvblxuICogQHBhcmFtIFttYXRyaXhdIHtNYXRyaXh9IE9wdGlvbmFsIG1hdHJpeCB0byBhcHBseSB0byB0aGUgZGlzcGxheSBvYmplY3QgYmVmb3JlIHJlbmRlcmluZy5cbiAqIEBwYXJhbSBbY2xlYXI9ZmFsc2VdIHtib29sZWFufSBJZiB0cnVlIHRoZSB0ZXh0dXJlIHdpbGwgYmUgY2xlYXJlZCBiZWZvcmUgdGhlIGRpc3BsYXlPYmplY3QgaXMgZHJhd25cbiAqIEBwYXJhbSBbcmVzdG9yZVdvcmxkVHJhbnNmb3JtPXRydWVdIHtib29sZWFufSBJZiB0cnVlIHRoZSBkaXNwbGF5T2JqZWN0J3Mgd29ybGRUcmFuc2Zvcm0vd29ybGRBbHBoYSBhbmQgYWxsIGNoaWxkcmVuXG4gKiAgdHJhbnNmb3JtYXRpb25zIHdpbGwgYmUgcmVzdG9yZWQuIE5vdCByZXN0b3JpbmcgdGhpcyBpbmZvcm1hdGlvbiB3aWxsIGJlIGEgbGl0dGxlIGZhc3Rlci5cbiAqL1xuUmVuZGVyVGV4dHVyZS5wcm90b3R5cGUucmVuZGVyV2ViR0wgPSBmdW5jdGlvbiAoZGlzcGxheU9iamVjdCwgbWF0cml4LCBjbGVhciwgcmVzdG9yZVdvcmxkVHJhbnNmb3JtKSB7XG4gICAgaWYgKCF0aGlzLnZhbGlkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIHJlc3RvcmVXb3JsZFRyYW5zZm9ybSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgcmVzdG9yZVdvcmxkVHJhbnNmb3JtID0gdHJ1ZTtcbiAgICB9XG5cbiAgICB2YXIgdGVtcEFscGhhLFxuICAgICAgICB0ZW1wVHJhbnNmb3JtO1xuXG4gICAgaWYgKHJlc3RvcmVXb3JsZFRyYW5zZm9ybSkge1xuICAgICAgICB0ZW1wQWxwaGEgPSBkaXNwbGF5T2JqZWN0LndvcmxkQWxwaGE7XG4gICAgICAgIHRlbXBUcmFuc2Zvcm0gPSBkaXNwbGF5T2JqZWN0LndvcmxkVHJhbnNmb3JtLnRvQXJyYXkoKTtcbiAgICB9XG5cbiAgICAvL1RPT0QgcmVwbGFjZSBwb3NpdGlvbiB3aXRoIG1hdHJpeC4uXG5cbiAgICAvL0xldHMgY3JlYXRlIGEgbmljZSBtYXRyaXggdG8gYXBwbHkgdG8gb3VyIGRpc3BsYXkgb2JqZWN0LiBGcmFtZSBidWZmZXJzIGNvbWUgaW4gdXBzaWRlIGRvd24gc28gd2UgbmVlZCB0byBmbGlwIHRoZSBtYXRyaXhcbiAgICB2YXIgd3QgPSBkaXNwbGF5T2JqZWN0LndvcmxkVHJhbnNmb3JtO1xuXG4gICAgd3QuaWRlbnRpdHkoKTtcbiAgICB3dC50cmFuc2xhdGUoMCwgdGhpcy5wcm9qZWN0aW9uLnkgKiAyKTtcblxuICAgIGlmIChtYXRyaXgpIHtcbiAgICAgICAgd3QuYXBwZW5kKG1hdHJpeCk7XG4gICAgfVxuXG4gICAgd3Quc2NhbGUoMSwtMSk7XG5cbiAgICAvLyBzZXRXb3JsZCBBbHBoYSB0byBlbnN1cmUgdGhhdCB0aGUgb2JqZWN0IGlzIHJlbmRlcmVyIGF0IGZ1bGwgb3BhY2l0eVxuICAgIGRpc3BsYXlPYmplY3Qud29ybGRBbHBoYSA9IDE7XG5cbiAgICAvLyBUaW1lIHRvIHVwZGF0ZSBhbGwgdGhlIGNoaWxkcmVuIG9mIHRoZSBkaXNwbGF5T2JqZWN0IHdpdGggdGhlIG5ldyBtYXRyaXguLlxuICAgIHZhciBjaGlsZHJlbiA9IGRpc3BsYXlPYmplY3QuY2hpbGRyZW47XG4gICAgdmFyIGksIGo7XG5cbiAgICBmb3IgKGkgPSAwLCBqID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgKytpKSB7XG4gICAgICAgIGNoaWxkcmVuW2ldLnVwZGF0ZVRyYW5zZm9ybSgpO1xuICAgIH1cblxuICAgIC8vIHRpbWUgZm9yIHRoZSB3ZWJHTCBmdW4gc3R1ZmYhXG4gICAgdmFyIGdsID0gdGhpcy5yZW5kZXJlci5nbDtcblxuICAgIGdsLnZpZXdwb3J0KDAsIDAsIHRoaXMud2lkdGggKiB0aGlzLnJlc29sdXRpb24sIHRoaXMuaGVpZ2h0ICogdGhpcy5yZXNvbHV0aW9uKTtcblxuICAgIGdsLmJpbmRGcmFtZWJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgdGhpcy50ZXh0dXJlQnVmZmVyLmZyYW1lQnVmZmVyICk7XG5cbiAgICBpZiAoY2xlYXIpIHtcbiAgICAgICAgdGhpcy50ZXh0dXJlQnVmZmVyLmNsZWFyKCk7XG4gICAgfVxuXG4gICAgdGhpcy5yZW5kZXJlci5zcHJpdGVCYXRjaC5kaXJ0eSA9IHRydWU7XG5cbiAgICB0aGlzLnJlbmRlcmVyLnJlbmRlckRpc3BsYXlPYmplY3QoZGlzcGxheU9iamVjdCwgdGhpcy5wcm9qZWN0aW9uLCB0aGlzLnRleHR1cmVCdWZmZXIuZnJhbWVCdWZmZXIpO1xuXG4gICAgdGhpcy5yZW5kZXJlci5zcHJpdGVCYXRjaC5kaXJ0eSA9IHRydWU7XG5cbiAgICBpZiAocmVzdG9yZVdvcmxkVHJhbnNmb3JtKSB7XG4gICAgICAgIGRpc3BsYXlPYmplY3Qud29ybGRBbHBoYSA9IHRlbXBBbHBoYTtcbiAgICAgICAgZGlzcGxheU9iamVjdC53b3JsZFRyYW5zZm9ybS5mcm9tQXJyYXkodGVtcFRyYW5zZm9ybSk7XG5cbiAgICAgICAgZm9yIChpID0gMCwgaiA9IGNoaWxkcmVuLmxlbmd0aDsgaSA8IGo7ICsraSkge1xuICAgICAgICAgICAgY2hpbGRyZW5baV0udXBkYXRlVHJhbnNmb3JtKCk7XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG5cbi8qKlxuICogSW50ZXJuYWwgbWV0aG9kIGFzc2lnbmVkIHRvIHRoZSBgcmVuZGVyYCBwcm9wZXJ0eSBpZiB1c2luZyBhIENhbnZhc1JlbmRlcmVyLlxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0gZGlzcGxheU9iamVjdCB7RGlzcGxheU9iamVjdH0gVGhlIGRpc3BsYXkgb2JqZWN0IHRvIHJlbmRlciB0aGlzIHRleHR1cmUgb25cbiAqIEBwYXJhbSBbbWF0cml4XSB7TWF0cml4fSBPcHRpb25hbCBtYXRyaXggdG8gYXBwbHkgdG8gdGhlIGRpc3BsYXkgb2JqZWN0IGJlZm9yZSByZW5kZXJpbmcuXG4gKiBAcGFyYW0gW2NsZWFyXSB7Ym9vbGVhbn0gSWYgdHJ1ZSB0aGUgdGV4dHVyZSB3aWxsIGJlIGNsZWFyZWQgYmVmb3JlIHRoZSBkaXNwbGF5T2JqZWN0IGlzIGRyYXduXG4gKiBAcGFyYW0gW3Jlc3RvcmVXb3JsZFRyYW5zZm9ybT10cnVlXSB7Ym9vbGVhbn0gSWYgdHJ1ZSB0aGUgZGlzcGxheU9iamVjdCdzIHdvcmxkVHJhbnNmb3JtL3dvcmxkQWxwaGEgYW5kIGFsbCBjaGlsZHJlblxuICogIHRyYW5zZm9ybWF0aW9ucyB3aWxsIGJlIHJlc3RvcmVkLiBOb3QgcmVzdG9yaW5nIHRoaXMgaW5mb3JtYXRpb24gd2lsbCBiZSBhIGxpdHRsZSBmYXN0ZXIuXG4gKi9cblJlbmRlclRleHR1cmUucHJvdG90eXBlLnJlbmRlckNhbnZhcyA9IGZ1bmN0aW9uIChkaXNwbGF5T2JqZWN0LCBtYXRyaXgsIGNsZWFyLCByZXN0b3JlV29ybGRUcmFuc2Zvcm0pIHtcbiAgICBpZiAoIXRoaXMudmFsaWQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgcmVzdG9yZVdvcmxkVHJhbnNmb3JtID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICByZXN0b3JlV29ybGRUcmFuc2Zvcm0gPSB0cnVlO1xuICAgIH1cblxuICAgIHZhciB0ZW1wQWxwaGEsXG4gICAgICAgIHRlbXBUcmFuc2Zvcm07XG5cbiAgICBpZiAocmVzdG9yZVdvcmxkVHJhbnNmb3JtKSB7XG4gICAgICAgIHRlbXBBbHBoYSA9IGRpc3BsYXlPYmplY3Qud29ybGRBbHBoYTtcbiAgICAgICAgdGVtcFRyYW5zZm9ybSA9IGRpc3BsYXlPYmplY3Qud29ybGRUcmFuc2Zvcm0udG9BcnJheSgpO1xuICAgIH1cblxuICAgIHZhciB3dCA9IGRpc3BsYXlPYmplY3Qud29ybGRUcmFuc2Zvcm07XG4gICAgd3QuaWRlbnRpdHkoKTtcbiAgICBpZiAobWF0cml4KSB7XG4gICAgICAgIHd0LmFwcGVuZChtYXRyaXgpO1xuICAgIH1cblxuICAgIC8vIHNldFdvcmxkIEFscGhhIHRvIGVuc3VyZSB0aGF0IHRoZSBvYmplY3QgaXMgcmVuZGVyZXIgYXQgZnVsbCBvcGFjaXR5XG4gICAgZGlzcGxheU9iamVjdC53b3JsZEFscGhhID0gMTtcblxuICAgIC8vIFRpbWUgdG8gdXBkYXRlIGFsbCB0aGUgY2hpbGRyZW4gb2YgdGhlIGRpc3BsYXlPYmplY3Qgd2l0aCB0aGUgbmV3IG1hdHJpeC4uXG4gICAgdmFyIGNoaWxkcmVuID0gZGlzcGxheU9iamVjdC5jaGlsZHJlbjtcbiAgICB2YXIgaSwgajtcblxuICAgIGZvciAoaSA9IDAsIGogPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyArK2kpIHtcbiAgICAgICAgY2hpbGRyZW5baV0udXBkYXRlVHJhbnNmb3JtKCk7XG4gICAgfVxuXG4gICAgaWYgKGNsZWFyKSB7XG4gICAgICAgIHRoaXMudGV4dHVyZUJ1ZmZlci5jbGVhcigpO1xuICAgIH1cblxuICAgIHZhciBjb250ZXh0ID0gdGhpcy50ZXh0dXJlQnVmZmVyLmNvbnRleHQ7XG5cbiAgICB2YXIgcmVhbFJlc29sdXRpb24gPSB0aGlzLnJlbmRlcmVyLnJlc29sdXRpb247XG5cbiAgICB0aGlzLnJlbmRlcmVyLnJlc29sdXRpb24gPSB0aGlzLnJlc29sdXRpb247XG5cbiAgICB0aGlzLnJlbmRlcmVyLnJlbmRlckRpc3BsYXlPYmplY3QoZGlzcGxheU9iamVjdCwgY29udGV4dCk7XG5cbiAgICB0aGlzLnJlbmRlcmVyLnJlc29sdXRpb24gPSByZWFsUmVzb2x1dGlvbjtcblxuICAgIGlmIChyZXN0b3JlV29ybGRUcmFuc2Zvcm0pIHtcbiAgICAgICAgZGlzcGxheU9iamVjdC53b3JsZEFscGhhID0gdGVtcEFscGhhO1xuICAgICAgICBkaXNwbGF5T2JqZWN0LndvcmxkVHJhbnNmb3JtLmZyb21BcnJheSh0ZW1wVHJhbnNmb3JtKTtcblxuICAgICAgICBmb3IgKGkgPSAwLCBqID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgKytpKSB7XG4gICAgICAgICAgICBjaGlsZHJlbltpXS51cGRhdGVUcmFuc2Zvcm0oKTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cbi8qKlxuICogV2lsbCByZXR1cm4gYSBIVE1MIEltYWdlIG9mIHRoZSB0ZXh0dXJlXG4gKlxuICogQHJldHVybiB7SW1hZ2V9XG4gKi9cblJlbmRlclRleHR1cmUucHJvdG90eXBlLmdldEltYWdlID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBpbWFnZSA9IG5ldyBJbWFnZSgpO1xuICAgIGltYWdlLnNyYyA9IHRoaXMuZ2V0QmFzZTY0KCk7XG4gICAgcmV0dXJuIGltYWdlO1xufTtcblxuLyoqXG4gKiBXaWxsIHJldHVybiBhIGEgYmFzZTY0IGVuY29kZWQgc3RyaW5nIG9mIHRoaXMgdGV4dHVyZS4gSXQgd29ya3MgYnkgY2FsbGluZyBSZW5kZXJUZXh0dXJlLmdldENhbnZhcyBhbmQgdGhlbiBydW5uaW5nIHRvRGF0YVVSTCBvbiB0aGF0LlxuICpcbiAqIEByZXR1cm4ge3N0cmluZ30gQSBiYXNlNjQgZW5jb2RlZCBzdHJpbmcgb2YgdGhlIHRleHR1cmUuXG4gKi9cblJlbmRlclRleHR1cmUucHJvdG90eXBlLmdldEJhc2U2NCA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5nZXRDYW52YXMoKS50b0RhdGFVUkwoKTtcbn07XG5cbi8qKlxuICogQ3JlYXRlcyBhIENhbnZhcyBlbGVtZW50LCByZW5kZXJzIHRoaXMgUmVuZGVyVGV4dHVyZSB0byBpdCBhbmQgdGhlbiByZXR1cm5zIGl0LlxuICpcbiAqIEByZXR1cm4ge0hUTUxDYW52YXNFbGVtZW50fSBBIENhbnZhcyBlbGVtZW50IHdpdGggdGhlIHRleHR1cmUgcmVuZGVyZWQgb24uXG4gKi9cblJlbmRlclRleHR1cmUucHJvdG90eXBlLmdldENhbnZhcyA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5yZW5kZXJlci50eXBlID09PSBDT05TVC5XRUJHTF9SRU5ERVJFUikge1xuICAgICAgICB2YXIgZ2wgPSAgdGhpcy5yZW5kZXJlci5nbDtcbiAgICAgICAgdmFyIHdpZHRoID0gdGhpcy50ZXh0dXJlQnVmZmVyLndpZHRoO1xuICAgICAgICB2YXIgaGVpZ2h0ID0gdGhpcy50ZXh0dXJlQnVmZmVyLmhlaWdodDtcblxuICAgICAgICB2YXIgd2ViR0xQaXhlbHMgPSBuZXcgVWludDhBcnJheSg0ICogd2lkdGggKiBoZWlnaHQpO1xuXG4gICAgICAgIGdsLmJpbmRGcmFtZWJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgdGhpcy50ZXh0dXJlQnVmZmVyLmZyYW1lQnVmZmVyKTtcbiAgICAgICAgZ2wucmVhZFBpeGVscygwLCAwLCB3aWR0aCwgaGVpZ2h0LCBnbC5SR0JBLCBnbC5VTlNJR05FRF9CWVRFLCB3ZWJHTFBpeGVscyk7XG4gICAgICAgIGdsLmJpbmRGcmFtZWJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgbnVsbCk7XG5cbiAgICAgICAgdmFyIHRlbXBDYW52YXMgPSBuZXcgQ2FudmFzQnVmZmVyKHdpZHRoLCBoZWlnaHQpO1xuICAgICAgICB2YXIgY2FudmFzRGF0YSA9IHRlbXBDYW52YXMuY29udGV4dC5nZXRJbWFnZURhdGEoMCwgMCwgd2lkdGgsIGhlaWdodCk7XG4gICAgICAgIGNhbnZhc0RhdGEuZGF0YS5zZXQod2ViR0xQaXhlbHMpO1xuXG4gICAgICAgIHRlbXBDYW52YXMuY29udGV4dC5wdXRJbWFnZURhdGEoY2FudmFzRGF0YSwgMCwgMCk7XG5cbiAgICAgICAgcmV0dXJuIHRlbXBDYW52YXMuY2FudmFzO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudGV4dHVyZUJ1ZmZlci5jYW52YXM7XG4gICAgfVxufTtcbiIsInZhciBCYXNlVGV4dHVyZSA9IHJlcXVpcmUoJy4vQmFzZVRleHR1cmUnKSxcbiAgICBWaWRlb0Jhc2VUZXh0dXJlID0gcmVxdWlyZSgnLi9WaWRlb0Jhc2VUZXh0dXJlJyksXG4gICAgVGV4dHVyZVV2cyA9IHJlcXVpcmUoJy4vVGV4dHVyZVV2cycpLFxuICAgIGV2ZW50VGFyZ2V0ID0gcmVxdWlyZSgnLi4vdXRpbHMvZXZlbnRUYXJnZXQnKSxcbiAgICBtYXRoID0gcmVxdWlyZSgnLi4vbWF0aCcpLFxuICAgIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMnKTtcblxuLyoqXG4gKiBBIHRleHR1cmUgc3RvcmVzIHRoZSBpbmZvcm1hdGlvbiB0aGF0IHJlcHJlc2VudHMgYW4gaW1hZ2Ugb3IgcGFydCBvZiBhbiBpbWFnZS4gSXQgY2Fubm90IGJlIGFkZGVkXG4gKiB0byB0aGUgZGlzcGxheSBsaXN0IGRpcmVjdGx5LiBJbnN0ZWFkIHVzZSBpdCBhcyB0aGUgdGV4dHVyZSBmb3IgYSBTcHJpdGUuIElmIG5vIGZyYW1lIGlzIHByb3ZpZGVkIHRoZW4gdGhlIHdob2xlIGltYWdlIGlzIHVzZWQuXG4gKlxuICogQGNsYXNzXG4gKiBAbWl4ZXMgZXZlbnRUYXJnZXRcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIGJhc2VUZXh0dXJlIHtCYXNlVGV4dHVyZX0gVGhlIGJhc2UgdGV4dHVyZSBzb3VyY2UgdG8gY3JlYXRlIHRoZSB0ZXh0dXJlIGZyb21cbiAqIEBwYXJhbSBbZnJhbWVdIHtSZWN0YW5nbGV9IFRoZSByZWN0YW5nbGUgZnJhbWUgb2YgdGhlIHRleHR1cmUgdG8gc2hvd1xuICogQHBhcmFtIFtjcm9wXSB7UmVjdGFuZ2xlfSBUaGUgYXJlYSBvZiBvcmlnaW5hbCB0ZXh0dXJlXG4gKiBAcGFyYW0gW3RyaW1dIHtSZWN0YW5nbGV9IFRyaW1tZWQgdGV4dHVyZSByZWN0YW5nbGVcbiAqL1xuZnVuY3Rpb24gVGV4dHVyZShiYXNlVGV4dHVyZSwgZnJhbWUsIGNyb3AsIHRyaW0pIHtcbiAgICAvKipcbiAgICAgKiBEb2VzIHRoaXMgVGV4dHVyZSBoYXZlIGFueSBmcmFtZSBkYXRhIGFzc2lnbmVkIHRvIGl0P1xuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLm5vRnJhbWUgPSBmYWxzZTtcblxuICAgIGlmICghZnJhbWUpIHtcbiAgICAgICAgdGhpcy5ub0ZyYW1lID0gdHJ1ZTtcbiAgICAgICAgZnJhbWUgPSBuZXcgbWF0aC5SZWN0YW5nbGUoMCwgMCwgMSwgMSk7XG4gICAgfVxuXG4gICAgaWYgKGJhc2VUZXh0dXJlIGluc3RhbmNlb2YgVGV4dHVyZSkge1xuICAgICAgICBiYXNlVGV4dHVyZSA9IGJhc2VUZXh0dXJlLmJhc2VUZXh0dXJlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBiYXNlIHRleHR1cmUgdGhhdCB0aGlzIHRleHR1cmUgdXNlcy5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0Jhc2VUZXh0dXJlfVxuICAgICAqL1xuICAgIHRoaXMuYmFzZVRleHR1cmUgPSBiYXNlVGV4dHVyZTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBmcmFtZSBzcGVjaWZpZXMgdGhlIHJlZ2lvbiBvZiB0aGUgYmFzZSB0ZXh0dXJlIHRoYXQgdGhpcyB0ZXh0dXJlIHVzZXNcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1JlY3RhbmdsZX1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuX2ZyYW1lID0gZnJhbWU7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdGV4dHVyZSB0cmltIGRhdGEuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtSZWN0YW5nbGV9XG4gICAgICovXG4gICAgdGhpcy50cmltID0gdHJpbTtcblxuICAgIC8qKlxuICAgICAqIFRoaXMgd2lsbCBsZXQgdGhlIHJlbmRlcmVyIGtub3cgaWYgdGhlIHRleHR1cmUgaXMgdmFsaWQuIElmIGl0J3Mgbm90IHRoZW4gaXQgY2Fubm90IGJlIHJlbmRlcmVkLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLnZhbGlkID0gZmFsc2U7XG5cbiAgICAvKipcbiAgICAgKiBUaGlzIHdpbGwgbGV0IGEgcmVuZGVyZXIga25vdyB0aGF0IGEgdGV4dHVyZSBoYXMgYmVlbiB1cGRhdGVkICh1c2VkIG1haW5seSBmb3Igd2ViR0wgdXYgdXBkYXRlcylcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5yZXF1aXJlc1VwZGF0ZSA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICogVGhlIFdlYkdMIFVWIGRhdGEgY2FjaGUuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtvYmplY3R9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl91dnMgPSBudWxsO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHdpZHRoIG9mIHRoZSBUZXh0dXJlIGluIHBpeGVscy5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLndpZHRoID0gMDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBoZWlnaHQgb2YgdGhlIFRleHR1cmUgaW4gcGl4ZWxzLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMuaGVpZ2h0ID0gMDtcblxuICAgIC8qKlxuICAgICAqIFRoaXMgaXMgdGhlIGFyZWEgb2YgdGhlIEJhc2VUZXh0dXJlIGltYWdlIHRvIGFjdHVhbGx5IGNvcHkgdG8gdGhlIENhbnZhcyAvIFdlYkdMIHdoZW4gcmVuZGVyaW5nLFxuICAgICAqIGlycmVzcGVjdGl2ZSBvZiB0aGUgYWN0dWFsIGZyYW1lIHNpemUgb3IgcGxhY2VtZW50ICh3aGljaCBjYW4gYmUgaW5mbHVlbmNlZCBieSB0cmltbWVkIHRleHR1cmUgYXRsYXNlcylcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1JlY3RhbmdsZX1cbiAgICAgKi9cbiAgICB0aGlzLmNyb3AgPSBjcm9wIHx8IG5ldyBtYXRoLlJlY3RhbmdsZSgwLCAwLCAxLCAxKTtcblxuICAgIGlmIChiYXNlVGV4dHVyZS5oYXNMb2FkZWQpIHtcbiAgICAgICAgaWYgKHRoaXMubm9GcmFtZSkge1xuICAgICAgICAgICAgZnJhbWUgPSBuZXcgbWF0aC5SZWN0YW5nbGUoMCwgMCwgYmFzZVRleHR1cmUud2lkdGgsIGJhc2VUZXh0dXJlLmhlaWdodCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5mcmFtZSA9IGZyYW1lO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgYmFzZVRleHR1cmUuYWRkRXZlbnRMaXN0ZW5lcignbG9hZGVkJywgdGhpcy5vbkJhc2VUZXh0dXJlTG9hZGVkLmJpbmQodGhpcykpO1xuICAgIH1cbn1cblxuVGV4dHVyZS5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBUZXh0dXJlO1xubW9kdWxlLmV4cG9ydHMgPSBUZXh0dXJlO1xuXG5ldmVudFRhcmdldC5taXhpbihUZXh0dXJlLnByb3RvdHlwZSk7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKFRleHR1cmUucHJvdG90eXBlLCB7XG4gICAgbmVlZHNVcGRhdGU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5iYXNlVGV4dHVyZS5uZWVkc1VwZGF0ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsKSB7XG4gICAgICAgICAgICB0aGlzLmJhc2VUZXh0dXJlLm5lZWRzVXBkYXRlID0gdmFsO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIGZyYW1lOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2ZyYW1lO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChmcmFtZSkge1xuICAgICAgICAgICAgdGhpcy5fZnJhbWUgPSBmcmFtZTtcblxuICAgICAgICAgICAgdGhpcy5ub0ZyYW1lID0gZmFsc2U7XG5cbiAgICAgICAgICAgIHRoaXMud2lkdGggPSBmcmFtZS53aWR0aDtcbiAgICAgICAgICAgIHRoaXMuaGVpZ2h0ID0gZnJhbWUuaGVpZ2h0O1xuXG4gICAgICAgICAgICB0aGlzLmNyb3AueCA9IGZyYW1lLng7XG4gICAgICAgICAgICB0aGlzLmNyb3AueSA9IGZyYW1lLnk7XG4gICAgICAgICAgICB0aGlzLmNyb3Aud2lkdGggPSBmcmFtZS53aWR0aDtcbiAgICAgICAgICAgIHRoaXMuY3JvcC5oZWlnaHQgPSBmcmFtZS5oZWlnaHQ7XG5cbiAgICAgICAgICAgIGlmICghdGhpcy50cmltICYmIChmcmFtZS54ICsgZnJhbWUud2lkdGggPiB0aGlzLmJhc2VUZXh0dXJlLndpZHRoIHx8IGZyYW1lLnkgKyBmcmFtZS5oZWlnaHQgPiB0aGlzLmJhc2VUZXh0dXJlLmhlaWdodCkpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1RleHR1cmUgRXJyb3I6IGZyYW1lIGRvZXMgbm90IGZpdCBpbnNpZGUgdGhlIGJhc2UgVGV4dHVyZSBkaW1lbnNpb25zICcgKyB0aGlzKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy52YWxpZCA9IGZyYW1lICYmIGZyYW1lLndpZHRoICYmIGZyYW1lLmhlaWdodCAmJiB0aGlzLmJhc2VUZXh0dXJlLnNvdXJjZSAmJiB0aGlzLmJhc2VUZXh0dXJlLmhhc0xvYWRlZDtcblxuICAgICAgICAgICAgaWYgKHRoaXMudHJpbSkge1xuICAgICAgICAgICAgICAgIHRoaXMud2lkdGggPSB0aGlzLnRyaW0ud2lkdGg7XG4gICAgICAgICAgICAgICAgdGhpcy5oZWlnaHQgPSB0aGlzLnRyaW0uaGVpZ2h0O1xuICAgICAgICAgICAgICAgIHRoaXMuX2ZyYW1lLndpZHRoID0gdGhpcy50cmltLndpZHRoO1xuICAgICAgICAgICAgICAgIHRoaXMuX2ZyYW1lLmhlaWdodCA9IHRoaXMudHJpbS5oZWlnaHQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0aGlzLnZhbGlkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fdXBkYXRlVXZzKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59KTtcblxuLyoqXG4gKiBDYWxsZWQgd2hlbiB0aGUgYmFzZSB0ZXh0dXJlIGlzIGxvYWRlZFxuICpcbiAqIEBwcml2YXRlXG4gKi9cblRleHR1cmUucHJvdG90eXBlLm9uQmFzZVRleHR1cmVMb2FkZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGJhc2VUZXh0dXJlID0gdGhpcy5iYXNlVGV4dHVyZTtcbiAgICBiYXNlVGV4dHVyZS5yZW1vdmVFdmVudExpc3RlbmVyKCdsb2FkZWQnLCB0aGlzLm9uTG9hZGVkKTtcblxuICAgIGlmICh0aGlzLm5vRnJhbWUpIHtcbiAgICAgICAgdGhpcy5mcmFtZSA9IG5ldyBtYXRoLlJlY3RhbmdsZSgwLCAwLCBiYXNlVGV4dHVyZS53aWR0aCwgYmFzZVRleHR1cmUuaGVpZ2h0KTtcbiAgICB9XG5cbiAgICB0aGlzLmRpc3BhdGNoRXZlbnQoIHsgdHlwZTogJ3VwZGF0ZScsIGNvbnRlbnQ6IHRoaXMgfSApO1xufTtcblxuLyoqXG4gKiBEZXN0cm95cyB0aGlzIHRleHR1cmVcbiAqXG4gKiBAcGFyYW0gZGVzdHJveUJhc2Uge2Jvb2xlYW59IFdoZXRoZXIgdG8gZGVzdHJveSB0aGUgYmFzZSB0ZXh0dXJlIGFzIHdlbGxcbiAqL1xuVGV4dHVyZS5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uIChkZXN0cm95QmFzZSkge1xuICAgIGlmIChkZXN0cm95QmFzZSkge1xuICAgICAgICB0aGlzLmJhc2VUZXh0dXJlLmRlc3Ryb3koKTtcbiAgICB9XG5cbiAgICB0aGlzLnZhbGlkID0gZmFsc2U7XG59O1xuXG4vKipcbiAqIFVwZGF0ZXMgdGhlIGludGVybmFsIFdlYkdMIFVWIGNhY2hlLlxuICpcbiAqIEBwcml2YXRlXG4gKi9cblRleHR1cmUucHJvdG90eXBlLl91cGRhdGVVdnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKCF0aGlzLl91dnMpIHtcbiAgICAgICAgdGhpcy5fdXZzID0gbmV3IFRleHR1cmVVdnMoKTtcbiAgICB9XG5cbiAgICB2YXIgZnJhbWUgPSB0aGlzLmNyb3A7XG4gICAgdmFyIHR3ID0gdGhpcy5iYXNlVGV4dHVyZS53aWR0aDtcbiAgICB2YXIgdGggPSB0aGlzLmJhc2VUZXh0dXJlLmhlaWdodDtcblxuICAgIHRoaXMuX3V2cy54MCA9IGZyYW1lLnggLyB0dztcbiAgICB0aGlzLl91dnMueTAgPSBmcmFtZS55IC8gdGg7XG5cbiAgICB0aGlzLl91dnMueDEgPSAoZnJhbWUueCArIGZyYW1lLndpZHRoKSAvIHR3O1xuICAgIHRoaXMuX3V2cy55MSA9IGZyYW1lLnkgLyB0aDtcblxuICAgIHRoaXMuX3V2cy54MiA9IChmcmFtZS54ICsgZnJhbWUud2lkdGgpIC8gdHc7XG4gICAgdGhpcy5fdXZzLnkyID0gKGZyYW1lLnkgKyBmcmFtZS5oZWlnaHQpIC8gdGg7XG5cbiAgICB0aGlzLl91dnMueDMgPSBmcmFtZS54IC8gdHc7XG4gICAgdGhpcy5fdXZzLnkzID0gKGZyYW1lLnkgKyBmcmFtZS5oZWlnaHQpIC8gdGg7XG59O1xuXG4vKipcbiAqIEhlbHBlciBmdW5jdGlvbiB0aGF0IGNyZWF0ZXMgYSBUZXh0dXJlIG9iamVjdCBmcm9tIHRoZSBnaXZlbiBpbWFnZSB1cmwuXG4gKiBJZiB0aGUgaW1hZ2UgaXMgbm90IGluIHRoZSB0ZXh0dXJlIGNhY2hlIGl0IHdpbGwgYmUgIGNyZWF0ZWQgYW5kIGxvYWRlZC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAcGFyYW0gaW1hZ2VVcmwge3N0cmluZ30gVGhlIGltYWdlIHVybCBvZiB0aGUgdGV4dHVyZVxuICogQHBhcmFtIGNyb3Nzb3JpZ2luIHtib29sZWFufSBXaGV0aGVyIHJlcXVlc3RzIHNob3VsZCBiZSB0cmVhdGVkIGFzIGNyb3Nzb3JpZ2luXG4gKiBAcGFyYW0gc2NhbGVNb2RlIHtudW1iZXJ9IFNlZSB7eyNjcm9zc0xpbmsgXCJQSVhJL3NjYWxlTW9kZXM6cHJvcGVydHlcIn19c2NhbGVNb2Rlc3t7L2Nyb3NzTGlua319IGZvciBwb3NzaWJsZSB2YWx1ZXNcbiAqIEByZXR1cm4gVGV4dHVyZVxuICovXG5UZXh0dXJlLmZyb21JbWFnZSA9IGZ1bmN0aW9uIChpbWFnZVVybCwgY3Jvc3NvcmlnaW4sIHNjYWxlTW9kZSkge1xuICAgIHZhciB0ZXh0dXJlID0gdXRpbHMuVGV4dHVyZUNhY2hlW2ltYWdlVXJsXTtcblxuICAgIGlmICghdGV4dHVyZSkge1xuICAgICAgICB0ZXh0dXJlID0gbmV3IFRleHR1cmUoQmFzZVRleHR1cmUuZnJvbUltYWdlKGltYWdlVXJsLCBjcm9zc29yaWdpbiwgc2NhbGVNb2RlKSk7XG4gICAgICAgIHV0aWxzLlRleHR1cmVDYWNoZVtpbWFnZVVybF0gPSB0ZXh0dXJlO1xuICAgIH1cblxuICAgIHJldHVybiB0ZXh0dXJlO1xufTtcblxuLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdGhhdCByZXR1cm5zIGEgVGV4dHVyZSBvYmplY3RlZCBiYXNlZCBvbiB0aGUgZ2l2ZW4gZnJhbWUgaWQuXG4gKiBJZiB0aGUgZnJhbWUgaWQgaXMgbm90IGluIHRoZSB0ZXh0dXJlIGNhY2hlIGFuIGVycm9yIHdpbGwgYmUgdGhyb3duLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBwYXJhbSBmcmFtZUlkIHtzdHJpbmd9IFRoZSBmcmFtZSBpZCBvZiB0aGUgdGV4dHVyZVxuICogQHJldHVybiBUZXh0dXJlXG4gKi9cblRleHR1cmUuZnJvbUZyYW1lID0gZnVuY3Rpb24gKGZyYW1lSWQpIHtcbiAgICB2YXIgdGV4dHVyZSA9IHV0aWxzLlRleHR1cmVDYWNoZVtmcmFtZUlkXTtcbiAgICBpZiAoIXRleHR1cmUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdUaGUgZnJhbWVJZCBcIicgKyBmcmFtZUlkICsgJ1wiIGRvZXMgbm90IGV4aXN0IGluIHRoZSB0ZXh0dXJlIGNhY2hlICcpO1xuICAgIH1cbiAgICByZXR1cm4gdGV4dHVyZTtcbn07XG5cbi8qKlxuICogSGVscGVyIGZ1bmN0aW9uIHRoYXQgY3JlYXRlcyBhIG5ldyBUZXh0dXJlIGJhc2VkIG9uIHRoZSBnaXZlbiBjYW52YXMgZWxlbWVudC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAcGFyYW0gY2FudmFzIHtDYW52YXN9IFRoZSBjYW52YXMgZWxlbWVudCBzb3VyY2Ugb2YgdGhlIHRleHR1cmVcbiAqIEBwYXJhbSBzY2FsZU1vZGUge251bWJlcn0gU2VlIHt7I2Nyb3NzTGluayBcIlBJWEkvc2NhbGVNb2Rlczpwcm9wZXJ0eVwifX1zY2FsZU1vZGVze3svY3Jvc3NMaW5rfX0gZm9yIHBvc3NpYmxlIHZhbHVlc1xuICogQHJldHVybiB7VGV4dHVyZX1cbiAqL1xuVGV4dHVyZS5mcm9tQ2FudmFzID0gZnVuY3Rpb24gKGNhbnZhcywgc2NhbGVNb2RlKSB7XG4gICAgcmV0dXJuIG5ldyBUZXh0dXJlKEJhc2VUZXh0dXJlLmZyb21DYW52YXMoY2FudmFzLCBzY2FsZU1vZGUpKTtcbn07XG5cbi8qKlxuICogSGVscGVyIGZ1bmN0aW9uIHRoYXQgY3JlYXRlcyBhIG5ldyBUZXh0dXJlIGJhc2VkIG9uIHRoZSBnaXZlbiB2aWRlbyBlbGVtZW50LlxuICpcbiAqIEBzdGF0aWNcbiAqIEBwYXJhbSB2aWRlbyB7SFRNTFZpZGVvRWxlbWVudH1cbiAqIEBwYXJhbSBzY2FsZU1vZGUge251bWJlcn0gU2VlIHt7I2Nyb3NzTGluayBcIlBJWEkvc2NhbGVNb2Rlczpwcm9wZXJ0eVwifX1zY2FsZU1vZGVze3svY3Jvc3NMaW5rfX0gZm9yIHBvc3NpYmxlIHZhbHVlc1xuICogQHJldHVybiB7VGV4dHVyZX0gQSBUZXh0dXJlXG4gKi9cblRleHR1cmUuZnJvbVZpZGVvID0gZnVuY3Rpb24gKHZpZGVvLCBzY2FsZU1vZGUpIHtcbiAgICByZXR1cm4gbmV3IFRleHR1cmUoVmlkZW9CYXNlVGV4dHVyZS5iYXNlVGV4dHVyZUZyb21WaWRlbyh2aWRlbywgc2NhbGVNb2RlKSk7XG59O1xuXG4vKipcbiAqIEFkZHMgYSB0ZXh0dXJlIHRvIHRoZSBnbG9iYWwgdXRpbHMuVGV4dHVyZUNhY2hlLiBUaGlzIGNhY2hlIGlzIHNoYXJlZCBhY3Jvc3MgdGhlIHdob2xlIFBJWEkgb2JqZWN0LlxuICpcbiAqIEBzdGF0aWNcbiAqIEBwYXJhbSB0ZXh0dXJlIHtUZXh0dXJlfSBUaGUgVGV4dHVyZSB0byBhZGQgdG8gdGhlIGNhY2hlLlxuICogQHBhcmFtIGlkIHtzdHJpbmd9IFRoZSBpZCB0aGF0IHRoZSB0ZXh0dXJlIHdpbGwgYmUgc3RvcmVkIGFnYWluc3QuXG4gKi9cblRleHR1cmUuYWRkVGV4dHVyZVRvQ2FjaGUgPSBmdW5jdGlvbiAodGV4dHVyZSwgaWQpIHtcbiAgICB1dGlscy5UZXh0dXJlQ2FjaGVbaWRdID0gdGV4dHVyZTtcbn07XG5cbi8qKlxuICogUmVtb3ZlIGEgdGV4dHVyZSBmcm9tIHRoZSBnbG9iYWwgdXRpbHMuVGV4dHVyZUNhY2hlLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBwYXJhbSBpZCB7c3RyaW5nfSBUaGUgaWQgb2YgdGhlIHRleHR1cmUgdG8gYmUgcmVtb3ZlZFxuICogQHJldHVybiB7VGV4dHVyZX0gVGhlIHRleHR1cmUgdGhhdCB3YXMgcmVtb3ZlZFxuICovXG5UZXh0dXJlLnJlbW92ZVRleHR1cmVGcm9tQ2FjaGUgPSBmdW5jdGlvbiAoaWQpIHtcbiAgICB2YXIgdGV4dHVyZSA9IHV0aWxzLlRleHR1cmVDYWNoZVtpZF07XG5cbiAgICBkZWxldGUgdXRpbHMuVGV4dHVyZUNhY2hlW2lkXTtcbiAgICBkZWxldGUgdXRpbHMuQmFzZVRleHR1cmVDYWNoZVtpZF07XG5cbiAgICByZXR1cm4gdGV4dHVyZTtcbn07XG5cblRleHR1cmUuZW1wdHlUZXh0dXJlID0gbmV3IFRleHR1cmUobmV3IEJhc2VUZXh0dXJlKCkpO1xuIiwiZnVuY3Rpb24gVGV4dHVyZVV2cygpIHtcbiAgICB0aGlzLngwID0gMDtcbiAgICB0aGlzLnkwID0gMDtcblxuICAgIHRoaXMueDEgPSAwO1xuICAgIHRoaXMueTEgPSAwO1xuXG4gICAgdGhpcy54MiA9IDA7XG4gICAgdGhpcy55MiA9IDA7XG5cbiAgICB0aGlzLngzID0gMDtcbiAgICB0aGlzLnkzID0gMDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBUZXh0dXJlVXZzO1xuIiwidmFyIEJhc2VUZXh0dXJlID0gcmVxdWlyZSgnLi9CYXNlVGV4dHVyZScpLFxuICAgIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMnKTtcblxuLyoqXG4gKiBBIHRleHR1cmUgb2YgYSBbcGxheWluZ10gVmlkZW8uXG4gKlxuICogU2VlIHRoZSBbXCJkZXVzXCIgZGVtb10oaHR0cDovL3d3dy5nb29kYm95ZGlnaXRhbC5jb20vcGl4aWpzL2V4YW1wbGVzL2RldXMvKS5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEJhc2VUZXh0dXJlXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSBzb3VyY2Uge0hUTUxWaWRlb0VsZW1lbnR9XG4gKiBAcGFyYW0gW3NjYWxlTW9kZV0ge251bWJlcn0gU2VlIHtAbGluayBzY2FsZU1vZGVzfSBmb3IgcG9zc2libGUgdmFsdWVzXG4gKi9cbmZ1bmN0aW9uIFZpZGVvQmFzZVRleHR1cmUoc291cmNlLCBzY2FsZU1vZGUpIHtcbiAgICBpZiAoIXNvdXJjZSl7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gdmlkZW8gc291cmNlIGVsZW1lbnQgc3BlY2lmaWVkLicpO1xuICAgIH1cblxuICAgIC8vIGhvb2sgaW4gaGVyZSB0byBjaGVjayBpZiB2aWRlbyBpcyBhbHJlYWR5IGF2YWlsYWJsZS5cbiAgICAvLyBCYXNlVGV4dHVyZSBsb29rcyBmb3IgYSBzb3VyY2UuY29tcGxldGUgYm9vbGVhbiwgcGx1cyB3aWR0aCAmIGhlaWdodC5cblxuICAgIGlmICgoc291cmNlLnJlYWR5U3RhdGUgPT09IHNvdXJjZS5IQVZFX0VOT1VHSF9EQVRBIHx8IHNvdXJjZS5yZWFkeVN0YXRlID09PSBzb3VyY2UuSEFWRV9GVVRVUkVfREFUQSkgJiYgc291cmNlLndpZHRoICYmIHNvdXJjZS5oZWlnaHQpIHtcbiAgICAgICAgc291cmNlLmNvbXBsZXRlID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBCYXNlVGV4dHVyZS5jYWxsKHRoaXMsIHNvdXJjZSwgc2NhbGVNb2RlKTtcblxuICAgIHRoaXMuYXV0b1VwZGF0ZSA9IGZhbHNlO1xuXG4gICAgdGhpcy5fYm91bmRPblVwZGF0ZSA9IHRoaXMuX29uVXBkYXRlLmJpbmQodGhpcyk7XG4gICAgdGhpcy5fYm91bmRPbkNhblBsYXkgPSB0aGlzLl9vbkNhblBsYXkuYmluZCh0aGlzKTtcblxuICAgIGlmICghc291cmNlLmNvbXBsZXRlKSB7XG4gICAgICAgIHNvdXJjZS5hZGRFdmVudExpc3RlbmVyKCdjYW5wbGF5JywgdGhpcy5fYm91bmRPbkNhblBsYXkpO1xuICAgICAgICBzb3VyY2UuYWRkRXZlbnRMaXN0ZW5lcignY2FucGxheXRocm91Z2gnLCB0aGlzLl9ib3VuZE9uQ2FuUGxheSk7XG5cbiAgICAgICAgLy8gc3RhcnRlZCBwbGF5aW5nLi5cbiAgICAgICAgc291cmNlLmFkZEV2ZW50TGlzdGVuZXIoJ3BsYXknLCB0aGlzLl9vblBsYXlTdGFydC5iaW5kKHRoaXMpKTtcbiAgICAgICAgc291cmNlLmFkZEV2ZW50TGlzdGVuZXIoJ3BhdXNlJywgdGhpcy5fb25QbGF5U3RvcC5iaW5kKHRoaXMpKTtcbiAgICB9XG5cbiAgICB0aGlzLl9fbG9hZGVkID0gZmFsc2U7XG59XG5cblZpZGVvQmFzZVRleHR1cmUucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShCYXNlVGV4dHVyZS5wcm90b3R5cGUpO1xuVmlkZW9CYXNlVGV4dHVyZS5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBWaWRlb0Jhc2VUZXh0dXJlO1xubW9kdWxlLmV4cG9ydHMgPSBWaWRlb0Jhc2VUZXh0dXJlO1xuXG5WaWRlb0Jhc2VUZXh0dXJlLnByb3RvdHlwZS5fb25VcGRhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHRoaXMuYXV0b1VwZGF0ZSkge1xuICAgICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKHRoaXMuX2JvdW5kT25VcGRhdGUpO1xuICAgICAgICB0aGlzLm5lZWRzVXBkYXRlID0gdHJ1ZTtcbiAgICB9XG59O1xuXG5WaWRlb0Jhc2VUZXh0dXJlLnByb3RvdHlwZS5fb25QbGF5U3RhcnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKCF0aGlzLmF1dG9VcGRhdGUpIHtcbiAgICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSh0aGlzLl9ib3VuZE9uVXBkYXRlKTtcbiAgICAgICAgdGhpcy5hdXRvVXBkYXRlID0gdHJ1ZTtcbiAgICB9XG59O1xuXG5WaWRlb0Jhc2VUZXh0dXJlLnByb3RvdHlwZS5fb25QbGF5U3RvcCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmF1dG9VcGRhdGUgPSBmYWxzZTtcbn07XG5cblZpZGVvQmFzZVRleHR1cmUucHJvdG90eXBlLl9vbkNhblBsYXkgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5oYXNMb2FkZWQgPSB0cnVlO1xuXG4gICAgaWYgKHRoaXMuc291cmNlKSB7XG4gICAgICAgIHRoaXMuc291cmNlLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2NhbnBsYXknLCB0aGlzLl9ib3VuZE9uQ2FuUGxheSk7XG4gICAgICAgIHRoaXMuc291cmNlLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2NhbnBsYXl0aHJvdWdoJywgdGhpcy5fYm91bmRPbkNhblBsYXkpO1xuXG4gICAgICAgIHRoaXMud2lkdGggPSB0aGlzLnNvdXJjZS52aWRlb1dpZHRoO1xuICAgICAgICB0aGlzLmhlaWdodCA9IHRoaXMuc291cmNlLnZpZGVvSGVpZ2h0O1xuXG4gICAgICAgIHRoaXMuc291cmNlLnBsYXkoKTtcblxuICAgICAgICAvLyBwcmV2ZW50IG11bHRpcGxlIGxvYWRlZCBkaXNwYXRjaGVzLi5cbiAgICAgICAgaWYoIXRoaXMuX19sb2FkZWQpe1xuICAgICAgICAgICAgdGhpcy5fX2xvYWRlZCA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLmVtaXQoJ2xvYWRlZCcsIHRoaXMpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuVmlkZW9CYXNlVGV4dHVyZS5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5zb3VyY2UgJiYgdGhpcy5zb3VyY2UuX3BpeGlJZCkge1xuICAgICAgICB1dGlscy5CYXNlVGV4dHVyZUNhY2hlWyB0aGlzLnNvdXJjZS5fcGl4aUlkIF0gPSBudWxsO1xuICAgICAgICBkZWxldGUgdXRpbHMuQmFzZVRleHR1cmVDYWNoZVsgdGhpcy5zb3VyY2UuX3BpeGlJZCBdO1xuXG4gICAgICAgIHRoaXMuc291cmNlLl9waXhpSWQgPSBudWxsO1xuICAgICAgICBkZWxldGUgdGhpcy5zb3VyY2UuX3BpeGlJZDtcbiAgICB9XG5cbiAgICBCYXNlVGV4dHVyZS5wcm90b3R5cGUuZGVzdHJveS5jYWxsKHRoaXMpO1xufTtcblxuLyoqXG4gKiBNaW1pYyBQaXhpIEJhc2VUZXh0dXJlLmZyb20uLi4uIG1ldGhvZC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAcGFyYW0gdmlkZW8ge0hUTUxWaWRlb0VsZW1lbnR9XG4gKiBAcGFyYW0gc2NhbGVNb2RlIHtudW1iZXJ9IFNlZSB7QGxpbmsgc2NhbGVNb2Rlc30gZm9yIHBvc3NpYmxlIHZhbHVlc1xuICogQHJldHVybiB7VmlkZW9CYXNlVGV4dHVyZX1cbiAqL1xuVmlkZW9CYXNlVGV4dHVyZS5mcm9tVmlkZW8gPSBmdW5jdGlvbiAodmlkZW8sIHNjYWxlTW9kZSkge1xuICAgIGlmICghdmlkZW8uX3BpeGlJZCkge1xuICAgICAgICB2aWRlby5fcGl4aUlkID0gJ3ZpZGVvXycgKyB1dGlscy51dWlkKCk7XG4gICAgfVxuXG4gICAgdmFyIGJhc2VUZXh0dXJlID0gdXRpbHMuQmFzZVRleHR1cmVDYWNoZVt2aWRlby5fcGl4aUlkXTtcblxuICAgIGlmICghYmFzZVRleHR1cmUpIHtcbiAgICAgICAgYmFzZVRleHR1cmUgPSBuZXcgVmlkZW9CYXNlVGV4dHVyZSh2aWRlbywgc2NhbGVNb2RlKTtcbiAgICAgICAgdXRpbHMuQmFzZVRleHR1cmVDYWNoZVsgdmlkZW8uX3BpeGlJZCBdID0gYmFzZVRleHR1cmU7XG4gICAgfVxuXG4gICAgcmV0dXJuIGJhc2VUZXh0dXJlO1xufTtcblxuLyoqXG4gKiBNaW1pYyBQaXhpIEJhc2VUZXh0dXJlLmZyb20uLi4uIG1ldGhvZC5cbiAqXG4gKiBUaGlzIGNhbiBiZSB1c2VkIGluIGEgY291cGxlIHdheXMsIHN1Y2ggYXM6XG4gKlxuICogYGBganNcbiAqIHZhciB0ZXh0dXJlID0gUElYSS5WaWRlb0Jhc2VUZXh0dXJlLmZyb21VcmwoJ2h0dHA6Ly9teWRvbWFpbi5jb20vdmlkZW8ubXA0Jyk7XG4gKlxuICogdmFyIHRleHR1cmUgPSBQSVhJLlZpZGVvQmFzZVRleHR1cmUuZnJvbVVybCh7IHNyYzogJ2h0dHA6Ly9teWRvbWFpbi5jb20vdmlkZW8ubXA0JywgbWltZTogJ3ZpZGVvL21wNCcgfSk7XG4gKlxuICogdmFyIHRleHR1cmUgPSBQSVhJLlZpZGVvQmFzZVRleHR1cmUuZnJvbVVybHMoWycvdmlkZW8ud2VibScsICcvdmlkZW8ubXA0J10pO1xuICpcbiAqIHZhciB0ZXh0dXJlID0gUElYSS5WaWRlb0Jhc2VUZXh0dXJlLmZyb21VcmxzKFtcbiAqICAgICB7IHNyYzogJy92aWRlby53ZWJtJywgbWltZTogJ3ZpZGVvL3dlYm0nIH0sXG4gKiAgICAgeyBzcmM6ICcvdmlkZW8ubXA0JywgbWltZTogJ3ZpZGVvL21wNCcgfVxuICogXSk7XG4gKiBgYGBcbiAqXG4gKiBAYWxpYXMgZnJvbVVybHNcbiAqIEBzdGF0aWNcbiAqIEBwYXJhbSB2aWRlb1NyYyB7c3RyaW5nfG9iamVjdHxzdHJpbmdbXXxvYmplY3RbXX0gVGhlIFVSTChzKSBmb3IgdGhlIHZpZGVvLlxuICogQHBhcmFtIFt2aWRlb1NyYy5zcmNdIHtzdHJpbmd9IE9uZSBvZiB0aGUgc291cmNlIHVybHMgZm9yIHRoZSB2aWRlb1xuICogQHBhcmFtIFt2aWRlb1NyYy5taW1lXSB7c3RyaW5nfSBUaGUgbWltZXR5cGUgb2YgdGhlIHZpZGVvIChlLmcuICd2aWRlby9tcDQnKS4gSWYgbm90IHNwZWNpZmllZFxuICogIHRoZSB1cmwncyBleHRlbnNpb24gd2lsbCBiZSB1c2VkIGFzIHRoZSBzZWNvbmQgcGFydCBvZiB0aGUgbWltZSB0eXBlLlxuICogQHBhcmFtIHNjYWxlTW9kZSB7bnVtYmVyfSBTZWUge0BsaW5rIHNjYWxlTW9kZXN9IGZvciBwb3NzaWJsZSB2YWx1ZXNcbiAqIEByZXR1cm4ge1ZpZGVvQmFzZVRleHR1cmV9XG4gKi9cblZpZGVvQmFzZVRleHR1cmUuZnJvbVVybCA9IGZ1bmN0aW9uICh2aWRlb1NyYywgc2NhbGVNb2RlKSB7XG4gICAgdmFyIHZpZGVvID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndmlkZW8nKTtcblxuICAgIC8vIGFycmF5IG9mIG9iamVjdHMgb3Igc3RyaW5nc1xuICAgIGlmIChBcnJheS5pc0FycmF5KHZpZGVvU3JjKSkge1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZpZGVvU3JjLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICB2aWRlby5hcHBlbmRDaGlsZChjcmVhdGVTb3VyY2UodmlkZW9TcmMuc3JjIHx8IHZpZGVvU3JjLCB2aWRlb1NyYy5taW1lKSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gc2luZ2xlIG9iamVjdCBvciBzdHJpbmdcbiAgICBlbHNlIHtcbiAgICAgICAgdmlkZW8uYXBwZW5kQ2hpbGQoY3JlYXRlU291cmNlKHZpZGVvU3JjLnNyYyB8fCB2aWRlb1NyYywgdmlkZW9TcmMubWltZSkpO1xuICAgIH1cblxuICAgIHZpZGVvLmxvYWQoKTtcbiAgICB2aWRlby5wbGF5KCk7XG5cbiAgICByZXR1cm4gVmlkZW9CYXNlVGV4dHVyZS50ZXh0dXJlRnJvbVZpZGVvKHZpZGVvLCBzY2FsZU1vZGUpO1xufTtcblxuVmlkZW9CYXNlVGV4dHVyZS5mcm9tVXJscyA9IFZpZGVvQmFzZVRleHR1cmUuZnJvbVVybDtcblxuZnVuY3Rpb24gY3JlYXRlU291cmNlKHBhdGgsIHR5cGUpIHtcbiAgICBpZiAoIXR5cGUpIHtcbiAgICAgICAgdHlwZSA9ICd2aWRlby8nICsgcGF0aC5zdWJzdHIocGF0aC5sYXN0SW5kZXhPZignLicpICsgMSk7XG4gICAgfVxuXG4gICAgdmFyIHNvdXJjZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NvdXJjZScpO1xuXG4gICAgc291cmNlLnNyYyA9IHBhdGg7XG4gICAgc291cmNlLnR5cGUgPSB0eXBlO1xuXG4gICAgcmV0dXJuIHNvdXJjZTtcbn1cbiIsIi8qKlxuICogQ3JlYXRlcyBhbiBob21vZ2Vub3VzIG9iamVjdCBmb3IgdHJhY2tpbmcgZXZlbnRzIHNvIHVzZXJzIGNhbiBrbm93IHdoYXQgdG8gZXhwZWN0LlxuICpcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gdGFyZ2V0IHtvYmplY3R9IFRoZSB0YXJnZXQgb2JqZWN0IHRoYXQgdGhlIGV2ZW50IGlzIGNhbGxlZCBvblxuICogQHBhcmFtIG5hbWUge3N0cmluZ30gVGhlIHN0cmluZyBuYW1lIG9mIHRoZSBldmVudCB0aGF0IHdhcyB0cmlnZ2VyZWRcbiAqIEBwYXJhbSBkYXRhIHtvYmplY3R9IEFyYml0cmFyeSBldmVudCBkYXRhIHRvIHBhc3MgYWxvbmdcbiAqL1xuZnVuY3Rpb24gRXZlbnREYXRhKHRhcmdldCwgbmFtZSwgZGF0YSkge1xuICAgIC8vIGZvciBkdWNrIHR5cGluZyBpbiB0aGUgXCIub24oKVwiIGZ1bmN0aW9uXG4gICAgdGhpcy5fX2lzRXZlbnRPYmplY3QgPSB0cnVlO1xuXG4gICAgLyoqXG4gICAgICogVHJhY2tzIHRoZSBzdGF0ZSBvZiBidWJibGluZyBwcm9wYWdhdGlvbi4gRG8gbm90XG4gICAgICogc2V0IHRoaXMgZGlyZWN0bHksIGluc3RlYWQgdXNlIGBldmVudC5zdG9wUHJvcGFnYXRpb24oKWBcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKi9cbiAgICB0aGlzLnN0b3BwZWQgPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqIFRyYWNrcyB0aGUgc3RhdGUgb2Ygc2libGluZyBsaXN0ZW5lciBwcm9wYWdhdGlvbi4gRG8gbm90XG4gICAgICogc2V0IHRoaXMgZGlyZWN0bHksIGluc3RlYWQgdXNlIGBldmVudC5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKWBcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKi9cbiAgICB0aGlzLnN0b3BwZWRJbW1lZGlhdGUgPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBvcmlnaW5hbCB0YXJnZXQgdGhlIGV2ZW50IHRyaWdnZXJlZCBvbi5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge29iamVjdH1cbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKi9cbiAgICB0aGlzLnRhcmdldCA9IHRhcmdldDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBzdHJpbmcgbmFtZSBvZiB0aGUgZXZlbnQgdGhhdCB0aGlzIHJlcHJlc2VudHMuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtzdHJpbmd9XG4gICAgICogQHJlYWRvbmx5XG4gICAgICovXG4gICAgdGhpcy50eXBlID0gbmFtZTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBkYXRhIHRoYXQgd2FzIHBhc3NlZCBpbiB3aXRoIHRoaXMgZXZlbnQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtvYmplY3R9XG4gICAgICogQHJlYWRvbmx5XG4gICAgICovXG4gICAgdGhpcy5kYXRhID0gZGF0YTtcblxuICAgIC8qKlxuICAgICAqIFRoZSB0aW1lc3RhbXAgd2hlbiB0aGUgZXZlbnQgb2NjdXJyZWQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQHJlYWRvbmx5XG4gICAgICovXG4gICAgdGhpcy50aW1lU3RhbXAgPSBEYXRlLm5vdygpO1xufVxuXG5FdmVudERhdGEucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gRXZlbnREYXRhO1xubW9kdWxlLmV4cG9ydHMgPSBFdmVudERhdGE7XG5cbi8qKlxuICogU3RvcHMgdGhlIHByb3BhZ2F0aW9uIG9mIGV2ZW50cyB1cCB0aGUgc2NlbmUgZ3JhcGggKHByZXZlbnRzIGJ1YmJsaW5nKS5cbiAqXG4gKi9cbkV2ZW50RGF0YS5wcm90b3R5cGUuc3RvcFByb3BhZ2F0aW9uID0gZnVuY3Rpb24gc3RvcFByb3BhZ2F0aW9uKCkge1xuICAgIHRoaXMuc3RvcHBlZCA9IHRydWU7XG59O1xuXG4vKipcbiAqIFN0b3BzIHRoZSBwcm9wYWdhdGlvbiBvZiBldmVudHMgdG8gc2libGluZyBsaXN0ZW5lcnMgKG5vIGxvbmdlciBjYWxscyBhbnkgbGlzdGVuZXJzKS5cbiAqXG4gKi9cbkV2ZW50RGF0YS5wcm90b3R5cGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uID0gZnVuY3Rpb24gc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCkge1xuICAgIHRoaXMuc3RvcHBlZEltbWVkaWF0ZSA9IHRydWU7XG59O1xuIiwiLy9UT0RPOiBIYXZlIEdyYXBoaWNzIHVzZSBodHRwczovL2dpdGh1Yi5jb20vbWF0dGRlc2wvc2hhcGUyZFxuLy8gYW5kIGh0dHBzOi8vZ2l0aHViLmNvbS9tYXR0ZGVzbC9zaGFwZTJkLXRyaWFuZ3VsYXRlIGluc3RlYWQgb2YgY3VzdG9tIGNvZGUuXG5cbi8qXG4gICAgUG9seUsgbGlicmFyeVxuICAgIHVybDogaHR0cDovL3BvbHlrLml2YW5rLm5ldFxuICAgIFJlbGVhc2VkIHVuZGVyIE1JVCBsaWNlbmNlLlxuXG4gICAgQ29weXJpZ2h0IChjKSAyMDEyIEl2YW4gS3Vja2lyXG5cbiAgICBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvblxuICAgIG9idGFpbmluZyBhIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uXG4gICAgZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0byBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0XG4gICAgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsXG4gICAgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcbiAgICBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGVcbiAgICBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZ1xuICAgIGNvbmRpdGlvbnM6XG5cbiAgICBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZVxuICAgIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuXG4gICAgVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCxcbiAgICBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVNcbiAgICBPRiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORFxuICAgIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUXG4gICAgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksXG4gICAgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HXG4gICAgRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUlxuICAgIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS5cblxuICAgIFRoaXMgaXMgYW4gYW1hemluZyBsaWIhXG5cbiAgICBTbGlnaHRseSBtb2RpZmllZCBieSBNYXQgR3JvdmVzIChtYXRncm92ZXMuY29tKTtcbiovXG5cbi8qKlxuICogQmFzZWQgb24gdGhlIFBvbHlrIGxpYnJhcnkgaHR0cDovL3BvbHlrLml2YW5rLm5ldCByZWxlYXNlZCB1bmRlciBNSVQgbGljZW5jZS5cbiAqIFRoaXMgaXMgYW4gYW1hemluZyBsaWIhXG4gKiBTbGlnaHRseSBtb2RpZmllZCBieSBNYXQgR3JvdmVzIChtYXRncm92ZXMuY29tKTtcbiAqXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xudmFyIFBvbHlLID0gbW9kdWxlLmV4cG9ydHMgPSB7fTtcblxuLyoqXG4gKiBUcmlhbmd1bGF0ZXMgc2hhcGVzIGZvciB3ZWJHTCBncmFwaGljIGZpbGxzLlxuICpcbiAqL1xuUG9seUsuVHJpYW5ndWxhdGUgPSBmdW5jdGlvbiAocCkge1xuICAgIHZhciBzaWduID0gdHJ1ZTtcblxuICAgIHZhciBuID0gcC5sZW5ndGggPj4gMTtcbiAgICBpZiAobiA8IDMpIHJldHVybiBbXTtcblxuICAgIHZhciB0Z3MgPSBbXTtcbiAgICB2YXIgYXZsID0gW107XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuOyBpKyspIGF2bC5wdXNoKGkpO1xuXG4gICAgaSA9IDA7XG4gICAgdmFyIGFsID0gbjtcbiAgICB3aGlsZShhbCA+IDMpIHtcbiAgICAgICAgdmFyIGkwID0gYXZsWyhpKzApJWFsXTtcbiAgICAgICAgdmFyIGkxID0gYXZsWyhpKzEpJWFsXTtcbiAgICAgICAgdmFyIGkyID0gYXZsWyhpKzIpJWFsXTtcblxuICAgICAgICB2YXIgYXggPSBwWzIqaTBdLCAgYXkgPSBwWzIqaTArMV07XG4gICAgICAgIHZhciBieCA9IHBbMippMV0sICBieSA9IHBbMippMSsxXTtcbiAgICAgICAgdmFyIGN4ID0gcFsyKmkyXSwgIGN5ID0gcFsyKmkyKzFdO1xuXG4gICAgICAgIHZhciBlYXJGb3VuZCA9IGZhbHNlO1xuICAgICAgICBpZiAoUG9seUsuX2NvbnZleChheCwgYXksIGJ4LCBieSwgY3gsIGN5LCBzaWduKSkge1xuICAgICAgICAgICAgZWFyRm91bmQgPSB0cnVlO1xuICAgICAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBhbDsgaisrKSB7XG4gICAgICAgICAgICAgICAgdmFyIHZpID0gYXZsW2pdO1xuICAgICAgICAgICAgICAgIGlmICh2aSA9PT0gaTAgfHwgdmkgPT09IGkxIHx8IHZpID09PSBpMikgY29udGludWU7XG5cbiAgICAgICAgICAgICAgICBpZiAoUG9seUsuX1BvaW50SW5UcmlhbmdsZShwWzIqdmldLCBwWzIqdmkrMV0sIGF4LCBheSwgYngsIGJ5LCBjeCwgY3kpKSB7XG4gICAgICAgICAgICAgICAgICAgIGVhckZvdW5kID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChlYXJGb3VuZCkge1xuICAgICAgICAgICAgdGdzLnB1c2goaTAsIGkxLCBpMik7XG4gICAgICAgICAgICBhdmwuc3BsaWNlKChpKzEpJWFsLCAxKTtcbiAgICAgICAgICAgIGFsLS07XG4gICAgICAgICAgICBpID0gMDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChpKysgPiAzKmFsKSB7XG4gICAgICAgICAgICAvLyBuZWVkIHRvIGZsaXAgZmxpcCByZXZlcnNlIGl0IVxuICAgICAgICAgICAgLy8gcmVzZXQhXG4gICAgICAgICAgICBpZiAoc2lnbikge1xuICAgICAgICAgICAgICAgIHRncyA9IFtdO1xuICAgICAgICAgICAgICAgIGF2bCA9IFtdO1xuICAgICAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBuOyBpKyspIGF2bC5wdXNoKGkpO1xuXG4gICAgICAgICAgICAgICAgaSA9IDA7XG4gICAgICAgICAgICAgICAgYWwgPSBuO1xuXG4gICAgICAgICAgICAgICAgc2lnbiA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgLy8gICB3aW5kb3cuY29uc29sZS5sb2coXCJQSVhJIFdhcm5pbmc6IHNoYXBlIHRvbyBjb21wbGV4IHRvIGZpbGxcIik7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB0Z3MucHVzaChhdmxbMF0sIGF2bFsxXSwgYXZsWzJdKTtcbiAgICByZXR1cm4gdGdzO1xufTtcblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciBhIHBvaW50IGlzIHdpdGhpbiBhIHRyaWFuZ2xlXG4gKlxuICogQHBhcmFtIHB4IHtudW1iZXJ9IHggY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHBhcmFtIHB5IHtudW1iZXJ9IHkgY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHBhcmFtIGF4IHtudW1iZXJ9IHggY29vcmRpbmF0ZSBvZiB0aGUgYSBwb2ludCBvZiB0aGUgdHJpYW5nbGVcbiAqIEBwYXJhbSBheSB7bnVtYmVyfSB5IGNvb3JkaW5hdGUgb2YgdGhlIGEgcG9pbnQgb2YgdGhlIHRyaWFuZ2xlXG4gKiBAcGFyYW0gYngge251bWJlcn0geCBjb29yZGluYXRlIG9mIHRoZSBiIHBvaW50IG9mIHRoZSB0cmlhbmdsZVxuICogQHBhcmFtIGJ5IHtudW1iZXJ9IHkgY29vcmRpbmF0ZSBvZiB0aGUgYiBwb2ludCBvZiB0aGUgdHJpYW5nbGVcbiAqIEBwYXJhbSBjeCB7bnVtYmVyfSB4IGNvb3JkaW5hdGUgb2YgdGhlIGMgcG9pbnQgb2YgdGhlIHRyaWFuZ2xlXG4gKiBAcGFyYW0gY3kge251bWJlcn0geSBjb29yZGluYXRlIG9mIHRoZSBjIHBvaW50IG9mIHRoZSB0cmlhbmdsZVxuICogQHByaXZhdGVcbiAqIEByZXR1cm4ge2Jvb2xlYW59XG4gKi9cblBvbHlLLl9Qb2ludEluVHJpYW5nbGUgPSBmdW5jdGlvbiAocHgsIHB5LCBheCwgYXksIGJ4LCBieSwgY3gsIGN5KSB7XG4gICAgdmFyIHYweCA9IGN4LWF4O1xuICAgIHZhciB2MHkgPSBjeS1heTtcbiAgICB2YXIgdjF4ID0gYngtYXg7XG4gICAgdmFyIHYxeSA9IGJ5LWF5O1xuICAgIHZhciB2MnggPSBweC1heDtcbiAgICB2YXIgdjJ5ID0gcHktYXk7XG5cbiAgICB2YXIgZG90MDAgPSB2MHgqdjB4K3YweSp2MHk7XG4gICAgdmFyIGRvdDAxID0gdjB4KnYxeCt2MHkqdjF5O1xuICAgIHZhciBkb3QwMiA9IHYweCp2MngrdjB5KnYyeTtcbiAgICB2YXIgZG90MTEgPSB2MXgqdjF4K3YxeSp2MXk7XG4gICAgdmFyIGRvdDEyID0gdjF4KnYyeCt2MXkqdjJ5O1xuXG4gICAgdmFyIGludkRlbm9tID0gMSAvIChkb3QwMCAqIGRvdDExIC0gZG90MDEgKiBkb3QwMSk7XG4gICAgdmFyIHUgPSAoZG90MTEgKiBkb3QwMiAtIGRvdDAxICogZG90MTIpICogaW52RGVub207XG4gICAgdmFyIHYgPSAoZG90MDAgKiBkb3QxMiAtIGRvdDAxICogZG90MDIpICogaW52RGVub207XG5cbiAgICAvLyBDaGVjayBpZiBwb2ludCBpcyBpbiB0cmlhbmdsZVxuICAgIHJldHVybiAodSA+PSAwKSAmJiAodiA+PSAwKSAmJiAodSArIHYgPCAxKTtcbn07XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgYSBzaGFwZSBpcyBjb252ZXhcbiAqXG4gKiBAcHJpdmF0ZVxuICogQHJldHVybiB7Ym9vbGVhbn1cbiAqL1xuUG9seUsuX2NvbnZleCA9IGZ1bmN0aW9uIChheCwgYXksIGJ4LCBieSwgY3gsIGN5LCBzaWduKSB7XG4gICAgcmV0dXJuICgoYXktYnkpKihjeC1ieCkgKyAoYngtYXgpKihjeS1ieSkgPj0gMCkgPT09IHNpZ247XG59O1xuIiwidmFyIEV2ZW50RGF0YSA9IHJlcXVpcmUoJy4vRXZlbnREYXRhJyk7XG5cbi8qKlxuICogTWl4aW5zIGV2ZW50IGVtaXR0ZXIgZnVuY3Rpb25hbGl0eSB0byBhbiBvYmplY3QuXG4gKlxuICogQG1peGluXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBleGFtcGxlXG4gKiAgICAgIGZ1bmN0aW9uIE15RW1pdHRlcigpIHt9XG4gKlxuICogICAgICBldmVudFRhcmdldC5taXhpbihNeUVtaXR0ZXIucHJvdG90eXBlKTtcbiAqXG4gKiAgICAgIHZhciBlbSA9IG5ldyBNeUVtaXR0ZXIoKTtcbiAqICAgICAgZW0uZW1pdCgnZXZlbnROYW1lJywgJ3NvbWUgZGF0YScsICdzb21lIG1vcmUgZGF0YScsIHt9LCBudWxsLCAuLi4pO1xuICovXG5mdW5jdGlvbiBldmVudFRhcmdldChvYmopIHtcbiAgICAvKipcbiAgICAgKiBSZXR1cm4gYSBsaXN0IG9mIGFzc2lnbmVkIGV2ZW50IGxpc3RlbmVycy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBldmVudE5hbWUge3N0cmluZ30gVGhlIGV2ZW50cyB0aGF0IHNob3VsZCBiZSBsaXN0ZWQuXG4gICAgICogQHJldHVybiB7QXJyYXl9IEFuIGFycmF5IG9mIGxpc3RlbmVyIGZ1bmN0aW9uc1xuICAgICAqL1xuICAgIG9iai5saXN0ZW5lcnMgPSBmdW5jdGlvbiBsaXN0ZW5lcnMoZXZlbnROYW1lKSB7XG4gICAgICAgIHRoaXMuX2xpc3RlbmVycyA9IHRoaXMuX2xpc3RlbmVycyB8fCB7fTtcblxuICAgICAgICByZXR1cm4gdGhpcy5fbGlzdGVuZXJzW2V2ZW50TmFtZV0gPyB0aGlzLl9saXN0ZW5lcnNbZXZlbnROYW1lXS5zbGljZSgpIDogW107XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEVtaXQgYW4gZXZlbnQgdG8gYWxsIHJlZ2lzdGVyZWQgZXZlbnQgbGlzdGVuZXJzLlxuICAgICAqXG4gICAgICogQGFsaWFzIGRpc3BhdGNoRXZlbnRcbiAgICAgKiBAcGFyYW0gZXZlbnROYW1lIHtzdHJpbmd9IFRoZSBuYW1lIG9mIHRoZSBldmVudC5cbiAgICAgKiBAcmV0dXJuIHtib29sZWFufSBJbmRpY2F0aW9uIGlmIHdlJ3ZlIGVtaXR0ZWQgYW4gZXZlbnQuXG4gICAgICovXG4gICAgb2JqLmVtaXQgPSBvYmouZGlzcGF0Y2hFdmVudCA9IGZ1bmN0aW9uIGVtaXQoZXZlbnROYW1lLCBkYXRhKSB7XG4gICAgICAgIHRoaXMuX2xpc3RlbmVycyA9IHRoaXMuX2xpc3RlbmVycyB8fCB7fTtcblxuICAgICAgICAvLyBmYXN0IHJldHVybiB3aGVuIHRoZXJlIGFyZSBubyBsaXN0ZW5lcnNcbiAgICAgICAgaWYgKCF0aGlzLl9saXN0ZW5lcnNbZXZlbnROYW1lXSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy9iYWNrd2FyZHMgY29tcGF0IHdpdGggb2xkIG1ldGhvZCBcIi5lbWl0KHsgdHlwZTogJ3NvbWV0aGluZycgfSlcIlxuICAgICAgICBpZiAodHlwZW9mIGV2ZW50TmFtZSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIGRhdGEgPSBldmVudE5hbWU7XG4gICAgICAgICAgICBldmVudE5hbWUgPSBldmVudE5hbWUudHlwZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vZW5zdXJlIHdlIGFyZSB1c2luZyBhIHJlYWwgcGl4aSBldmVudFxuICAgICAgICBpZiAoIWRhdGEgfHwgZGF0YS5fX2lzRXZlbnRPYmplY3QgIT09IHRydWUpIHtcbiAgICAgICAgICAgIGRhdGEgPSBuZXcgRXZlbnREYXRhKHRoaXMsIGV2ZW50TmFtZSwgZGF0YSk7XG4gICAgICAgIH1cblxuICAgICAgICAvL2l0ZXJhdGUgdGhlIGxpc3RlbmVyc1xuICAgICAgICB2YXIgbGlzdGVuZXJzID0gdGhpcy5fbGlzdGVuZXJzW2V2ZW50TmFtZV0uc2xpY2UoMCksXG4gICAgICAgICAgICBsZW5ndGggPSBsaXN0ZW5lcnMubGVuZ3RoLFxuICAgICAgICAgICAgZm4gPSBsaXN0ZW5lcnNbMF0sXG4gICAgICAgICAgICBpO1xuXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW5ndGg7IGZuID0gbGlzdGVuZXJzWysraV0pIHtcbiAgICAgICAgICAgIC8vY2FsbCB0aGUgZXZlbnQgbGlzdGVuZXJcbiAgICAgICAgICAgIGZuLmNhbGwodGhpcywgZGF0YSk7XG5cbiAgICAgICAgICAgIC8vaWYgXCJzdG9wSW1tZWRpYXRlUHJvcGFnYXRpb25cIiBpcyBjYWxsZWQsIHN0b3AgY2FsbGluZyBzaWJsaW5nIGV2ZW50c1xuICAgICAgICAgICAgaWYgKGRhdGEuc3RvcHBlZEltbWVkaWF0ZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy9pZiBcInN0b3BQcm9wYWdhdGlvblwiIGlzIGNhbGxlZCB0aGVuIGRvbid0IGJ1YmJsZSB0aGUgZXZlbnRcbiAgICAgICAgaWYgKGRhdGEuc3RvcHBlZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICAvL2J1YmJsZSB0aGlzIGV2ZW50IHVwIHRoZSBzY2VuZSBncmFwaFxuICAgICAgICBpZiAodGhpcy5wYXJlbnQgJiYgdGhpcy5wYXJlbnQuZW1pdCkge1xuICAgICAgICAgICAgdGhpcy5wYXJlbnQuZW1pdC5jYWxsKHRoaXMucGFyZW50LCBldmVudE5hbWUsIGRhdGEpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlZ2lzdGVyIGEgbmV3IEV2ZW50TGlzdGVuZXIgZm9yIHRoZSBnaXZlbiBldmVudC5cbiAgICAgKlxuICAgICAqIEBhbGlhcyBhZGRFdmVudExpc3RlbmVyXG4gICAgICogQHBhcmFtIGV2ZW50TmFtZSB7c3RyaW5nfSBOYW1lIG9mIHRoZSBldmVudC5cbiAgICAgKiBAcGFyYW0gY2FsbGJhY2sge0Z1bmN0b259IGZuIENhbGxiYWNrIGZ1bmN0aW9uLlxuICAgICAqL1xuICAgIG9iai5vbiA9IG9iai5hZGRFdmVudExpc3RlbmVyID0gZnVuY3Rpb24gb24oZXZlbnROYW1lLCBmbikge1xuICAgICAgICB0aGlzLl9saXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnMgfHwge307XG5cbiAgICAgICAgKHRoaXMuX2xpc3RlbmVyc1tldmVudE5hbWVdID0gdGhpcy5fbGlzdGVuZXJzW2V2ZW50TmFtZV0gfHwgW10pXG4gICAgICAgICAgICAucHVzaChmbik7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEFkZCBhbiBFdmVudExpc3RlbmVyIHRoYXQncyBvbmx5IGNhbGxlZCBvbmNlLlxuICAgICAqXG4gICAgICogQHBhcmFtIGV2ZW50TmFtZSB7c3RyaW5nfSBOYW1lIG9mIHRoZSBldmVudC5cbiAgICAgKiBAcGFyYW0gY2FsbGJhY2sge0Z1bmN0aW9ufSBDYWxsYmFjayBmdW5jdGlvbi5cbiAgICAgKi9cbiAgICBvYmoub25jZSA9IGZ1bmN0aW9uIG9uY2UoZXZlbnROYW1lLCBmbikge1xuICAgICAgICB0aGlzLl9saXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnMgfHwge307XG5cbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICBmdW5jdGlvbiBvbmNlSGFuZGxlcldyYXBwZXIoKSB7XG4gICAgICAgICAgICBmbi5hcHBseShzZWxmLm9mZihldmVudE5hbWUsIG9uY2VIYW5kbGVyV3JhcHBlciksIGFyZ3VtZW50cyk7XG4gICAgICAgIH1cbiAgICAgICAgb25jZUhhbmRsZXJXcmFwcGVyLl9vcmlnaW5hbEhhbmRsZXIgPSBmbjtcblxuICAgICAgICByZXR1cm4gdGhpcy5vbihldmVudE5hbWUsIG9uY2VIYW5kbGVyV3JhcHBlcik7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlbW92ZSBldmVudCBsaXN0ZW5lcnMuXG4gICAgICpcbiAgICAgKiBAYWxpYXMgcmVtb3ZlRXZlbnRMaXN0ZW5lclxuICAgICAqIEBwYXJhbSBldmVudE5hbWUge3N0cmluZ30gVGhlIGV2ZW50IHdlIHdhbnQgdG8gcmVtb3ZlLlxuICAgICAqIEBwYXJhbSBjYWxsYmFjayB7RnVuY3Rpb259IFRoZSBsaXN0ZW5lciB0aGF0IHdlIG5lZWQgdG8gZmluZC5cbiAgICAgKi9cbiAgICBvYmoub2ZmID0gb2JqLnJlbW92ZUV2ZW50TGlzdGVuZXIgPSBmdW5jdGlvbiBvZmYoZXZlbnROYW1lLCBmbikge1xuICAgICAgICB0aGlzLl9saXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnMgfHwge307XG5cbiAgICAgICAgaWYgKCF0aGlzLl9saXN0ZW5lcnNbZXZlbnROYW1lXSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgbGlzdCA9IHRoaXMuX2xpc3RlbmVyc1tldmVudE5hbWVdLFxuICAgICAgICAgICAgaSA9IGZuID8gbGlzdC5sZW5ndGggOiAwO1xuXG4gICAgICAgIHdoaWxlKGktLSA+IDApIHtcbiAgICAgICAgICAgIGlmIChsaXN0W2ldID09PSBmbiB8fCBsaXN0W2ldLl9vcmlnaW5hbEhhbmRsZXIgPT09IGZuKSB7XG4gICAgICAgICAgICAgICAgbGlzdC5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobGlzdC5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLl9saXN0ZW5lcnNbZXZlbnROYW1lXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmUgYWxsIGxpc3RlbmVycyBvciBvbmx5IHRoZSBsaXN0ZW5lcnMgZm9yIHRoZSBzcGVjaWZpZWQgZXZlbnQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gZXZlbnROYW1lIHtzdHJpbmd9IFRoZSBldmVudCB5b3Ugd2FudCB0byByZW1vdmUgYWxsIGxpc3RlbmVycyBmb3IuXG4gICAgICovXG4gICAgb2JqLnJlbW92ZUFsbExpc3RlbmVycyA9IGZ1bmN0aW9uIHJlbW92ZUFsbExpc3RlbmVycyhldmVudE5hbWUpIHtcbiAgICAgICAgdGhpcy5fbGlzdGVuZXJzID0gdGhpcy5fbGlzdGVuZXJzIHx8IHt9O1xuXG4gICAgICAgIGlmICghdGhpcy5fbGlzdGVuZXJzW2V2ZW50TmFtZV0pIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG5cbiAgICAgICAgZGVsZXRlIHRoaXMuX2xpc3RlbmVyc1tldmVudE5hbWVdO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG59XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIC8qKlxuICAgICAqIE1peGVzIGluIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBldmVudFRhcmdldCBwcm90b3R5cGUgb250byBhbm90aGVyIG9iamVjdFxuICAgICAqXG4gICAgICogQHBhcmFtIG9iamVjdCB7b2JqZWN0fSBUaGUgb2JqIHRvIG1peCBpbnRvXG4gICAgICovXG4gICAgbWl4aW46IGZ1bmN0aW9uIG1peGluKG9iaikge1xuICAgICAgICBldmVudFRhcmdldChvYmopO1xuICAgIH1cbn07XG4iLCJ2YXIgQ09OU1QgPSByZXF1aXJlKCcuLi9jb25zdCcpO1xuXG4vKipcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG52YXIgdXRpbHMgPSBtb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBfdWlkOiAwLFxuICAgIF9zYWlkSGVsbG86IGZhbHNlLFxuXG4gICAgUG9seUs6ICAgICAgcmVxdWlyZSgnLi9Qb2x5SycpLFxuICAgIEV2ZW50RGF0YTogIHJlcXVpcmUoJy4vRXZlbnREYXRhJyksXG4gICAgZXZlbnRUYXJnZXQ6IHJlcXVpcmUoJy4vZXZlbnRUYXJnZXQnKSxcblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIG5leHQgdXVpZFxuICAgICAqXG4gICAgICogQHJldHVybiB7bnVtYmVyfSBUaGUgbmV4dCB1dWlkIHRvIHVzZS5cbiAgICAgKi9cbiAgICB1dWlkOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiArK3V0aWxzLl91aWQ7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENvbnZlcnRzIGEgaGV4IGNvbG9yIG51bWJlciB0byBhbiBbUiwgRywgQl0gYXJyYXlcbiAgICAgKlxuICAgICAqIEBwYXJhbSBoZXgge251bWJlcn1cbiAgICAgKiBAcmV0dXJuIHtudW1iZXJbXX0gQW4gYXJyYXkgcmVwcmVzZW50aW5nIHRoZSBbUiwgRywgQl0gb2YgdGhlIGNvbG9yLlxuICAgICAqL1xuICAgIGhleDJyZ2I6IGZ1bmN0aW9uIChoZXgsIG91dCkge1xuICAgICAgICBvdXQgPSBvdXQgfHwgW107XG5cbiAgICAgICAgb3V0WzBdID0gKGhleCA+PiAxNiAmIDB4RkYpIC8gMjU1O1xuICAgICAgICBvdXRbMV0gPSAoaGV4ID4+IDggJiAweEZGKSAvIDI1NTtcbiAgICAgICAgb3V0WzJdID0gKGhleCAmIDB4RkYpIC8gMjU1O1xuXG4gICAgICAgIHJldHVybiBvdXQ7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENvbnZlcnRzIGEgaGV4IGNvbG9yIG51bWJlciB0byBhIHN0cmluZy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBoZXgge251bWJlcn1cbiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBzdHJpbmcgY29sb3IuXG4gICAgICovXG4gICAgaGV4MnN0cmluZzogZnVuY3Rpb24gKGhleCkge1xuICAgICAgICBoZXggPSBoZXgudG9TdHJpbmcoMTYpO1xuICAgICAgICBoZXggPSAnMDAwMDAwJy5zdWJzdHIoMCwgNiAtIGhleC5sZW5ndGgpICsgaGV4O1xuXG4gICAgICAgIHJldHVybiAnIycgKyBoZXg7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENvbnZlcnRzIGEgY29sb3IgYXMgYW4gW1IsIEcsIEJdIGFycmF5IHRvIGEgaGV4IG51bWJlclxuICAgICAqXG4gICAgICogQHBhcmFtIHJnYiB7bnVtYmVyW119XG4gICAgICogQHJldHVybiB7bnVtYmVyfSBUaGUgY29sb3IgbnVtYmVyXG4gICAgICovXG4gICAgcmdiMmhleDogZnVuY3Rpb24gKHJnYikge1xuICAgICAgICByZXR1cm4gKChyZ2JbMF0qMjU1IDw8IDE2KSArIChyZ2JbMV0qMjU1IDw8IDgpICsgcmdiWzJdKjI1NSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENoZWNrcyB3aGV0aGVyIHRoZSBDYW52YXMgQmxlbmRNb2RlcyBhcmUgc3VwcG9ydGVkIGJ5IHRoZSBjdXJyZW50IGJyb3dzZXJcbiAgICAgKlxuICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IHdoZXRoZXIgdGhleSBhcmUgc3VwcG9ydGVkXG4gICAgICovXG4gICAgY2FuVXNlTmV3Q2FudmFzQmxlbmRNb2RlczogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodHlwZW9mIGRvY3VtZW50ID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpLFxuICAgICAgICAgICAgY29udGV4dCA9IGNhbnZhcy5nZXRDb250ZXh0KCcyZCcpO1xuXG4gICAgICAgIGNhbnZhcy53aWR0aCA9IDE7XG4gICAgICAgIGNhbnZhcy5oZWlnaHQgPSAxO1xuXG4gICAgICAgIGNvbnRleHQuZmlsbFN0eWxlID0gJyMwMDAnO1xuICAgICAgICBjb250ZXh0LmZpbGxSZWN0KDAsIDAsIDEsIDEpO1xuXG4gICAgICAgIGNvbnRleHQuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uID0gJ211bHRpcGx5JztcblxuICAgICAgICBjb250ZXh0LmZpbGxTdHlsZSA9ICcjZmZmJztcbiAgICAgICAgY29udGV4dC5maWxsUmVjdCgwLCAwLCAxLCAxKTtcblxuICAgICAgICByZXR1cm4gY29udGV4dC5nZXRJbWFnZURhdGEoMCwwLDEsMSkuZGF0YVswXSA9PT0gMDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogR2l2ZW4gYSBudW1iZXIsIHRoaXMgZnVuY3Rpb24gcmV0dXJucyB0aGUgY2xvc2VzdCBudW1iZXIgdGhhdCBpcyBhIHBvd2VyIG9mIHR3b1xuICAgICAqIHRoaXMgZnVuY3Rpb24gaXMgdGFrZW4gZnJvbSBTdGFybGluZyBGcmFtZXdvcmsgYXMgaXRzIHByZXR0eSBuZWF0IDspXG4gICAgICpcbiAgICAgKiBAcGFyYW0gbnVtYmVyIHtudW1iZXJ9XG4gICAgICogQHJldHVybiB7bnVtYmVyfSB0aGUgY2xvc2VzdCBudW1iZXIgdGhhdCBpcyBhIHBvd2VyIG9mIHR3b1xuICAgICAqL1xuICAgIGdldE5leHRQb3dlck9mVHdvOiBmdW5jdGlvbiAobnVtYmVyKSB7XG4gICAgICAgIC8vIHNlZTogaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Qb3dlcl9vZl90d28jRmFzdF9hbGdvcml0aG1fdG9fY2hlY2tfaWZfYV9wb3NpdGl2ZV9udW1iZXJfaXNfYV9wb3dlcl9vZl90d29cbiAgICAgICAgaWYgKG51bWJlciA+IDAgJiYgKG51bWJlciAmIChudW1iZXIgLSAxKSkgPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybiBudW1iZXI7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gMTtcblxuICAgICAgICAgICAgd2hpbGUgKHJlc3VsdCA8IG51bWJlcikge1xuICAgICAgICAgICAgICAgIHJlc3VsdCA8PD0gMTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBjaGVja3MgaWYgdGhlIGdpdmVuIHdpZHRoIGFuZCBoZWlnaHQgbWFrZSBhIHBvd2VyIG9mIHR3byByZWN0YW5nbGVcbiAgICAgKlxuICAgICAqIEBwYXJhbSB3aWR0aCB7bnVtYmVyfVxuICAgICAqIEBwYXJhbSBoZWlnaHQge251bWJlcn1cbiAgICAgKiBAcmV0dXJuIHtib29sZWFufVxuICAgICAqL1xuICAgIGlzUG93ZXJPZlR3bzogZnVuY3Rpb24gKHdpZHRoLCBoZWlnaHQpIHtcbiAgICAgICAgcmV0dXJuICh3aWR0aCA+IDAgJiYgKHdpZHRoICYgKHdpZHRoIC0gMSkpID09PSAwICYmIGhlaWdodCA+IDAgJiYgKGhlaWdodCAmIChoZWlnaHQgLSAxKSkgPT09IDApO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBMb2dzIG91dCB0aGUgdmVyc2lvbiBhbmQgcmVuZGVyZXIgaW5mb3JtYXRpb24gZm9yIHRoaXMgcnVubmluZyBpbnN0YW5jZSBvZiBQSVhJLlxuICAgICAqIElmIHlvdSBkb24ndCB3YW50IHRvIHNlZSB0aGlzIG1lc3NhZ2UgeW91IGNhbiBzZXQgYFBJWEkudXRpbHMuX3NhaWRIZWxsbyA9IHRydWU7YFxuICAgICAqIHNvIHRoZSBsaWJyYXJ5IHRoaW5rcyBpdCBhbHJlYWR5IHNhaWQgaXQuIEtlZXAgaW4gbWluZCB0aGF0IGRvaW5nIHRoYXQgd2lsbCBmb3JldmVyXG4gICAgICogbWFrZXMgeW91IGEgamVyayBmYWNlLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgc3RyaW5nIHJlbmRlcmVyIHR5cGUgdG8gbG9nLlxuICAgICAqIEBjb25zdGFudFxuICAgICAqIEBzdGF0aWNcbiAgICAgKi9cbiAgICBzYXlIZWxsbzogZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgICAgaWYgKHV0aWxzLl9zYWlkSGVsbG8pIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChuYXZpZ2F0b3IudXNlckFnZW50LnRvTG93ZXJDYXNlKCkuaW5kZXhPZignY2hyb21lJykgPiAtMSkge1xuICAgICAgICAgICAgdmFyIGFyZ3MgPSBbXG4gICAgICAgICAgICAgICAgJyVjICVjICVjIFBpeGkuanMgJyArIENPTlNULlZFUlNJT04gKyAnIC0gJyArIHR5cGUgKyAnICAlYyAnICsgJyAlYyAnICsgJyBodHRwOi8vd3d3LnBpeGlqcy5jb20vICAlYyAlYyDimaUlY+KZpSVj4pmlICcsXG4gICAgICAgICAgICAgICAgJ2JhY2tncm91bmQ6ICNmZjY2YTUnLFxuICAgICAgICAgICAgICAgICdiYWNrZ3JvdW5kOiAjZmY2NmE1JyxcbiAgICAgICAgICAgICAgICAnY29sb3I6ICNmZjY2YTU7IGJhY2tncm91bmQ6ICMwMzAzMDc7JyxcbiAgICAgICAgICAgICAgICAnYmFja2dyb3VuZDogI2ZmNjZhNScsXG4gICAgICAgICAgICAgICAgJ2JhY2tncm91bmQ6ICNmZmMzZGMnLFxuICAgICAgICAgICAgICAgICdiYWNrZ3JvdW5kOiAjZmY2NmE1JyxcbiAgICAgICAgICAgICAgICAnY29sb3I6ICNmZjI0MjQ7IGJhY2tncm91bmQ6ICNmZmYnLFxuICAgICAgICAgICAgICAgICdjb2xvcjogI2ZmMjQyNDsgYmFja2dyb3VuZDogI2ZmZicsXG4gICAgICAgICAgICAgICAgJ2NvbG9yOiAjZmYyNDI0OyBiYWNrZ3JvdW5kOiAjZmZmJ1xuICAgICAgICAgICAgXTtcblxuICAgICAgICAgICAgY29uc29sZS5sb2cuYXBwbHkoY29uc29sZSwgYXJncyk7IC8vanNoaW50IGlnbm9yZTpsaW5lXG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAod2luZG93LmNvbnNvbGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdQaXhpLmpzICcgKyBDT05TVC5WRVJTSU9OICsgJyAtICcgKyB0eXBlICsgJyAtIGh0dHA6Ly93d3cucGl4aWpzLmNvbS8nKTsgLy9qc2hpbnQgaWdub3JlOmxpbmVcbiAgICAgICAgfVxuXG4gICAgICAgIHV0aWxzLl9zYWlkSGVsbG8gPSB0cnVlO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBBIHdyYXBwZXIgZm9yIGFqYXggcmVxdWVzdHMgdG8gYmUgaGFuZGxlZCBjcm9zcyBicm93c2VyXG4gICAgICpcbiAgICAgKiBUT0RPOiBSZXBsYWNlIHRoaXMgd2lsIHN1cGVyYWdlbnRcbiAgICAgKlxuICAgICAqIEBjbGFzc1xuICAgICAqIEBuYW1lc3BhY2UgUElYSVxuICAgICAqL1xuICAgIEFqYXhSZXF1ZXN0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBhY3RpdmV4bW9kZXMgPSBbJ01zeG1sMi5YTUxIVFRQLjYuMCcsICdNc3htbDIuWE1MSFRUUC4zLjAnLCAnTWljcm9zb2Z0LlhNTEhUVFAnXTsgLy9hY3RpdmVYIHZlcnNpb25zIHRvIGNoZWNrIGZvciBpbiBJRVxuXG4gICAgICAgIGlmICh3aW5kb3cuQWN0aXZlWE9iamVjdCkgeyAvL1Rlc3QgZm9yIHN1cHBvcnQgZm9yIEFjdGl2ZVhPYmplY3QgaW4gSUUgZmlyc3QgKGFzIFhNTEh0dHBSZXF1ZXN0IGluIElFNyBpcyBicm9rZW4pXG4gICAgICAgICAgICBmb3IgKHZhciBpPTA7IGk8YWN0aXZleG1vZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgdHJ5e1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbmV3IHdpbmRvdy5BY3RpdmVYT2JqZWN0KGFjdGl2ZXhtb2Rlc1tpXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhdGNoKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgLy9zdXBwcmVzcyBlcnJvclxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh3aW5kb3cuWE1MSHR0cFJlcXVlc3QpIC8vIGlmIE1vemlsbGEsIFNhZmFyaSBldGNcbiAgICAgICAge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyB3aW5kb3cuWE1MSHR0cFJlcXVlc3QoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvLyBUT0RPOiByZWZhY3RvciBvdXQgdGhpc1xuICAgIEFuaW1DYWNoZToge30sXG4gICAgRnJhbWVDYWNoZToge30sXG4gICAgVGV4dHVyZUNhY2hlOiB7fSxcbiAgICBCYXNlVGV4dHVyZUNhY2hlOiB7fVxufTtcbiIsInZhciBjb3JlID0gcmVxdWlyZSgnLi4vY29yZScpO1xuXG4vKipcbiAqIEEgTW92aWVDbGlwIGlzIGEgc2ltcGxlIHdheSB0byBkaXNwbGF5IGFuIGFuaW1hdGlvbiBkZXBpY3RlZCBieSBhIGxpc3Qgb2YgdGV4dHVyZXMuXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBTcHJpdGVcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHRleHR1cmVzIHtUZXh0dXJlW119IGFuIGFycmF5IG9mIHtUZXh0dXJlfSBvYmplY3RzIHRoYXQgbWFrZSB1cCB0aGUgYW5pbWF0aW9uXG4gKi9cbmZ1bmN0aW9uIE1vdmllQ2xpcCh0ZXh0dXJlcykge1xuICAgIGNvcmUuU3ByaXRlLmNhbGwodGhpcywgdGV4dHVyZXNbMF0pO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGFycmF5IG9mIHRleHR1cmVzIHRoYXQgbWFrZSB1cCB0aGUgYW5pbWF0aW9uXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIFRleHR1cmVbXVxuICAgICAqL1xuICAgIHRoaXMudGV4dHVyZXMgPSB0ZXh0dXJlcztcblxuICAgIC8qKlxuICAgICAqIFRoZSBzcGVlZCB0aGF0IHRoZSBNb3ZpZUNsaXAgd2lsbCBwbGF5IGF0LiBIaWdoZXIgaXMgZmFzdGVyLCBsb3dlciBpcyBzbG93ZXJcbiAgICAgKlxuICAgICAqIEBtZW1iZXIgbnVtYmVyXG4gICAgICogQGRlZmF1bHQgMVxuICAgICAqL1xuICAgIHRoaXMuYW5pbWF0aW9uU3BlZWQgPSAxO1xuXG4gICAgLyoqXG4gICAgICogV2hldGhlciBvciBub3QgdGhlIG1vdmllIGNsaXAgcmVwZWF0cyBhZnRlciBwbGF5aW5nLlxuICAgICAqXG4gICAgICogQG1lbWJlciBib29sZWFuXG4gICAgICogQGRlZmF1bHQgdHJ1ZVxuICAgICAqL1xuICAgIHRoaXMubG9vcCA9IHRydWU7XG5cbiAgICAvKipcbiAgICAgKiBGdW5jdGlvbiB0byBjYWxsIHdoZW4gYSBNb3ZpZUNsaXAgZmluaXNoZXMgcGxheWluZ1xuICAgICAqXG4gICAgICogQG1ldGhvZFxuICAgICAqIEBtZW1iZXJvZiBNb3ZpZUNsaXAjXG4gICAgICovXG4gICAgdGhpcy5vbkNvbXBsZXRlID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBNb3ZpZUNsaXBzIGN1cnJlbnQgZnJhbWUgaW5kZXggKHRoaXMgbWF5IG5vdCBoYXZlIHRvIGJlIGEgd2hvbGUgbnVtYmVyKVxuICAgICAqXG4gICAgICogQG1lbWJlciBudW1iZXJcbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICogQHJlYWRvbmx5XG4gICAgICovXG4gICAgdGhpcy5jdXJyZW50RnJhbWUgPSAwO1xuXG4gICAgLyoqXG4gICAgICogSW5kaWNhdGVzIGlmIHRoZSBNb3ZpZUNsaXAgaXMgY3VycmVudGx5IHBsYXlpbmdcbiAgICAgKlxuICAgICAqIEBtZW1iZXIgYm9vbGVhblxuICAgICAqIEByZWFkb25seVxuICAgICAqL1xuICAgIHRoaXMucGxheWluZyA9IGZhbHNlO1xufVxuXG4vLyBjb25zdHJ1Y3RvclxuTW92aWVDbGlwLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoY29yZS5TcHJpdGUucHJvdG90eXBlKTtcbk1vdmllQ2xpcC5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBNb3ZpZUNsaXA7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKE1vdmllQ2xpcC5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiB0b3RhbEZyYW1lcyBpcyB0aGUgdG90YWwgbnVtYmVyIG9mIGZyYW1lcyBpbiB0aGUgTW92aWVDbGlwLiBUaGlzIGlzIHRoZSBzYW1lIGFzIG51bWJlciBvZiB0ZXh0dXJlc1xuICAgICAqIGFzc2lnbmVkIHRvIHRoZSBNb3ZpZUNsaXAuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyXG4gICAgICogQG1lbWJlcm9mIE1vdmllQ2xpcCNcbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICogQHJlYWRvbmx5XG4gICAgICovXG4gICAgdG90YWxGcmFtZXM6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnRleHR1cmVzLmxlbmd0aDtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG4vKipcbiAqIFN0b3BzIHRoZSBNb3ZpZUNsaXBcbiAqXG4gKi9cbk1vdmllQ2xpcC5wcm90b3R5cGUuc3RvcCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnBsYXlpbmcgPSBmYWxzZTtcbn07XG5cbi8qKlxuICogUGxheXMgdGhlIE1vdmllQ2xpcFxuICpcbiAqL1xuTW92aWVDbGlwLnByb3RvdHlwZS5wbGF5ID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMucGxheWluZyA9IHRydWU7XG59O1xuXG4vKipcbiAqIFN0b3BzIHRoZSBNb3ZpZUNsaXAgYW5kIGdvZXMgdG8gYSBzcGVjaWZpYyBmcmFtZVxuICpcbiAqIEBwYXJhbSBmcmFtZU51bWJlciB7bnVtYmVyfSBmcmFtZSBpbmRleCB0byBzdG9wIGF0XG4gKi9cbk1vdmllQ2xpcC5wcm90b3R5cGUuZ290b0FuZFN0b3AgPSBmdW5jdGlvbiAoZnJhbWVOdW1iZXIpIHtcbiAgICB0aGlzLnBsYXlpbmcgPSBmYWxzZTtcbiAgICB0aGlzLmN1cnJlbnRGcmFtZSA9IGZyYW1lTnVtYmVyO1xuXG4gICAgdmFyIHJvdW5kID0gTWF0aC5yb3VuZCh0aGlzLmN1cnJlbnRGcmFtZSk7XG4gICAgdGhpcy5zZXRUZXh0dXJlKHRoaXMudGV4dHVyZXNbcm91bmQgJSB0aGlzLnRleHR1cmVzLmxlbmd0aF0pO1xufTtcblxuLyoqXG4gKiBHb2VzIHRvIGEgc3BlY2lmaWMgZnJhbWUgYW5kIGJlZ2lucyBwbGF5aW5nIHRoZSBNb3ZpZUNsaXBcbiAqXG4gKiBAcGFyYW0gZnJhbWVOdW1iZXIge251bWJlcn0gZnJhbWUgaW5kZXggdG8gc3RhcnQgYXRcbiAqL1xuTW92aWVDbGlwLnByb3RvdHlwZS5nb3RvQW5kUGxheSA9IGZ1bmN0aW9uIChmcmFtZU51bWJlcikge1xuICAgIHRoaXMuY3VycmVudEZyYW1lID0gZnJhbWVOdW1iZXI7XG4gICAgdGhpcy5wbGF5aW5nID0gdHJ1ZTtcbn07XG5cbi8qXG4gKiBVcGRhdGVzIHRoZSBvYmplY3QgdHJhbnNmb3JtIGZvciByZW5kZXJpbmdcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5Nb3ZpZUNsaXAucHJvdG90eXBlLnVwZGF0ZVRyYW5zZm9ybSA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmRpc3BsYXlPYmplY3RDb250YWluZXJVcGRhdGVUcmFuc2Zvcm0oKTtcblxuICAgIGlmICghdGhpcy5wbGF5aW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmN1cnJlbnRGcmFtZSArPSB0aGlzLmFuaW1hdGlvblNwZWVkO1xuXG4gICAgdmFyIHJvdW5kID0gTWF0aC5yb3VuZCh0aGlzLmN1cnJlbnRGcmFtZSk7XG5cbiAgICBpZiAocm91bmQgPCAwKSB7XG4gICAgICAgIGlmICh0aGlzLmxvb3ApIHtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudEZyYW1lICs9IHRoaXMudGV4dHVyZXMubGVuZ3RoO1xuICAgICAgICAgICAgdGhpcy50ZXh0dXJlID0gdGhpcy50ZXh0dXJlc1t0aGlzLmN1cnJlbnRGcmFtZV07XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmdvdG9BbmRTdG9wKDApO1xuXG4gICAgICAgICAgICBpZiAodGhpcy5vbkNvbXBsZXRlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5vbkNvbXBsZXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSBpZiAodGhpcy5sb29wIHx8IHJvdW5kIDwgdGhpcy50ZXh0dXJlcy5sZW5ndGgpIHtcbiAgICAgICAgdGhpcy50ZXh0dXJlID0gdGhpcy50ZXh0dXJlc1tyb3VuZCAlIHRoaXMudGV4dHVyZXMubGVuZ3RoXTtcbiAgICB9XG4gICAgZWxzZSBpZiAocm91bmQgPj0gdGhpcy50ZXh0dXJlcy5sZW5ndGgpIHtcbiAgICAgICAgdGhpcy5nb3RvQW5kU3RvcCh0aGlzLnRleHR1cmVzLmxlbmd0aCAtIDEpO1xuXG4gICAgICAgIGlmICh0aGlzLm9uQ29tcGxldGUpIHtcbiAgICAgICAgICAgIHRoaXMub25Db21wbGV0ZSgpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuLyoqXG4gKiBBIHNob3J0IGhhbmQgd2F5IG9mIGNyZWF0aW5nIGEgbW92aWVjbGlwIGZyb20gYW4gYXJyYXkgb2YgZnJhbWUgaWRzXG4gKlxuICogQHN0YXRpY1xuICogQHBhcmFtIGZyYW1lcyB7c3RyaW5nW119IHRoZSBhcnJheSBvZiBmcmFtZXMgaWRzIHRoZSBtb3ZpZWNsaXAgd2lsbCB1c2UgYXMgaXRzIHRleHR1cmUgZnJhbWVzXG4gKi9cbk1vdmllQ2xpcC5mcm9tRnJhbWVzID0gZnVuY3Rpb24gKGZyYW1lcykge1xuICAgIHZhciB0ZXh0dXJlcyA9IFtdO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBmcmFtZXMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgdGV4dHVyZXMucHVzaChuZXcgY29yZS5UZXh0dXJlLmZyb21GcmFtZShmcmFtZXNbaV0pKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IE1vdmllQ2xpcCh0ZXh0dXJlcyk7XG59O1xuXG4vKipcbiAqIEEgc2hvcnQgaGFuZCB3YXkgb2YgY3JlYXRpbmcgYSBtb3ZpZWNsaXAgZnJvbSBhbiBhcnJheSBvZiBpbWFnZSBpZHNcbiAqXG4gKiBAc3RhdGljXG4gKiBAcGFyYW0gaW1hZ2VzIHtzdHJpbmdbXX0gdGhlIGFycmF5IG9mIGltYWdlIHVybHMgdGhlIG1vdmllY2xpcCB3aWxsIHVzZSBhcyBpdHMgdGV4dHVyZSBmcmFtZXNcbiAqL1xuTW92aWVDbGlwLmZyb21JbWFnZXMgPSBmdW5jdGlvbiAoaW1hZ2VzKSB7XG4gICAgdmFyIHRleHR1cmVzID0gW107XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGltYWdlcy5sZW5ndGg7ICsraSkge1xuICAgICAgICB0ZXh0dXJlcy5wdXNoKG5ldyBjb3JlLlRleHR1cmUuZnJvbUltYWdlKGltYWdlc1tpXSkpO1xuICAgIH1cblxuICAgIHJldHVybiBuZXcgTW92aWVDbGlwKHRleHR1cmVzKTtcbn07XG4iLCJ2YXIgU3RyaXAgPSByZXF1aXJlKCcuL1N0cmlwJyk7XG5cbi8qKlxuICpcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAZXh0ZW5kcyBTdHJpcFxuICogQHBhcmFtIHtUZXh0dXJlfSB0ZXh0dXJlIC0gVGhlIHRleHR1cmUgdG8gdXNlIG9uIHRoZSByb3BlLlxuICogQHBhcmFtIHtBcnJheX0gcG9pbnRzIC0gQW4gYXJyYXkgb2Yge1BvaW50fS5cbiAqXG4gKi9cbmZ1bmN0aW9uIFJvcGUodGV4dHVyZSwgcG9pbnRzKSB7XG4gICAgU3RyaXAuY2FsbCh0aGlzLCB0ZXh0dXJlKTtcbiAgICB0aGlzLnBvaW50cyA9IHBvaW50cztcblxuICAgIHRoaXMudmVydGljZXMgPSBuZXcgRmxvYXQzMkFycmF5KHBvaW50cy5sZW5ndGggKiA0KTtcbiAgICB0aGlzLnV2cyA9IG5ldyBGbG9hdDMyQXJyYXkocG9pbnRzLmxlbmd0aCAqIDQpO1xuICAgIHRoaXMuY29sb3JzID0gbmV3IEZsb2F0MzJBcnJheShwb2ludHMubGVuZ3RoICogMik7XG4gICAgdGhpcy5pbmRpY2VzID0gbmV3IFVpbnQxNkFycmF5KHBvaW50cy5sZW5ndGggKiAyKTtcblxuICAgIHRoaXMucmVmcmVzaCgpO1xufVxuXG5cbi8vIGNvbnN0cnVjdG9yXG5Sb3BlLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoU3RyaXAucHJvdG90eXBlKTtcblJvcGUucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gUm9wZTtcbm1vZHVsZS5leHBvcnRzID0gUm9wZTtcblxuLyoqXG4gKiBSZWZyZXNoZXNcbiAqXG4gKi9cblJvcGUucHJvdG90eXBlLnJlZnJlc2ggPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIHBvaW50cyA9IHRoaXMucG9pbnRzO1xuXG4gICAgaWYgKHBvaW50cy5sZW5ndGggPCAxKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgdXZzID0gdGhpcy51dnM7XG5cbiAgICB2YXIgaW5kaWNlcyA9IHRoaXMuaW5kaWNlcztcbiAgICB2YXIgY29sb3JzID0gdGhpcy5jb2xvcnM7XG5cbiAgICAvLyB0aGlzLmNvdW50IC09IDAuMjtcblxuICAgIHV2c1swXSA9IDA7XG4gICAgdXZzWzFdID0gMDtcbiAgICB1dnNbMl0gPSAwO1xuICAgIHV2c1szXSA9IDE7XG5cbiAgICBjb2xvcnNbMF0gPSAxO1xuICAgIGNvbG9yc1sxXSA9IDE7XG5cbiAgICBpbmRpY2VzWzBdID0gMDtcbiAgICBpbmRpY2VzWzFdID0gMTtcblxuICAgIHZhciB0b3RhbCA9IHBvaW50cy5sZW5ndGgsXG4gICAgICAgIHBvaW50LCBpbmRleCwgYW1vdW50O1xuXG4gICAgZm9yICh2YXIgaSA9IDE7IGkgPCB0b3RhbDsgaSsrKSB7XG4gICAgICAgIHBvaW50ID0gcG9pbnRzW2ldO1xuICAgICAgICBpbmRleCA9IGkgKiA0O1xuICAgICAgICAvLyB0aW1lIHRvIGRvIHNvbWUgc21hcnQgZHJhd2luZyFcbiAgICAgICAgYW1vdW50ID0gaSAvICh0b3RhbC0xKTtcblxuICAgICAgICBpZiAoaSUyKSB7XG4gICAgICAgICAgICB1dnNbaW5kZXhdID0gYW1vdW50O1xuICAgICAgICAgICAgdXZzW2luZGV4KzFdID0gMDtcblxuICAgICAgICAgICAgdXZzW2luZGV4KzJdID0gYW1vdW50O1xuICAgICAgICAgICAgdXZzW2luZGV4KzNdID0gMTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHV2c1tpbmRleF0gPSBhbW91bnQ7XG4gICAgICAgICAgICB1dnNbaW5kZXgrMV0gPSAwO1xuXG4gICAgICAgICAgICB1dnNbaW5kZXgrMl0gPSBhbW91bnQ7XG4gICAgICAgICAgICB1dnNbaW5kZXgrM10gPSAxO1xuICAgICAgICB9XG5cbiAgICAgICAgaW5kZXggPSBpICogMjtcbiAgICAgICAgY29sb3JzW2luZGV4XSA9IDE7XG4gICAgICAgIGNvbG9yc1tpbmRleCsxXSA9IDE7XG5cbiAgICAgICAgaW5kZXggPSBpICogMjtcbiAgICAgICAgaW5kaWNlc1tpbmRleF0gPSBpbmRleDtcbiAgICAgICAgaW5kaWNlc1tpbmRleCArIDFdID0gaW5kZXggKyAxO1xuICAgIH1cbn07XG5cbi8qXG4gKiBVcGRhdGVzIHRoZSBvYmplY3QgdHJhbnNmb3JtIGZvciByZW5kZXJpbmdcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5Sb3BlLnByb3RvdHlwZS51cGRhdGVUcmFuc2Zvcm0gPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIHBvaW50cyA9IHRoaXMucG9pbnRzO1xuXG4gICAgaWYgKHBvaW50cy5sZW5ndGggPCAxKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgbGFzdFBvaW50ID0gcG9pbnRzWzBdO1xuICAgIHZhciBuZXh0UG9pbnQ7XG4gICAgdmFyIHBlcnBYID0gMDtcbiAgICB2YXIgcGVycFkgPSAwO1xuXG4gICAgLy8gdGhpcy5jb3VudCAtPSAwLjI7XG5cbiAgICB2YXIgdmVydGljZXMgPSB0aGlzLnZlcnRpY2VzO1xuICAgIHZhciB0b3RhbCA9IHBvaW50cy5sZW5ndGgsXG4gICAgICAgIHBvaW50LCBpbmRleCwgcmF0aW8sIHBlcnBMZW5ndGgsIG51bTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdG90YWw7IGkrKykge1xuICAgICAgICBwb2ludCA9IHBvaW50c1tpXTtcbiAgICAgICAgaW5kZXggPSBpICogNDtcblxuICAgICAgICBpZiAoaSA8IHBvaW50cy5sZW5ndGgtMSkge1xuICAgICAgICAgICAgbmV4dFBvaW50ID0gcG9pbnRzW2krMV07XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBuZXh0UG9pbnQgPSBwb2ludDtcbiAgICAgICAgfVxuXG4gICAgICAgIHBlcnBZID0gLShuZXh0UG9pbnQueCAtIGxhc3RQb2ludC54KTtcbiAgICAgICAgcGVycFggPSBuZXh0UG9pbnQueSAtIGxhc3RQb2ludC55O1xuXG4gICAgICAgIHJhdGlvID0gKDEgLSAoaSAvICh0b3RhbC0xKSkpICogMTA7XG5cbiAgICAgICAgaWYgKHJhdGlvID4gMSkge1xuICAgICAgICAgICAgcmF0aW8gPSAxO1xuICAgICAgICB9XG5cbiAgICAgICAgcGVycExlbmd0aCA9IE1hdGguc3FydChwZXJwWCAqIHBlcnBYICsgcGVycFkgKiBwZXJwWSk7XG4gICAgICAgIG51bSA9IHRoaXMudGV4dHVyZS5oZWlnaHQgLyAyOyAvLygyMCArIE1hdGguYWJzKE1hdGguc2luKChpICsgdGhpcy5jb3VudCkgKiAwLjMpICogNTApICkqIHJhdGlvO1xuICAgICAgICBwZXJwWCAvPSBwZXJwTGVuZ3RoO1xuICAgICAgICBwZXJwWSAvPSBwZXJwTGVuZ3RoO1xuXG4gICAgICAgIHBlcnBYICo9IG51bTtcbiAgICAgICAgcGVycFkgKj0gbnVtO1xuXG4gICAgICAgIHZlcnRpY2VzW2luZGV4XSA9IHBvaW50LnggKyBwZXJwWDtcbiAgICAgICAgdmVydGljZXNbaW5kZXgrMV0gPSBwb2ludC55ICsgcGVycFk7XG4gICAgICAgIHZlcnRpY2VzW2luZGV4KzJdID0gcG9pbnQueCAtIHBlcnBYO1xuICAgICAgICB2ZXJ0aWNlc1tpbmRleCszXSA9IHBvaW50LnkgLSBwZXJwWTtcblxuICAgICAgICBsYXN0UG9pbnQgPSBwb2ludDtcbiAgICB9XG5cbiAgICB0aGlzLmRpc3BsYXlPYmplY3RDb250YWluZXJVcGRhdGVUcmFuc2Zvcm0oKTtcbn07XG5cbi8qKlxuICogU2V0cyB0aGUgdGV4dHVyZSB0aGF0IHRoZSBSb3BlIHdpbGwgdXNlXG4gKlxuICogQHBhcmFtIHRleHR1cmUge1RleHR1cmV9IHRoZSB0ZXh0dXJlIHRoYXQgd2lsbCBiZSB1c2VkXG4gKi9cblJvcGUucHJvdG90eXBlLnNldFRleHR1cmUgPSBmdW5jdGlvbiAodGV4dHVyZSkge1xuICAgIC8vIHN0b3AgY3VycmVudCB0ZXh0dXJlXG4gICAgdGhpcy50ZXh0dXJlID0gdGV4dHVyZTtcbiAgICAvL3RoaXMudXBkYXRlRnJhbWUgPSB0cnVlO1xufTtcbiIsInZhciBjb3JlID0gcmVxdWlyZSgnLi4vY29yZScpO1xuXG4vKipcbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIERpc3BsYXlPYmplY3RDb250YWluZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHRleHR1cmUge1RleHR1cmV9IFRoZSB0ZXh0dXJlIHRvIHVzZVxuICogQHBhcmFtIHdpZHRoIHtudW1iZXJ9IHRoZSB3aWR0aFxuICogQHBhcmFtIGhlaWdodCB7bnVtYmVyfSB0aGUgaGVpZ2h0XG4gKlxuICovXG5mdW5jdGlvbiBTdHJpcCh0ZXh0dXJlKSB7XG4gICAgY29yZS5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLmNhbGwodGhpcyk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdGV4dHVyZSBvZiB0aGUgc3RyaXBcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1RleHR1cmV9XG4gICAgICovXG4gICAgdGhpcy50ZXh0dXJlID0gdGV4dHVyZTtcblxuICAgIC8vIHNldCB1cCB0aGUgbWFpbiBiaXRzLi5cbiAgICB0aGlzLnV2cyA9IG5ldyBGbG9hdDMyQXJyYXkoWzAsIDEsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLCAxLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMSwgMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAsIDFdKTtcblxuICAgIHRoaXMudmVydGljZXMgPSBuZXcgRmxvYXQzMkFycmF5KFswLCAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxMDAsIDAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEwMCwgMTAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCAxMDBdKTtcblxuICAgIHRoaXMuY29sb3JzID0gbmV3IEZsb2F0MzJBcnJheShbMSwgMSwgMSwgMV0pO1xuXG4gICAgdGhpcy5pbmRpY2VzID0gbmV3IFVpbnQxNkFycmF5KFswLCAxLCAyLCAzXSk7XG5cbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRoZSBzdHJpcCBpcyBkaXJ0eSBvciBub3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5kaXJ0eSA9IHRydWU7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgYmxlbmQgbW9kZSB0byBiZSBhcHBsaWVkIHRvIHRoZSBzcHJpdGUuIFNldCB0byBibGVuZE1vZGVzLk5PUk1BTCB0byByZW1vdmUgYW55IGJsZW5kIG1vZGUuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgQ09OU1QuYmxlbmRNb2Rlcy5OT1JNQUw7XG4gICAgICovXG4gICAgdGhpcy5ibGVuZE1vZGUgPSBjb3JlLkNPTlNULmJsZW5kTW9kZXMuTk9STUFMO1xuXG4gICAgLyoqXG4gICAgICogVHJpYW5nbGVzIGluIGNhbnZhcyBtb2RlIGFyZSBhdXRvbWF0aWNhbGx5IGFudGlhbGlhc2VkLCB1c2UgdGhpcyB2YWx1ZSB0byBmb3JjZSB0cmlhbmdsZXMgdG8gb3ZlcmxhcCBhIGJpdCB3aXRoIGVhY2ggb3RoZXIuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5jYW52YXNQYWRkaW5nID0gMDtcblxuICAgIHRoaXMuZHJhd01vZGUgPSBTdHJpcC5EcmF3TW9kZXMuVFJJQU5HTEVfU1RSSVA7XG59XG5cbi8vIGNvbnN0cnVjdG9yXG5TdHJpcC5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKGNvcmUuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUpO1xuU3RyaXAucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gU3RyaXA7XG5tb2R1bGUuZXhwb3J0cyA9IFN0cmlwO1xuXG4vKipcbiAqIFJlbmRlcnMgdGhlIG9iamVjdCB1c2luZyB0aGUgV2ViR0wgcmVuZGVyZXJcbiAqXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9XG4gKi9cblN0cmlwLnByb3RvdHlwZS5yZW5kZXJXZWJHTCA9IGZ1bmN0aW9uIChyZW5kZXJlcikge1xuICAgIC8vIGlmIHRoZSBzcHJpdGUgaXMgbm90IHZpc2libGUgb3IgdGhlIGFscGhhIGlzIDAgdGhlbiBubyBuZWVkIHRvIHJlbmRlciB0aGlzIGVsZW1lbnRcbiAgICBpZiAoIXRoaXMudmlzaWJsZSB8fCB0aGlzLmFscGhhIDw9IDApIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIHJlbmRlciB0cmlhbmdsZSBzdHJpcC4uXG5cbiAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5zdG9wKCk7XG5cbiAgICAvLyBpbml0ISBpbml0IVxuICAgIGlmICghdGhpcy5fdmVydGV4QnVmZmVyKSB7XG4gICAgICAgIHRoaXMuX2luaXRXZWJHTChyZW5kZXJlcik7XG4gICAgfVxuXG4gICAgcmVuZGVyZXIuc2hhZGVyTWFuYWdlci5zZXRTaGFkZXIocmVuZGVyZXIuc2hhZGVyTWFuYWdlci5zdHJpcFNoYWRlcik7XG5cbiAgICB0aGlzLl9yZW5kZXJTdHJpcChyZW5kZXJlcik7XG5cbiAgICAvLy9yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLmFjdGl2YXRlRGVmYXVsdFNoYWRlcigpO1xuXG4gICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guc3RhcnQoKTtcblxuICAgIC8vVE9ETyBjaGVjayBjdWxsaW5nXG59O1xuXG5TdHJpcC5wcm90b3R5cGUuX2luaXRXZWJHTCA9IGZ1bmN0aW9uIChyZW5kZXJlcikge1xuICAgIC8vIGJ1aWxkIHRoZSBzdHJpcCFcbiAgICB2YXIgZ2wgPSByZW5kZXJlci5nbDtcblxuICAgIHRoaXMuX3ZlcnRleEJ1ZmZlciA9IGdsLmNyZWF0ZUJ1ZmZlcigpO1xuICAgIHRoaXMuX2luZGV4QnVmZmVyID0gZ2wuY3JlYXRlQnVmZmVyKCk7XG4gICAgdGhpcy5fdXZCdWZmZXIgPSBnbC5jcmVhdGVCdWZmZXIoKTtcbiAgICB0aGlzLl9jb2xvckJ1ZmZlciA9IGdsLmNyZWF0ZUJ1ZmZlcigpO1xuXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMuX3ZlcnRleEJ1ZmZlcik7XG4gICAgZ2wuYnVmZmVyRGF0YShnbC5BUlJBWV9CVUZGRVIsIHRoaXMudmVydGljZXMsIGdsLkRZTkFNSUNfRFJBVyk7XG5cbiAgICBnbC5iaW5kQnVmZmVyKGdsLkFSUkFZX0JVRkZFUiwgdGhpcy5fdXZCdWZmZXIpO1xuICAgIGdsLmJ1ZmZlckRhdGEoZ2wuQVJSQVlfQlVGRkVSLCAgdGhpcy51dnMsIGdsLlNUQVRJQ19EUkFXKTtcblxuICAgIGdsLmJpbmRCdWZmZXIoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLl9jb2xvckJ1ZmZlcik7XG4gICAgZ2wuYnVmZmVyRGF0YShnbC5BUlJBWV9CVUZGRVIsIHRoaXMuY29sb3JzLCBnbC5TVEFUSUNfRFJBVyk7XG5cbiAgICBnbC5iaW5kQnVmZmVyKGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCB0aGlzLl9pbmRleEJ1ZmZlcik7XG4gICAgZ2wuYnVmZmVyRGF0YShnbC5FTEVNRU5UX0FSUkFZX0JVRkZFUiwgdGhpcy5pbmRpY2VzLCBnbC5TVEFUSUNfRFJBVyk7XG59O1xuXG5TdHJpcC5wcm90b3R5cGUuX3JlbmRlclN0cmlwID0gZnVuY3Rpb24gKHJlbmRlcmVyKSB7XG4gICAgdmFyIGdsID0gcmVuZGVyZXIuZ2w7XG4gICAgdmFyIHByb2plY3Rpb24gPSByZW5kZXJlci5wcm9qZWN0aW9uLFxuICAgICAgICBvZmZzZXQgPSByZW5kZXJlci5vZmZzZXQsXG4gICAgICAgIHNoYWRlciA9IHJlbmRlcmVyLnNoYWRlck1hbmFnZXIuc3RyaXBTaGFkZXI7XG5cbiAgICB2YXIgZHJhd01vZGUgPSB0aGlzLmRyYXdNb2RlID09PSBTdHJpcC5EcmF3TW9kZXMuVFJJQU5HTEVfU1RSSVAgPyBnbC5UUklBTkdMRV9TVFJJUCA6IGdsLlRSSUFOR0xFUztcblxuICAgIC8vIGdsLnVuaWZvcm1NYXRyaXg0ZnYoc2hhZGVyUHJvZ3JhbS5tdk1hdHJpeFVuaWZvcm0sIGZhbHNlLCBtYXQ0UmVhbCk7XG5cbiAgICByZW5kZXJlci5ibGVuZE1vZGVNYW5hZ2VyLnNldEJsZW5kTW9kZSh0aGlzLmJsZW5kTW9kZSk7XG5cblxuICAgIC8vIHNldCB1bmlmb3Jtc1xuICAgIGdsLnVuaWZvcm1NYXRyaXgzZnYoc2hhZGVyLnRyYW5zbGF0aW9uTWF0cml4LCBmYWxzZSwgdGhpcy53b3JsZFRyYW5zZm9ybS50b0FycmF5KHRydWUpKTtcbiAgICBnbC51bmlmb3JtMmYoc2hhZGVyLnByb2plY3Rpb25WZWN0b3IsIHByb2plY3Rpb24ueCwgLXByb2plY3Rpb24ueSk7XG4gICAgZ2wudW5pZm9ybTJmKHNoYWRlci5vZmZzZXRWZWN0b3IsIC1vZmZzZXQueCwgLW9mZnNldC55KTtcbiAgICBnbC51bmlmb3JtMWYoc2hhZGVyLmFscGhhLCB0aGlzLndvcmxkQWxwaGEpO1xuXG4gICAgaWYgKCF0aGlzLmRpcnR5KSB7XG5cbiAgICAgICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMuX3ZlcnRleEJ1ZmZlcik7XG4gICAgICAgIGdsLmJ1ZmZlclN1YkRhdGEoZ2wuQVJSQVlfQlVGRkVSLCAwLCB0aGlzLnZlcnRpY2VzKTtcbiAgICAgICAgZ2wudmVydGV4QXR0cmliUG9pbnRlcihzaGFkZXIuYVZlcnRleFBvc2l0aW9uLCAyLCBnbC5GTE9BVCwgZmFsc2UsIDAsIDApO1xuXG4gICAgICAgIC8vIHVwZGF0ZSB0aGUgdXZzXG4gICAgICAgIGdsLmJpbmRCdWZmZXIoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLl91dkJ1ZmZlcik7XG4gICAgICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIoc2hhZGVyLmFUZXh0dXJlQ29vcmQsIDIsIGdsLkZMT0FULCBmYWxzZSwgMCwgMCk7XG5cbiAgICAgICAgZ2wuYWN0aXZlVGV4dHVyZShnbC5URVhUVVJFMCk7XG5cbiAgICAgICAgLy8gY2hlY2sgaWYgYSB0ZXh0dXJlIGlzIGRpcnR5Li5cbiAgICAgICAgaWYgKHRoaXMudGV4dHVyZS5iYXNlVGV4dHVyZS5fZGlydHlbZ2wuaWRdKSB7XG4gICAgICAgICAgICByZW5kZXJlci51cGRhdGVUZXh0dXJlKHRoaXMudGV4dHVyZS5iYXNlVGV4dHVyZSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyBiaW5kIHRoZSBjdXJyZW50IHRleHR1cmVcbiAgICAgICAgICAgIGdsLmJpbmRUZXh0dXJlKGdsLlRFWFRVUkVfMkQsIHRoaXMudGV4dHVyZS5iYXNlVGV4dHVyZS5fZ2xUZXh0dXJlc1tnbC5pZF0pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG9udCBuZWVkIHRvIHVwbG9hZCFcbiAgICAgICAgZ2wuYmluZEJ1ZmZlcihnbC5FTEVNRU5UX0FSUkFZX0JVRkZFUiwgdGhpcy5faW5kZXhCdWZmZXIpO1xuXG5cbiAgICB9XG4gICAgZWxzZSB7XG5cbiAgICAgICAgdGhpcy5kaXJ0eSA9IGZhbHNlO1xuICAgICAgICBnbC5iaW5kQnVmZmVyKGdsLkFSUkFZX0JVRkZFUiwgdGhpcy5fdmVydGV4QnVmZmVyKTtcbiAgICAgICAgZ2wuYnVmZmVyRGF0YShnbC5BUlJBWV9CVUZGRVIsIHRoaXMudmVydGljZXMsIGdsLlNUQVRJQ19EUkFXKTtcbiAgICAgICAgZ2wudmVydGV4QXR0cmliUG9pbnRlcihzaGFkZXIuYVZlcnRleFBvc2l0aW9uLCAyLCBnbC5GTE9BVCwgZmFsc2UsIDAsIDApO1xuXG4gICAgICAgIC8vIHVwZGF0ZSB0aGUgdXZzXG4gICAgICAgIGdsLmJpbmRCdWZmZXIoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLl91dkJ1ZmZlcik7XG4gICAgICAgIGdsLmJ1ZmZlckRhdGEoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLnV2cywgZ2wuU1RBVElDX0RSQVcpO1xuICAgICAgICBnbC52ZXJ0ZXhBdHRyaWJQb2ludGVyKHNoYWRlci5hVGV4dHVyZUNvb3JkLCAyLCBnbC5GTE9BVCwgZmFsc2UsIDAsIDApO1xuXG4gICAgICAgIGdsLmFjdGl2ZVRleHR1cmUoZ2wuVEVYVFVSRTApO1xuXG4gICAgICAgIC8vIGNoZWNrIGlmIGEgdGV4dHVyZSBpcyBkaXJ0eS4uXG4gICAgICAgIGlmICh0aGlzLnRleHR1cmUuYmFzZVRleHR1cmUuX2RpcnR5W2dsLmlkXSkge1xuICAgICAgICAgICAgcmVuZGVyZXIudXBkYXRlVGV4dHVyZSh0aGlzLnRleHR1cmUuYmFzZVRleHR1cmUpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZ2wuYmluZFRleHR1cmUoZ2wuVEVYVFVSRV8yRCwgdGhpcy50ZXh0dXJlLmJhc2VUZXh0dXJlLl9nbFRleHR1cmVzW2dsLmlkXSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkb250IG5lZWQgdG8gdXBsb2FkIVxuICAgICAgICBnbC5iaW5kQnVmZmVyKGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCB0aGlzLl9pbmRleEJ1ZmZlcik7XG4gICAgICAgIGdsLmJ1ZmZlckRhdGEoZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIsIHRoaXMuaW5kaWNlcywgZ2wuU1RBVElDX0RSQVcpO1xuXG4gICAgfVxuICAgIC8vY29uc29sZS5sb2coZ2wuVFJJQU5HTEVfU1RSSVApXG4gICAgLy9cbiAgICAvL1xuICAgIGdsLmRyYXdFbGVtZW50cyhkcmF3TW9kZSwgdGhpcy5pbmRpY2VzLmxlbmd0aCwgZ2wuVU5TSUdORURfU0hPUlQsIDApO1xuXG5cbn07XG5cbi8qKlxuICogUmVuZGVycyB0aGUgb2JqZWN0IHVzaW5nIHRoZSBDYW52YXMgcmVuZGVyZXJcbiAqXG4gKiBAcGFyYW0gcmVuZGVyZXIge0NhbnZhc1JlbmRlcmVyfVxuICovXG5TdHJpcC5wcm90b3R5cGUucmVuZGVyQ2FudmFzID0gZnVuY3Rpb24gKHJlbmRlcmVyKSB7XG4gICAgdmFyIGNvbnRleHQgPSByZW5kZXJlci5jb250ZXh0O1xuXG4gICAgdmFyIHRyYW5zZm9ybSA9IHRoaXMud29ybGRUcmFuc2Zvcm07XG5cbiAgICBpZiAocmVuZGVyZXIucm91bmRQaXhlbHMpIHtcbiAgICAgICAgY29udGV4dC5zZXRUcmFuc2Zvcm0odHJhbnNmb3JtLmEsIHRyYW5zZm9ybS5iLCB0cmFuc2Zvcm0uYywgdHJhbnNmb3JtLmQsIHRyYW5zZm9ybS50eCB8IDAsIHRyYW5zZm9ybS50eSB8IDApO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgY29udGV4dC5zZXRUcmFuc2Zvcm0odHJhbnNmb3JtLmEsIHRyYW5zZm9ybS5iLCB0cmFuc2Zvcm0uYywgdHJhbnNmb3JtLmQsIHRyYW5zZm9ybS50eCwgdHJhbnNmb3JtLnR5KTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5kcmF3TW9kZSA9PT0gU3RyaXAuRHJhd01vZGVzLlRSSUFOR0xFX1NUUklQKSB7XG4gICAgICAgIHRoaXMuX3JlbmRlckNhbnZhc1RyaWFuZ2xlU3RyaXAoY29udGV4dCk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLl9yZW5kZXJDYW52YXNUcmlhbmdsZXMoY29udGV4dCk7XG4gICAgfVxufTtcblxuU3RyaXAucHJvdG90eXBlLl9yZW5kZXJDYW52YXNUcmlhbmdsZVN0cmlwID0gZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICAvLyBkcmF3IHRyaWFuZ2xlcyEhXG4gICAgdmFyIHZlcnRpY2VzID0gdGhpcy52ZXJ0aWNlcztcbiAgICB2YXIgdXZzID0gdGhpcy51dnM7XG5cbiAgICB2YXIgbGVuZ3RoID0gdmVydGljZXMubGVuZ3RoIC8gMjtcbiAgICAvLyB0aGlzLmNvdW50Kys7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aCAtIDI7IGkrKykge1xuICAgICAgICAvLyBkcmF3IHNvbWUgdHJpYW5nbGVzIVxuICAgICAgICB2YXIgaW5kZXggPSBpICogMjtcbiAgICAgICAgdGhpcy5fcmVuZGVyQ2FudmFzRHJhd1RyaWFuZ2xlKGNvbnRleHQsIHZlcnRpY2VzLCB1dnMsIGluZGV4LCAoaW5kZXggKyAyKSwgKGluZGV4ICsgNCkpO1xuICAgIH1cbn07XG5cblN0cmlwLnByb3RvdHlwZS5fcmVuZGVyQ2FudmFzVHJpYW5nbGVzID0gZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICAvLyBkcmF3IHRyaWFuZ2xlcyEhXG4gICAgdmFyIHZlcnRpY2VzID0gdGhpcy52ZXJ0aWNlcztcbiAgICB2YXIgdXZzID0gdGhpcy51dnM7XG4gICAgdmFyIGluZGljZXMgPSB0aGlzLmluZGljZXM7XG5cbiAgICB2YXIgbGVuZ3RoID0gaW5kaWNlcy5sZW5ndGg7XG4gICAgLy8gdGhpcy5jb3VudCsrO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMykge1xuICAgICAgICAvLyBkcmF3IHNvbWUgdHJpYW5nbGVzIVxuICAgICAgICB2YXIgaW5kZXgwID0gaW5kaWNlc1tpXSAqIDIsIGluZGV4MSA9IGluZGljZXNbaSArIDFdICogMiwgaW5kZXgyID0gaW5kaWNlc1tpICsgMl0gKiAyO1xuICAgICAgICB0aGlzLl9yZW5kZXJDYW52YXNEcmF3VHJpYW5nbGUoY29udGV4dCwgdmVydGljZXMsIHV2cywgaW5kZXgwLCBpbmRleDEsIGluZGV4Mik7XG4gICAgfVxufTtcblxuU3RyaXAucHJvdG90eXBlLl9yZW5kZXJDYW52YXNEcmF3VHJpYW5nbGUgPSBmdW5jdGlvbiAoY29udGV4dCwgdmVydGljZXMsIHV2cywgaW5kZXgwLCBpbmRleDEsIGluZGV4Mikge1xuICAgIHZhciB0ZXh0dXJlU291cmNlID0gdGhpcy50ZXh0dXJlLmJhc2VUZXh0dXJlLnNvdXJjZTtcbiAgICB2YXIgdGV4dHVyZVdpZHRoID0gdGhpcy50ZXh0dXJlLndpZHRoO1xuICAgIHZhciB0ZXh0dXJlSGVpZ2h0ID0gdGhpcy50ZXh0dXJlLmhlaWdodDtcblxuICAgIHZhciB4MCA9IHZlcnRpY2VzW2luZGV4MF0sIHgxID0gdmVydGljZXNbaW5kZXgxXSwgeDIgPSB2ZXJ0aWNlc1tpbmRleDJdO1xuICAgIHZhciB5MCA9IHZlcnRpY2VzW2luZGV4MCArIDFdLCB5MSA9IHZlcnRpY2VzW2luZGV4MSArIDFdLCB5MiA9IHZlcnRpY2VzW2luZGV4MiArIDFdO1xuXG4gICAgdmFyIHUwID0gdXZzW2luZGV4MF0gKiB0ZXh0dXJlV2lkdGgsIHUxID0gdXZzW2luZGV4MV0gKiB0ZXh0dXJlV2lkdGgsIHUyID0gdXZzW2luZGV4Ml0gKiB0ZXh0dXJlV2lkdGg7XG4gICAgdmFyIHYwID0gdXZzW2luZGV4MCArIDFdICogdGV4dHVyZUhlaWdodCwgdjEgPSB1dnNbaW5kZXgxICsgMV0gKiB0ZXh0dXJlSGVpZ2h0LCB2MiA9IHV2c1tpbmRleDIgKyAxXSAqIHRleHR1cmVIZWlnaHQ7XG5cbiAgICBpZiAodGhpcy5jYW52YXNQYWRkaW5nID4gMCkge1xuICAgICAgICB2YXIgcGFkZGluZ1ggPSB0aGlzLmNhbnZhc1BhZGRpbmcgLyB0aGlzLndvcmxkVHJhbnNmb3JtLmE7XG4gICAgICAgIHZhciBwYWRkaW5nWSA9IHRoaXMuY2FudmFzUGFkZGluZyAvIHRoaXMud29ybGRUcmFuc2Zvcm0uZDtcbiAgICAgICAgdmFyIGNlbnRlclggPSAoeDAgKyB4MSArIHgyKSAvIDM7XG4gICAgICAgIHZhciBjZW50ZXJZID0gKHkwICsgeTEgKyB5MikgLyAzO1xuXG4gICAgICAgIHZhciBub3JtWCA9IHgwIC0gY2VudGVyWDtcbiAgICAgICAgdmFyIG5vcm1ZID0geTAgLSBjZW50ZXJZO1xuXG4gICAgICAgIHZhciBkaXN0ID0gTWF0aC5zcXJ0KG5vcm1YICogbm9ybVggKyBub3JtWSAqIG5vcm1ZKTtcbiAgICAgICAgeDAgPSBjZW50ZXJYICsgKG5vcm1YIC8gZGlzdCkgKiAoZGlzdCArIHBhZGRpbmdYKTtcbiAgICAgICAgeTAgPSBjZW50ZXJZICsgKG5vcm1ZIC8gZGlzdCkgKiAoZGlzdCArIHBhZGRpbmdZKTtcblxuICAgICAgICAvL1xuXG4gICAgICAgIG5vcm1YID0geDEgLSBjZW50ZXJYO1xuICAgICAgICBub3JtWSA9IHkxIC0gY2VudGVyWTtcblxuICAgICAgICBkaXN0ID0gTWF0aC5zcXJ0KG5vcm1YICogbm9ybVggKyBub3JtWSAqIG5vcm1ZKTtcbiAgICAgICAgeDEgPSBjZW50ZXJYICsgKG5vcm1YIC8gZGlzdCkgKiAoZGlzdCArIHBhZGRpbmdYKTtcbiAgICAgICAgeTEgPSBjZW50ZXJZICsgKG5vcm1ZIC8gZGlzdCkgKiAoZGlzdCArIHBhZGRpbmdZKTtcblxuICAgICAgICBub3JtWCA9IHgyIC0gY2VudGVyWDtcbiAgICAgICAgbm9ybVkgPSB5MiAtIGNlbnRlclk7XG5cbiAgICAgICAgZGlzdCA9IE1hdGguc3FydChub3JtWCAqIG5vcm1YICsgbm9ybVkgKiBub3JtWSk7XG4gICAgICAgIHgyID0gY2VudGVyWCArIChub3JtWCAvIGRpc3QpICogKGRpc3QgKyBwYWRkaW5nWCk7XG4gICAgICAgIHkyID0gY2VudGVyWSArIChub3JtWSAvIGRpc3QpICogKGRpc3QgKyBwYWRkaW5nWSk7XG4gICAgfVxuXG4gICAgY29udGV4dC5zYXZlKCk7XG4gICAgY29udGV4dC5iZWdpblBhdGgoKTtcblxuXG4gICAgY29udGV4dC5tb3ZlVG8oeDAsIHkwKTtcbiAgICBjb250ZXh0LmxpbmVUbyh4MSwgeTEpO1xuICAgIGNvbnRleHQubGluZVRvKHgyLCB5Mik7XG5cbiAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuXG4gICAgY29udGV4dC5jbGlwKCk7XG5cbiAgICAvLyBDb21wdXRlIG1hdHJpeCB0cmFuc2Zvcm1cbiAgICB2YXIgZGVsdGEgPSAgKHUwICogdjEpICAgICAgKyAodjAgKiB1MikgICAgICArICh1MSAqIHYyKSAgICAgIC0gKHYxICogdTIpICAgICAgLSAodjAgKiB1MSkgICAgICAtICh1MCAqIHYyKTtcbiAgICB2YXIgZGVsdGFBID0gKHgwICogdjEpICAgICAgKyAodjAgKiB4MikgICAgICArICh4MSAqIHYyKSAgICAgIC0gKHYxICogeDIpICAgICAgLSAodjAgKiB4MSkgICAgICAtICh4MCAqIHYyKTtcbiAgICB2YXIgZGVsdGFCID0gKHUwICogeDEpICAgICAgKyAoeDAgKiB1MikgICAgICArICh1MSAqIHgyKSAgICAgIC0gKHgxICogdTIpICAgICAgLSAoeDAgKiB1MSkgICAgICAtICh1MCAqIHgyKTtcbiAgICB2YXIgZGVsdGFDID0gKHUwICogdjEgKiB4MikgKyAodjAgKiB4MSAqIHUyKSArICh4MCAqIHUxICogdjIpIC0gKHgwICogdjEgKiB1MikgLSAodjAgKiB1MSAqIHgyKSAtICh1MCAqIHgxICogdjIpO1xuICAgIHZhciBkZWx0YUQgPSAoeTAgKiB2MSkgICAgICArICh2MCAqIHkyKSAgICAgICsgKHkxICogdjIpICAgICAgLSAodjEgKiB5MikgICAgICAtICh2MCAqIHkxKSAgICAgIC0gKHkwICogdjIpO1xuICAgIHZhciBkZWx0YUUgPSAodTAgKiB5MSkgICAgICArICh5MCAqIHUyKSAgICAgICsgKHUxICogeTIpICAgICAgLSAoeTEgKiB1MikgICAgICAtICh5MCAqIHUxKSAgICAgIC0gKHUwICogeTIpO1xuICAgIHZhciBkZWx0YUYgPSAodTAgKiB2MSAqIHkyKSArICh2MCAqIHkxICogdTIpICsgKHkwICogdTEgKiB2MikgLSAoeTAgKiB2MSAqIHUyKSAtICh2MCAqIHUxICogeTIpIC0gKHUwICogeTEgKiB2Mik7XG5cbiAgICBjb250ZXh0LnRyYW5zZm9ybShkZWx0YUEgLyBkZWx0YSwgZGVsdGFEIC8gZGVsdGEsXG4gICAgICAgIGRlbHRhQiAvIGRlbHRhLCBkZWx0YUUgLyBkZWx0YSxcbiAgICAgICAgZGVsdGFDIC8gZGVsdGEsIGRlbHRhRiAvIGRlbHRhKTtcblxuICAgIGNvbnRleHQuZHJhd0ltYWdlKHRleHR1cmVTb3VyY2UsIDAsIDApO1xuICAgIGNvbnRleHQucmVzdG9yZSgpO1xufTtcblxuXG5cbi8qKlxuICogUmVuZGVycyBhIGZsYXQgc3RyaXBcbiAqXG4gKiBAcGFyYW0gc3RyaXAge1N0cmlwfSBUaGUgU3RyaXAgdG8gcmVuZGVyXG4gKiBAcHJpdmF0ZVxuICovXG5TdHJpcC5wcm90b3R5cGUucmVuZGVyU3RyaXBGbGF0ID0gZnVuY3Rpb24gKHN0cmlwKSB7XG4gICAgdmFyIGNvbnRleHQgPSB0aGlzLmNvbnRleHQ7XG4gICAgdmFyIHZlcnRpY2VzID0gc3RyaXAudmVydGljZXM7XG5cbiAgICB2YXIgbGVuZ3RoID0gdmVydGljZXMubGVuZ3RoLzI7XG4gICAgLy8gdGhpcy5jb3VudCsrO1xuXG4gICAgY29udGV4dC5iZWdpblBhdGgoKTtcbiAgICBmb3IgKHZhciBpPTE7IGkgPCBsZW5ndGgtMjsgaSsrKSB7XG4gICAgICAgIC8vIGRyYXcgc29tZSB0cmlhbmdsZXMhXG4gICAgICAgIHZhciBpbmRleCA9IGkqMjtcblxuICAgICAgICB2YXIgeDAgPSB2ZXJ0aWNlc1tpbmRleF0sICAgeDEgPSB2ZXJ0aWNlc1tpbmRleCsyXSwgeDIgPSB2ZXJ0aWNlc1tpbmRleCs0XTtcbiAgICAgICAgdmFyIHkwID0gdmVydGljZXNbaW5kZXgrMV0sIHkxID0gdmVydGljZXNbaW5kZXgrM10sIHkyID0gdmVydGljZXNbaW5kZXgrNV07XG5cbiAgICAgICAgY29udGV4dC5tb3ZlVG8oeDAsIHkwKTtcbiAgICAgICAgY29udGV4dC5saW5lVG8oeDEsIHkxKTtcbiAgICAgICAgY29udGV4dC5saW5lVG8oeDIsIHkyKTtcbiAgICB9XG5cbiAgICBjb250ZXh0LmZpbGxTdHlsZSA9ICcjRkYwMDAwJztcbiAgICBjb250ZXh0LmZpbGwoKTtcbiAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xufTtcblxuLypcblN0cmlwLnByb3RvdHlwZS5zZXRUZXh0dXJlID0gZnVuY3Rpb24gKHRleHR1cmUpIHtcbiAgICAvL1RPRE8gU0VUIFRIRSBURVhUVVJFU1xuICAgIC8vVE9ETyBWSVNJQklMSVRZXG5cbiAgICAvLyBzdG9wIGN1cnJlbnQgdGV4dHVyZVxuICAgIHRoaXMudGV4dHVyZSA9IHRleHR1cmU7XG4gICAgdGhpcy53aWR0aCAgID0gdGV4dHVyZS5mcmFtZS53aWR0aDtcbiAgICB0aGlzLmhlaWdodCAgPSB0ZXh0dXJlLmZyYW1lLmhlaWdodDtcbiAgICB0aGlzLnVwZGF0ZUZyYW1lID0gdHJ1ZTtcbn07XG4gKi9cblxuLyoqXG4gKiBXaGVuIHRoZSB0ZXh0dXJlIGlzIHVwZGF0ZWQsIHRoaXMgZXZlbnQgd2lsbCBmaXJlIHRvIHVwZGF0ZSB0aGUgc2NhbGUgYW5kIGZyYW1lXG4gKlxuICogQHBhcmFtIGV2ZW50XG4gKiBAcHJpdmF0ZVxuICovXG5cblN0cmlwLnByb3RvdHlwZS5vblRleHR1cmVVcGRhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy51cGRhdGVGcmFtZSA9IHRydWU7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdGhlIGJvdW5kcyBvZiB0aGUgbWVzaCBhcyBhIHJlY3RhbmdsZS4gVGhlIGJvdW5kcyBjYWxjdWxhdGlvbiB0YWtlcyB0aGUgd29ybGRUcmFuc2Zvcm0gaW50byBhY2NvdW50LlxuICpcbiAqIEBwYXJhbSBtYXRyaXgge01hdHJpeH0gdGhlIHRyYW5zZm9ybWF0aW9uIG1hdHJpeCBvZiB0aGUgc3ByaXRlXG4gKiBAcmV0dXJuIHtSZWN0YW5nbGV9IHRoZSBmcmFtaW5nIHJlY3RhbmdsZVxuICovXG5TdHJpcC5wcm90b3R5cGUuZ2V0Qm91bmRzID0gZnVuY3Rpb24gKG1hdHJpeCkge1xuICAgIHZhciB3b3JsZFRyYW5zZm9ybSA9IG1hdHJpeCB8fCB0aGlzLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgdmFyIGEgPSB3b3JsZFRyYW5zZm9ybS5hO1xuICAgIHZhciBiID0gd29ybGRUcmFuc2Zvcm0uYjtcbiAgICB2YXIgYyA9IHdvcmxkVHJhbnNmb3JtLmM7XG4gICAgdmFyIGQgPSB3b3JsZFRyYW5zZm9ybS5kO1xuICAgIHZhciB0eCA9IHdvcmxkVHJhbnNmb3JtLnR4O1xuICAgIHZhciB0eSA9IHdvcmxkVHJhbnNmb3JtLnR5O1xuXG4gICAgdmFyIG1heFggPSAtSW5maW5pdHk7XG4gICAgdmFyIG1heFkgPSAtSW5maW5pdHk7XG5cbiAgICB2YXIgbWluWCA9IEluZmluaXR5O1xuICAgIHZhciBtaW5ZID0gSW5maW5pdHk7XG5cbiAgICB2YXIgdmVydGljZXMgPSB0aGlzLnZlcnRpY2VzO1xuICAgIGZvciAodmFyIGkgPSAwLCBuID0gdmVydGljZXMubGVuZ3RoOyBpIDwgbjsgaSArPSAyKSB7XG4gICAgICAgIHZhciByYXdYID0gdmVydGljZXNbaV0sIHJhd1kgPSB2ZXJ0aWNlc1tpICsgMV07XG4gICAgICAgIHZhciB4ID0gKGEgKiByYXdYKSArIChjICogcmF3WSkgKyB0eDtcbiAgICAgICAgdmFyIHkgPSAoZCAqIHJhd1kpICsgKGIgKiByYXdYKSArIHR5O1xuXG4gICAgICAgIG1pblggPSB4IDwgbWluWCA/IHggOiBtaW5YO1xuICAgICAgICBtaW5ZID0geSA8IG1pblkgPyB5IDogbWluWTtcblxuICAgICAgICBtYXhYID0geCA+IG1heFggPyB4IDogbWF4WDtcbiAgICAgICAgbWF4WSA9IHkgPiBtYXhZID8geSA6IG1heFk7XG4gICAgfVxuXG4gICAgaWYgKG1pblggPT09IC1JbmZpbml0eSB8fCBtYXhZID09PSBJbmZpbml0eSkge1xuICAgICAgICByZXR1cm4gY29yZS5tYXRoLlJlY3RhbmdsZS5FTVBUWTtcbiAgICB9XG5cbiAgICB2YXIgYm91bmRzID0gdGhpcy5fYm91bmRzO1xuXG4gICAgYm91bmRzLnggPSBtaW5YO1xuICAgIGJvdW5kcy53aWR0aCA9IG1heFggLSBtaW5YO1xuXG4gICAgYm91bmRzLnkgPSBtaW5ZO1xuICAgIGJvdW5kcy5oZWlnaHQgPSBtYXhZIC0gbWluWTtcblxuICAgIC8vIHN0b3JlIGEgcmVmZXJlbmNlIHNvIHRoYXQgaWYgdGhpcyBmdW5jdGlvbiBnZXRzIGNhbGxlZCBhZ2FpbiBpbiB0aGUgcmVuZGVyIGN5Y2xlIHdlIGRvIG5vdCBoYXZlIHRvIHJlY2FsY3VsYXRlXG4gICAgdGhpcy5fY3VycmVudEJvdW5kcyA9IGJvdW5kcztcblxuICAgIHJldHVybiBib3VuZHM7XG59O1xuXG4vKipcbiAqIERpZmZlcmVudCBkcmF3aW5nIGJ1ZmZlciBtb2RlcyBzdXBwb3J0ZWRcbiAqXG4gKiBAc3RhdGljXG4gKiBAY29uc3RhbnRcbiAqIEBwcm9wZXJ0eSB7b2JqZWN0fSBEcmF3TW9kZXNcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBEcmF3TW9kZXMuVFJJQU5HTEVfU1RSSVBcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBEcmF3TW9kZXMuVFJJQU5HTEVTXG4gKi9cblN0cmlwLkRyYXdNb2RlcyA9IHtcbiAgICBUUklBTkdMRV9TVFJJUDogMCxcbiAgICBUUklBTkdMRVM6IDFcbn07XG4iLCJ2YXIgY29yZSA9IHJlcXVpcmUoJy4uL2NvcmUnKTtcblxuLyoqXG4gKiBBIHRpbGluZyBzcHJpdGUgaXMgYSBmYXN0IHdheSBvZiByZW5kZXJpbmcgYSB0aWxpbmcgaW1hZ2VcbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIFNwcml0ZVxuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gdGV4dHVyZSB7VGV4dHVyZX0gdGhlIHRleHR1cmUgb2YgdGhlIHRpbGluZyBzcHJpdGVcbiAqIEBwYXJhbSB3aWR0aCB7bnVtYmVyfSAgdGhlIHdpZHRoIG9mIHRoZSB0aWxpbmcgc3ByaXRlXG4gKiBAcGFyYW0gaGVpZ2h0IHtudW1iZXJ9IHRoZSBoZWlnaHQgb2YgdGhlIHRpbGluZyBzcHJpdGVcbiAqL1xuZnVuY3Rpb24gVGlsaW5nU3ByaXRlKHRleHR1cmUsIHdpZHRoLCBoZWlnaHQpIHtcbiAgICBjb3JlLlNwcml0ZS5jYWxsKCB0aGlzLCB0ZXh0dXJlKTtcblxuICAgIC8qKlxuICAgICAqIFRoZSB3aXRoIG9mIHRoZSB0aWxpbmcgc3ByaXRlXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5fd2lkdGggPSB3aWR0aCB8fCAxMDA7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgaGVpZ2h0IG9mIHRoZSB0aWxpbmcgc3ByaXRlXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5faGVpZ2h0ID0gaGVpZ2h0IHx8IDEwMDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBzY2FsaW5nIG9mIHRoZSBpbWFnZSB0aGF0IGlzIGJlaW5nIHRpbGVkXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKi9cbiAgICB0aGlzLnRpbGVTY2FsZSA9IG5ldyBjb3JlLm1hdGguUG9pbnQoMSwxKTtcblxuICAgIC8qKlxuICAgICAqIEEgcG9pbnQgdGhhdCByZXByZXNlbnRzIHRoZSBzY2FsZSBvZiB0aGUgdGV4dHVyZSBvYmplY3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1BvaW50fVxuICAgICAqL1xuICAgIHRoaXMudGlsZVNjYWxlT2Zmc2V0ID0gbmV3IGNvcmUubWF0aC5Qb2ludCgxLDEpO1xuXG4gICAgLyoqXG4gICAgICogVGhlIG9mZnNldCBwb3NpdGlvbiBvZiB0aGUgaW1hZ2UgdGhhdCBpcyBiZWluZyB0aWxlZFxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICovXG4gICAgdGhpcy50aWxlUG9zaXRpb24gPSBuZXcgY29yZS5tYXRoLlBvaW50KDAsMCk7XG5cbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRoaXMgc3ByaXRlIGlzIHJlbmRlcmFibGUgb3Igbm90XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqIEBkZWZhdWx0IHRydWVcbiAgICAgKi9cbiAgICB0aGlzLnJlbmRlcmFibGUgPSB0cnVlO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHRpbnQgYXBwbGllZCB0byB0aGUgc3ByaXRlLiBUaGlzIGlzIGEgaGV4IHZhbHVlXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMHhGRkZGRkZcbiAgICAgKi9cbiAgICB0aGlzLnRpbnQgPSAweEZGRkZGRjtcblxuICAgIC8qKlxuICAgICAqIFRoZSBibGVuZCBtb2RlIHRvIGJlIGFwcGxpZWQgdG8gdGhlIHNwcml0ZVxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IGJsZW5kTW9kZXMuTk9STUFMO1xuICAgICAqL1xuICAgIHRoaXMuYmxlbmRNb2RlID0gY29yZS5DT05TVC5ibGVuZE1vZGVzLk5PUk1BTDtcbn1cblxuVGlsaW5nU3ByaXRlLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoY29yZS5TcHJpdGUucHJvdG90eXBlKTtcblRpbGluZ1Nwcml0ZS5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBUaWxpbmdTcHJpdGU7XG5tb2R1bGUuZXhwb3J0cyA9IFRpbGluZ1Nwcml0ZTtcblxuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhUaWxpbmdTcHJpdGUucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHdpZHRoIG9mIHRoZSBzcHJpdGUsIHNldHRpbmcgdGhpcyB3aWxsIGFjdHVhbGx5IG1vZGlmeSB0aGUgc2NhbGUgdG8gYWNoaWV2ZSB0aGUgdmFsdWUgc2V0XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIFRpbGluZ1Nwcml0ZSNcbiAgICAgKi9cbiAgICB3aWR0aDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl93aWR0aDtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuX3dpZHRoID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIGhlaWdodCBvZiB0aGUgVGlsaW5nU3ByaXRlLCBzZXR0aW5nIHRoaXMgd2lsbCBhY3R1YWxseSBtb2RpZnkgdGhlIHNjYWxlIHRvIGFjaGlldmUgdGhlIHZhbHVlIHNldFxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUaWxpbmdTcHJpdGUjXG4gICAgICovXG4gICAgaGVpZ2h0OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2hlaWdodDtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuX2hlaWdodCA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIHRleHR1cmU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fdGV4dHVyZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLl90ZXh0dXJlID09PSB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5fdGV4dHVyZSA9IHZhbHVlO1xuICAgICAgICAgICAgdGhpcy5yZWZyZXNoVGV4dHVyZSA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLmNhY2hlZFRpbnQgPSAweEZGRkZGRjtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG4vKipcbiAqIFJlbmRlcnMgdGhlIG9iamVjdCB1c2luZyB0aGUgV2ViR0wgcmVuZGVyZXJcbiAqXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9XG4gKi9cblRpbGluZ1Nwcml0ZS5wcm90b3R5cGUucmVuZGVyV2ViR0wgPSBmdW5jdGlvbiAocmVuZGVyZXIpIHtcbiAgICBpZiAoIXRoaXMudmlzaWJsZSB8fCB0aGlzLmFscGhhIDw9IDApIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciBpLCBqO1xuXG4gICAgaWYgKHRoaXMuX21hc2spIHtcbiAgICAgICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guc3RvcCgpO1xuICAgICAgICByZW5kZXJlci5tYXNrTWFuYWdlci5wdXNoTWFzayh0aGlzLm1hc2ssIHJlbmRlcmVyKTtcbiAgICAgICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guc3RhcnQoKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fZmlsdGVycykge1xuICAgICAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5mbHVzaCgpO1xuICAgICAgICByZW5kZXJlci5maWx0ZXJNYW5hZ2VyLnB1c2hGaWx0ZXIodGhpcy5fZmlsdGVyQmxvY2spO1xuICAgIH1cblxuXG5cbiAgICBpZiAoIXRoaXMudGlsaW5nVGV4dHVyZSB8fCB0aGlzLnJlZnJlc2hUZXh0dXJlKSB7XG4gICAgICAgIHRoaXMuZ2VuZXJhdGVUaWxpbmdUZXh0dXJlKHRydWUpO1xuXG4gICAgICAgIGlmICh0aGlzLnRpbGluZ1RleHR1cmUgJiYgdGhpcy50aWxpbmdUZXh0dXJlLm5lZWRzVXBkYXRlKSB7XG4gICAgICAgICAgICAvL1RPRE8gLSB0d2Vha2luZ1xuICAgICAgICAgICAgcmVuZGVyZXIudXBkYXRlVGV4dHVyZSh0aGlzLnRpbGluZ1RleHR1cmUuYmFzZVRleHR1cmUpO1xuICAgICAgICAgICAgdGhpcy50aWxpbmdUZXh0dXJlLm5lZWRzVXBkYXRlID0gZmFsc2U7XG4gICAgICAgICAgIC8vIHRoaXMudGlsaW5nVGV4dHVyZS5fdXZzID0gbnVsbDtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2gucmVuZGVyVGlsaW5nU3ByaXRlKHRoaXMpO1xuICAgIH1cbiAgICAvLyBzaW1wbGUgcmVuZGVyIGNoaWxkcmVuIVxuICAgIGZvciAoaT0wLGo9dGhpcy5jaGlsZHJlbi5sZW5ndGg7IGk8ajsgaSsrKSB7XG4gICAgICAgIHRoaXMuY2hpbGRyZW5baV0ucmVuZGVyV2ViR0wocmVuZGVyZXIpO1xuICAgIH1cblxuICAgIHJlbmRlcmVyLnNwcml0ZUJhdGNoLnN0b3AoKTtcblxuICAgIGlmICh0aGlzLl9maWx0ZXJzKSB7XG4gICAgICAgIHJlbmRlcmVyLmZpbHRlck1hbmFnZXIucG9wRmlsdGVyKCk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX21hc2spIHtcbiAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucG9wTWFzayh0aGlzLl9tYXNrLCByZW5kZXJlcik7XG4gICAgfVxuXG4gICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guc3RhcnQoKTtcbn07XG5cbi8qKlxuICogUmVuZGVycyB0aGUgb2JqZWN0IHVzaW5nIHRoZSBDYW52YXMgcmVuZGVyZXJcbiAqXG4gKiBAcGFyYW0gcmVuZGVyZXIge0NhbnZhc1JlbmRlcmVyfVxuICovXG5UaWxpbmdTcHJpdGUucHJvdG90eXBlLnJlbmRlckNhbnZhcyA9IGZ1bmN0aW9uIChyZW5kZXJlcikge1xuICAgIGlmICghdGhpcy52aXNpYmxlIHx8IHRoaXMuYWxwaGEgPD0gMCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIGNvbnRleHQgPSByZW5kZXJlci5jb250ZXh0O1xuXG4gICAgaWYgKHRoaXMuX21hc2spIHtcbiAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucHVzaE1hc2sodGhpcy5fbWFzaywgY29udGV4dCk7XG4gICAgfVxuXG4gICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IHRoaXMud29ybGRBbHBoYTtcblxuICAgIHZhciB0cmFuc2Zvcm0gPSB0aGlzLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgdmFyIGksajtcblxuICAgIHZhciByZXNvbHV0aW9uID0gcmVuZGVyZXIucmVzb2x1dGlvbjtcblxuICAgIGNvbnRleHQuc2V0VHJhbnNmb3JtKHRyYW5zZm9ybS5hICogcmVzb2x1dGlvbixcbiAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0uYiAqIHJlc29sdXRpb24sXG4gICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtLmMgKiByZXNvbHV0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybS5kICogcmVzb2x1dGlvbixcbiAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0udHggKiByZXNvbHV0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybS50eSAqIHJlc29sdXRpb24pO1xuXG4gICAgaWYgKCF0aGlzLl9fdGlsZVBhdHRlcm4gfHwgIHRoaXMucmVmcmVzaFRleHR1cmUpIHtcbiAgICAgICAgdGhpcy5nZW5lcmF0ZVRpbGluZ1RleHR1cmUoZmFsc2UpO1xuXG4gICAgICAgIGlmICh0aGlzLnRpbGluZ1RleHR1cmUpIHtcbiAgICAgICAgICAgIHRoaXMuX190aWxlUGF0dGVybiA9IGNvbnRleHQuY3JlYXRlUGF0dGVybih0aGlzLnRpbGluZ1RleHR1cmUuYmFzZVRleHR1cmUuc291cmNlLCAncmVwZWF0Jyk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBjaGVjayBibGVuZCBtb2RlXG4gICAgaWYgKHRoaXMuYmxlbmRNb2RlICE9PSByZW5kZXJlci5jdXJyZW50QmxlbmRNb2RlKSB7XG4gICAgICAgIHJlbmRlcmVyLmN1cnJlbnRCbGVuZE1vZGUgPSB0aGlzLmJsZW5kTW9kZTtcbiAgICAgICAgY29udGV4dC5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb24gPSByZW5kZXJlci5ibGVuZE1vZGVzW3JlbmRlcmVyLmN1cnJlbnRCbGVuZE1vZGVdO1xuICAgIH1cblxuICAgIHZhciB0aWxlUG9zaXRpb24gPSB0aGlzLnRpbGVQb3NpdGlvbjtcbiAgICB2YXIgdGlsZVNjYWxlID0gdGhpcy50aWxlU2NhbGU7XG5cbiAgICB0aWxlUG9zaXRpb24ueCAlPSB0aGlzLnRpbGluZ1RleHR1cmUuYmFzZVRleHR1cmUud2lkdGg7XG4gICAgdGlsZVBvc2l0aW9uLnkgJT0gdGhpcy50aWxpbmdUZXh0dXJlLmJhc2VUZXh0dXJlLmhlaWdodDtcblxuICAgIC8vIG9mZnNldCAtIG1ha2Ugc3VyZSB0byBhY2NvdW50IGZvciB0aGUgYW5jaG9yIHBvaW50Li5cbiAgICBjb250ZXh0LnNjYWxlKHRpbGVTY2FsZS54LHRpbGVTY2FsZS55KTtcbiAgICBjb250ZXh0LnRyYW5zbGF0ZSh0aWxlUG9zaXRpb24ueCArICh0aGlzLmFuY2hvci54ICogLXRoaXMuX3dpZHRoKSwgdGlsZVBvc2l0aW9uLnkgKyAodGhpcy5hbmNob3IueSAqIC10aGlzLl9oZWlnaHQpKTtcblxuICAgIGNvbnRleHQuZmlsbFN0eWxlID0gdGhpcy5fX3RpbGVQYXR0ZXJuO1xuXG4gICAgY29udGV4dC5maWxsUmVjdCgtdGlsZVBvc2l0aW9uLngsXG4gICAgICAgICAgICAgICAgICAgIC10aWxlUG9zaXRpb24ueSxcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fd2lkdGggLyB0aWxlU2NhbGUueCxcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5faGVpZ2h0IC8gdGlsZVNjYWxlLnkpO1xuXG4gICAgY29udGV4dC50cmFuc2xhdGUoLXRpbGVQb3NpdGlvbi54ICsgKHRoaXMuYW5jaG9yLnggKiB0aGlzLl93aWR0aCksIC10aWxlUG9zaXRpb24ueSArICh0aGlzLmFuY2hvci55ICogdGhpcy5faGVpZ2h0KSk7XG4gICAgY29udGV4dC5zY2FsZSgxIC8gdGlsZVNjYWxlLngsIDEgLyB0aWxlU2NhbGUueSk7XG5cbiAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICByZW5kZXJlci5tYXNrTWFuYWdlci5wb3BNYXNrKHJlbmRlcmVyLmNvbnRleHQpO1xuICAgIH1cblxuICAgIGZvciAoaSA9IDAsIGogPSB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGo7ICsraSkge1xuICAgICAgICB0aGlzLmNoaWxkcmVuW2ldLnJlbmRlckNhbnZhcyhyZW5kZXJlcik7XG4gICAgfVxufTtcblxuXG4vKipcbiAqIFJldHVybnMgdGhlIGZyYW1pbmcgcmVjdGFuZ2xlIG9mIHRoZSBzcHJpdGUgYXMgYSBSZWN0YW5nbGUgb2JqZWN0XG4qXG4gKiBAcmV0dXJuIHtSZWN0YW5nbGV9IHRoZSBmcmFtaW5nIHJlY3RhbmdsZVxuICovXG5UaWxpbmdTcHJpdGUucHJvdG90eXBlLmdldEJvdW5kcyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgd2lkdGggPSB0aGlzLl93aWR0aDtcbiAgICB2YXIgaGVpZ2h0ID0gdGhpcy5faGVpZ2h0O1xuXG4gICAgdmFyIHcwID0gd2lkdGggKiAoMS10aGlzLmFuY2hvci54KTtcbiAgICB2YXIgdzEgPSB3aWR0aCAqIC10aGlzLmFuY2hvci54O1xuXG4gICAgdmFyIGgwID0gaGVpZ2h0ICogKDEtdGhpcy5hbmNob3IueSk7XG4gICAgdmFyIGgxID0gaGVpZ2h0ICogLXRoaXMuYW5jaG9yLnk7XG5cbiAgICB2YXIgd29ybGRUcmFuc2Zvcm0gPSB0aGlzLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgdmFyIGEgPSB3b3JsZFRyYW5zZm9ybS5hO1xuICAgIHZhciBiID0gd29ybGRUcmFuc2Zvcm0uYjtcbiAgICB2YXIgYyA9IHdvcmxkVHJhbnNmb3JtLmM7XG4gICAgdmFyIGQgPSB3b3JsZFRyYW5zZm9ybS5kO1xuICAgIHZhciB0eCA9IHdvcmxkVHJhbnNmb3JtLnR4O1xuICAgIHZhciB0eSA9IHdvcmxkVHJhbnNmb3JtLnR5O1xuXG4gICAgdmFyIHgxID0gYSAqIHcxICsgYyAqIGgxICsgdHg7XG4gICAgdmFyIHkxID0gZCAqIGgxICsgYiAqIHcxICsgdHk7XG5cbiAgICB2YXIgeDIgPSBhICogdzAgKyBjICogaDEgKyB0eDtcbiAgICB2YXIgeTIgPSBkICogaDEgKyBiICogdzAgKyB0eTtcblxuICAgIHZhciB4MyA9IGEgKiB3MCArIGMgKiBoMCArIHR4O1xuICAgIHZhciB5MyA9IGQgKiBoMCArIGIgKiB3MCArIHR5O1xuXG4gICAgdmFyIHg0ID0gIGEgKiB3MSArIGMgKiBoMCArIHR4O1xuICAgIHZhciB5NCA9ICBkICogaDAgKyBiICogdzEgKyB0eTtcblxuICAgIHZhciBtaW5YLFxuICAgICAgICBtYXhYLFxuICAgICAgICBtaW5ZLFxuICAgICAgICBtYXhZO1xuXG4gICAgbWluWCA9IHgxO1xuICAgIG1pblggPSB4MiA8IG1pblggPyB4MiA6IG1pblg7XG4gICAgbWluWCA9IHgzIDwgbWluWCA/IHgzIDogbWluWDtcbiAgICBtaW5YID0geDQgPCBtaW5YID8geDQgOiBtaW5YO1xuXG4gICAgbWluWSA9IHkxO1xuICAgIG1pblkgPSB5MiA8IG1pblkgPyB5MiA6IG1pblk7XG4gICAgbWluWSA9IHkzIDwgbWluWSA/IHkzIDogbWluWTtcbiAgICBtaW5ZID0geTQgPCBtaW5ZID8geTQgOiBtaW5ZO1xuXG4gICAgbWF4WCA9IHgxO1xuICAgIG1heFggPSB4MiA+IG1heFggPyB4MiA6IG1heFg7XG4gICAgbWF4WCA9IHgzID4gbWF4WCA/IHgzIDogbWF4WDtcbiAgICBtYXhYID0geDQgPiBtYXhYID8geDQgOiBtYXhYO1xuXG4gICAgbWF4WSA9IHkxO1xuICAgIG1heFkgPSB5MiA+IG1heFkgPyB5MiA6IG1heFk7XG4gICAgbWF4WSA9IHkzID4gbWF4WSA/IHkzIDogbWF4WTtcbiAgICBtYXhZID0geTQgPiBtYXhZID8geTQgOiBtYXhZO1xuXG4gICAgdmFyIGJvdW5kcyA9IHRoaXMuX2JvdW5kcztcblxuICAgIGJvdW5kcy54ID0gbWluWDtcbiAgICBib3VuZHMud2lkdGggPSBtYXhYIC0gbWluWDtcblxuICAgIGJvdW5kcy55ID0gbWluWTtcbiAgICBib3VuZHMuaGVpZ2h0ID0gbWF4WSAtIG1pblk7XG5cbiAgICAvLyBzdG9yZSBhIHJlZmVyZW5jZSBzbyB0aGF0IGlmIHRoaXMgZnVuY3Rpb24gZ2V0cyBjYWxsZWQgYWdhaW4gaW4gdGhlIHJlbmRlciBjeWNsZSB3ZSBkbyBub3QgaGF2ZSB0byByZWNhbGN1bGF0ZVxuICAgIHRoaXMuX2N1cnJlbnRCb3VuZHMgPSBib3VuZHM7XG5cbiAgICByZXR1cm4gYm91bmRzO1xufTtcblxuLyoqXG4gKiBXaGVuIHRoZSB0ZXh0dXJlIGlzIHVwZGF0ZWQsIHRoaXMgZXZlbnQgd2lsbCBmaXJlIHRvIHVwZGF0ZSB0aGUgc2NhbGUgYW5kIGZyYW1lXG4gKlxuICogQHBhcmFtIGV2ZW50XG4gKiBAcHJpdmF0ZVxuICovXG5UaWxpbmdTcHJpdGUucHJvdG90eXBlLm9uVGV4dHVyZVVwZGF0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgIC8vIG92ZXJyaWRpbmcgdGhlIHNwcml0ZSB2ZXJzaW9uIG9mIHRoaXMhXG59O1xuXG4vKipcbiAqXG4gKiBAcGFyYW0gZm9yY2VQb3dlck9mVHdvIHtib29sZWFufSBXaGV0aGVyIHdlIHdhbnQgdG8gZm9yY2UgdGhlIHRleHR1cmUgdG8gYmUgYSBwb3dlciBvZiB0d29cbiAqL1xuVGlsaW5nU3ByaXRlLnByb3RvdHlwZS5nZW5lcmF0ZVRpbGluZ1RleHR1cmUgPSBmdW5jdGlvbiAoZm9yY2VQb3dlck9mVHdvKSB7XG4gICAgaWYgKCF0aGlzLnRleHR1cmUuYmFzZVRleHR1cmUuaGFzTG9hZGVkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgdGV4dHVyZSA9IHRoaXMub3JpZ2luYWxUZXh0dXJlIHx8IHRoaXMudGV4dHVyZTtcbiAgICB2YXIgZnJhbWUgPSB0ZXh0dXJlLmZyYW1lO1xuICAgIHZhciB0YXJnZXRXaWR0aCwgdGFyZ2V0SGVpZ2h0O1xuXG4gICAgLy8gIENoZWNrIHRoYXQgdGhlIGZyYW1lIGlzIHRoZSBzYW1lIHNpemUgYXMgdGhlIGJhc2UgdGV4dHVyZS5cbiAgICB2YXIgaXNGcmFtZSA9IGZyYW1lLndpZHRoICE9PSB0ZXh0dXJlLmJhc2VUZXh0dXJlLndpZHRoIHx8IGZyYW1lLmhlaWdodCAhPT0gdGV4dHVyZS5iYXNlVGV4dHVyZS5oZWlnaHQ7XG5cbiAgICB2YXIgbmV3VGV4dHVyZVJlcXVpcmVkID0gZmFsc2U7XG5cbiAgICBpZiAoIWZvcmNlUG93ZXJPZlR3bykge1xuICAgICAgICBpZiAoaXNGcmFtZSkge1xuICAgICAgICAgICAgdGFyZ2V0V2lkdGggPSBmcmFtZS53aWR0aDtcbiAgICAgICAgICAgIHRhcmdldEhlaWdodCA9IGZyYW1lLmhlaWdodDtcblxuICAgICAgICAgICAgbmV3VGV4dHVyZVJlcXVpcmVkID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdGFyZ2V0V2lkdGggPSBjb3JlLnV0aWxzLmdldE5leHRQb3dlck9mVHdvKGZyYW1lLndpZHRoKTtcbiAgICAgICAgdGFyZ2V0SGVpZ2h0ID0gY29yZS51dGlscy5nZXROZXh0UG93ZXJPZlR3byhmcmFtZS5oZWlnaHQpO1xuXG4gICAgICAgIC8vICBJZiB0aGUgQmFzZVRleHR1cmUgZGltZW5zaW9ucyBkb24ndCBtYXRjaCB0aGUgdGV4dHVyZSBmcmFtZSB0aGVuIHdlIG5lZWQgYSBuZXcgdGV4dHVyZSBhbnl3YXkgYmVjYXVzZSBpdCdzIHBhcnQgb2YgYSB0ZXh0dXJlIGF0bGFzXG4gICAgICAgIGlmIChmcmFtZS53aWR0aCAhPT0gdGFyZ2V0V2lkdGggfHwgZnJhbWUuaGVpZ2h0ICE9PSB0YXJnZXRIZWlnaHQgfHwgdGV4dHVyZS5iYXNlVGV4dHVyZS53aWR0aCAhPT0gdGFyZ2V0V2lkdGggfHwgdGV4dHVyZS5iYXNlVGV4dHVyZS5oZWlnaHQgfHwgdGFyZ2V0SGVpZ2h0KSB7XG4gICAgICAgICAgICBuZXdUZXh0dXJlUmVxdWlyZWQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG5ld1RleHR1cmVSZXF1aXJlZCkge1xuICAgICAgICB2YXIgY2FudmFzQnVmZmVyO1xuXG4gICAgICAgIGlmICh0aGlzLnRpbGluZ1RleHR1cmUgJiYgdGhpcy50aWxpbmdUZXh0dXJlLmlzVGlsaW5nKSB7XG4gICAgICAgICAgICBjYW52YXNCdWZmZXIgPSB0aGlzLnRpbGluZ1RleHR1cmUuY2FudmFzQnVmZmVyO1xuICAgICAgICAgICAgY2FudmFzQnVmZmVyLnJlc2l6ZSh0YXJnZXRXaWR0aCwgdGFyZ2V0SGVpZ2h0KTtcbiAgICAgICAgICAgIHRoaXMudGlsaW5nVGV4dHVyZS5iYXNlVGV4dHVyZS53aWR0aCA9IHRhcmdldFdpZHRoO1xuICAgICAgICAgICAgdGhpcy50aWxpbmdUZXh0dXJlLmJhc2VUZXh0dXJlLmhlaWdodCA9IHRhcmdldEhlaWdodDtcbiAgICAgICAgICAgIHRoaXMudGlsaW5nVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBjYW52YXNCdWZmZXIgPSBuZXcgY29yZS5DYW52YXNCdWZmZXIodGFyZ2V0V2lkdGgsIHRhcmdldEhlaWdodCk7XG5cbiAgICAgICAgICAgIHRoaXMudGlsaW5nVGV4dHVyZSA9IGNvcmUuVGV4dHVyZS5mcm9tQ2FudmFzKGNhbnZhc0J1ZmZlci5jYW52YXMpO1xuICAgICAgICAgICAgdGhpcy50aWxpbmdUZXh0dXJlLmNhbnZhc0J1ZmZlciA9IGNhbnZhc0J1ZmZlcjtcbiAgICAgICAgICAgIHRoaXMudGlsaW5nVGV4dHVyZS5pc1RpbGluZyA9IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICBjYW52YXNCdWZmZXIuY29udGV4dC5kcmF3SW1hZ2UodGV4dHVyZS5iYXNlVGV4dHVyZS5zb3VyY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dHVyZS5jcm9wLngsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dHVyZS5jcm9wLnksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dHVyZS5jcm9wLndpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHR1cmUuY3JvcC5oZWlnaHQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldFdpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldEhlaWdodCk7XG5cbiAgICAgICAgdGhpcy50aWxlU2NhbGVPZmZzZXQueCA9IGZyYW1lLndpZHRoIC8gdGFyZ2V0V2lkdGg7XG4gICAgICAgIHRoaXMudGlsZVNjYWxlT2Zmc2V0LnkgPSBmcmFtZS5oZWlnaHQgLyB0YXJnZXRIZWlnaHQ7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICAvLyAgVE9ETyAtIHN3aXRjaGluZz9cbiAgICAgICAgaWYgKHRoaXMudGlsaW5nVGV4dHVyZSAmJiB0aGlzLnRpbGluZ1RleHR1cmUuaXNUaWxpbmcpIHtcbiAgICAgICAgICAgIC8vIGRlc3Ryb3kgdGhlIHRpbGluZyB0ZXh0dXJlIVxuICAgICAgICAgICAgLy8gVE9ETyBjb3VsZCBzdG9yZSB0aGlzIHNvbWV3aGVyZT9cbiAgICAgICAgICAgIHRoaXMudGlsaW5nVGV4dHVyZS5kZXN0cm95KHRydWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy50aWxlU2NhbGVPZmZzZXQueCA9IDE7XG4gICAgICAgIHRoaXMudGlsZVNjYWxlT2Zmc2V0LnkgPSAxO1xuICAgICAgICB0aGlzLnRpbGluZ1RleHR1cmUgPSB0ZXh0dXJlO1xuICAgIH1cblxuICAgIHRoaXMucmVmcmVzaFRleHR1cmUgPSBmYWxzZTtcblxuICAgIHRoaXMub3JpZ2luYWxUZXh0dXJlID0gdGhpcy50ZXh0dXJlO1xuICAgIHRoaXMudGV4dHVyZSA9IHRoaXMudGlsaW5nVGV4dHVyZTtcblxuICAgIHRoaXMudGlsaW5nVGV4dHVyZS5iYXNlVGV4dHVyZS5fcG93ZXJPZjIgPSB0cnVlO1xufTtcbiIsIi8qKlxuICogQGZpbGUgICAgICAgIE1haW4gZXhwb3J0IG9mIHRoZSBQSVhJIGV4dHJhcyBsaWJyYXJ5XG4gKiBAYXV0aG9yICAgICAgTWF0IEdyb3ZlcyA8bWF0QGdvb2Rib3lkaWdpdGFsLmNvbT5cbiAqIEBjb3B5cmlnaHQgICAyMDEzLTIwMTUgR29vZEJveURpZ2l0YWxcbiAqIEBsaWNlbnNlICAgICB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL0dvb2RCb3lEaWdpdGFsL3BpeGkuanMvYmxvYi9tYXN0ZXIvTElDRU5TRXxNSVQgTGljZW5zZX1cbiAqL1xuXG4vKipcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBNb3ZpZUNsaXA6ICAgICAgcmVxdWlyZSgnLi9Nb3ZpZUNsaXAnKSxcbiAgICBSb3BlOiAgICAgICAgICAgcmVxdWlyZSgnLi9Sb3BlJyksXG4gICAgU3RyaXA6ICAgICAgICAgIHJlcXVpcmUoJy4vU3RyaXAnKSxcbiAgICBUaWxpbmdTcHJpdGU6ICAgcmVxdWlyZSgnLi9UaWxpbmdTcHJpdGUnKVxufTtcbiIsIi8qKlxuICogVGhpcyBpcyB0aGUgYmFzZSBjbGFzcyBmb3IgY3JlYXRpbmcgYSBQSVhJIGZpbHRlci4gQ3VycmVudGx5IG9ubHkgV2ViR0wgc3VwcG9ydHMgZmlsdGVycy5cbiAqIElmIHlvdSB3YW50IHRvIG1ha2UgYSBjdXN0b20gZmlsdGVyIHRoaXMgc2hvdWxkIGJlIHlvdXIgYmFzZSBjbGFzcy5cbiAqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIGZyYWdtZW50U3JjIHtzdHJpbmd8c3RyaW5nW119IFRoZSBmcmFnbWVudCBzb3VyY2UgaW4gYW4gYXJyYXkgb2Ygc3RyaW5ncy5cbiAqIEBwYXJhbSB1bmlmb3JtcyB7b2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgdW5pZm9ybXMgZm9yIHRoaXMgZmlsdGVyLlxuICovXG5mdW5jdGlvbiBBYnN0cmFjdEZpbHRlcihmcmFnbWVudFNyYywgdW5pZm9ybXMpIHtcbiAgICAvKipcbiAgICAgKiBBbiBhcnJheSBvZiBwYXNzZXMgLSBzb21lIGZpbHRlcnMgY29udGFpbiBhIGZldyBzdGVwcyB0aGlzIGFycmF5IHNpbXBseSBzdG9yZXMgdGhlIHN0ZXBzIGluIGEgbGluaWVhciBmYXNoaW9uLlxuICAgICAqIEZvciBleGFtcGxlIHRoZSBibHVyIGZpbHRlciBoYXMgdHdvIHBhc3NlcyBibHVyWCBhbmQgYmx1clkuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtBYnN0cmFjdEZpbHRlcltdfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5wYXNzZXMgPSBbdGhpc107XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtTaGFkZXJbXX1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuc2hhZGVycyA9IFtdO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMucGFkZGluZyA9IDA7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtvYmplY3R9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLnVuaWZvcm1zID0gdW5pZm9ybXMgfHwge307XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtzdHJpbmdbXX1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSB0eXBlb2YgZnJhZ21lbnRTcmMgPT09ICdzdHJpbmcnID8gZnJhZ21lbnRTcmMuc3BsaXQoJycpIDogKGZyYWdtZW50U3JjIHx8IFtdKTtcbn1cblxuQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQWJzdHJhY3RGaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IEFic3RyYWN0RmlsdGVyO1xuXG4vKipcbiAqIFN5bmNzIHRoZSB1bmlmb3JtcyBiZXR3ZWVuIHRoZSBjbGFzcyBvYmplY3QgYW5kIHRoZSBzaGFkZXJzLlxuICpcbiAqL1xuQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlLnN5bmNVbmlmb3JtcyA9IGZ1bmN0aW9uICgpIHtcbiAgICBmb3IgKHZhciBpID0gMCwgaiA9IHRoaXMuc2hhZGVycy5sZW5ndGg7IGkgPCBqOyArK2kpIHtcbiAgICAgICAgdGhpcy5zaGFkZXJzW2ldLmRpcnR5ID0gdHJ1ZTtcbiAgICB9XG59O1xuXG4vKlxuQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlLmFwcGx5ID0gZnVuY3Rpb24gKGZyYW1lQnVmZmVyKSB7XG4gICAgLy8gVE9ETyA6KVxufTtcbiovXG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyk7XG5cbi8qKlxuICogVGhlIEFscGhhTWFza0ZpbHRlciBjbGFzcyB1c2VzIHRoZSBwaXhlbCB2YWx1ZXMgZnJvbSB0aGUgc3BlY2lmaWVkIHRleHR1cmUgKGNhbGxlZCB0aGUgZGlzcGxhY2VtZW50IG1hcCkgdG8gcGVyZm9ybSBhIGRpc3BsYWNlbWVudCBvZiBhbiBvYmplY3QuXG4gKiBZb3UgY2FuIHVzZSB0aGlzIGZpbHRlciB0byBhcHBseSBhbGwgbWFub3Igb2YgY3Jhenkgd2FycGluZyBlZmZlY3RzXG4gKiBDdXJyZW50bHkgdGhlIHIgcHJvcGVydHkgb2YgdGhlIHRleHR1cmUgaXMgdXNlZCB0byBvZmZzZXQgdGhlIHggYW5kIHRoZSBnIHByb3BlcnR5IG9mIHRoZSB0ZXh0dXJlIGlzIHVzZWQgdG8gb2Zmc2V0IHRoZSB5LlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHRleHR1cmUge1RleHR1cmV9IFRoZSB0ZXh0dXJlIHVzZWQgZm9yIHRoZSBkaXNwbGFjZW1lbnQgbWFwICogbXVzdCBiZSBwb3dlciBvZiAyIHRleHR1cmUgYXQgdGhlIG1vbWVudFxuICovXG5mdW5jdGlvbiBBbHBoYU1hc2tGaWx0ZXIodGV4dHVyZSkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLl9wb3dlck9mMiA9IHRydWU7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgbWFzazogICAgICAgICAgIHsgdHlwZTogJ3NhbXBsZXIyRCcsICAgIHZhbHVlOiB0ZXh0dXJlIH0sXG4gICAgICAgIG1hcERpbWVuc2lvbnM6ICB7IHR5cGU6ICcyZicsICAgICAgICAgICB2YWx1ZTogeyB4OiAxLCB5OiA1MTEyIH0gfSxcbiAgICAgICAgZGltZW5zaW9uczogICAgIHsgdHlwZTogJzRmdicsICAgICAgICAgIHZhbHVlOiBbMCwgMCwgMCwgMF0gfSxcbiAgICAgICAgb2Zmc2V0OiAgICAgICAgIHsgdHlwZTogJzJmJywgICAgICAgICAgIHZhbHVlOiB7IHg6IDAsIHk6IDAgfSB9XG4gICAgfTtcblxuICAgIGlmICh0ZXh0dXJlLmJhc2VUZXh0dXJlLmhhc0xvYWRlZCkge1xuICAgICAgICB0aGlzLnVuaWZvcm1zLm1hc2sudmFsdWUueCA9IHRleHR1cmUud2lkdGg7XG4gICAgICAgIHRoaXMudW5pZm9ybXMubWFzay52YWx1ZS55ID0gdGV4dHVyZS5oZWlnaHQ7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLmJvdW5kTG9hZGVkRnVuY3Rpb24gPSB0aGlzLm9uVGV4dHVyZUxvYWRlZC5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHRleHR1cmUuYmFzZVRleHR1cmUub24oJ2xvYWRlZCcsIHRoaXMuYm91bmRMb2FkZWRGdW5jdGlvbik7XG4gICAgfVxuXG4gICAgdGhpcy5mcmFnbWVudFNyYyA9IFtcbiAgICAgICAgJ3ByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OycsXG5cbiAgICAgICAgJ3ZhcnlpbmcgdmVjMiB2VGV4dHVyZUNvb3JkOycsXG4gICAgICAgICd2YXJ5aW5nIHZlYzQgdkNvbG9yOycsXG5cbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCBtYXNrOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzIgbWFwRGltZW5zaW9uczsnLFxuICAgICAgICAndW5pZm9ybSB2ZWM0IGRpbWVuc2lvbnM7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBvZmZzZXQ7JyxcblxuICAgICAgICAndm9pZCBtYWluKCkgeycsXG4gICAgICAgICcgICB2ZWMyIG1hcENvcmRzID0gdlRleHR1cmVDb29yZC54eTsnLFxuICAgICAgICAnICAgbWFwQ29yZHMgKz0gKGRpbWVuc2lvbnMuencgKyBvZmZzZXQpLyBkaW1lbnNpb25zLnh5IDsnLFxuICAgICAgICAnICAgbWFwQ29yZHMueSAqPSAtMS4wOycsXG4gICAgICAgICcgICBtYXBDb3Jkcy55ICs9IDEuMDsnLFxuICAgICAgICAnICAgbWFwQ29yZHMgKj0gZGltZW5zaW9ucy54eSAvIG1hcERpbWVuc2lvbnM7JyxcblxuICAgICAgICAnICAgdmVjNCBvcmlnaW5hbCA9ICB0ZXh0dXJlMkQodVNhbXBsZXIsIHZUZXh0dXJlQ29vcmQpOycsXG4gICAgICAgICcgICBmbG9hdCBtYXNrQWxwaGEgPSAgdGV4dHVyZTJEKG1hc2ssIG1hcENvcmRzKS5yOycsXG4gICAgICAgICcgICBvcmlnaW5hbCAqPSBtYXNrQWxwaGE7JyxcbiAgICAgICAgLy8nICAgb3JpZ2luYWwucmdiICo9IG1hc2tBbHBoYTsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gIG9yaWdpbmFsOycsXG4gICAgICAgIC8vJyAgIGdsX0ZyYWdDb2xvciA9IGdsX0ZyYWdDb2xvcjsnLFxuICAgICAgICAnfSdcbiAgICBdO1xufVxuXG5BbHBoYU1hc2tGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuQWxwaGFNYXNrRmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEFscGhhTWFza0ZpbHRlcjtcbm1vZHVsZS5leHBvcnRzID0gQWxwaGFNYXNrRmlsdGVyO1xuXG4vKipcbiAqIFNldHMgdGhlIG1hcCBkaW1lbnNpb25zIHVuaWZvcm1zIHdoZW4gdGhlIHRleHR1cmUgYmVjb21lcyBhdmFpbGFibGUuXG4gKlxuICovXG5BbHBoYU1hc2tGaWx0ZXIucHJvdG90eXBlLm9uVGV4dHVyZUxvYWRlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnVuaWZvcm1zLm1hcERpbWVuc2lvbnMudmFsdWUueCA9IHRoaXMudW5pZm9ybXMubWFzay52YWx1ZS53aWR0aDtcbiAgICB0aGlzLnVuaWZvcm1zLm1hcERpbWVuc2lvbnMudmFsdWUueSA9IHRoaXMudW5pZm9ybXMubWFzay52YWx1ZS5oZWlnaHQ7XG5cbiAgICB0aGlzLnVuaWZvcm1zLm1hc2sudmFsdWUuYmFzZVRleHR1cmUub2ZmKCdsb2FkZWQnLCB0aGlzLmJvdW5kTG9hZGVkRnVuY3Rpb24pO1xufTtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQWxwaGFNYXNrRmlsdGVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSB0ZXh0dXJlIHVzZWQgZm9yIHRoZSBkaXNwbGFjZW1lbnQgbWFwLiBNdXN0IGJlIHBvd2VyIG9mIDIgc2l6ZWQgdGV4dHVyZS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1RleHR1cmV9XG4gICAgICogQG1lbWJlcm9mIEFscGhhTWFza0ZpbHRlciNcbiAgICAgKi9cbiAgICBtYXA6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5tYXNrLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5tYXNrLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIG9mZnNldCB1c2VkIHRvIG1vdmUgdGhlIGRpc3BsYWNlbWVudCBtYXAuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKiBAbWVtYmVyb2YgQWxwaGFNYXNrRmlsdGVyI1xuICAgICAqL1xuICAgIG9mZnNldDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudW5pZm9ybXMub2Zmc2V0LnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLm9mZnNldC52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyk7XG5cbi8qKlxuICogQGF1dGhvciBWaWNvIEB2aWNvY290ZWFcbiAqIG9yaWdpbmFsIHNoYWRlciA6IGh0dHBzOi8vd3d3LnNoYWRlcnRveS5jb20vdmlldy9sc3NHRGogYnkgQG1vdkFYMTNoXG4gKi9cblxuLyoqXG4gKiBBbiBBU0NJSSBmaWx0ZXIuXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBBYnN0cmFjdEZpbHRlclxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbmZ1bmN0aW9uIEFzY2lpRmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgZGltZW5zaW9uczogeyB0eXBlOiAnNGZ2JywgdmFsdWU6IG5ldyBGbG9hdDMyQXJyYXkoWzEwMDAwLCAxMDAsIDEwLCAxMF0pIH0sXG4gICAgICAgIHBpeGVsU2l6ZTogIHsgdHlwZTogJzFmJywgdmFsdWU6IDh9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd1bmlmb3JtIHZlYzQgZGltZW5zaW9uczsnLFxuICAgICAgICAndW5pZm9ybSBmbG9hdCBwaXhlbFNpemU7JyxcbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG5cbiAgICAgICAgJ2Zsb2F0IGNoYXJhY3RlcihmbG9hdCBuLCB2ZWMyIHApJyxcbiAgICAgICAgJ3snLFxuICAgICAgICAnICAgIHAgPSBmbG9vcihwKnZlYzIoNC4wLCAtNC4wKSArIDIuNSk7JyxcbiAgICAgICAgJyAgICBpZiAoY2xhbXAocC54LCAwLjAsIDQuMCkgPT0gcC54ICYmIGNsYW1wKHAueSwgMC4wLCA0LjApID09IHAueSknLFxuICAgICAgICAnICAgIHsnLFxuICAgICAgICAnICAgICAgICBpZiAoaW50KG1vZChuL2V4cDIocC54ICsgNS4wKnAueSksIDIuMCkpID09IDEpIHJldHVybiAxLjA7JyxcbiAgICAgICAgJyAgICB9JyxcbiAgICAgICAgJyAgICByZXR1cm4gMC4wOycsXG4gICAgICAgICd9JyxcblxuICAgICAgICAndm9pZCBtYWluKCknLFxuICAgICAgICAneycsXG4gICAgICAgICcgICAgdmVjMiB1diA9IGdsX0ZyYWdDb29yZC54eTsnLFxuICAgICAgICAnICAgIHZlYzMgY29sID0gdGV4dHVyZTJEKHVTYW1wbGVyLCBmbG9vciggdXYgLyBwaXhlbFNpemUgKSAqIHBpeGVsU2l6ZSAvIGRpbWVuc2lvbnMueHkpLnJnYjsnLFxuXG4gICAgICAgICcgICAgI2lmZGVmIEhBU19HUkVFTlNDUkVFTicsXG4gICAgICAgICcgICAgZmxvYXQgZ3JheSA9IChjb2wuciArIGNvbC5iKS8yLjA7JyxcbiAgICAgICAgJyAgICAjZWxzZScsXG4gICAgICAgICcgICAgZmxvYXQgZ3JheSA9IChjb2wuciArIGNvbC5nICsgY29sLmIpLzMuMDsnLFxuICAgICAgICAnICAgICNlbmRpZicsXG5cbiAgICAgICAgJyAgICBmbG9hdCBuID0gIDY1NTM2LjA7ICAgICAgICAgICAgIC8vIC4nLFxuICAgICAgICAnICAgIGlmIChncmF5ID4gMC4yKSBuID0gNjU2MDAuMDsgICAgLy8gOicsXG4gICAgICAgICcgICAgaWYgKGdyYXkgPiAwLjMpIG4gPSAzMzI3NzIuMDsgICAvLyAqJyxcbiAgICAgICAgJyAgICBpZiAoZ3JheSA+IDAuNCkgbiA9IDE1MjU1MDg2LjA7IC8vIG8nLFxuICAgICAgICAnICAgIGlmIChncmF5ID4gMC41KSBuID0gMjMzODUxNjQuMDsgLy8gJicsXG4gICAgICAgICcgICAgaWYgKGdyYXkgPiAwLjYpIG4gPSAxNTI1MjAxNC4wOyAvLyA4JyxcbiAgICAgICAgJyAgICBpZiAoZ3JheSA+IDAuNykgbiA9IDEzMTk5NDUyLjA7IC8vIEAnLFxuICAgICAgICAnICAgIGlmIChncmF5ID4gMC44KSBuID0gMTE1MTI4MTAuMDsgLy8gIycsXG5cbiAgICAgICAgJyAgICB2ZWMyIHAgPSBtb2QoIHV2IC8gKCBwaXhlbFNpemUgKiAwLjUgKSwgMi4wKSAtIHZlYzIoMS4wKTsnLFxuICAgICAgICAnICAgIGNvbCA9IGNvbCAqIGNoYXJhY3RlcihuLCBwKTsnLFxuXG4gICAgICAgICcgICAgZ2xfRnJhZ0NvbG9yID0gdmVjNChjb2wsIDEuMCk7JyxcbiAgICAgICAgJ30nXG4gICAgXTtcbn1cblxuQXNjaWlGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuQXNjaWlGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQXNjaWlGaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IEFzY2lpRmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhBc2NpaUZpbHRlci5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBUaGUgcGl4ZWwgc2l6ZSB1c2VkIGJ5IHRoZSBmaWx0ZXIuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIEFzY2lpRmlsdGVyI1xuICAgICAqL1xuICAgIHNpemU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5waXhlbFNpemUudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLnBpeGVsU2l6ZS52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyksXG4gICAgQmx1clhGaWx0ZXIgPSByZXF1aXJlKCcuL0JsdXJYRmlsdGVyJyksXG4gICAgQmx1cllGaWx0ZXIgPSByZXF1aXJlKCcuL0JsdXJZRmlsdGVyJyk7XG5cbi8qKlxuICogVGhlIEJsdXJGaWx0ZXIgYXBwbGllcyBhIEdhdXNzaWFuIGJsdXIgdG8gYW4gb2JqZWN0LlxuICogVGhlIHN0cmVuZ3RoIG9mIHRoZSBibHVyIGNhbiBiZSBzZXQgZm9yIHgtIGFuZCB5LWF4aXMgc2VwYXJhdGVseS5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gQmx1ckZpbHRlcigpIHtcbiAgICBBYnN0cmFjdEZpbHRlci5jYWxsKHRoaXMpO1xuXG4gICAgdGhpcy5ibHVyWEZpbHRlciA9IG5ldyBCbHVyWEZpbHRlcigpO1xuICAgIHRoaXMuYmx1cllGaWx0ZXIgPSBuZXcgQmx1cllGaWx0ZXIoKTtcblxuICAgIHRoaXMucGFzc2VzID0gW3RoaXMuYmx1clhGaWx0ZXIsIHRoaXMuYmx1cllGaWx0ZXJdO1xufVxuXG5CbHVyRmlsdGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlKTtcbkJsdXJGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQmx1ckZpbHRlcjtcbm1vZHVsZS5leHBvcnRzID0gQmx1ckZpbHRlcjtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQmx1ckZpbHRlci5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBzdHJlbmd0aCBvZiBib3RoIHRoZSBibHVyWCBhbmQgYmx1clkgcHJvcGVydGllcyBzaW11bHRhbmVvdXNseVxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJPZiBCbHVyRmlsdGVyI1xuICAgICAqIEBkZWZhdWx0IDJcbiAgICAgKi9cbiAgICBibHVyOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuYmx1clhGaWx0ZXIuYmx1cjtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuYmx1clhGaWx0ZXIuYmx1ciA9IHRoaXMuYmx1cllGaWx0ZXIuYmx1ciA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFNldHMgdGhlIHN0cmVuZ3RoIG9mIHRoZSBibHVyWCBwcm9wZXJ0eVxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJPZiBCbHVyRmlsdGVyI1xuICAgICAqIEBkZWZhdWx0IDJcbiAgICAgKi9cbiAgICBibHVyWDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmJsdXJYRmlsdGVyLmJsdXI7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLmJsdXJYRmlsdGVyLmJsdXIgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBzdHJlbmd0aCBvZiB0aGUgYmx1clkgcHJvcGVydHlcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyT2YgQmx1ckZpbHRlciNcbiAgICAgKiBAZGVmYXVsdCAyXG4gICAgICovXG4gICAgYmx1clk6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5ibHVyWUZpbHRlci5ibHVyO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy5ibHVyWUZpbHRlci5ibHVyID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKSxcbiAgICBibHVyRmFjdG9yID0gMSAvIDcwMDA7XG5cbi8qKlxuICogVGhlIEJsdXJYRmlsdGVyIGFwcGxpZXMgYSBob3Jpem9udGFsIEdhdXNzaWFuIGJsdXIgdG8gYW4gb2JqZWN0LlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBCbHVyWEZpbHRlcigpIHtcbiAgICBBYnN0cmFjdEZpbHRlci5jYWxsKHRoaXMpO1xuXG4gICAgLy8gc2V0IHRoZSB1bmlmb3Jtc1xuICAgIHRoaXMudW5pZm9ybXMgPSB7XG4gICAgICAgIGJsdXI6IHsgdHlwZTogJzFmJywgdmFsdWU6IDEgLyA1MTIgfVxuICAgIH07XG5cbiAgICB0aGlzLmZyYWdtZW50U3JjID0gW1xuICAgICAgICAncHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7JyxcblxuICAgICAgICAndmFyeWluZyB2ZWMyIHZUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAndW5pZm9ybSBmbG9hdCBibHVyOycsXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCB1U2FtcGxlcjsnLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICB2ZWM0IHN1bSA9IHZlYzQoMC4wKTsnLFxuXG4gICAgICAgICcgICBzdW0gKz0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCAtIDQuMCpibHVyLCB2VGV4dHVyZUNvb3JkLnkpKSAqIDAuMDU7JyxcbiAgICAgICAgJyAgIHN1bSArPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZlYzIodlRleHR1cmVDb29yZC54IC0gMy4wKmJsdXIsIHZUZXh0dXJlQ29vcmQueSkpICogMC4wOTsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLnggLSAyLjAqYmx1ciwgdlRleHR1cmVDb29yZC55KSkgKiAwLjEyOycsXG4gICAgICAgICcgICBzdW0gKz0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCAtIGJsdXIsIHZUZXh0dXJlQ29vcmQueSkpICogMC4xNTsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLngsIHZUZXh0dXJlQ29vcmQueSkpICogMC4xNjsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLnggKyBibHVyLCB2VGV4dHVyZUNvb3JkLnkpKSAqIDAuMTU7JyxcbiAgICAgICAgJyAgIHN1bSArPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZlYzIodlRleHR1cmVDb29yZC54ICsgMi4wKmJsdXIsIHZUZXh0dXJlQ29vcmQueSkpICogMC4xMjsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLnggKyAzLjAqYmx1ciwgdlRleHR1cmVDb29yZC55KSkgKiAwLjA5OycsXG4gICAgICAgICcgICBzdW0gKz0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCArIDQuMCpibHVyLCB2VGV4dHVyZUNvb3JkLnkpKSAqIDAuMDU7JyxcblxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gc3VtOycsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cbkJsdXJYRmlsdGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlKTtcbkJsdXJYRmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEJsdXJYRmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBCbHVyWEZpbHRlcjtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQmx1clhGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgc3RyZW5ndGggb2YgYm90aCB0aGUgYmx1ci5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgQmx1clhGaWx0ZXIjXG4gICAgICogQGRlZmF1bHQgMlxuICAgICAqL1xuICAgIGJsdXI6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5ibHVyLnZhbHVlIC8gYmx1ckZhY3RvcjtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuYmx1ci52YWx1ZSA9IGJsdXJGYWN0b3IgKiB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuIiwidmFyIEFic3RyYWN0RmlsdGVyID0gcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpLFxuICAgIGJsdXJGYWN0b3IgPSAxIC8gNzAwMDtcblxuLyoqXG4gKiBUaGUgQmx1cllGaWx0ZXIgYXBwbGllcyBhIHZlcnRpY2FsIEdhdXNzaWFuIGJsdXIgdG8gYW4gb2JqZWN0LlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBCbHVyWUZpbHRlcigpIHtcbiAgICBBYnN0cmFjdEZpbHRlci5jYWxsKHRoaXMpO1xuXG4gICAgLy8gc2V0IHRoZSB1bmlmb3Jtc1xuICAgIHRoaXMudW5pZm9ybXMgPSB7XG4gICAgICAgIGJsdXI6IHsgdHlwZTogJzFmJywgdmFsdWU6IDEgLyA1MTIgfVxuICAgIH07XG5cbiAgICB0aGlzLmZyYWdtZW50U3JjID0gW1xuICAgICAgICAncHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7JyxcblxuICAgICAgICAndmFyeWluZyB2ZWMyIHZUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAndW5pZm9ybSBmbG9hdCBibHVyOycsXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCB1U2FtcGxlcjsnLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICB2ZWM0IHN1bSA9IHZlYzQoMC4wKTsnLFxuXG4gICAgICAgICcgICBzdW0gKz0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCwgdlRleHR1cmVDb29yZC55IC0gNC4wKmJsdXIpKSAqIDAuMDU7JyxcbiAgICAgICAgJyAgIHN1bSArPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZlYzIodlRleHR1cmVDb29yZC54LCB2VGV4dHVyZUNvb3JkLnkgLSAzLjAqYmx1cikpICogMC4wOTsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLngsIHZUZXh0dXJlQ29vcmQueSAtIDIuMCpibHVyKSkgKiAwLjEyOycsXG4gICAgICAgICcgICBzdW0gKz0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCwgdlRleHR1cmVDb29yZC55IC0gYmx1cikpICogMC4xNTsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLngsIHZUZXh0dXJlQ29vcmQueSkpICogMC4xNjsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLngsIHZUZXh0dXJlQ29vcmQueSArIGJsdXIpKSAqIDAuMTU7JyxcbiAgICAgICAgJyAgIHN1bSArPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZlYzIodlRleHR1cmVDb29yZC54LCB2VGV4dHVyZUNvb3JkLnkgKyAyLjAqYmx1cikpICogMC4xMjsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLngsIHZUZXh0dXJlQ29vcmQueSArIDMuMCpibHVyKSkgKiAwLjA5OycsXG4gICAgICAgICcgICBzdW0gKz0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCwgdlRleHR1cmVDb29yZC55ICsgNC4wKmJsdXIpKSAqIDAuMDU7JyxcblxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gc3VtOycsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cbkJsdXJZRmlsdGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlKTtcbkJsdXJZRmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEJsdXJZRmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBCbHVyWUZpbHRlcjtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQmx1cllGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgc3RyZW5ndGggb2YgYm90aCB0aGUgYmx1ci5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgQmx1cllGaWx0ZXJcbiAgICAgKiBAZGVmYXVsdCAyXG4gICAgICovXG4gICAgYmx1cjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmJsdXIudmFsdWUgLyBibHVyRmFjdG9yO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgLy90aGlzLnBhZGRpbmcgPSB2YWx1ZTtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuYmx1ci52YWx1ZSA9IGJsdXJGYWN0b3IgKiB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuIiwidmFyIEFic3RyYWN0RmlsdGVyID0gcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpO1xuXG4vKipcbiAqIFRoZSBDb2xvck1hdHJpeEZpbHRlciBjbGFzcyBsZXRzIHlvdSBhcHBseSBhIDR4NCBtYXRyaXggdHJhbnNmb3JtYXRpb24gb24gdGhlIFJHQkFcbiAqIGNvbG9yIGFuZCBhbHBoYSB2YWx1ZXMgb2YgZXZlcnkgcGl4ZWwgb24geW91ciBkaXNwbGF5T2JqZWN0IHRvIHByb2R1Y2UgYSByZXN1bHRcbiAqIHdpdGggYSBuZXcgc2V0IG9mIFJHQkEgY29sb3IgYW5kIGFscGhhIHZhbHVlcy4gSXQncyBwcmV0dHkgcG93ZXJmdWwhXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBBYnN0cmFjdEZpbHRlclxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbmZ1bmN0aW9uIENvbG9yTWF0cml4RmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgbWF0cml4OiB7IHR5cGU6ICdtYXQ0JywgdmFsdWU6IFsxLCAwLCAwLCAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAsIDEsIDAsIDAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMCwgMCwgMSwgMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCAwLCAwLCAxXSB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IGludmVydDsnLFxuICAgICAgICAndW5pZm9ybSBtYXQ0IG1hdHJpeDsnLFxuICAgICAgICAndW5pZm9ybSBzYW1wbGVyMkQgdVNhbXBsZXI7JyxcblxuICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkKSAqIG1hdHJpeDsnLFxuICAgICAgICAnfSdcbiAgICBdO1xufVxuXG5Db2xvck1hdHJpeEZpbHRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEFic3RyYWN0RmlsdGVyLnByb3RvdHlwZSk7XG5Db2xvck1hdHJpeEZpbHRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDb2xvck1hdHJpeEZpbHRlcjtcbm1vZHVsZS5leHBvcnRzID0gQ29sb3JNYXRyaXhGaWx0ZXI7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKENvbG9yTWF0cml4RmlsdGVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFNldHMgdGhlIG1hdHJpeCBvZiB0aGUgY29sb3IgbWF0cml4IGZpbHRlclxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyW119XG4gICAgICogQG1lbWJlcm9mIENvbG9yTWF0cml4RmlsdGVyI1xuICAgICAqIEBkZWZhdWx0IFsxLCAwLCAwLCAwLCAwLCAxLCAwLCAwLCAwLCAwLCAxLCAwLCAwLCAwLCAwLCAxXVxuICAgICAqL1xuICAgIG1hdHJpeDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLm1hdHJpeC52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMubWF0cml4LnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKTtcblxuLyoqXG4gKiBUaGlzIGxvd2VycyB0aGUgY29sb3IgZGVwdGggb2YgeW91ciBpbWFnZSBieSB0aGUgZ2l2ZW4gYW1vdW50LCBwcm9kdWNpbmcgYW4gaW1hZ2Ugd2l0aCBhIHNtYWxsZXIgcGFsZXR0ZS5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gQ29sb3JTdGVwRmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgc3RlcDogeyB0eXBlOiAnMWYnLCB2YWx1ZTogNSB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuICAgICAgICAndmFyeWluZyB2ZWMyIHZUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IHN0ZXA7JyxcblxuICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAnICAgdmVjNCBjb2xvciA9IHRleHR1cmUyRCh1U2FtcGxlciwgdlRleHR1cmVDb29yZCk7JyxcbiAgICAgICAgJyAgIGNvbG9yID0gZmxvb3IoY29sb3IgKiBzdGVwKSAvIHN0ZXA7JyxcbiAgICAgICAgJyAgIGdsX0ZyYWdDb2xvciA9IGNvbG9yOycsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cbkNvbG9yU3RlcEZpbHRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEFic3RyYWN0RmlsdGVyLnByb3RvdHlwZSk7XG5Db2xvclN0ZXBGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQ29sb3JTdGVwRmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBDb2xvclN0ZXBGaWx0ZXI7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKENvbG9yU3RlcEZpbHRlci5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBUaGUgbnVtYmVyIG9mIHN0ZXBzIHRvIHJlZHVjZSB0aGUgcGFsZXR0ZSBieS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgQ29sb3JTdGVwRmlsdGVyI1xuICAgICAqL1xuICAgIHN0ZXA6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5zdGVwLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5zdGVwLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKTtcblxuLyoqXG4gKiBUaGUgQ29udm9sdXRpb25GaWx0ZXIgY2xhc3MgYXBwbGllcyBhIG1hdHJpeCBjb252b2x1dGlvbiBmaWx0ZXIgZWZmZWN0LlxuICogQSBjb252b2x1dGlvbiBjb21iaW5lcyBwaXhlbHMgaW4gdGhlIGlucHV0IGltYWdlIHdpdGggbmVpZ2hib3JpbmcgcGl4ZWxzIHRvIHByb2R1Y2UgYSBuZXcgaW1hZ2UuXG4gKiBBIHdpZGUgdmFyaWV0eSBvZiBpbWFnZSBlZmZlY3RzIGNhbiBiZSBhY2hpZXZlZCB0aHJvdWdoIGNvbnZvbHV0aW9ucywgaW5jbHVkaW5nIGJsdXJyaW5nLCBlZGdlXG4gKiBkZXRlY3Rpb24sIHNoYXJwZW5pbmcsIGVtYm9zc2luZywgYW5kIGJldmVsaW5nLiBUaGUgbWF0cml4IHNob3VsZCBiZSBzcGVjaWZpZWQgYXMgYSA5IHBvaW50IEFycmF5LlxuICogU2VlIGh0dHA6Ly9kb2NzLmdpbXAub3JnL2VuL3BsdWctaW4tY29udm1hdHJpeC5odG1sIGZvciBtb3JlIGluZm8uXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBBYnN0cmFjdEZpbHRlclxuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gbWF0cml4IHtudW1iZXJbXX0gQW4gYXJyYXkgb2YgdmFsdWVzIHVzZWQgZm9yIG1hdHJpeCB0cmFuc2Zvcm1hdGlvbi4gU3BlY2lmaWVkIGFzIGEgOSBwb2ludCBBcnJheS5cbiAqIEBwYXJhbSB3aWR0aCB7bnVtYmVyfSBXaWR0aCBvZiB0aGUgb2JqZWN0IHlvdSBhcmUgdHJhbnNmb3JtaW5nXG4gKiBAcGFyYW0gaGVpZ2h0IHtudW1iZXJ9IEhlaWdodCBvZiB0aGUgb2JqZWN0IHlvdSBhcmUgdHJhbnNmb3JtaW5nXG4gKi9cbmZ1bmN0aW9uIENvbnZvbHV0aW9uRmlsdGVyKG1hdHJpeCwgd2lkdGgsIGhlaWdodCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgbWF0cml4OiAgICAgeyB0eXBlOiAnMWZ2JywgdmFsdWU6IG5ldyBGbG9hdDMyQXJyYXkobWF0cml4KSB9LFxuICAgICAgICB0ZXhlbFNpemVYOiB7IHR5cGU6ICcxZicsIHZhbHVlOiAxIC8gd2lkdGggfSxcbiAgICAgICAgdGV4ZWxTaXplWTogeyB0eXBlOiAnMWYnLCB2YWx1ZTogMSAvIGhlaWdodCB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIG1lZGl1bXAgdmVjMiB2VGV4dHVyZUNvb3JkOycsXG5cbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHRleHR1cmU7JyxcbiAgICAgICAgJ3VuaWZvcm0gZmxvYXQgdGV4ZWxTaXplWDsnLFxuICAgICAgICAndW5pZm9ybSBmbG9hdCB0ZXhlbFNpemVZOycsXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IG1hdHJpeFs5XTsnLFxuXG4gICAgICAgICd2ZWMyIHB4ID0gdmVjMih0ZXhlbFNpemVYLCB0ZXhlbFNpemVZKTsnLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICB2ZWM0IGMxMSA9IHRleHR1cmUyRCh0ZXh0dXJlLCB2VGV4dHVyZUNvb3JkIC0gcHgpOycsIC8vIHRvcCBsZWZ0XG4gICAgICAgICcgICB2ZWM0IGMxMiA9IHRleHR1cmUyRCh0ZXh0dXJlLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCwgdlRleHR1cmVDb29yZC55IC0gcHgueSkpOycsIC8vIHRvcCBjZW50ZXJcbiAgICAgICAgJyAgIHZlYzQgYzEzID0gdGV4dHVyZTJEKHRleHR1cmUsIHZlYzIodlRleHR1cmVDb29yZC54ICsgcHgueCwgdlRleHR1cmVDb29yZC55IC0gcHgueSkpOycsIC8vIHRvcCByaWdodFxuXG4gICAgICAgICcgICB2ZWM0IGMyMSA9IHRleHR1cmUyRCh0ZXh0dXJlLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCAtIHB4LngsIHZUZXh0dXJlQ29vcmQueSkgKTsnLCAvLyBtaWQgbGVmdFxuICAgICAgICAnICAgdmVjNCBjMjIgPSB0ZXh0dXJlMkQodGV4dHVyZSwgdlRleHR1cmVDb29yZCk7JywgLy8gbWlkIGNlbnRlclxuICAgICAgICAnICAgdmVjNCBjMjMgPSB0ZXh0dXJlMkQodGV4dHVyZSwgdmVjMih2VGV4dHVyZUNvb3JkLnggKyBweC54LCB2VGV4dHVyZUNvb3JkLnkpICk7JywgLy8gbWlkIHJpZ2h0XG5cbiAgICAgICAgJyAgIHZlYzQgYzMxID0gdGV4dHVyZTJEKHRleHR1cmUsIHZlYzIodlRleHR1cmVDb29yZC54IC0gcHgueCwgdlRleHR1cmVDb29yZC55ICsgcHgueSkgKTsnLCAvLyBib3R0b20gbGVmdFxuICAgICAgICAnICAgdmVjNCBjMzIgPSB0ZXh0dXJlMkQodGV4dHVyZSwgdmVjMih2VGV4dHVyZUNvb3JkLngsIHZUZXh0dXJlQ29vcmQueSArIHB4LnkpICk7JywgLy8gYm90dG9tIGNlbnRlclxuICAgICAgICAnICAgdmVjNCBjMzMgPSB0ZXh0dXJlMkQodGV4dHVyZSwgdlRleHR1cmVDb29yZCArIHB4ICk7JywgLy8gYm90dG9tIHJpZ2h0XG5cbiAgICAgICAgJyAgIGdsX0ZyYWdDb2xvciA9ICcsXG4gICAgICAgICcgICAgICAgYzExICogbWF0cml4WzBdICsgYzEyICogbWF0cml4WzFdICsgYzEzICogbWF0cml4WzJdICsnLFxuICAgICAgICAnICAgICAgIGMyMSAqIG1hdHJpeFszXSArIGMyMiAqIG1hdHJpeFs0XSArIGMyMyAqIG1hdHJpeFs1XSArJyxcbiAgICAgICAgJyAgICAgICBjMzEgKiBtYXRyaXhbNl0gKyBjMzIgKiBtYXRyaXhbN10gKyBjMzMgKiBtYXRyaXhbOF07JyxcbiAgICAgICAgJyAgIGdsX0ZyYWdDb2xvci5hID0gYzIyLmE7JyxcbiAgICAgICAgJ30nXG4gICAgXTtcbn1cblxuQ29udm9sdXRpb25GaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuQ29udm9sdXRpb25GaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQ29udm9sdXRpb25GaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IENvbnZvbHV0aW9uRmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhDb252b2x1dGlvbkZpbHRlci5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBBbiBhcnJheSBvZiB2YWx1ZXMgdXNlZCBmb3IgbWF0cml4IHRyYW5zZm9ybWF0aW9uLiBTcGVjaWZpZWQgYXMgYSA5IHBvaW50IEFycmF5LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyW119XG4gICAgICogQG1lbWJlcm9mIENvbnZvbHV0aW9uRmlsdGVyI1xuICAgICAqL1xuICAgIG1hdHJpeDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLm1hdHJpeC52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMubWF0cml4LnZhbHVlID0gbmV3IEZsb2F0MzJBcnJheSh2YWx1ZSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogV2lkdGggb2YgdGhlIG9iamVjdCB5b3UgYXJlIHRyYW5zZm9ybWluZ1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBDb252b2x1dGlvbkZpbHRlciNcbiAgICAgKi9cbiAgICB3aWR0aDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLnRleGVsU2l6ZVgudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLnRleGVsU2l6ZVgudmFsdWUgPSAxL3ZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEhlaWdodCBvZiB0aGUgb2JqZWN0IHlvdSBhcmUgdHJhbnNmb3JtaW5nXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIENvbnZvbHV0aW9uRmlsdGVyI1xuICAgICAqL1xuICAgIGhlaWdodDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLnRleGVsU2l6ZVkudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLnRleGVsU2l6ZVkudmFsdWUgPSAxL3ZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyk7XG5cbi8qKlxuICogQSBDcm9zcyBIYXRjaCBlZmZlY3QgZmlsdGVyLlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBDcm9zc0hhdGNoRmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgYmx1cjogeyB0eXBlOiAnMWYnLCB2YWx1ZTogMSAvIDUxMiB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IGJsdXI7JyxcbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG5cbiAgICAgICAgJ3ZvaWQgbWFpbih2b2lkKSB7JyxcbiAgICAgICAgJyAgICBmbG9hdCBsdW0gPSBsZW5ndGgodGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkLnh5KS5yZ2IpOycsXG5cbiAgICAgICAgJyAgICBnbF9GcmFnQ29sb3IgPSB2ZWM0KDEuMCwgMS4wLCAxLjAsIDEuMCk7JyxcblxuICAgICAgICAnICAgIGlmIChsdW0gPCAxLjAwKSB7JyxcbiAgICAgICAgJyAgICAgICAgaWYgKG1vZChnbF9GcmFnQ29vcmQueCArIGdsX0ZyYWdDb29yZC55LCAxMC4wKSA9PSAwLjApIHsnLFxuICAgICAgICAnICAgICAgICAgICAgZ2xfRnJhZ0NvbG9yID0gdmVjNCgwLjAsIDAuMCwgMC4wLCAxLjApOycsXG4gICAgICAgICcgICAgICAgIH0nLFxuICAgICAgICAnICAgIH0nLFxuXG4gICAgICAgICcgICAgaWYgKGx1bSA8IDAuNzUpIHsnLFxuICAgICAgICAnICAgICAgICBpZiAobW9kKGdsX0ZyYWdDb29yZC54IC0gZ2xfRnJhZ0Nvb3JkLnksIDEwLjApID09IDAuMCkgeycsXG4gICAgICAgICcgICAgICAgICAgICBnbF9GcmFnQ29sb3IgPSB2ZWM0KDAuMCwgMC4wLCAwLjAsIDEuMCk7JyxcbiAgICAgICAgJyAgICAgICAgfScsXG4gICAgICAgICcgICAgfScsXG5cbiAgICAgICAgJyAgICBpZiAobHVtIDwgMC41MCkgeycsXG4gICAgICAgICcgICAgICAgIGlmIChtb2QoZ2xfRnJhZ0Nvb3JkLnggKyBnbF9GcmFnQ29vcmQueSAtIDUuMCwgMTAuMCkgPT0gMC4wKSB7JyxcbiAgICAgICAgJyAgICAgICAgICAgIGdsX0ZyYWdDb2xvciA9IHZlYzQoMC4wLCAwLjAsIDAuMCwgMS4wKTsnLFxuICAgICAgICAnICAgICAgICB9JyxcbiAgICAgICAgJyAgICB9JyxcblxuICAgICAgICAnICAgIGlmIChsdW0gPCAwLjMpIHsnLFxuICAgICAgICAnICAgICAgICBpZiAobW9kKGdsX0ZyYWdDb29yZC54IC0gZ2xfRnJhZ0Nvb3JkLnkgLSA1LjAsIDEwLjApID09IDAuMCkgeycsXG4gICAgICAgICcgICAgICAgICAgICBnbF9GcmFnQ29sb3IgPSB2ZWM0KDAuMCwgMC4wLCAwLjAsIDEuMCk7JyxcbiAgICAgICAgJyAgICAgICAgfScsXG4gICAgICAgICcgICAgfScsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cbkNyb3NzSGF0Y2hGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuQ3Jvc3NIYXRjaEZpbHRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDcm9zc0hhdGNoRmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBDcm9zc0hhdGNoRmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhDcm9zc0hhdGNoRmlsdGVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFNldHMgdGhlIHN0cmVuZ3RoIG9mIGJvdGggdGhlIGJsdXIuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIENyb3NzSGF0Y2hGaWx0ZXIjXG4gICAgICogQGRlZmF1bHQgMlxuICAgICAqL1xuICAgIGJsdXI6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5ibHVyLnZhbHVlIC8gKDEvNzAwMCk7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICAvL3RoaXMucGFkZGluZyA9IHZhbHVlO1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5ibHVyLnZhbHVlID0gKDEvNzAwMCkgKiB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuIiwidmFyIEFic3RyYWN0RmlsdGVyID0gcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpO1xuXG4vKipcbiAqIFRoZSBEaXNwbGFjZW1lbnRGaWx0ZXIgY2xhc3MgdXNlcyB0aGUgcGl4ZWwgdmFsdWVzIGZyb20gdGhlIHNwZWNpZmllZCB0ZXh0dXJlIChjYWxsZWQgdGhlIGRpc3BsYWNlbWVudCBtYXApIHRvIHBlcmZvcm0gYSBkaXNwbGFjZW1lbnQgb2YgYW4gb2JqZWN0LlxuICogWW91IGNhbiB1c2UgdGhpcyBmaWx0ZXIgdG8gYXBwbHkgYWxsIG1hbm9yIG9mIGNyYXp5IHdhcnBpbmcgZWZmZWN0c1xuICogQ3VycmVudGx5IHRoZSByIHByb3BlcnR5IG9mIHRoZSB0ZXh0dXJlIGlzIHVzZWQgb2Zmc2V0IHRoZSB4IGFuZCB0aGUgZyBwcm9wZXJ0eSBvZiB0aGUgdGV4dHVyZSBpcyB1c2VkIHRvIG9mZnNldCB0aGUgeS5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSB0ZXh0dXJlIHtUZXh0dXJlfSBUaGUgdGV4dHVyZSB1c2VkIGZvciB0aGUgZGlzcGxhY2VtZW50IG1hcCAqIG11c3QgYmUgcG93ZXIgb2YgMiB0ZXh0dXJlIGF0IHRoZSBtb21lbnRcbiAqL1xuZnVuY3Rpb24gRGlzcGxhY2VtZW50RmlsdGVyKHRleHR1cmUpIHtcbiAgICBBYnN0cmFjdEZpbHRlci5jYWxsKHRoaXMpO1xuXG4gICAgdGV4dHVyZS5iYXNlVGV4dHVyZS5fcG93ZXJPZjIgPSB0cnVlO1xuXG4gICAgLy8gc2V0IHRoZSB1bmlmb3Jtc1xuICAgIHRoaXMudW5pZm9ybXMgPSB7XG4gICAgICAgIGRpc3BsYWNlbWVudE1hcDogeyB0eXBlOiAnc2FtcGxlcjJEJywgdmFsdWU6IHRleHR1cmUgfSxcbiAgICAgICAgc2NhbGU6ICAgICAgICAgICB7IHR5cGU6ICcyZicsICB2YWx1ZTogeyB4OiAzMCwgeTogMzAgfSB9LFxuICAgICAgICBvZmZzZXQ6ICAgICAgICAgIHsgdHlwZTogJzJmJywgIHZhbHVlOiB7IHg6IDAsICB5OiAwIH0gfSxcbiAgICAgICAgbWFwRGltZW5zaW9uczogICB7IHR5cGU6ICcyZicsICB2YWx1ZTogeyB4OiAxLCAgeTogNTExMiB9IH0sXG4gICAgICAgIGRpbWVuc2lvbnM6ICAgICAgeyB0eXBlOiAnNGZ2JywgdmFsdWU6IFswLCAwLCAwLCAwXSB9XG4gICAgfTtcblxuICAgIGlmICh0ZXh0dXJlLmJhc2VUZXh0dXJlLmhhc0xvYWRlZCkge1xuICAgICAgICB0aGlzLm9uVGV4dHVyZUxvYWRlZCgpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdGhpcy5ib3VuZExvYWRlZEZ1bmN0aW9uID0gdGhpcy5vblRleHR1cmVMb2FkZWQuYmluZCh0aGlzKTtcblxuICAgICAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLm9uKCdsb2FkZWQnLCB0aGlzLmJvdW5kTG9hZGVkRnVuY3Rpb24pO1xuICAgIH1cblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCBkaXNwbGFjZW1lbnRNYXA7JyxcbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzIgc2NhbGU7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBvZmZzZXQ7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjNCBkaW1lbnNpb25zOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzIgbWFwRGltZW5zaW9uczsnLC8vID0gdmVjMigyNTYuMCwgMjU2LjApOycsXG4gICAgICAgIC8vICdjb25zdCB2ZWMyIHRleHR1cmVEaW1lbnNpb25zID0gdmVjMig3NTAuMCwgNzUwLjApOycsXG5cbiAgICAgICAgJ3ZvaWQgbWFpbih2b2lkKSB7JyxcbiAgICAgICAgJyAgIHZlYzIgbWFwQ29yZHMgPSB2VGV4dHVyZUNvb3JkLnh5OycsXG4gICAgICAgICcgICBtYXBDb3JkcyArPSAoZGltZW5zaW9ucy56dyArIG9mZnNldCkvIGRpbWVuc2lvbnMueHkgOycsXG4gICAgICAgICcgICBtYXBDb3Jkcy55ICo9IC0xLjA7JyxcbiAgICAgICAgJyAgIG1hcENvcmRzLnkgKz0gMS4wOycsXG5cbiAgICAgICAgJyAgIHZlYzIgbWF0U2FtcGxlID0gdGV4dHVyZTJEKGRpc3BsYWNlbWVudE1hcCwgbWFwQ29yZHMpLnh5OycsXG4gICAgICAgICcgICBtYXRTYW1wbGUgLT0gMC41OycsXG4gICAgICAgICcgICBtYXRTYW1wbGUgKj0gc2NhbGU7JyxcbiAgICAgICAgJyAgIG1hdFNhbXBsZSAvPSBtYXBEaW1lbnNpb25zOycsXG5cbiAgICAgICAgJyAgIGdsX0ZyYWdDb2xvciA9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLnggKyBtYXRTYW1wbGUueCwgdlRleHR1cmVDb29yZC55ICsgbWF0U2FtcGxlLnkpKTsnLFxuXG4gICAgICAgIC8vVE9ETzogSXMgdGhpcyBuZWVkZWQ/XG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IucmdiID0gbWl4KCBnbF9GcmFnQ29sb3IucmdiLCBnbF9GcmFnQ29sb3IucmdiLCAxLjApOycsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cbkRpc3BsYWNlbWVudEZpbHRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEFic3RyYWN0RmlsdGVyLnByb3RvdHlwZSk7XG5EaXNwbGFjZW1lbnRGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gRGlzcGxhY2VtZW50RmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBEaXNwbGFjZW1lbnRGaWx0ZXI7XG5cbi8qKlxuICogU2V0cyB0aGUgbWFwIGRpbWVuc2lvbnMgdW5pZm9ybXMgd2hlbiB0aGUgdGV4dHVyZSBiZWNvbWVzIGF2YWlsYWJsZS5cbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5EaXNwbGFjZW1lbnRGaWx0ZXIucHJvdG90eXBlLm9uVGV4dHVyZUxvYWRlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnVuaWZvcm1zLm1hcERpbWVuc2lvbnMudmFsdWUueCA9IHRoaXMudW5pZm9ybXMuZGlzcGxhY2VtZW50TWFwLnZhbHVlLndpZHRoO1xuICAgIHRoaXMudW5pZm9ybXMubWFwRGltZW5zaW9ucy52YWx1ZS55ID0gdGhpcy51bmlmb3Jtcy5kaXNwbGFjZW1lbnRNYXAudmFsdWUuaGVpZ2h0O1xuXG4gICAgdGhpcy51bmlmb3Jtcy5kaXNwbGFjZW1lbnRNYXAudmFsdWUuYmFzZVRleHR1cmUub2ZmKCdsb2FkZWQnLCB0aGlzLmJvdW5kTG9hZGVkRnVuY3Rpb24pO1xufTtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoRGlzcGxhY2VtZW50RmlsdGVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSB0ZXh0dXJlIHVzZWQgZm9yIHRoZSBkaXNwbGFjZW1lbnQgbWFwLiBNdXN0IGJlIHBvd2VyIG9mIDIgdGV4dHVyZS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1RleHR1cmV9XG4gICAgICogQG1lbWJlcm9mIERpc3BsYWNlbWVudEZpbHRlciNcbiAgICAgKi9cbiAgICBtYXA6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5kaXNwbGFjZW1lbnRNYXAudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLmRpc3BsYWNlbWVudE1hcC52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBtdWx0aXBsaWVyIHVzZWQgdG8gc2NhbGUgdGhlIGRpc3BsYWNlbWVudCByZXN1bHQgZnJvbSB0aGUgbWFwIGNhbGN1bGF0aW9uLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICogQG1lbWJlcm9mIERpc3BsYWNlbWVudEZpbHRlciNcbiAgICAgKi9cbiAgICBzY2FsZToge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLnNjYWxlLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5zY2FsZS52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBvZmZzZXQgdXNlZCB0byBtb3ZlIHRoZSBkaXNwbGFjZW1lbnQgbWFwLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICogQG1lbWJlcm9mIERpc3BsYWNlbWVudEZpbHRlciNcbiAgICAgKi9cbiAgICBvZmZzZXQ6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5vZmZzZXQudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLm9mZnNldC52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyk7XG5cbi8qKlxuICogQGF1dGhvciBNYXQgR3JvdmVzIGh0dHA6Ly9tYXRncm92ZXMuY29tLyBARG9vcm1hdDIzXG4gKiBvcmlnaW5hbCBmaWx0ZXI6IGh0dHBzOi8vZ2l0aHViLmNvbS9ldmFudy9nbGZ4LmpzL2Jsb2IvbWFzdGVyL3NyYy9maWx0ZXJzL2Z1bi9kb3RzY3JlZW4uanNcbiAqL1xuXG4vKipcbiAqIFRoaXMgZmlsdGVyIGFwcGxpZXMgYSBkb3RzY3JlZW4gZWZmZWN0IG1ha2luZyBkaXNwbGF5IG9iamVjdHMgYXBwZWFyIHRvIGJlIG1hZGUgb3V0IG9mXG4gKiBibGFjayBhbmQgd2hpdGUgaGFsZnRvbmUgZG90cyBsaWtlIGFuIG9sZCBwcmludGVyLlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBEb3RTY3JlZW5GaWx0ZXIoKSB7XG4gICAgQWJzdHJhY3RGaWx0ZXIuY2FsbCh0aGlzKTtcblxuICAgIC8vIHNldCB0aGUgdW5pZm9ybXNcbiAgICB0aGlzLnVuaWZvcm1zID0ge1xuICAgICAgICBzY2FsZTogICAgICB7IHR5cGU6ICcxZicsIHZhbHVlOiAxIH0sXG4gICAgICAgIGFuZ2xlOiAgICAgIHsgdHlwZTogJzFmJywgdmFsdWU6IDUgfSxcbiAgICAgICAgZGltZW5zaW9uczogeyB0eXBlOiAnNGZ2JywgdmFsdWU6IFswLCAwLCAwLCAwXSB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIHZlYzQgZGltZW5zaW9uczsnLFxuICAgICAgICAndW5pZm9ybSBzYW1wbGVyMkQgdVNhbXBsZXI7JyxcblxuICAgICAgICAndW5pZm9ybSBmbG9hdCBhbmdsZTsnLFxuICAgICAgICAndW5pZm9ybSBmbG9hdCBzY2FsZTsnLFxuXG4gICAgICAgICdmbG9hdCBwYXR0ZXJuKCkgeycsXG4gICAgICAgICcgICBmbG9hdCBzID0gc2luKGFuZ2xlKSwgYyA9IGNvcyhhbmdsZSk7JyxcbiAgICAgICAgJyAgIHZlYzIgdGV4ID0gdlRleHR1cmVDb29yZCAqIGRpbWVuc2lvbnMueHk7JyxcbiAgICAgICAgJyAgIHZlYzIgcG9pbnQgPSB2ZWMyKCcsXG4gICAgICAgICcgICAgICAgYyAqIHRleC54IC0gcyAqIHRleC55LCcsXG4gICAgICAgICcgICAgICAgcyAqIHRleC54ICsgYyAqIHRleC55JyxcbiAgICAgICAgJyAgICkgKiBzY2FsZTsnLFxuICAgICAgICAnICAgcmV0dXJuIChzaW4ocG9pbnQueCkgKiBzaW4ocG9pbnQueSkpICogNC4wOycsXG4gICAgICAgICd9JyxcblxuICAgICAgICAndm9pZCBtYWluKCkgeycsXG4gICAgICAgICcgICB2ZWM0IGNvbG9yID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkKTsnLFxuICAgICAgICAnICAgZmxvYXQgYXZlcmFnZSA9IChjb2xvci5yICsgY29sb3IuZyArIGNvbG9yLmIpIC8gMy4wOycsXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IgPSB2ZWM0KHZlYzMoYXZlcmFnZSAqIDEwLjAgLSA1LjAgKyBwYXR0ZXJuKCkpLCBjb2xvci5hKTsnLFxuICAgICAgICAnfSdcbiAgICBdO1xufVxuXG5Eb3RTY3JlZW5GaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuRG90U2NyZWVuRmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IERvdFNjcmVlbkZpbHRlcjtcbm1vZHVsZS5leHBvcnRzID0gRG90U2NyZWVuRmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhEb3RTY3JlZW5GaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHNjYWxlIG9mIHRoZSBlZmZlY3QuXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBEb3RTY3JlZW5GaWx0ZXIjXG4gICAgICovXG4gICAgc2NhbGU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5zY2FsZS52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuc2NhbGUudmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgcmFkaXVzIG9mIHRoZSBlZmZlY3QuXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBEb3RTY3JlZW5GaWx0ZXIjXG4gICAgICovXG4gICAgYW5nbGU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5hbmdsZS52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuYW5nbGUudmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuIiwiLyoqXG4gKiBBIHRhcmdldCBhbmQgcGFzcyBpbmZvIG9iamVjdCBmb3IgZmlsdGVycy5cbiAqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBGaWx0ZXJCbG9jaygpIHtcbiAgICAvKipcbiAgICAgKiBUaGUgdmlzaWJsZSBzdGF0ZSBvZiB0aGlzIEZpbHRlckJsb2NrLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLnZpc2libGUgPSB0cnVlO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHJlbmRlcmFibGUgc3RhdGUgb2YgdGhpcyBGaWx0ZXJCbG9jay5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5yZW5kZXJhYmxlID0gdHJ1ZTtcbn1cblxuRmlsdGVyQmxvY2sucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gRmlsdGVyQmxvY2s7XG5tb2R1bGUuZXhwb3J0cyA9IEZpbHRlckJsb2NrO1xuIiwidmFyIEFic3RyYWN0RmlsdGVyID0gcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpO1xuXG4vKipcbiAqIFRoaXMgZ3JleXNjYWxlcyB0aGUgcGFsZXR0ZSBvZiB5b3VyIERpc3BsYXkgT2JqZWN0cy5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gR3JheUZpbHRlcigpIHtcbiAgICBBYnN0cmFjdEZpbHRlci5jYWxsKHRoaXMpO1xuXG4gICAgLy8gc2V0IHRoZSB1bmlmb3Jtc1xuICAgIHRoaXMudW5pZm9ybXMgPSB7XG4gICAgICAgIGdyYXk6IHsgdHlwZTogJzFmJywgdmFsdWU6IDEgfVxuICAgIH07XG5cbiAgICB0aGlzLmZyYWdtZW50U3JjID0gW1xuICAgICAgICAncHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7JyxcblxuICAgICAgICAndmFyeWluZyB2ZWMyIHZUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAndW5pZm9ybSBzYW1wbGVyMkQgdVNhbXBsZXI7JyxcbiAgICAgICAgJ3VuaWZvcm0gZmxvYXQgZ3JheTsnLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IgPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZUZXh0dXJlQ29vcmQpOycsXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IucmdiID0gbWl4KGdsX0ZyYWdDb2xvci5yZ2IsIHZlYzMoMC4yMTI2KmdsX0ZyYWdDb2xvci5yICsgMC43MTUyKmdsX0ZyYWdDb2xvci5nICsgMC4wNzIyKmdsX0ZyYWdDb2xvci5iKSwgZ3JheSk7JyxcbiAgICAgLy8gICAnICAgZ2xfRnJhZ0NvbG9yID0gZ2xfRnJhZ0NvbG9yOycsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cbkdyYXlGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuR3JheUZpbHRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBHcmF5RmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBHcmF5RmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhHcmF5RmlsdGVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSBzdHJlbmd0aCBvZiB0aGUgZ3JheS4gMSB3aWxsIG1ha2UgdGhlIG9iamVjdCBibGFjayBhbmQgd2hpdGUsIDAgd2lsbCBtYWtlIHRoZSBvYmplY3QgaXRzIG5vcm1hbCBjb2xvci5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgR3JheUZpbHRlciNcbiAgICAgKi9cbiAgICBncmF5OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudW5pZm9ybXMuZ3JheS52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuZ3JheS52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyk7XG5cbi8qKlxuICogVGhpcyBpbnZlcnRzIHlvdXIgRGlzcGxheSBPYmplY3RzIGNvbG9ycy5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gSW52ZXJ0RmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgaW52ZXJ0OiB7IHR5cGU6ICcxZicsIHZhbHVlOiAxIH1cbiAgICB9O1xuXG4gICAgdGhpcy5mcmFnbWVudFNyYyA9IFtcbiAgICAgICAgJ3ByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OycsXG5cbiAgICAgICAgJ3ZhcnlpbmcgdmVjMiB2VGV4dHVyZUNvb3JkOycsXG4gICAgICAgICd2YXJ5aW5nIHZlYzQgdkNvbG9yOycsXG5cbiAgICAgICAgJ3VuaWZvcm0gZmxvYXQgaW52ZXJ0OycsXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCB1U2FtcGxlcjsnLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IgPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZUZXh0dXJlQ29vcmQpOycsXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IucmdiID0gbWl4KCAodmVjMygxKS1nbF9GcmFnQ29sb3IucmdiKSAqIGdsX0ZyYWdDb2xvci5hLCBnbF9GcmFnQ29sb3IucmdiLCAxLjAgLSBpbnZlcnQpOycsXG4gICAgICAgIC8vJyAgIGdsX0ZyYWdDb2xvci5yZ2IgPSBnbF9GcmFnQ29sb3IucmdiICAqIGdsX0ZyYWdDb2xvci5hOycsXG4gICAgICAvLyAgJyAgIGdsX0ZyYWdDb2xvciA9IGdsX0ZyYWdDb2xvciAqIHZDb2xvcjsnLFxuICAgICAgICAnfSdcbiAgICBdO1xufVxuXG5JbnZlcnRGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuSW52ZXJ0RmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEludmVydEZpbHRlcjtcbm1vZHVsZS5leHBvcnRzID0gSW52ZXJ0RmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhJbnZlcnRGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHN0cmVuZ3RoIG9mIHRoZSBpbnZlcnQuIDEgd2lsbCBmdWxseSBpbnZlcnQgdGhlIGNvbG9ycywgMCB3aWxsIG1ha2UgdGhlIG9iamVjdCBpdHMgbm9ybWFsIGNvbG9yXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIEludmVydEZpbHRlciNcbiAgICAgKi9cbiAgICBpbnZlcnQ6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5pbnZlcnQudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLmludmVydC52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyk7XG5cbi8qKlxuICogQGF1dGhvciBWaWNvIEB2aWNvY290ZWFcbiAqIG9yaWdpbmFsIGZpbHRlcjogaHR0cHM6Ly9naXRodWIuY29tL2V2YW53L2dsZnguanMvYmxvYi9tYXN0ZXIvc3JjL2ZpbHRlcnMvYWRqdXN0L25vaXNlLmpzXG4gKi9cblxuLyoqXG4gKiBBIE5vaXNlIGVmZmVjdCBmaWx0ZXIuXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBBYnN0cmFjdEZpbHRlclxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbmZ1bmN0aW9uIE5vaXNlRmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgbm9pc2U6IHsgdHlwZTogJzFmJywgdmFsdWU6IDAuNSB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IG5vaXNlOycsXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCB1U2FtcGxlcjsnLFxuXG4gICAgICAgICdmbG9hdCByYW5kKHZlYzIgY28pIHsnLFxuICAgICAgICAnICAgIHJldHVybiBmcmFjdChzaW4oZG90KGNvLnh5ICx2ZWMyKDEyLjk4OTgsNzguMjMzKSkpICogNDM3NTguNTQ1Myk7JyxcbiAgICAgICAgJ30nLFxuXG4gICAgICAgICd2b2lkIG1haW4oKSB7JyxcbiAgICAgICAgJyAgICB2ZWM0IGNvbG9yID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkKTsnLFxuXG4gICAgICAgICcgICAgZmxvYXQgZGlmZiA9IChyYW5kKHZUZXh0dXJlQ29vcmQpIC0gMC41KSAqIG5vaXNlOycsXG4gICAgICAgICcgICAgY29sb3IuciArPSBkaWZmOycsXG4gICAgICAgICcgICAgY29sb3IuZyArPSBkaWZmOycsXG4gICAgICAgICcgICAgY29sb3IuYiArPSBkaWZmOycsXG5cbiAgICAgICAgJyAgICBnbF9GcmFnQ29sb3IgPSBjb2xvcjsnLFxuICAgICAgICAnfSdcbiAgICBdO1xufVxuXG5Ob2lzZUZpbHRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEFic3RyYWN0RmlsdGVyLnByb3RvdHlwZSk7XG5Ob2lzZUZpbHRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBOb2lzZUZpbHRlcjtcbm1vZHVsZS5leHBvcnRzID0gTm9pc2VGaWx0ZXI7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKE5vaXNlRmlsdGVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSBhbW91bnQgb2Ygbm9pc2UgdG8gYXBwbHkuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIE5vaXNlRmlsdGVyI1xuICAgICAqIEBkZWZhdWx0IDAuNVxuICAgICAqL1xuICAgIG5vaXNlOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudW5pZm9ybXMubm9pc2UudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLmRpcnR5ID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMubm9pc2UudmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuIiwidmFyIEFic3RyYWN0RmlsdGVyID0gcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpO1xuXG4vKipcbiAqIFRoZSBOb3JtYWxNYXBGaWx0ZXIgY2xhc3MgdXNlcyB0aGUgcGl4ZWwgdmFsdWVzIGZyb20gdGhlIHNwZWNpZmllZCB0ZXh0dXJlIChjYWxsZWQgdGhlIGRpc3BsYWNlbWVudCBtYXApIHRvIHBlcmZvcm0gYSBkaXNwbGFjZW1lbnQgb2YgYW4gb2JqZWN0LlxuICogWW91IGNhbiB1c2UgdGhpcyBmaWx0ZXIgdG8gYXBwbHkgYWxsIG1hbm9yIG9mIGNyYXp5IHdhcnBpbmcgZWZmZWN0c1xuICogQ3VycmVudGx5IHRoZSByIHByb3BlcnR5IG9mIHRoZSB0ZXh0dXJlIGlzIHVzZWQgb2Zmc2V0IHRoZSB4IGFuZCB0aGUgZyBwcm9wZXJ0eSBvZiB0aGUgdGV4dHVyZSBpcyB1c2VkIHRvIG9mZnNldCB0aGUgeS5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSB0ZXh0dXJlIHtUZXh0dXJlfSBUaGUgdGV4dHVyZSB1c2VkIGZvciB0aGUgbm9ybWFsIG1hcCwgbXVzdCBiZSBwb3dlciBvZiAyIHRleHR1cmUgYXQgdGhlIG1vbWVudFxuICovXG5mdW5jdGlvbiBOb3JtYWxNYXBGaWx0ZXIodGV4dHVyZSkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLl9wb3dlck9mMiA9IHRydWU7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgZGlzcGxhY2VtZW50TWFwOiAgeyB0eXBlOiAnc2FtcGxlcjJEJywgdmFsdWU6IHRleHR1cmUgfSxcbiAgICAgICAgc2NhbGU6ICAgICAgICAgICAgeyB0eXBlOiAnMmYnLCB2YWx1ZTogeyB4OiAxNSwgeTogMTUgfSB9LFxuICAgICAgICBvZmZzZXQ6ICAgICAgICAgICB7IHR5cGU6ICcyZicsIHZhbHVlOiB7IHg6IDAsICB5OiAwIH0gfSxcbiAgICAgICAgbWFwRGltZW5zaW9uczogICAgeyB0eXBlOiAnMmYnLCB2YWx1ZTogeyB4OiAxLCAgeTogMSB9IH0sXG4gICAgICAgIGRpbWVuc2lvbnM6ICAgICAgIHsgdHlwZTogJzRmJywgdmFsdWU6IFswLCAwLCAwLCAwXSB9LFxuICAgICAgICAvLyBMaWdodERpcjogICAgICAgICB7IHR5cGU6ICdmMycsIHZhbHVlOiBbMCwgMSwgMF0gfSxcbiAgICAgICAgTGlnaHRQb3M6ICAgICAgICAgeyB0eXBlOiAnM2YnLCB2YWx1ZTogWzAsIDEsIDBdIH1cbiAgICB9O1xuXG4gICAgaWYgKHRleHR1cmUuYmFzZVRleHR1cmUuaGFzTG9hZGVkKSB7XG4gICAgICAgIHRoaXMub25UZXh0dXJlTG9hZGVkKCk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLmJvdW5kTG9hZGVkRnVuY3Rpb24gPSB0aGlzLm9uVGV4dHVyZUxvYWRlZC5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHRleHR1cmUuYmFzZVRleHR1cmUub24oJ2xvYWRlZCcsIHRoaXMuYm91bmRMb2FkZWRGdW5jdGlvbik7XG4gICAgfVxuXG4gICAgdGhpcy5mcmFnbWVudFNyYyA9IFtcbiAgICAgICAgJ3ByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OycsXG5cbiAgICAgICAgJ3ZhcnlpbmcgdmVjMiB2VGV4dHVyZUNvb3JkOycsXG4gICAgICAgICd2YXJ5aW5nIGZsb2F0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCBkaXNwbGFjZW1lbnRNYXA7JyxcbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG5cbiAgICAgICAgJ3VuaWZvcm0gdmVjNCBkaW1lbnNpb25zOycsXG5cbiAgICAgICAgJ2NvbnN0IHZlYzIgUmVzb2x1dGlvbiA9IHZlYzIoMS4wLDEuMCk7JywgICAgICAvL3Jlc29sdXRpb24gb2Ygc2NyZWVuXG4gICAgICAgICd1bmlmb3JtIHZlYzMgTGlnaHRQb3M7JywgICAgLy9saWdodCBwb3NpdGlvbiwgbm9ybWFsaXplZFxuICAgICAgICAnY29uc3QgdmVjNCBMaWdodENvbG9yID0gdmVjNCgxLjAsIDEuMCwgMS4wLCAxLjApOycsICAgICAgLy9saWdodCBSR0JBIC0tIGFscGhhIGlzIGludGVuc2l0eVxuICAgICAgICAnY29uc3QgdmVjNCBBbWJpZW50Q29sb3IgPSB2ZWM0KDEuMCwgMS4wLCAxLjAsIDAuNSk7JywgICAgLy9hbWJpZW50IFJHQkEgLS0gYWxwaGEgaXMgaW50ZW5zaXR5XG4gICAgICAgICdjb25zdCB2ZWMzIEZhbGxvZmYgPSB2ZWMzKDAuMCwgMS4wLCAwLjIpOycsICAgICAgICAgLy9hdHRlbnVhdGlvbiBjb2VmZmljaWVudHNcblxuICAgICAgICAndW5pZm9ybSB2ZWMzIExpZ2h0RGlyOycsLy8nID0gdmVjMygxLjAsIDAuMCwgMS4wKTsnLFxuXG5cbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBtYXBEaW1lbnNpb25zOycsLy8gPSB2ZWMyKDI1Ni4wLCAyNTYuMCk7JyxcblxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICB2ZWMyIG1hcENvcmRzID0gdlRleHR1cmVDb29yZC54eTsnLFxuXG4gICAgICAgICcgICB2ZWM0IGNvbG9yID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkLnN0KTsnLFxuICAgICAgICAnICAgdmVjMyBuQ29sb3IgPSB0ZXh0dXJlMkQoZGlzcGxhY2VtZW50TWFwLCB2VGV4dHVyZUNvb3JkLnN0KS5yZ2I7JyxcblxuXG4gICAgICAgICcgICBtYXBDb3JkcyAqPSB2ZWMyKGRpbWVuc2lvbnMueC81MTIuMCwgZGltZW5zaW9ucy55LzUxMi4wKTsnLFxuXG4gICAgICAgICcgICBtYXBDb3Jkcy55ICo9IC0xLjA7JyxcbiAgICAgICAgJyAgIG1hcENvcmRzLnkgKz0gMS4wOycsXG5cbiAgICAgICAgLy9SR0JBIG9mIG91ciBkaWZmdXNlIGNvbG9yXG4gICAgICAgICcgICB2ZWM0IERpZmZ1c2VDb2xvciA9IHRleHR1cmUyRCh1U2FtcGxlciwgdlRleHR1cmVDb29yZCk7JyxcblxuICAgICAgICAvL1JHQiBvZiBvdXIgbm9ybWFsIG1hcFxuICAgICAgICAnICAgdmVjMyBOb3JtYWxNYXAgPSB0ZXh0dXJlMkQoZGlzcGxhY2VtZW50TWFwLCBtYXBDb3JkcykucmdiOycsXG5cbiAgICAgICAgLy9UaGUgZGVsdGEgcG9zaXRpb24gb2YgbGlnaHRcbiAgICAgICAgLy8ndmVjMyBMaWdodERpciA9IHZlYzMoTGlnaHRQb3MueHkgLSAoZ2xfRnJhZ0Nvb3JkLnh5IC8gUmVzb2x1dGlvbi54eSksIExpZ2h0UG9zLnopOycsXG4gICAgICAgICcgICB2ZWMzIExpZ2h0RGlyID0gdmVjMyhMaWdodFBvcy54eSAtIChtYXBDb3Jkcy54eSksIExpZ2h0UG9zLnopOycsXG4gICAgICAgIC8vQ29ycmVjdCBmb3IgYXNwZWN0IHJhdGlvXG4gICAgICAgIC8vICcgICBMaWdodERpci54ICo9IFJlc29sdXRpb24ueCAvIFJlc29sdXRpb24ueTsnLFxuXG4gICAgICAgIC8vRGV0ZXJtaW5lIGRpc3RhbmNlICh1c2VkIGZvciBhdHRlbnVhdGlvbikgQkVGT1JFIHdlIG5vcm1hbGl6ZSBvdXIgTGlnaHREaXJcbiAgICAgICAgJyAgIGZsb2F0IEQgPSBsZW5ndGgoTGlnaHREaXIpOycsXG5cbiAgICAgICAgLy9ub3JtYWxpemUgb3VyIHZlY3RvcnNcbiAgICAgICAgJyAgIHZlYzMgTiA9IG5vcm1hbGl6ZShOb3JtYWxNYXAgKiAyLjAgLSAxLjApOycsXG4gICAgICAgICcgICB2ZWMzIEwgPSBub3JtYWxpemUoTGlnaHREaXIpOycsXG5cbiAgICAgICAgLy9QcmUtbXVsdGlwbHkgbGlnaHQgY29sb3Igd2l0aCBpbnRlbnNpdHlcbiAgICAgICAgLy9UaGVuIHBlcmZvcm0gJ04gZG90IEwnIHRvIGRldGVybWluZSBvdXIgZGlmZnVzZSB0ZXJtXG4gICAgICAgICcgICB2ZWMzIERpZmZ1c2UgPSAoTGlnaHRDb2xvci5yZ2IgKiBMaWdodENvbG9yLmEpICogbWF4KGRvdChOLCBMKSwgMC4wKTsnLFxuXG4gICAgICAgIC8vcHJlLW11bHRpcGx5IGFtYmllbnQgY29sb3Igd2l0aCBpbnRlbnNpdHlcbiAgICAgICAgJyAgIHZlYzMgQW1iaWVudCA9IEFtYmllbnRDb2xvci5yZ2IgKiBBbWJpZW50Q29sb3IuYTsnLFxuXG4gICAgICAgIC8vY2FsY3VsYXRlIGF0dGVudWF0aW9uXG4gICAgICAgICcgICBmbG9hdCBBdHRlbnVhdGlvbiA9IDEuMCAvICggRmFsbG9mZi54ICsgKEZhbGxvZmYueSpEKSArIChGYWxsb2ZmLnoqRCpEKSApOycsXG5cbiAgICAgICAgLy90aGUgY2FsY3VsYXRpb24gd2hpY2ggYnJpbmdzIGl0IGFsbCB0b2dldGhlclxuICAgICAgICAnICAgdmVjMyBJbnRlbnNpdHkgPSBBbWJpZW50ICsgRGlmZnVzZSAqIEF0dGVudWF0aW9uOycsXG4gICAgICAgICcgICB2ZWMzIEZpbmFsQ29sb3IgPSBEaWZmdXNlQ29sb3IucmdiICogSW50ZW5zaXR5OycsXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IgPSB2Q29sb3IgKiB2ZWM0KEZpbmFsQ29sb3IsIERpZmZ1c2VDb2xvci5hKTsnLFxuICAgICAgICAvLyAnICAgZ2xfRnJhZ0NvbG9yID0gdmVjNCgxLjAsIDAuMCwgMC4wLCBBdHRlbnVhdGlvbik7JywvL3ZDb2xvciAqIHZlYzQoRmluYWxDb2xvciwgRGlmZnVzZUNvbG9yLmEpOycsXG5cbiAgICAgICAgLyovLyBub3JtYWxpc2UgY29sb3JcbiAgICAgICAgJyAgIHZlYzMgbm9ybWFsID0gbm9ybWFsaXplKG5Db2xvciAqIDIuMCAtIDEuMCk7JyxcblxuICAgICAgICAnICAgdmVjMyBkZWx0YVBvcyA9IHZlYzMoIChsaWdodC54eSAtIGdsX0ZyYWdDb29yZC54eSkgLyByZXNvbHV0aW9uLnh5LCBsaWdodC56ICk7JyxcblxuICAgICAgICAnICAgZmxvYXQgbGFtYmVydCA9IGNsYW1wKGRvdChub3JtYWwsIGxpZ2h0RGlyKSwgMC4wLCAxLjApOycsXG5cbiAgICAgICAgJyAgIGZsb2F0IGQgPSBzcXJ0KGRvdChkZWx0YVBvcywgZGVsdGFQb3MpKTsnLFxuICAgICAgICAnICAgZmxvYXQgYXR0ID0gMS4wIC8gKCBhdHRlbnVhdGlvbi54ICsgKGF0dGVudWF0aW9uLnkqZCkgKyAoYXR0ZW51YXRpb24ueipkKmQpICk7JyxcblxuICAgICAgICAnICAgdmVjMyByZXN1bHQgPSAoYW1iaWVudENvbG9yICogYW1iaWVudEludGVuc2l0eSkgKyAobGlnaHRDb2xvci5yZ2IgKiBsYW1iZXJ0KSAqIGF0dDsnLFxuICAgICAgICAnICAgcmVzdWx0ICo9IGNvbG9yLnJnYjsnLFxuXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IgPSB2ZWM0KHJlc3VsdCwgMS4wKTsnLCovXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cbk5vcm1hbE1hcEZpbHRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEFic3RyYWN0RmlsdGVyLnByb3RvdHlwZSk7XG5Ob3JtYWxNYXBGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gTm9ybWFsTWFwRmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBOb3JtYWxNYXBGaWx0ZXI7XG5cbi8qKlxuICogU2V0cyB0aGUgbWFwIGRpbWVuc2lvbnMgdW5pZm9ybXMgd2hlbiB0aGUgdGV4dHVyZSBiZWNvbWVzIGF2YWlsYWJsZS5cbiAqXG4gKi9cbk5vcm1hbE1hcEZpbHRlci5wcm90b3R5cGUub25UZXh0dXJlTG9hZGVkID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMudW5pZm9ybXMubWFwRGltZW5zaW9ucy52YWx1ZS54ID0gdGhpcy51bmlmb3Jtcy5kaXNwbGFjZW1lbnRNYXAudmFsdWUud2lkdGg7XG4gICAgdGhpcy51bmlmb3Jtcy5tYXBEaW1lbnNpb25zLnZhbHVlLnkgPSB0aGlzLnVuaWZvcm1zLmRpc3BsYWNlbWVudE1hcC52YWx1ZS5oZWlnaHQ7XG5cbiAgICB0aGlzLnVuaWZvcm1zLmRpc3BsYWNlbWVudE1hcC52YWx1ZS5iYXNlVGV4dHVyZS5vZmYoJ2xvYWRlZCcsIHRoaXMuYm91bmRMb2FkZWRGdW5jdGlvbik7XG59O1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhOb3JtYWxNYXBGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHRleHR1cmUgdXNlZCBmb3IgdGhlIGRpc3BsYWNlbWVudCBtYXAuIE11c3QgYmUgcG93ZXIgb2YgMiB0ZXh0dXJlLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7VGV4dHVyZX1cbiAgICAgKiBAbWVtYmVyb2YgTm9ybWFsTWFwRmlsdGVyI1xuICAgICAqL1xuICAgIG1hcDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmRpc3BsYWNlbWVudE1hcC52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuZGlzcGxhY2VtZW50TWFwLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIG11bHRpcGxpZXIgdXNlZCB0byBzY2FsZSB0aGUgZGlzcGxhY2VtZW50IHJlc3VsdCBmcm9tIHRoZSBtYXAgY2FsY3VsYXRpb24uXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKiBAbWVtYmVyb2YgTm9ybWFsTWFwRmlsdGVyI1xuICAgICAqL1xuICAgIHNjYWxlOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudW5pZm9ybXMuc2NhbGUudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLnNjYWxlLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIG9mZnNldCB1c2VkIHRvIG1vdmUgdGhlIGRpc3BsYWNlbWVudCBtYXAuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKiBAbWVtYmVyb2YgTm9ybWFsTWFwRmlsdGVyI1xuICAgICAqL1xuICAgIG9mZnNldDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLm9mZnNldC52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMub2Zmc2V0LnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKTtcblxuLyoqXG4gKiBUaGlzIGZpbHRlciBhcHBsaWVzIGEgcGl4ZWxhdGUgZWZmZWN0IG1ha2luZyBkaXNwbGF5IG9iamVjdHMgYXBwZWFyICdibG9ja3knLlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBQaXhlbGF0ZUZpbHRlcigpIHtcbiAgICBBYnN0cmFjdEZpbHRlci5jYWxsKHRoaXMpO1xuXG4gICAgLy8gc2V0IHRoZSB1bmlmb3Jtc1xuICAgIHRoaXMudW5pZm9ybXMgPSB7XG4gICAgICAgIGludmVydDogICAgIHsgdHlwZTogJzFmJywgICB2YWx1ZTogMCB9LFxuICAgICAgICBkaW1lbnNpb25zOiB7IHR5cGU6ICc0ZnYnLCAgdmFsdWU6IG5ldyBGbG9hdDMyQXJyYXkoWzEwMDAwLCAxMDAsIDEwLCAxMF0pIH0sXG4gICAgICAgIHBpeGVsU2l6ZTogIHsgdHlwZTogJzJmJywgICB2YWx1ZTogeyB4OiAxMCwgeTogMTAgfSB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIHZlYzIgdGVzdERpbTsnLFxuICAgICAgICAndW5pZm9ybSB2ZWM0IGRpbWVuc2lvbnM7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBwaXhlbFNpemU7JyxcbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG5cbiAgICAgICAgJ3ZvaWQgbWFpbih2b2lkKSB7JyxcbiAgICAgICAgJyAgIHZlYzIgY29vcmQgPSB2VGV4dHVyZUNvb3JkOycsXG5cbiAgICAgICAgJyAgIHZlYzIgc2l6ZSA9IGRpbWVuc2lvbnMueHkvcGl4ZWxTaXplOycsXG5cbiAgICAgICAgJyAgIHZlYzIgY29sb3IgPSBmbG9vciggKCB2VGV4dHVyZUNvb3JkICogc2l6ZSApICkgLyBzaXplICsgcGl4ZWxTaXplL2RpbWVuc2lvbnMueHkgKiAwLjU7JyxcbiAgICAgICAgJyAgIGdsX0ZyYWdDb2xvciA9IHRleHR1cmUyRCh1U2FtcGxlciwgY29sb3IpOycsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cblBpeGVsYXRlRmlsdGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlKTtcblBpeGVsYXRlRmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFBpeGVsYXRlRmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBQaXhlbGF0ZUZpbHRlcjtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoUGl4ZWxhdGVGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhpcyBhIHBvaW50IHRoYXQgZGVzY3JpYmVzIHRoZSBzaXplIG9mIHRoZSBibG9ja3MuIHggaXMgdGhlIHdpZHRoIG9mIHRoZSBibG9jayBhbmQgeSBpcyB0aGUgaGVpZ2h0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICogQG1lbWJlcm9mIFBpeGVsYXRlRmlsdGVyI1xuICAgICAqL1xuICAgIHNpemU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5waXhlbFNpemUudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLnBpeGVsU2l6ZS52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyk7XG5cbi8qKlxuICogQW4gUkdCIFNwbGl0IEZpbHRlci5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gUkdCU3BsaXRGaWx0ZXIoKSB7XG4gICAgQWJzdHJhY3RGaWx0ZXIuY2FsbCh0aGlzKTtcblxuICAgIHRoaXMucGFzc2VzID0gW3RoaXNdO1xuXG4gICAgLy8gc2V0IHRoZSB1bmlmb3Jtc1xuICAgIHRoaXMudW5pZm9ybXMgPSB7XG4gICAgICAgIHJlZDogICAgICAgIHsgdHlwZTogJzJmJywgdmFsdWU6IHsgeDogMjAsIHk6IDIwIH0gfSxcbiAgICAgICAgZ3JlZW46ICAgICAgeyB0eXBlOiAnMmYnLCB2YWx1ZTogeyB4OiAtMjAsIHk6IDIwIH0gfSxcbiAgICAgICAgYmx1ZTogICAgICAgeyB0eXBlOiAnMmYnLCB2YWx1ZTogeyB4OiAyMCwgeTogLTIwIH0gfSxcbiAgICAgICAgZGltZW5zaW9uczogeyB0eXBlOiAnNGZ2JywgdmFsdWU6IFswLCAwLCAwLCAwXSB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIHZlYzIgcmVkOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzIgZ3JlZW47JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBibHVlOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzQgZGltZW5zaW9uczsnLFxuICAgICAgICAndW5pZm9ybSBzYW1wbGVyMkQgdVNhbXBsZXI7JyxcblxuICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yLnIgPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZUZXh0dXJlQ29vcmQgKyByZWQvZGltZW5zaW9ucy54eSkucjsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yLmcgPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZUZXh0dXJlQ29vcmQgKyBncmVlbi9kaW1lbnNpb25zLnh5KS5nOycsXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IuYiA9IHRleHR1cmUyRCh1U2FtcGxlciwgdlRleHR1cmVDb29yZCArIGJsdWUvZGltZW5zaW9ucy54eSkuYjsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yLmEgPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZUZXh0dXJlQ29vcmQpLmE7JyxcbiAgICAgICAgJ30nXG4gICAgXTtcbn1cblxuUkdCU3BsaXRGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuUkdCU3BsaXRGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gUkdCU3BsaXRGaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFJHQlNwbGl0RmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhSR0JTcGxpdEZpbHRlci5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBSZWQgY2hhbm5lbCBvZmZzZXQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKiBAbWVtYmVyb2YgUkdCU3BsaXRGaWx0ZXIjXG4gICAgICovXG4gICAgcmVkOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudW5pZm9ybXMucmVkLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5yZWQudmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBHcmVlbiBjaGFubmVsIG9mZnNldC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1BvaW50fVxuICAgICAqIEBtZW1iZXJvZiBSR0JTcGxpdEZpbHRlciNcbiAgICAgKi9cbiAgICBncmVlbjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmdyZWVuLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5ncmVlbi52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEJsdWUgb2Zmc2V0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICogQG1lbWJlcm9mIFJHQlNwbGl0RmlsdGVyI1xuICAgICAqL1xuICAgIGJsdWU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5ibHVlLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5ibHVlLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKTtcblxuLyoqXG4gKiBUaGlzIGFwcGxpZXMgYSBzZXBpYSBlZmZlY3QgdG8geW91ciBEaXNwbGF5IE9iamVjdHMuXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBBYnN0cmFjdEZpbHRlclxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbmZ1bmN0aW9uIFNlcGlhRmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgc2VwaWE6IHsgdHlwZTogJzFmJywgdmFsdWU6IDEgfVxuICAgIH07XG5cbiAgICB0aGlzLmZyYWdtZW50U3JjID0gW1xuICAgICAgICAncHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7JyxcblxuICAgICAgICAndmFyeWluZyB2ZWMyIHZUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAndW5pZm9ybSBmbG9hdCBzZXBpYTsnLFxuICAgICAgICAndW5pZm9ybSBzYW1wbGVyMkQgdVNhbXBsZXI7JyxcblxuICAgICAgICAnY29uc3QgbWF0MyBzZXBpYU1hdHJpeCA9IG1hdDMoMC4zNTg4LCAwLjcwNDQsIDAuMTM2OCwgMC4yOTkwLCAwLjU4NzAsIDAuMTE0MCwgMC4yMzkyLCAwLjQ2OTYsIDAuMDkxMik7JyxcblxuICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkKTsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yLnJnYiA9IG1peCggZ2xfRnJhZ0NvbG9yLnJnYiwgZ2xfRnJhZ0NvbG9yLnJnYiAqIHNlcGlhTWF0cml4LCBzZXBpYSk7JyxcbiAgICAgICAgJ30nXG4gICAgXTtcbn1cblxuU2VwaWFGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuU2VwaWFGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gU2VwaWFGaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFNlcGlhRmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhTZXBpYUZpbHRlci5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBUaGUgc3RyZW5ndGggb2YgdGhlIHNlcGlhLiAxIHdpbGwgYXBwbHkgdGhlIGZ1bGwgc2VwaWEgZWZmZWN0LCAwIHdpbGwgbWFrZSB0aGUgb2JqZWN0IGl0cyBub3JtYWwgY29sb3IuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIFNlcGlhRmlsdGVyI1xuICAgICAqL1xuICAgIHNlcGlhOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudW5pZm9ybXMuc2VwaWEudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLnNlcGlhLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKTtcblxuLyoqXG4gKiBBIFNtYXJ0IEJsdXIgRmlsdGVyLlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBTbWFydEJsdXJGaWx0ZXIoKSB7XG4gICAgQWJzdHJhY3RGaWx0ZXIuY2FsbCh0aGlzKTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCB1U2FtcGxlcjsnLFxuICAgICAgICAnY29uc3QgdmVjMiBkZWx0YSA9IHZlYzIoMS4wLzEwLjAsIDAuMCk7JyxcblxuICAgICAgICAnZmxvYXQgcmFuZG9tKHZlYzMgc2NhbGUsIGZsb2F0IHNlZWQpIHsnLFxuICAgICAgICAnICAgcmV0dXJuIGZyYWN0KHNpbihkb3QoZ2xfRnJhZ0Nvb3JkLnh5eiArIHNlZWQsIHNjYWxlKSkgKiA0Mzc1OC41NDUzICsgc2VlZCk7JyxcbiAgICAgICAgJ30nLFxuXG5cbiAgICAgICAgJ3ZvaWQgbWFpbih2b2lkKSB7JyxcbiAgICAgICAgJyAgIHZlYzQgY29sb3IgPSB2ZWM0KDAuMCk7JyxcbiAgICAgICAgJyAgIGZsb2F0IHRvdGFsID0gMC4wOycsXG5cbiAgICAgICAgJyAgIGZsb2F0IG9mZnNldCA9IHJhbmRvbSh2ZWMzKDEyLjk4OTgsIDc4LjIzMywgMTUxLjcxODIpLCAwLjApOycsXG5cbiAgICAgICAgJyAgIGZvciAoZmxvYXQgdCA9IC0zMC4wOyB0IDw9IDMwLjA7IHQrKykgeycsXG4gICAgICAgICcgICAgICAgZmxvYXQgcGVyY2VudCA9ICh0ICsgb2Zmc2V0IC0gMC41KSAvIDMwLjA7JyxcbiAgICAgICAgJyAgICAgICBmbG9hdCB3ZWlnaHQgPSAxLjAgLSBhYnMocGVyY2VudCk7JyxcbiAgICAgICAgJyAgICAgICB2ZWM0IHNhbXBsZSA9IHRleHR1cmUyRCh1U2FtcGxlciwgdlRleHR1cmVDb29yZCArIGRlbHRhICogcGVyY2VudCk7JyxcbiAgICAgICAgJyAgICAgICBzYW1wbGUucmdiICo9IHNhbXBsZS5hOycsXG4gICAgICAgICcgICAgICAgY29sb3IgKz0gc2FtcGxlICogd2VpZ2h0OycsXG4gICAgICAgICcgICAgICAgdG90YWwgKz0gd2VpZ2h0OycsXG4gICAgICAgICcgICB9JyxcblxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gY29sb3IgLyB0b3RhbDsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yLnJnYiAvPSBnbF9GcmFnQ29sb3IuYSArIDAuMDAwMDE7JyxcbiAgICAgICAgJ30nXG4gICAgXTtcbn1cblxuU21hcnRCbHVyRmlsdGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlKTtcblNtYXJ0Qmx1ckZpbHRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBTbWFydEJsdXJGaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFNtYXJ0Qmx1ckZpbHRlcjtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKSxcbiAgICBUaWx0U2hpZnRYRmlsdGVyID0gcmVxdWlyZSgnLi9UaWx0U2hpZnRYRmlsdGVyJyksXG4gICAgVGlsdFNoaWZ0WUZpbHRlciA9IHJlcXVpcmUoJy4vVGlsdFNoaWZ0WUZpbHRlcicpO1xuXG4vKipcbiAqIEBhdXRob3IgVmljbyBAdmljb2NvdGVhXG4gKiBvcmlnaW5hbCBmaWx0ZXIgaHR0cHM6Ly9naXRodWIuY29tL2V2YW53L2dsZnguanMvYmxvYi9tYXN0ZXIvc3JjL2ZpbHRlcnMvYmx1ci90aWx0c2hpZnQuanMgYnkgRXZhbiBXYWxsYWNlIDogaHR0cDovL21hZGVieWV2YW4uY29tL1xuICovXG5cbi8qKlxuICogQSBUaWx0U2hpZnQgRmlsdGVyLiBNYW5hZ2VzIHRoZSBwYXNzIG9mIGJvdGggYSBUaWx0U2hpZnRYRmlsdGVyIGFuZCBUaWx0U2hpZnRZRmlsdGVyLlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBUaWx0U2hpZnRGaWx0ZXIoKSB7XG4gICAgQWJzdHJhY3RGaWx0ZXIuY2FsbCh0aGlzKTtcblxuICAgIHRoaXMudGlsdFNoaWZ0WEZpbHRlciA9IG5ldyBUaWx0U2hpZnRYRmlsdGVyKCk7XG4gICAgdGhpcy50aWx0U2hpZnRZRmlsdGVyID0gbmV3IFRpbHRTaGlmdFlGaWx0ZXIoKTtcblxuICAgIHRoaXMudGlsdFNoaWZ0WEZpbHRlci51cGRhdGVEZWx0YSgpO1xuICAgIHRoaXMudGlsdFNoaWZ0WEZpbHRlci51cGRhdGVEZWx0YSgpO1xuXG4gICAgdGhpcy5wYXNzZXMgPSBbdGhpcy50aWx0U2hpZnRYRmlsdGVyLCB0aGlzLnRpbHRTaGlmdFlGaWx0ZXJdO1xufVxuXG5UaWx0U2hpZnRGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuVGlsdFNoaWZ0RmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFRpbHRTaGlmdEZpbHRlcjtcbm1vZHVsZS5leHBvcnRzID0gVGlsdFNoaWZ0RmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhUaWx0U2hpZnRGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHN0cmVuZ3RoIG9mIHRoZSBibHVyLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUaWx0U2hpZnRGaWx0ZXIjXG4gICAgICovXG4gICAgYmx1cjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnRpbHRTaGlmdFhGaWx0ZXIuYmx1cjtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudGlsdFNoaWZ0WEZpbHRlci5ibHVyID0gdGhpcy50aWx0U2hpZnRZRmlsdGVyLmJsdXIgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgc3RyZW5ndGggb2YgdGhlIGdyYWRpZW50IGJsdXIuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIFRpbHRTaGlmdEZpbHRlciNcbiAgICAgKi9cbiAgICBncmFkaWVudEJsdXI6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy50aWx0U2hpZnRYRmlsdGVyLmdyYWRpZW50Qmx1cjtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudGlsdFNoaWZ0WEZpbHRlci5ncmFkaWVudEJsdXIgPSB0aGlzLnRpbHRTaGlmdFlGaWx0ZXIuZ3JhZGllbnRCbHVyID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIFkgdmFsdWUgdG8gc3RhcnQgdGhlIGVmZmVjdCBhdC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgVGlsdFNoaWZ0RmlsdGVyI1xuICAgICAqL1xuICAgIHN0YXJ0OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudGlsdFNoaWZ0WEZpbHRlci5zdGFydDtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudGlsdFNoaWZ0WEZpbHRlci5zdGFydCA9IHRoaXMudGlsdFNoaWZ0WUZpbHRlci5zdGFydCA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBZIHZhbHVlIHRvIGVuZCB0aGUgZWZmZWN0IGF0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUaWx0U2hpZnRGaWx0ZXIjXG4gICAgICovXG4gICAgZW5kOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudGlsdFNoaWZ0WEZpbHRlci5lbmQ7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnRpbHRTaGlmdFhGaWx0ZXIuZW5kID0gdGhpcy50aWx0U2hpZnRZRmlsdGVyLmVuZCA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcbn0pO1xuIiwidmFyIEFic3RyYWN0RmlsdGVyID0gcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpO1xuXG4vKipcbiAqIEBhdXRob3IgVmljbyBAdmljb2NvdGVhXG4gKiBvcmlnaW5hbCBmaWx0ZXIgaHR0cHM6Ly9naXRodWIuY29tL2V2YW53L2dsZnguanMvYmxvYi9tYXN0ZXIvc3JjL2ZpbHRlcnMvYmx1ci90aWx0c2hpZnQuanMgYnkgRXZhbiBXYWxsYWNlIDogaHR0cDovL21hZGVieWV2YW4uY29tL1xuICovXG5cbi8qKlxuICogQSBUaWx0U2hpZnRYRmlsdGVyLlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBUaWx0U2hpZnRYRmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgYmx1cjogICAgICAgICAgIHsgdHlwZTogJzFmJywgdmFsdWU6IDEwMCB9LFxuICAgICAgICBncmFkaWVudEJsdXI6ICAgeyB0eXBlOiAnMWYnLCB2YWx1ZTogNjAwIH0sXG4gICAgICAgIHN0YXJ0OiAgICAgICAgICB7IHR5cGU6ICcyZicsIHZhbHVlOiB7IHg6IDAsICAgIHk6IHdpbmRvdy5zY3JlZW5IZWlnaHQgLyAyIH0gfSxcbiAgICAgICAgZW5kOiAgICAgICAgICAgIHsgdHlwZTogJzJmJywgdmFsdWU6IHsgeDogNjAwLCAgeTogd2luZG93LnNjcmVlbkhlaWdodCAvIDIgfSB9LFxuICAgICAgICBkZWx0YTogICAgICAgICAgeyB0eXBlOiAnMmYnLCB2YWx1ZTogeyB4OiAzMCwgICB5OiAzMCB9IH0sXG4gICAgICAgIHRleFNpemU6ICAgICAgICB7IHR5cGU6ICcyZicsIHZhbHVlOiB7IHg6IHdpbmRvdy5zY3JlZW5XaWR0aCwgeTogd2luZG93LnNjcmVlbkhlaWdodCB9IH1cbiAgICB9O1xuXG4gICAgdGhpcy51cGRhdGVEZWx0YSgpO1xuXG4gICAgdGhpcy5mcmFnbWVudFNyYyA9IFtcbiAgICAgICAgJ3ByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OycsXG5cbiAgICAgICAgJ3ZhcnlpbmcgdmVjMiB2VGV4dHVyZUNvb3JkOycsXG5cbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IGJsdXI7JyxcbiAgICAgICAgJ3VuaWZvcm0gZmxvYXQgZ3JhZGllbnRCbHVyOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzIgc3RhcnQ7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBlbmQ7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBkZWx0YTsnLFxuICAgICAgICAndW5pZm9ybSB2ZWMyIHRleFNpemU7JyxcblxuICAgICAgICAnZmxvYXQgcmFuZG9tKHZlYzMgc2NhbGUsIGZsb2F0IHNlZWQpIHsnLFxuICAgICAgICAnICAgcmV0dXJuIGZyYWN0KHNpbihkb3QoZ2xfRnJhZ0Nvb3JkLnh5eiArIHNlZWQsIHNjYWxlKSkgKiA0Mzc1OC41NDUzICsgc2VlZCk7JyxcbiAgICAgICAgJ30nLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICAgdmVjNCBjb2xvciA9IHZlYzQoMC4wKTsnLFxuICAgICAgICAnICAgIGZsb2F0IHRvdGFsID0gMC4wOycsXG5cbiAgICAgICAgJyAgICBmbG9hdCBvZmZzZXQgPSByYW5kb20odmVjMygxMi45ODk4LCA3OC4yMzMsIDE1MS43MTgyKSwgMC4wKTsnLFxuICAgICAgICAnICAgIHZlYzIgbm9ybWFsID0gbm9ybWFsaXplKHZlYzIoc3RhcnQueSAtIGVuZC55LCBlbmQueCAtIHN0YXJ0LngpKTsnLFxuICAgICAgICAnICAgIGZsb2F0IHJhZGl1cyA9IHNtb290aHN0ZXAoMC4wLCAxLjAsIGFicyhkb3QodlRleHR1cmVDb29yZCAqIHRleFNpemUgLSBzdGFydCwgbm9ybWFsKSkgLyBncmFkaWVudEJsdXIpICogYmx1cjsnLFxuXG4gICAgICAgICcgICAgZm9yIChmbG9hdCB0ID0gLTMwLjA7IHQgPD0gMzAuMDsgdCsrKSB7JyxcbiAgICAgICAgJyAgICAgICAgZmxvYXQgcGVyY2VudCA9ICh0ICsgb2Zmc2V0IC0gMC41KSAvIDMwLjA7JyxcbiAgICAgICAgJyAgICAgICAgZmxvYXQgd2VpZ2h0ID0gMS4wIC0gYWJzKHBlcmNlbnQpOycsXG4gICAgICAgICcgICAgICAgIHZlYzQgc2FtcGxlID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkICsgZGVsdGEgLyB0ZXhTaXplICogcGVyY2VudCAqIHJhZGl1cyk7JyxcbiAgICAgICAgJyAgICAgICAgc2FtcGxlLnJnYiAqPSBzYW1wbGUuYTsnLFxuICAgICAgICAnICAgICAgICBjb2xvciArPSBzYW1wbGUgKiB3ZWlnaHQ7JyxcbiAgICAgICAgJyAgICAgICAgdG90YWwgKz0gd2VpZ2h0OycsXG4gICAgICAgICcgICAgfScsXG5cbiAgICAgICAgJyAgICBnbF9GcmFnQ29sb3IgPSBjb2xvciAvIHRvdGFsOycsXG4gICAgICAgICcgICAgZ2xfRnJhZ0NvbG9yLnJnYiAvPSBnbF9GcmFnQ29sb3IuYSArIDAuMDAwMDE7JyxcbiAgICAgICAgJ30nXG4gICAgXTtcbn1cblxuVGlsdFNoaWZ0WEZpbHRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEFic3RyYWN0RmlsdGVyLnByb3RvdHlwZSk7XG5UaWx0U2hpZnRYRmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFRpbHRTaGlmdFhGaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFRpbHRTaGlmdFhGaWx0ZXI7XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgZmlsdGVyIGRlbHRhIHZhbHVlcy5cbiAqXG4gKi9cblRpbHRTaGlmdFhGaWx0ZXIucHJvdG90eXBlLnVwZGF0ZURlbHRhID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBkeCA9IHRoaXMudW5pZm9ybXMuZW5kLnZhbHVlLnggLSB0aGlzLnVuaWZvcm1zLnN0YXJ0LnZhbHVlLng7XG4gICAgdmFyIGR5ID0gdGhpcy51bmlmb3Jtcy5lbmQudmFsdWUueSAtIHRoaXMudW5pZm9ybXMuc3RhcnQudmFsdWUueTtcbiAgICB2YXIgZCA9IE1hdGguc3FydChkeCAqIGR4ICsgZHkgKiBkeSk7XG5cbiAgICB0aGlzLnVuaWZvcm1zLmRlbHRhLnZhbHVlLnggPSBkeCAvIGQ7XG4gICAgdGhpcy51bmlmb3Jtcy5kZWx0YS52YWx1ZS55ID0gZHkgLyBkO1xufTtcblxuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhUaWx0U2hpZnRYRmlsdGVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSBzdHJlbmd0aCBvZiB0aGUgYmx1ci5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgVGlsdHRTaGlmdFhGaWx0ZXIjXG4gICAgICovXG4gICAgYmx1cjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmJsdXIudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLmJsdXIudmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgc3RyZW5ndGggb2YgdGhlIGdyYWRpZW50IGJsdXIuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIFRpbHR0U2hpZnRYRmlsdGVyI1xuICAgICAqL1xuICAgIGdyYWRpZW50Qmx1cjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmdyYWRpZW50Qmx1ci52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuZ3JhZGllbnRCbHVyLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIFggdmFsdWUgdG8gc3RhcnQgdGhlIGVmZmVjdCBhdC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgVGlsdHRTaGlmdFhGaWx0ZXIjXG4gICAgICovXG4gICAgc3RhcnQ6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5zdGFydC52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuc3RhcnQudmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlRGVsdGEoKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgWCB2YWx1ZSB0byBlbmQgdGhlIGVmZmVjdCBhdC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgVGlsdHRTaGlmdFhGaWx0ZXIjXG4gICAgICovXG4gICAgZW5kOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudW5pZm9ybXMuZW5kLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5lbmQudmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlRGVsdGEoKTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuIiwidmFyIEFic3RyYWN0RmlsdGVyID0gcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpO1xuXG4vKipcbiAqIEBhdXRob3IgVmljbyBAdmljb2NvdGVhXG4gKiBvcmlnaW5hbCBmaWx0ZXIgaHR0cHM6Ly9naXRodWIuY29tL2V2YW53L2dsZnguanMvYmxvYi9tYXN0ZXIvc3JjL2ZpbHRlcnMvYmx1ci90aWx0c2hpZnQuanMgYnkgRXZhbiBXYWxsYWNlIDogaHR0cDovL21hZGVieWV2YW4uY29tL1xuICovXG5cbi8qKlxuICogQSBUaWx0U2hpZnRZRmlsdGVyLlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBUaWx0U2hpZnRZRmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgYmx1cjogICAgICAgICAgIHsgdHlwZTogJzFmJywgdmFsdWU6IDEwMCB9LFxuICAgICAgICBncmFkaWVudEJsdXI6ICAgeyB0eXBlOiAnMWYnLCB2YWx1ZTogNjAwIH0sXG4gICAgICAgIHN0YXJ0OiAgICAgICAgICB7IHR5cGU6ICcyZicsIHZhbHVlOiB7IHg6IDAsICAgIHk6IHdpbmRvdy5zY3JlZW5IZWlnaHQgLyAyIH0gfSxcbiAgICAgICAgZW5kOiAgICAgICAgICAgIHsgdHlwZTogJzJmJywgdmFsdWU6IHsgeDogNjAwLCAgeTogd2luZG93LnNjcmVlbkhlaWdodCAvIDIgfSB9LFxuICAgICAgICBkZWx0YTogICAgICAgICAgeyB0eXBlOiAnMmYnLCB2YWx1ZTogeyB4OiAzMCwgICB5OiAzMCB9IH0sXG4gICAgICAgIHRleFNpemU6ICAgICAgICB7IHR5cGU6ICcyZicsIHZhbHVlOiB7IHg6IHdpbmRvdy5zY3JlZW5XaWR0aCwgeTogd2luZG93LnNjcmVlbkhlaWdodCB9IH1cbiAgICB9O1xuXG4gICAgdGhpcy51cGRhdGVEZWx0YSgpO1xuXG4gICAgdGhpcy5mcmFnbWVudFNyYyA9IFtcbiAgICAgICAgJ3ByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OycsXG5cbiAgICAgICAgJ3ZhcnlpbmcgdmVjMiB2VGV4dHVyZUNvb3JkOycsXG5cbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IGJsdXI7JyxcbiAgICAgICAgJ3VuaWZvcm0gZmxvYXQgZ3JhZGllbnRCbHVyOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzIgc3RhcnQ7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBlbmQ7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBkZWx0YTsnLFxuICAgICAgICAndW5pZm9ybSB2ZWMyIHRleFNpemU7JyxcblxuICAgICAgICAnZmxvYXQgcmFuZG9tKHZlYzMgc2NhbGUsIGZsb2F0IHNlZWQpIHsnLFxuICAgICAgICAnICAgcmV0dXJuIGZyYWN0KHNpbihkb3QoZ2xfRnJhZ0Nvb3JkLnh5eiArIHNlZWQsIHNjYWxlKSkgKiA0Mzc1OC41NDUzICsgc2VlZCk7JyxcbiAgICAgICAgJ30nLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICAgdmVjNCBjb2xvciA9IHZlYzQoMC4wKTsnLFxuICAgICAgICAnICAgIGZsb2F0IHRvdGFsID0gMC4wOycsXG5cbiAgICAgICAgJyAgICBmbG9hdCBvZmZzZXQgPSByYW5kb20odmVjMygxMi45ODk4LCA3OC4yMzMsIDE1MS43MTgyKSwgMC4wKTsnLFxuICAgICAgICAnICAgIHZlYzIgbm9ybWFsID0gbm9ybWFsaXplKHZlYzIoc3RhcnQueSAtIGVuZC55LCBlbmQueCAtIHN0YXJ0LngpKTsnLFxuICAgICAgICAnICAgIGZsb2F0IHJhZGl1cyA9IHNtb290aHN0ZXAoMC4wLCAxLjAsIGFicyhkb3QodlRleHR1cmVDb29yZCAqIHRleFNpemUgLSBzdGFydCwgbm9ybWFsKSkgLyBncmFkaWVudEJsdXIpICogYmx1cjsnLFxuXG4gICAgICAgICcgICAgZm9yIChmbG9hdCB0ID0gLTMwLjA7IHQgPD0gMzAuMDsgdCsrKSB7JyxcbiAgICAgICAgJyAgICAgICAgZmxvYXQgcGVyY2VudCA9ICh0ICsgb2Zmc2V0IC0gMC41KSAvIDMwLjA7JyxcbiAgICAgICAgJyAgICAgICAgZmxvYXQgd2VpZ2h0ID0gMS4wIC0gYWJzKHBlcmNlbnQpOycsXG4gICAgICAgICcgICAgICAgIHZlYzQgc2FtcGxlID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkICsgZGVsdGEgLyB0ZXhTaXplICogcGVyY2VudCAqIHJhZGl1cyk7JyxcbiAgICAgICAgJyAgICAgICAgc2FtcGxlLnJnYiAqPSBzYW1wbGUuYTsnLFxuICAgICAgICAnICAgICAgICBjb2xvciArPSBzYW1wbGUgKiB3ZWlnaHQ7JyxcbiAgICAgICAgJyAgICAgICAgdG90YWwgKz0gd2VpZ2h0OycsXG4gICAgICAgICcgICAgfScsXG5cbiAgICAgICAgJyAgICBnbF9GcmFnQ29sb3IgPSBjb2xvciAvIHRvdGFsOycsXG4gICAgICAgICcgICAgZ2xfRnJhZ0NvbG9yLnJnYiAvPSBnbF9GcmFnQ29sb3IuYSArIDAuMDAwMDE7JyxcbiAgICAgICAgJ30nXG4gICAgXTtcbn1cblxuVGlsdFNoaWZ0WUZpbHRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEFic3RyYWN0RmlsdGVyLnByb3RvdHlwZSk7XG5UaWx0U2hpZnRZRmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFRpbHRTaGlmdFlGaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFRpbHRTaGlmdFlGaWx0ZXI7XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgZmlsdGVyIGRlbHRhIHZhbHVlcy5cbiAqXG4gKi9cblRpbHRTaGlmdFlGaWx0ZXIucHJvdG90eXBlLnVwZGF0ZURlbHRhID0gZnVuY3Rpb24gKCl7XG4gICAgdmFyIGR4ID0gdGhpcy51bmlmb3Jtcy5lbmQudmFsdWUueCAtIHRoaXMudW5pZm9ybXMuc3RhcnQudmFsdWUueDtcbiAgICB2YXIgZHkgPSB0aGlzLnVuaWZvcm1zLmVuZC52YWx1ZS55IC0gdGhpcy51bmlmb3Jtcy5zdGFydC52YWx1ZS55O1xuICAgIHZhciBkID0gTWF0aC5zcXJ0KGR4ICogZHggKyBkeSAqIGR5KTtcbiAgICB0aGlzLnVuaWZvcm1zLmRlbHRhLnZhbHVlLnggPSAtZHkgLyBkO1xuICAgIHRoaXMudW5pZm9ybXMuZGVsdGEudmFsdWUueSA9IGR4IC8gZDtcbn07XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKFRpbHRTaGlmdFlGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHN0cmVuZ3RoIG9mIHRoZSBibHVyLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUaWx0U2hpZnRZRmlsdGVyI1xuICAgICAqL1xuICAgIGJsdXI6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5ibHVyLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5ibHVyLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIHN0cmVuZ3RoIG9mIHRoZSBncmFkaWVudCBibHVyLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUaWx0U2hpZnRZRmlsdGVyI1xuICAgICAqL1xuICAgIGdyYWRpZW50Qmx1cjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmdyYWRpZW50Qmx1ci52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuZ3JhZGllbnRCbHVyLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIFkgdmFsdWUgdG8gc3RhcnQgdGhlIGVmZmVjdCBhdC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgVGlsdFNoaWZ0WUZpbHRlciNcbiAgICAgKi9cbiAgICBzdGFydDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLnN0YXJ0LnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5zdGFydC52YWx1ZSA9IHZhbHVlO1xuICAgICAgICAgICAgdGhpcy51cGRhdGVEZWx0YSgpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBZIHZhbHVlIHRvIGVuZCB0aGUgZWZmZWN0IGF0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUaWx0U2hpZnRZRmlsdGVyI1xuICAgICAqL1xuICAgIGVuZDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmVuZC52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuZW5kLnZhbHVlID0gdmFsdWU7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZURlbHRhKCk7XG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKTtcblxuLyoqXG4gKiBUaGlzIGZpbHRlciBhcHBsaWVzIGEgdHdpc3QgZWZmZWN0IG1ha2luZyBkaXNwbGF5IG9iamVjdHMgYXBwZWFyIHR3aXN0ZWQgaW4gdGhlIGdpdmVuIGRpcmVjdGlvbi5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gVHdpc3RGaWx0ZXIoKSB7XG4gICAgQWJzdHJhY3RGaWx0ZXIuY2FsbCh0aGlzKTtcblxuICAgIC8vIHNldCB0aGUgdW5pZm9ybXNcbiAgICB0aGlzLnVuaWZvcm1zID0ge1xuICAgICAgICByYWRpdXM6ICAgICB7IHR5cGU6ICcxZicsIHZhbHVlOiAwLjV9LFxuICAgICAgICBhbmdsZTogICAgICB7IHR5cGU6ICcxZicsIHZhbHVlOiA1fSxcbiAgICAgICAgb2Zmc2V0OiAgICAgeyB0eXBlOiAnMmYnLCB2YWx1ZTogeyB4OiAwLjUsIHk6IDAuNSB9IH1cbiAgICB9O1xuXG4gICAgdGhpcy5mcmFnbWVudFNyYyA9IFtcbiAgICAgICAgJ3ByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OycsXG5cbiAgICAgICAgJ3ZhcnlpbmcgdmVjMiB2VGV4dHVyZUNvb3JkOycsXG4gICAgICAgICd2YXJ5aW5nIHZlYzQgdkNvbG9yOycsXG5cbiAgICAgICAgJ3VuaWZvcm0gZmxvYXQgcmFkaXVzOycsXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IGFuZ2xlOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzIgb2Zmc2V0OycsXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCB1U2FtcGxlcjsnLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICB2ZWMyIGNvb3JkID0gdlRleHR1cmVDb29yZCAtIG9mZnNldDsnLFxuICAgICAgICAnICAgZmxvYXQgZGlzdGFuY2UgPSBsZW5ndGgoY29vcmQpOycsXG5cbiAgICAgICAgJyAgIGlmIChkaXN0YW5jZSA8IHJhZGl1cykgeycsXG4gICAgICAgICcgICAgICAgZmxvYXQgcmF0aW8gPSAocmFkaXVzIC0gZGlzdGFuY2UpIC8gcmFkaXVzOycsXG4gICAgICAgICcgICAgICAgZmxvYXQgYW5nbGVNb2QgPSByYXRpbyAqIHJhdGlvICogYW5nbGU7JyxcbiAgICAgICAgJyAgICAgICBmbG9hdCBzID0gc2luKGFuZ2xlTW9kKTsnLFxuICAgICAgICAnICAgICAgIGZsb2F0IGMgPSBjb3MoYW5nbGVNb2QpOycsXG4gICAgICAgICcgICAgICAgY29vcmQgPSB2ZWMyKGNvb3JkLnggKiBjIC0gY29vcmQueSAqIHMsIGNvb3JkLnggKiBzICsgY29vcmQueSAqIGMpOycsXG4gICAgICAgICcgICB9JyxcblxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gdGV4dHVyZTJEKHVTYW1wbGVyLCBjb29yZCtvZmZzZXQpOycsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cblR3aXN0RmlsdGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlKTtcblR3aXN0RmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFR3aXN0RmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBUd2lzdEZpbHRlcjtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoVHdpc3RGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhpcyBwb2ludCBkZXNjcmliZXMgdGhlIHRoZSBvZmZzZXQgb2YgdGhlIHR3aXN0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICogQG1lbWJlcm9mIFR3aXN0RmlsdGVyI1xuICAgICAqL1xuICAgIG9mZnNldDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLm9mZnNldC52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMub2Zmc2V0LnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhpcyByYWRpdXMgb2YgdGhlIHR3aXN0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUd2lzdEZpbHRlciNcbiAgICAgKi9cbiAgICByYWRpdXM6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5yYWRpdXMudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLnJhZGl1cy52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoaXMgYW5nbGUgb2YgdGhlIHR3aXN0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUd2lzdEZpbHRlciNcbiAgICAgKi9cbiAgICBhbmdsZToge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmFuZ2xlLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5hbmdsZS52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCIvKipcbiAqIEBmaWxlICAgICAgICBNYWluIGV4cG9ydCBvZiB0aGUgUElYSSBmaWx0ZXJzIGxpYnJhcnlcbiAqIEBhdXRob3IgICAgICBNYXQgR3JvdmVzIDxtYXRAZ29vZGJveWRpZ2l0YWwuY29tPlxuICogQGNvcHlyaWdodCAgIDIwMTMtMjAxNSBHb29kQm95RGlnaXRhbFxuICogQGxpY2Vuc2UgICAgIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vR29vZEJveURpZ2l0YWwvcGl4aS5qcy9ibG9iL21hc3Rlci9MSUNFTlNFfE1JVCBMaWNlbnNlfVxuICovXG5cbi8qKlxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEFic3RyYWN0RmlsdGVyOiAgICAgcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpLFxuICAgIEFscGhhTWFza0ZpbHRlcjogICAgcmVxdWlyZSgnLi9BbHBoYU1hc2tGaWx0ZXInKSxcbiAgICBBc2NpaUZpbHRlcjogICAgICAgIHJlcXVpcmUoJy4vQXNjaWlGaWx0ZXInKSxcbiAgICBCbHVyRmlsdGVyOiAgICAgICAgIHJlcXVpcmUoJy4vQmx1ckZpbHRlcicpLFxuICAgIEJsdXJYRmlsdGVyOiAgICAgICAgcmVxdWlyZSgnLi9CbHVyWEZpbHRlcicpLFxuICAgIEJsdXJZRmlsdGVyOiAgICAgICAgcmVxdWlyZSgnLi9CbHVyWUZpbHRlcicpLFxuICAgIENvbG9yTWF0cml4RmlsdGVyOiAgcmVxdWlyZSgnLi9Db2xvck1hdHJpeEZpbHRlcicpLFxuICAgIENvbG9yU3RlcEZpbHRlcjogICAgcmVxdWlyZSgnLi9Db2xvclN0ZXBGaWx0ZXInKSxcbiAgICBDb252b2x1dGlvbkZpbHRlcjogIHJlcXVpcmUoJy4vQ29udm9sdXRpb25GaWx0ZXInKSxcbiAgICBDcm9zc0hhdGNoRmlsdGVyOiAgIHJlcXVpcmUoJy4vQ3Jvc3NIYXRjaEZpbHRlcicpLFxuICAgIERpc3BsYWNlbWVudEZpbHRlcjogcmVxdWlyZSgnLi9EaXNwbGFjZW1lbnRGaWx0ZXInKSxcbiAgICBEb3RTY3JlZW5GaWx0ZXI6ICAgIHJlcXVpcmUoJy4vRG90U2NyZWVuRmlsdGVyJyksXG4gICAgRmlsdGVyQmxvY2s6ICAgICAgICByZXF1aXJlKCcuL0ZpbHRlckJsb2NrJyksXG4gICAgR3JheUZpbHRlcjogICAgICAgICByZXF1aXJlKCcuL0dyYXlGaWx0ZXInKSxcbiAgICBJbnZlcnRGaWx0ZXI6ICAgICAgIHJlcXVpcmUoJy4vSW52ZXJ0RmlsdGVyJyksXG4gICAgTm9pc2VGaWx0ZXI6ICAgICAgICByZXF1aXJlKCcuL05vaXNlRmlsdGVyJyksXG4gICAgTm9ybWFsTWFwRmlsdGVyOiAgICByZXF1aXJlKCcuL05vcm1hbE1hcEZpbHRlcicpLFxuICAgIFBpeGVsYXRlRmlsdGVyOiAgICAgcmVxdWlyZSgnLi9QaXhlbGF0ZUZpbHRlcicpLFxuICAgIFJHQlNwbGl0RmlsdGVyOiAgICAgcmVxdWlyZSgnLi9SR0JTcGxpdEZpbHRlcicpLFxuICAgIFNlcGlhRmlsdGVyOiAgICAgICAgcmVxdWlyZSgnLi9TZXBpYUZpbHRlcicpLFxuICAgIFNtYXJ0Qmx1ckZpbHRlcjogICAgcmVxdWlyZSgnLi9TbWFydEJsdXJGaWx0ZXInKSxcbiAgICBUaWx0U2hpZnRGaWx0ZXI6ICAgIHJlcXVpcmUoJy4vVGlsdFNoaWZ0RmlsdGVyJyksXG4gICAgVGlsdFNoaWZ0WEZpbHRlcjogICByZXF1aXJlKCcuL1RpbHRTaGlmdFhGaWx0ZXInKSxcbiAgICBUaWx0U2hpZnRZRmlsdGVyOiAgIHJlcXVpcmUoJy4vVGlsdFNoaWZ0WUZpbHRlcicpLFxuICAgIFR3aXN0RmlsdGVyOiAgICAgICAgcmVxdWlyZSgnLi9Ud2lzdEZpbHRlcicpXG59O1xuIiwidmFyIGNvcmUgPSByZXF1aXJlKCcuLi9jb3JlJyk7XG5cbi8qKlxuICogSG9sZHMgYWxsIGluZm9ybWF0aW9uIHJlbGF0ZWQgdG8gYW4gSW50ZXJhY3Rpb24gZXZlbnRcbiAqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBJbnRlcmFjdGlvbkRhdGEoKSB7XG4gICAgLyoqXG4gICAgICogVGhpcyBwb2ludCBzdG9yZXMgdGhlIGdsb2JhbCBjb29yZHMgb2Ygd2hlcmUgdGhlIHRvdWNoL21vdXNlIGV2ZW50IGhhcHBlbmVkXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKi9cbiAgICB0aGlzLmdsb2JhbCA9IG5ldyBjb3JlLm1hdGguUG9pbnQoKTtcblxuICAgIC8qKlxuICAgICAqIFRoZSB0YXJnZXQgU3ByaXRlIHRoYXQgd2FzIGludGVyYWN0ZWQgd2l0aFxuICAgICAqXG4gICAgICogQG1lbWJlciB7U3ByaXRlfVxuICAgICAqL1xuICAgIHRoaXMudGFyZ2V0ID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqIFdoZW4gcGFzc2VkIHRvIGFuIGV2ZW50IGhhbmRsZXIsIHRoaXMgd2lsbCBiZSB0aGUgb3JpZ2luYWwgRE9NIEV2ZW50IHRoYXQgd2FzIGNhcHR1cmVkXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtFdmVudH1cbiAgICAgKi9cbiAgICB0aGlzLm9yaWdpbmFsRXZlbnQgPSBudWxsO1xufVxuXG5JbnRlcmFjdGlvbkRhdGEucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gSW50ZXJhY3Rpb25EYXRhO1xubW9kdWxlLmV4cG9ydHMgPSBJbnRlcmFjdGlvbkRhdGE7XG5cbi8qKlxuICogVGhpcyB3aWxsIHJldHVybiB0aGUgbG9jYWwgY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBkaXNwbGF5T2JqZWN0IGZvciB0aGlzIEludGVyYWN0aW9uRGF0YVxuICpcbiAqIEBwYXJhbSBkaXNwbGF5T2JqZWN0IHtEaXNwbGF5T2JqZWN0fSBUaGUgRGlzcGxheU9iamVjdCB0aGF0IHlvdSB3b3VsZCBsaWtlIHRoZSBsb2NhbCBjb29yZHMgb2ZmXG4gKiBAcGFyYW0gW3BvaW50XSB7UG9pbnR9IEEgUG9pbnQgb2JqZWN0IGluIHdoaWNoIHRvIHN0b3JlIHRoZSB2YWx1ZSwgb3B0aW9uYWwgKG90aGVyd2lzZSB3aWxsIGNyZWF0ZSBhIG5ldyBwb2ludClcbiAqIEByZXR1cm4ge1BvaW50fSBBIHBvaW50IGNvbnRhaW5pbmcgdGhlIGNvb3JkaW5hdGVzIG9mIHRoZSBJbnRlcmFjdGlvbkRhdGEgcG9zaXRpb24gcmVsYXRpdmUgdG8gdGhlIERpc3BsYXlPYmplY3RcbiAqL1xuSW50ZXJhY3Rpb25EYXRhLnByb3RvdHlwZS5nZXRMb2NhbFBvc2l0aW9uID0gZnVuY3Rpb24gKGRpc3BsYXlPYmplY3QsIHBvaW50KSB7XG4gICAgdmFyIHdvcmxkVHJhbnNmb3JtID0gZGlzcGxheU9iamVjdC53b3JsZFRyYW5zZm9ybTtcbiAgICB2YXIgZ2xvYmFsID0gdGhpcy5nbG9iYWw7XG5cbiAgICAvLyBkbyBhIGNoZWVreSB0cmFuc2Zvcm0gdG8gZ2V0IHRoZSBtb3VzZSBjb29yZHM7XG4gICAgdmFyIGEwMCA9IHdvcmxkVHJhbnNmb3JtLmEsIGEwMSA9IHdvcmxkVHJhbnNmb3JtLmMsIGEwMiA9IHdvcmxkVHJhbnNmb3JtLnR4LFxuICAgICAgICBhMTAgPSB3b3JsZFRyYW5zZm9ybS5iLCBhMTEgPSB3b3JsZFRyYW5zZm9ybS5kLCBhMTIgPSB3b3JsZFRyYW5zZm9ybS50eSxcbiAgICAgICAgaWQgPSAxIC8gKGEwMCAqIGExMSArIGEwMSAqIC1hMTApO1xuXG4gICAgcG9pbnQgPSBwb2ludCB8fCBuZXcgY29yZS5tYXRoLlBvaW50KCk7XG5cbiAgICBwb2ludC54ID0gYTExICogaWQgKiBnbG9iYWwueCArIC1hMDEgKiBpZCAqIGdsb2JhbC55ICsgKGExMiAqIGEwMSAtIGEwMiAqIGExMSkgKiBpZDtcbiAgICBwb2ludC55ID0gYTAwICogaWQgKiBnbG9iYWwueSArIC1hMTAgKiBpZCAqIGdsb2JhbC54ICsgKC1hMTIgKiBhMDAgKyBhMDIgKiBhMTApICogaWQ7XG5cbiAgICAvLyBzZXQgdGhlIG1vdXNlIGNvb3Jkcy4uLlxuICAgIHJldHVybiBwb2ludDtcbn07XG4iLCJ2YXIgY29yZSA9IHJlcXVpcmUoJy4uL2NvcmUnKSxcbiAgICBJbnRlcmFjdGlvbkRhdGEgPSByZXF1aXJlKCcuL0ludGVyYWN0aW9uRGF0YScpO1xuXG4vLyBUT0RPOiBPYnZpb3VzbHkgcmV3cml0ZSB0aGlzLi4uXG52YXIgSU5URVJBQ1RJT05fRlJFUVVFTkNZID0gMzA7XG52YXIgQVVUT19QUkVWRU5UX0RFRkFVTFQgPSB0cnVlO1xuXG4vKipcbiAqIFRoZSBpbnRlcmFjdGlvbiBtYW5hZ2VyIGRlYWxzIHdpdGggbW91c2UgYW5kIHRvdWNoIGV2ZW50cy4gQW55IERpc3BsYXlPYmplY3QgY2FuIGJlIGludGVyYWN0aXZlXG4gKiBpZiBpdHMgaW50ZXJhY3RpdmUgcGFyYW1ldGVyIGlzIHNldCB0byB0cnVlXG4gKiBUaGlzIG1hbmFnZXIgYWxzbyBzdXBwb3J0cyBtdWx0aXRvdWNoLlxuICpcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gc3RhZ2Uge1N0YWdlfSBUaGUgc3RhZ2UgdG8gaGFuZGxlIGludGVyYWN0aW9uc1xuICovXG5mdW5jdGlvbiBJbnRlcmFjdGlvbk1hbmFnZXIoc3RhZ2UpIHtcbiAgICAvKipcbiAgICAgKiBBIHJlZmVyZW5jZSB0byB0aGUgc3RhZ2VcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1N0YWdlfVxuICAgICAqL1xuICAgIHRoaXMuc3RhZ2UgPSBzdGFnZTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBtb3VzZSBkYXRhXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtJbnRlcmFjdGlvbkRhdGF9XG4gICAgICovXG4gICAgdGhpcy5tb3VzZSA9IG5ldyBJbnRlcmFjdGlvbkRhdGEoKTtcblxuICAgIC8qKlxuICAgICAqIEFuIG9iamVjdCB0aGF0IHN0b3JlcyBjdXJyZW50IHRvdWNoZXMgKEludGVyYWN0aW9uRGF0YSkgYnkgaWQgcmVmZXJlbmNlXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtvYmplY3R9XG4gICAgICovXG4gICAgdGhpcy50b3VjaGVzID0ge307XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMudGVtcFBvaW50ID0gbmV3IGNvcmUubWF0aC5Qb2ludCgpO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAZGVmYXVsdFxuICAgICAqL1xuICAgIHRoaXMubW91c2VvdmVyRW5hYmxlZCA9IHRydWU7XG5cbiAgICAvKipcbiAgICAgKiBUaW55IGxpdHRsZSBpbnRlcmFjdGl2ZURhdGEgcG9vbCAhXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLnBvb2wgPSBbXTtcblxuICAgIC8qKlxuICAgICAqIEFuIGFycmF5IGNvbnRhaW5pbmcgYWxsIHRoZSBpdGVyYXRpdmUgaXRlbXMgZnJvbSB0aGUgb3VyIGludGVyYWN0aXZlIHRyZWVcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0FycmF5fVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zID0gW107XG5cbiAgICAvKipcbiAgICAgKiBUaGUgRE9NIGVsZW1lbnQgdG8gYmluZCB0by5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0hUTUxFbGVtZW50fVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQgPSBudWxsO1xuXG4gICAgLyoqXG4gICAgICogSGF2ZSBldmVudHMgYmVlbiBhdHRhY2hlZCB0byB0aGUgZG9tIGVsZW1lbnQ/XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5ldmVudHNBZGRlZCA9IGZhbHNlO1xuXG4gICAgLy90aGlzIHdpbGwgbWFrZSBpdCBzbyB0aGF0IHlvdSBkb24ndCBoYXZlIHRvIGNhbGwgYmluZCBhbGwgdGhlIHRpbWVcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge0Z1bmN0aW9ufVxuICAgICAqL1xuICAgIHRoaXMub25Nb3VzZU1vdmUgPSB0aGlzLm9uTW91c2VNb3ZlLmJpbmQoIHRoaXMgKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge0Z1bmN0aW9ufVxuICAgICAqL1xuICAgIHRoaXMub25Nb3VzZURvd24gPSB0aGlzLm9uTW91c2VEb3duLmJpbmQodGhpcyk7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtGdW5jdGlvbn1cbiAgICAgKi9cbiAgICB0aGlzLm9uTW91c2VPdXQgPSB0aGlzLm9uTW91c2VPdXQuYmluZCh0aGlzKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge0Z1bmN0aW9ufVxuICAgICAqL1xuICAgIHRoaXMub25Nb3VzZVVwID0gdGhpcy5vbk1vdXNlVXAuYmluZCh0aGlzKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge0Z1bmN0aW9ufVxuICAgICAqL1xuICAgIHRoaXMub25Ub3VjaFN0YXJ0ID0gdGhpcy5vblRvdWNoU3RhcnQuYmluZCh0aGlzKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge0Z1bmN0aW9ufVxuICAgICAqL1xuICAgIHRoaXMub25Ub3VjaEVuZCA9IHRoaXMub25Ub3VjaEVuZC5iaW5kKHRoaXMpO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7RnVuY3Rpb259XG4gICAgICovXG4gICAgdGhpcy5vblRvdWNoTW92ZSA9IHRoaXMub25Ub3VjaE1vdmUuYmluZCh0aGlzKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLmxhc3QgPSAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGNzcyBzdHlsZSBvZiB0aGUgY3Vyc29yIHRoYXQgaXMgYmVpbmcgdXNlZFxuICAgICAqIEBtZW1iZXIge3N0cmluZ31cbiAgICAgKi9cbiAgICB0aGlzLmN1cnJlbnRDdXJzb3JTdHlsZSA9ICdpbmhlcml0JztcblxuICAgIC8qKlxuICAgICAqIElzIHNldCB0byB0cnVlIHdoZW4gdGhlIG1vdXNlIGlzIG1vdmVkIG91dCBvZiB0aGUgY2FudmFzXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLm1vdXNlT3V0ID0gZmFsc2U7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5yZXNvbHV0aW9uID0gMTtcblxuICAgIC8vIHVzZWQgZm9yIGhpdCB0ZXN0aW5nXG4gICAgdGhpcy5fdGVtcFBvaW50ID0gbmV3IGNvcmUubWF0aC5Qb2ludCgpO1xufVxuXG5JbnRlcmFjdGlvbk1hbmFnZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gSW50ZXJhY3Rpb25NYW5hZ2VyO1xubW9kdWxlLmV4cG9ydHMgPSBJbnRlcmFjdGlvbk1hbmFnZXI7XG5cbi8qKlxuICogQ29sbGVjdHMgYW4gaW50ZXJhY3RpdmUgc3ByaXRlIHJlY3Vyc2l2ZWx5IHRvIGhhdmUgdGhlaXIgaW50ZXJhY3Rpb25zIG1hbmFnZWRcbiAqXG4gKiBAcGFyYW0gZGlzcGxheU9iamVjdCB7RGlzcGxheU9iamVjdH0gdGhlIGRpc3BsYXlPYmplY3QgdG8gY29sbGVjdFxuICogQHBhcmFtIGlQYXJlbnQge0Rpc3BsYXlPYmplY3R9IHRoZSBkaXNwbGF5IG9iamVjdCdzIHBhcmVudFxuICogQHByaXZhdGVcbiAqL1xuSW50ZXJhY3Rpb25NYW5hZ2VyLnByb3RvdHlwZS5jb2xsZWN0SW50ZXJhY3RpdmVTcHJpdGUgPSBmdW5jdGlvbiAoZGlzcGxheU9iamVjdCwgaVBhcmVudCkge1xuICAgIHZhciBjaGlsZHJlbiA9IGRpc3BsYXlPYmplY3QuY2hpbGRyZW47XG4gICAgdmFyIGxlbmd0aCA9IGNoaWxkcmVuLmxlbmd0aDtcblxuICAgIC8vIG1ha2UgYW4gaW50ZXJhY3Rpb24gdHJlZS4uLiB7aXRlbS5fX2ludGVyYWN0aXZlUGFyZW50fVxuICAgIGZvciAodmFyIGkgPSBsZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgICB2YXIgY2hpbGQgPSBjaGlsZHJlbltpXTtcblxuICAgICAgICAvLyBwdXNoIGFsbCBpbnRlcmFjdGl2ZSBiaXRzXG4gICAgICAgIGlmIChjaGlsZC5faW50ZXJhY3RpdmUpIHtcbiAgICAgICAgICAgIGlQYXJlbnQuaW50ZXJhY3RpdmVDaGlsZHJlbiA9IHRydWU7XG4gICAgICAgICAgICAvL2NoaWxkLl9faVBhcmVudCA9IGlQYXJlbnQ7XG4gICAgICAgICAgICB0aGlzLmludGVyYWN0aXZlSXRlbXMucHVzaChjaGlsZCk7XG5cbiAgICAgICAgICAgIGlmIChjaGlsZC5jaGlsZHJlbi5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jb2xsZWN0SW50ZXJhY3RpdmVTcHJpdGUoY2hpbGQsIGNoaWxkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNoaWxkLl9faVBhcmVudCA9IG51bGw7XG4gICAgICAgICAgICBpZiAoY2hpbGQuY2hpbGRyZW4ubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHRoaXMuY29sbGVjdEludGVyYWN0aXZlU3ByaXRlKGNoaWxkLCBpUGFyZW50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgfVxufTtcblxuLyoqXG4gKiBTZXRzIHRoZSBET00gZWxlbWVudCB3aGljaCB3aWxsIHJlY2VpdmUgbW91c2UvdG91Y2ggZXZlbnRzLiBUaGlzIGlzIHVzZWZ1bCBmb3Igd2hlbiB5b3UgaGF2ZVxuICogb3RoZXIgRE9NIGVsZW1lbnRzIG9uIHRvcCBvZiB0aGUgcmVuZGVyZXJzIENhbnZhcyBlbGVtZW50LiBXaXRoIHRoaXMgeW91J2xsIGJlIGJhbGUgdG8gZGVsZXRlZ2F0ZVxuICogYW5vdGhlciBET00gZWxlbWVudCB0byByZWNlaXZlIHRob3NlIGV2ZW50cy5cbiAqXG4gKiBAcGFyYW0gZWxlbWVudCB7SFRNTEVsZW1lbnR9IHRoZSBET00gZWxlbWVudCB3aGljaCB3aWxsIHJlY2VpdmUgbW91c2UgYW5kIHRvdWNoIGV2ZW50cy5cbiAqIEBwYXJhbSBbcmVzb2x1dGlvbj0xXSB7bnVtYmVyfSBUSGUgcmVzb2x1dGlvbiBvZiB0aGUgbmV3IGVsZW1lbnQgKHJlbGF0aXZlIHRvIHRoZSBjYW52YXMpLlxuICogQHByaXZhdGVcbiAqL1xuSW50ZXJhY3Rpb25NYW5hZ2VyLnByb3RvdHlwZS5zZXRUYXJnZXRFbGVtZW50ID0gZnVuY3Rpb24gKGVsZW1lbnQsIHJlc29sdXRpb24pIHtcbiAgICB0aGlzLnJlbW92ZUV2ZW50cygpO1xuXG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQgPSBlbGVtZW50O1xuXG4gICAgdGhpcy5yZXNvbHV0aW9uID0gcmVzb2x1dGlvbiB8fCAxO1xuXG4gICAgdGhpcy5hZGRFdmVudHMoKTtcbn07XG5cbi8qKlxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUuYWRkRXZlbnRzID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICghdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh3aW5kb3cubmF2aWdhdG9yLm1zUG9pbnRlckVuYWJsZWQpIHtcbiAgICAgICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQuc3R5bGVbJy1tcy1jb250ZW50LXpvb21pbmcnXSA9ICdub25lJztcbiAgICAgICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQuc3R5bGVbJy1tcy10b3VjaC1hY3Rpb24nXSA9ICdub25lJztcbiAgICB9XG5cbiAgICB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZW1vdmUnLCAgICB0aGlzLm9uTW91c2VNb3ZlLCB0cnVlKTtcbiAgICB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZWRvd24nLCAgICB0aGlzLm9uTW91c2VEb3duLCB0cnVlKTtcbiAgICB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZW91dCcsICAgICB0aGlzLm9uTW91c2VPdXQsIHRydWUpO1xuXG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigndG91Y2hzdGFydCcsICAgdGhpcy5vblRvdWNoU3RhcnQsIHRydWUpO1xuICAgIHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNoZW5kJywgICAgIHRoaXMub25Ub3VjaEVuZCwgdHJ1ZSk7XG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigndG91Y2htb3ZlJywgICAgdGhpcy5vblRvdWNoTW92ZSwgdHJ1ZSk7XG5cbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsICB0aGlzLm9uTW91c2VVcCwgdHJ1ZSk7XG5cbiAgICB0aGlzLmV2ZW50c0FkZGVkID0gdHJ1ZTtcbn07XG5cbi8qKlxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUucmVtb3ZlRXZlbnRzID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICghdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh3aW5kb3cubmF2aWdhdG9yLm1zUG9pbnRlckVuYWJsZWQpIHtcbiAgICAgICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQuc3R5bGVbJy1tcy1jb250ZW50LXpvb21pbmcnXSA9ICcnO1xuICAgICAgICB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5zdHlsZVsnLW1zLXRvdWNoLWFjdGlvbiddID0gJyc7XG4gICAgfVxuXG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgdGhpcy5vbk1vdXNlTW92ZSwgdHJ1ZSk7XG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgdGhpcy5vbk1vdXNlRG93biwgdHJ1ZSk7XG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2VvdXQnLCAgdGhpcy5vbk1vdXNlT3V0LCB0cnVlKTtcblxuICAgIHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNoc3RhcnQnLCB0aGlzLm9uVG91Y2hTdGFydCwgdHJ1ZSk7XG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigndG91Y2hlbmQnLCAgdGhpcy5vblRvdWNoRW5kLCB0cnVlKTtcbiAgICB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCd0b3VjaG1vdmUnLCB0aGlzLm9uVG91Y2hNb3ZlLCB0cnVlKTtcblxuICAgIHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50ID0gbnVsbDtcblxuICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgIHRoaXMub25Nb3VzZVVwLCB0cnVlKTtcblxuICAgIHRoaXMuZXZlbnRzQWRkZWQgPSBmYWxzZTtcbn07XG5cbi8qKlxuICogdXBkYXRlcyB0aGUgc3RhdGUgb2YgaW50ZXJhY3RpdmUgb2JqZWN0c1xuICpcbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUudXBkYXRlID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICghdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIGZyZXF1ZW5jeSBvZiAzMGZwcz8/XG4gICAgdmFyIG5vdyA9IERhdGUubm93KCk7XG4gICAgdmFyIGRpZmYgPSBub3cgLSB0aGlzLmxhc3Q7XG4gICAgZGlmZiA9IChkaWZmICogSU5URVJBQ1RJT05fRlJFUVVFTkNZICkgLyAxMDAwO1xuICAgIGlmIChkaWZmIDwgMSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5sYXN0ID0gbm93O1xuXG4gICAgdmFyIGkgPSAwO1xuXG4gICAgLy8gb2suLiBzbyBtb3VzZSBldmVudHM/P1xuICAgIC8vIHllcyBmb3Igbm93IDopXG4gICAgLy8gT1BUSU1JU0UgLSBob3cgb2Z0ZW4gdG8gY2hlY2s/P1xuICAgIGlmICh0aGlzLmRpcnR5KSB7XG4gICAgICAgIHRoaXMucmVidWlsZEludGVyYWN0aXZlR3JhcGgoKTtcbiAgICB9XG5cbiAgICAvLyBsb29wIHRocm91Z2ggaW50ZXJhY3RpdmUgb2JqZWN0cyFcbiAgICB2YXIgbGVuZ3RoID0gdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zLmxlbmd0aDtcbiAgICB2YXIgY3Vyc29yID0gJ2luaGVyaXQnO1xuICAgIHZhciBvdmVyID0gZmFsc2U7XG5cbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGl0ZW0gPSB0aGlzLmludGVyYWN0aXZlSXRlbXNbaV07XG5cbiAgICAgICAgLy8gT1BUSU1JU0FUSU9OIC0gb25seSBjYWxjdWxhdGUgZXZlcnkgdGltZSBpZiB0aGUgbW91c2Vtb3ZlIGZ1bmN0aW9uIGV4aXN0cy4uXG4gICAgICAgIC8vIE9LIHNvLi4gZG9lcyB0aGUgb2JqZWN0IGhhdmUgYW55IG90aGVyIGludGVyYWN0aXZlIGZ1bmN0aW9ucz9cbiAgICAgICAgLy8gaGl0LXRlc3QgdGhlIGNsaXAhXG4gICAgICAgLy8gaWYgKGl0ZW0ubW91c2VvdmVyIHx8IGl0ZW0ubW91c2VvdXQgfHwgaXRlbS5idXR0b25Nb2RlKVxuICAgICAgIC8vIHtcbiAgICAgICAgLy8gb2sgc28gdGhlcmUgYXJlIHNvbWUgZnVuY3Rpb25zIHNvIGxldHMgaGl0IHRlc3QgaXQuLlxuICAgICAgICBpdGVtLl9faGl0ID0gdGhpcy5oaXRUZXN0KGl0ZW0sIHRoaXMubW91c2UpO1xuICAgICAgICB0aGlzLm1vdXNlLnRhcmdldCA9IGl0ZW07XG4gICAgICAgIC8vIG9rIHNvIGRlYWwgd2l0aCBpbnRlcmFjdGlvbnMuLlxuICAgICAgICAvLyBsb29rcyBsaWtlIHRoZXJlIHdhcyBhIGhpdCFcbiAgICAgICAgaWYgKGl0ZW0uX19oaXQgJiYgIW92ZXIpIHtcbiAgICAgICAgICAgIGlmIChpdGVtLmJ1dHRvbk1vZGUpIHtcbiAgICAgICAgICAgICAgICBjdXJzb3IgPSBpdGVtLmRlZmF1bHRDdXJzb3I7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghaXRlbS5pbnRlcmFjdGl2ZUNoaWxkcmVuKSB7XG4gICAgICAgICAgICAgICAgb3ZlciA9IHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghaXRlbS5fX2lzT3Zlcikge1xuICAgICAgICAgICAgICAgIGlmIChpdGVtLm1vdXNlb3Zlcikge1xuICAgICAgICAgICAgICAgICAgICBpdGVtLm1vdXNlb3ZlciAodGhpcy5tb3VzZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGl0ZW0uX19pc092ZXIgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgaWYgKGl0ZW0uX19pc092ZXIpIHtcbiAgICAgICAgICAgICAgICAvLyByb2xsIG91dCFcbiAgICAgICAgICAgICAgICBpZiAoaXRlbS5tb3VzZW91dCkge1xuICAgICAgICAgICAgICAgICAgICBpdGVtLm1vdXNlb3V0ICh0aGlzLm1vdXNlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaXRlbS5fX2lzT3ZlciA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuY3VycmVudEN1cnNvclN0eWxlICE9PSBjdXJzb3IpIHtcbiAgICAgICAgdGhpcy5jdXJyZW50Q3Vyc29yU3R5bGUgPSBjdXJzb3I7XG4gICAgICAgIHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LnN0eWxlLmN1cnNvciA9IGN1cnNvcjtcbiAgICB9XG59O1xuXG4vKipcbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUucmVidWlsZEludGVyYWN0aXZlR3JhcGggPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5kaXJ0eSA9IGZhbHNlO1xuXG4gICAgdmFyIGxlbiA9IHRoaXMuaW50ZXJhY3RpdmVJdGVtcy5sZW5ndGg7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgIHRoaXMuaW50ZXJhY3RpdmVJdGVtc1tpXS5pbnRlcmFjdGl2ZUNoaWxkcmVuID0gZmFsc2U7XG4gICAgfVxuXG4gICAgdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zLmxlbmd0aCA9IDA7XG5cbiAgICBpZiAodGhpcy5zdGFnZS5pbnRlcmFjdGl2ZSkge1xuICAgICAgICB0aGlzLmludGVyYWN0aXZlSXRlbXMucHVzaCh0aGlzLnN0YWdlKTtcbiAgICB9XG5cbiAgICAvLyBHbyB0aHJvdWdoIGFuZCBjb2xsZWN0IGFsbCB0aGUgb2JqZWN0cyB0aGF0IGFyZSBpbnRlcmFjdGl2ZS4uXG4gICAgdGhpcy5jb2xsZWN0SW50ZXJhY3RpdmVTcHJpdGUodGhpcy5zdGFnZSwgdGhpcy5zdGFnZSk7XG59O1xuXG4vKipcbiAqIElzIGNhbGxlZCB3aGVuIHRoZSBtb3VzZSBtb3ZlcyBhY3Jvc3MgdGhlIHJlbmRlcmVyIGVsZW1lbnRcbiAqXG4gKiBAcGFyYW0gZXZlbnQge0V2ZW50fSBUaGUgRE9NIGV2ZW50IG9mIHRoZSBtb3VzZSBtb3ZpbmdcbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUub25Nb3VzZU1vdmUgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnJlYnVpbGRJbnRlcmFjdGl2ZUdyYXBoKCk7XG4gICAgfVxuXG4gICAgdGhpcy5tb3VzZS5vcmlnaW5hbEV2ZW50ID0gZXZlbnQ7XG5cbiAgICAvLyBUT0RPIG9wdGltaXplIGJ5IG5vdCBjaGVjayBFVkVSWSBUSU1FISBtYXliZSBoYWxmIGFzIG9mdGVuPyAvL1xuICAgIHZhciByZWN0ID0gdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cbiAgICB0aGlzLm1vdXNlLmdsb2JhbC54ID0gKGV2ZW50LmNsaWVudFggLSByZWN0LmxlZnQpICogKHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LndpZHRoIC8gcmVjdC53aWR0aCkgLyB0aGlzLnJlc29sdXRpb247XG4gICAgdGhpcy5tb3VzZS5nbG9iYWwueSA9IChldmVudC5jbGllbnRZIC0gcmVjdC50b3ApICogKCB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5oZWlnaHQgLyByZWN0LmhlaWdodCkgLyB0aGlzLnJlc29sdXRpb247XG5cbiAgICB2YXIgbGVuZ3RoID0gdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zLmxlbmd0aDtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGl0ZW0gPSB0aGlzLmludGVyYWN0aXZlSXRlbXNbaV07XG5cbiAgICAgICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24hXG4gICAgICAgIGlmIChpdGVtLm1vdXNlbW92ZSkge1xuICAgICAgICAgICAgaXRlbS5tb3VzZW1vdmUodGhpcy5tb3VzZSk7XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4vKipcbiAqIElzIGNhbGxlZCB3aGVuIHRoZSBtb3VzZSBidXR0b24gaXMgcHJlc3NlZCBkb3duIG9uIHRoZSByZW5kZXJlciBlbGVtZW50XG4gKlxuICogQHBhcmFtIGV2ZW50IHtFdmVudH0gVGhlIERPTSBldmVudCBvZiBhIG1vdXNlIGJ1dHRvbiBiZWluZyBwcmVzc2VkIGRvd25cbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUub25Nb3VzZURvd24gPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnJlYnVpbGRJbnRlcmFjdGl2ZUdyYXBoKCk7XG4gICAgfVxuXG4gICAgdGhpcy5tb3VzZS5vcmlnaW5hbEV2ZW50ID0gZXZlbnQ7XG5cbiAgICBpZiAoQVVUT19QUkVWRU5UX0RFRkFVTFQpIHtcbiAgICAgICAgdGhpcy5tb3VzZS5vcmlnaW5hbEV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuXG4gICAgLy8gbG9vcCB0aHJvdWdoIGludGVyYWN0aW9uIHRyZWUuLi5cbiAgICAvLyBoaXQgdGVzdCBlYWNoIGl0ZW0hIC0+XG4gICAgLy8gZ2V0IGludGVyYWN0aXZlIGl0ZW1zIHVuZGVyIHBvaW50Pz9cbiAgICAvL3N0YWdlLl9faVxuICAgIHZhciBsZW5ndGggPSB0aGlzLmludGVyYWN0aXZlSXRlbXMubGVuZ3RoO1xuXG4gICAgdmFyIGUgPSB0aGlzLm1vdXNlLm9yaWdpbmFsRXZlbnQ7XG4gICAgdmFyIGlzUmlnaHRCdXR0b24gPSBlLmJ1dHRvbiA9PT0gMiB8fCBlLndoaWNoID09PSAzO1xuICAgIHZhciBkb3duRnVuY3Rpb24gPSBpc1JpZ2h0QnV0dG9uID8gJ3JpZ2h0ZG93bicgOiAnbW91c2Vkb3duJztcbiAgICB2YXIgY2xpY2tGdW5jdGlvbiA9IGlzUmlnaHRCdXR0b24gPyAncmlnaHRjbGljaycgOiAnY2xpY2snO1xuICAgIHZhciBidXR0b25Jc0Rvd24gPSBpc1JpZ2h0QnV0dG9uID8gJ19fcmlnaHRJc0Rvd24nIDogJ19fbW91c2VJc0Rvd24nO1xuICAgIHZhciBpc0Rvd24gPSBpc1JpZ2h0QnV0dG9uID8gJ19faXNSaWdodERvd24nIDogJ19faXNEb3duJztcblxuICAgIC8vIHdoaWxlXG4gICAgLy8gaGl0IHRlc3RcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBpdGVtID0gdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zW2ldO1xuXG4gICAgICAgIGlmIChpdGVtW2Rvd25GdW5jdGlvbl0gfHwgaXRlbVtjbGlja0Z1bmN0aW9uXSkge1xuICAgICAgICAgICAgaXRlbVtidXR0b25Jc0Rvd25dID0gdHJ1ZTtcbiAgICAgICAgICAgIGl0ZW0uX19oaXQgPSB0aGlzLmhpdFRlc3QoaXRlbSwgdGhpcy5tb3VzZSk7XG5cbiAgICAgICAgICAgIGlmIChpdGVtLl9faGl0KSB7XG4gICAgICAgICAgICAgICAgLy9jYWxsIHRoZSBmdW5jdGlvbiFcbiAgICAgICAgICAgICAgICBpZiAoaXRlbVtkb3duRnVuY3Rpb25dKSB7XG4gICAgICAgICAgICAgICAgICAgIGl0ZW1bZG93bkZ1bmN0aW9uXSh0aGlzLm1vdXNlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaXRlbVtpc0Rvd25dID0gdHJ1ZTtcblxuICAgICAgICAgICAgICAgIC8vIGp1c3QgdGhlIG9uZSFcbiAgICAgICAgICAgICAgICBpZiAoIWl0ZW0uaW50ZXJhY3RpdmVDaGlsZHJlbikge1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4vKipcbiAqIElzIGNhbGxlZCB3aGVuIHRoZSBtb3VzZSBpcyBtb3ZlZCBvdXQgb2YgdGhlIHJlbmRlcmVyIGVsZW1lbnRcbiAqXG4gKiBAcGFyYW0gZXZlbnQge0V2ZW50fSBUaGUgRE9NIGV2ZW50IG9mIGEgbW91c2UgYmVpbmcgbW92ZWQgb3V0XG4gKiBAcHJpdmF0ZVxuICovXG5JbnRlcmFjdGlvbk1hbmFnZXIucHJvdG90eXBlLm9uTW91c2VPdXQgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnJlYnVpbGRJbnRlcmFjdGl2ZUdyYXBoKCk7XG4gICAgfVxuXG4gICAgdGhpcy5tb3VzZS5vcmlnaW5hbEV2ZW50ID0gZXZlbnQ7XG5cbiAgICB2YXIgbGVuZ3RoID0gdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zLmxlbmd0aDtcblxuICAgIHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LnN0eWxlLmN1cnNvciA9ICdpbmhlcml0JztcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGl0ZW0gPSB0aGlzLmludGVyYWN0aXZlSXRlbXNbaV07XG4gICAgICAgIGlmIChpdGVtLl9faXNPdmVyKSB7XG4gICAgICAgICAgICB0aGlzLm1vdXNlLnRhcmdldCA9IGl0ZW07XG4gICAgICAgICAgICBpZiAoaXRlbS5tb3VzZW91dCkge1xuICAgICAgICAgICAgICAgIGl0ZW0ubW91c2VvdXQodGhpcy5tb3VzZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpdGVtLl9faXNPdmVyID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLm1vdXNlT3V0ID0gdHJ1ZTtcblxuICAgIC8vIG1vdmUgdGhlIG1vdXNlIHRvIGFuIGltcG9zc2libGUgcG9zaXRpb25cbiAgICB0aGlzLm1vdXNlLmdsb2JhbC54ID0gLTEwMDAwO1xuICAgIHRoaXMubW91c2UuZ2xvYmFsLnkgPSAtMTAwMDA7XG59O1xuXG4vKipcbiAqIElzIGNhbGxlZCB3aGVuIHRoZSBtb3VzZSBidXR0b24gaXMgcmVsZWFzZWQgb24gdGhlIHJlbmRlcmVyIGVsZW1lbnRcbiAqXG4gKiBAcGFyYW0gZXZlbnQge0V2ZW50fSBUaGUgRE9NIGV2ZW50IG9mIGEgbW91c2UgYnV0dG9uIGJlaW5nIHJlbGVhc2VkXG4gKiBAcHJpdmF0ZVxuICovXG5JbnRlcmFjdGlvbk1hbmFnZXIucHJvdG90eXBlLm9uTW91c2VVcCA9IGZ1bmN0aW9uIChldmVudCkge1xuICAgIGlmICh0aGlzLmRpcnR5KSB7XG4gICAgICAgIHRoaXMucmVidWlsZEludGVyYWN0aXZlR3JhcGgoKTtcbiAgICB9XG5cbiAgICB0aGlzLm1vdXNlLm9yaWdpbmFsRXZlbnQgPSBldmVudDtcblxuICAgIHZhciBsZW5ndGggPSB0aGlzLmludGVyYWN0aXZlSXRlbXMubGVuZ3RoO1xuICAgIHZhciB1cCA9IGZhbHNlO1xuXG4gICAgdmFyIGUgPSB0aGlzLm1vdXNlLm9yaWdpbmFsRXZlbnQ7XG4gICAgdmFyIGlzUmlnaHRCdXR0b24gPSBlLmJ1dHRvbiA9PT0gMiB8fCBlLndoaWNoID09PSAzO1xuXG4gICAgdmFyIHVwRnVuY3Rpb24gPSBpc1JpZ2h0QnV0dG9uID8gJ3JpZ2h0dXAnIDogJ21vdXNldXAnO1xuICAgIHZhciBjbGlja0Z1bmN0aW9uID0gaXNSaWdodEJ1dHRvbiA/ICdyaWdodGNsaWNrJyA6ICdjbGljayc7XG4gICAgdmFyIHVwT3V0c2lkZUZ1bmN0aW9uID0gaXNSaWdodEJ1dHRvbiA/ICdyaWdodHVwb3V0c2lkZScgOiAnbW91c2V1cG91dHNpZGUnO1xuICAgIHZhciBpc0Rvd24gPSBpc1JpZ2h0QnV0dG9uID8gJ19faXNSaWdodERvd24nIDogJ19faXNEb3duJztcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGl0ZW0gPSB0aGlzLmludGVyYWN0aXZlSXRlbXNbaV07XG5cbiAgICAgICAgaWYgKGl0ZW1bY2xpY2tGdW5jdGlvbl0gfHwgaXRlbVt1cEZ1bmN0aW9uXSB8fCBpdGVtW3VwT3V0c2lkZUZ1bmN0aW9uXSkge1xuICAgICAgICAgICAgaXRlbS5fX2hpdCA9IHRoaXMuaGl0VGVzdChpdGVtLCB0aGlzLm1vdXNlKTtcblxuICAgICAgICAgICAgaWYgKGl0ZW0uX19oaXQgJiYgIXVwKSB7XG4gICAgICAgICAgICAgICAgLy9jYWxsIHRoZSBmdW5jdGlvbiFcbiAgICAgICAgICAgICAgICBpZiAoaXRlbVt1cEZ1bmN0aW9uXSkge1xuICAgICAgICAgICAgICAgICAgICBpdGVtW3VwRnVuY3Rpb25dKHRoaXMubW91c2UpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoaXRlbVtpc0Rvd25dKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpdGVtW2NsaWNrRnVuY3Rpb25dKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpdGVtW2NsaWNrRnVuY3Rpb25dKHRoaXMubW91c2UpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKCFpdGVtLmludGVyYWN0aXZlQ2hpbGRyZW4pIHtcbiAgICAgICAgICAgICAgICAgICAgdXAgPSB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmIChpdGVtW2lzRG93bl0pIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGl0ZW1bdXBPdXRzaWRlRnVuY3Rpb25dKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpdGVtW3VwT3V0c2lkZUZ1bmN0aW9uXSh0aGlzLm1vdXNlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaXRlbVtpc0Rvd25dID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4vKipcbiAqIFRlc3RzIGlmIHRoZSBjdXJyZW50IG1vdXNlIGNvb3JkaW5hdGVzIGhpdCBhIHNwcml0ZVxuICpcbiAqIEBwYXJhbSBpdGVtIHtEaXNwbGF5T2JqZWN0fSBUaGUgZGlzcGxheU9iamVjdCB0byB0ZXN0IGZvciBhIGhpdFxuICogQHBhcmFtIGludGVyYWN0aW9uRGF0YSB7SW50ZXJhY3Rpb25EYXRhfSBUaGUgaW50ZXJhY3Rpb25EYXRhIG9iamVjdCB0byB1cGRhdGUgaW4gdGhlIGNhc2UgdGhlcmUgaXMgYSBoaXRcbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUuaGl0VGVzdCA9IGZ1bmN0aW9uIChpdGVtLCBpbnRlcmFjdGlvbkRhdGEpIHtcbiAgICB2YXIgZ2xvYmFsID0gaW50ZXJhY3Rpb25EYXRhLmdsb2JhbDtcblxuICAgIGlmICghaXRlbS53b3JsZFZpc2libGUpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIG1hcCB0aGUgZ2xvYmFsIHBvaW50IHRvIGxvY2FsIHNwYWNlLlxuICAgIGl0ZW0ud29ybGRUcmFuc2Zvcm0uYXBwbHlJbnZlcnNlKGdsb2JhbCwgIHRoaXMuX3RlbXBQb2ludCk7XG5cbiAgICB2YXIgeCA9IHRoaXMuX3RlbXBQb2ludC54LFxuICAgICAgICB5ID0gdGhpcy5fdGVtcFBvaW50LnksXG4gICAgICAgIGk7XG5cbiAgICBpbnRlcmFjdGlvbkRhdGEudGFyZ2V0ID0gaXRlbTtcblxuICAgIC8vYSBzcHJpdGUgb3IgZGlzcGxheSBvYmplY3Qgd2l0aCBhIGhpdCBhcmVhIGRlZmluZWRcbiAgICBpZiAoaXRlbS5oaXRBcmVhICYmIGl0ZW0uaGl0QXJlYS5jb250YWlucykge1xuICAgICAgICByZXR1cm4gaXRlbS5oaXRBcmVhLmNvbnRhaW5zKHgsIHkpO1xuICAgIH1cbiAgICAvLyBhIHNwcml0ZSB3aXRoIG5vIGhpdGFyZWEgZGVmaW5lZFxuICAgIGVsc2UgaWYgKGl0ZW0gaW5zdGFuY2VvZiBjb3JlLlNwcml0ZSkge1xuICAgICAgICB2YXIgd2lkdGggPSBpdGVtLnRleHR1cmUuZnJhbWUud2lkdGg7XG4gICAgICAgIHZhciBoZWlnaHQgPSBpdGVtLnRleHR1cmUuZnJhbWUuaGVpZ2h0O1xuICAgICAgICB2YXIgeDEgPSAtd2lkdGggKiBpdGVtLmFuY2hvci54O1xuICAgICAgICB2YXIgeTE7XG5cbiAgICAgICAgaWYgKHggPiB4MSAmJiB4IDwgeDEgKyB3aWR0aCkge1xuICAgICAgICAgICAgeTEgPSAtaGVpZ2h0ICogaXRlbS5hbmNob3IueTtcblxuICAgICAgICAgICAgaWYgKHkgPiB5MSAmJiB5IDwgeTEgKyBoZWlnaHQpIHtcbiAgICAgICAgICAgICAgICAvLyBzZXQgdGhlIHRhcmdldCBwcm9wZXJ0eSBpZiBhIGhpdCBpcyB0cnVlIVxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIGVsc2UgaWYgKGl0ZW0gaW5zdGFuY2VvZiBjb3JlLkdyYXBoaWNzKSB7XG4gICAgICAgIHZhciBncmFwaGljc0RhdGEgPSBpdGVtLmdyYXBoaWNzRGF0YTtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGdyYXBoaWNzRGF0YS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIGRhdGEgPSBncmFwaGljc0RhdGFbaV07XG5cbiAgICAgICAgICAgIGlmICghZGF0YS5maWxsKSB7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIG9ubHkgZGVhbCB3aXRoIGZpbGxzLi5cbiAgICAgICAgICAgIGlmIChkYXRhLnNoYXBlKSB7XG4gICAgICAgICAgICAgICAgaWYgKGRhdGEuc2hhcGUuY29udGFpbnMoeCwgeSkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy9pbnRlcmFjdGlvbkRhdGEudGFyZ2V0ID0gaXRlbTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgdmFyIGxlbmd0aCA9IGl0ZW0uY2hpbGRyZW4ubGVuZ3RoO1xuXG4gICAgZm9yIChpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciB0ZW1wSXRlbSA9IGl0ZW0uY2hpbGRyZW5baV07XG4gICAgICAgIHZhciBoaXQgPSB0aGlzLmhpdFRlc3QodGVtcEl0ZW0sIGludGVyYWN0aW9uRGF0YSk7XG4gICAgICAgIGlmIChoaXQpIHtcbiAgICAgICAgICAgIC8vIGhtbS4uIFRPRE8gU0VUIENPUlJFQ1QgVEFSR0VUP1xuICAgICAgICAgICAgaW50ZXJhY3Rpb25EYXRhLnRhcmdldCA9IGl0ZW07XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59O1xuXG4vKipcbiAqIElzIGNhbGxlZCB3aGVuIGEgdG91Y2ggaXMgbW92ZWQgYWNyb3NzIHRoZSByZW5kZXJlciBlbGVtZW50XG4gKlxuICogQHBhcmFtIGV2ZW50IHtFdmVudH0gVGhlIERPTSBldmVudCBvZiBhIHRvdWNoIG1vdmluZyBhY3Jvc3MgdGhlIHJlbmRlcmVyIHZpZXdcbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUub25Ub3VjaE1vdmUgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnJlYnVpbGRJbnRlcmFjdGl2ZUdyYXBoKCk7XG4gICAgfVxuXG4gICAgdmFyIHJlY3QgPSB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICB2YXIgY2hhbmdlZFRvdWNoZXMgPSBldmVudC5jaGFuZ2VkVG91Y2hlcztcbiAgICB2YXIgdG91Y2hEYXRhO1xuICAgIHZhciBpID0gMDtcblxuICAgIGZvciAoaSA9IDA7IGkgPCBjaGFuZ2VkVG91Y2hlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgdG91Y2hFdmVudCA9IGNoYW5nZWRUb3VjaGVzW2ldO1xuICAgICAgICB0b3VjaERhdGEgPSB0aGlzLnRvdWNoZXNbdG91Y2hFdmVudC5pZGVudGlmaWVyXTtcbiAgICAgICAgdG91Y2hEYXRhLm9yaWdpbmFsRXZlbnQgPSBldmVudDtcblxuICAgICAgICAvLyB1cGRhdGUgdGhlIHRvdWNoIHBvc2l0aW9uXG4gICAgICAgIHRvdWNoRGF0YS5nbG9iYWwueCA9ICggKHRvdWNoRXZlbnQuY2xpZW50WCAtIHJlY3QubGVmdCkgKiAodGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQud2lkdGggLyByZWN0LndpZHRoKSApIC8gdGhpcy5yZXNvbHV0aW9uO1xuICAgICAgICB0b3VjaERhdGEuZ2xvYmFsLnkgPSAoICh0b3VjaEV2ZW50LmNsaWVudFkgLSByZWN0LnRvcCkgICogKHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LmhlaWdodCAvIHJlY3QuaGVpZ2h0KSApICAvIHRoaXMucmVzb2x1dGlvbjtcbiAgICAgICAgaWYgKG5hdmlnYXRvci5pc0NvY29vbkpTICYmICFyZWN0LmxlZnQgJiYgIXJlY3QudG9wICYmICFldmVudC50YXJnZXQuc3R5bGUud2lkdGggJiYgIWV2ZW50LnRhcmdldC5zdHlsZS5oZWlnaHQpIHtcbiAgICAgICAgICAgIC8vU3VwcG9ydCBmb3IgQ29jb29uSlMgZnVsbHNjcmVlbiBzY2FsZSBtb2Rlc1xuICAgICAgICAgICAgdG91Y2hEYXRhLmdsb2JhbC54ID0gdG91Y2hFdmVudC5jbGllbnRYO1xuICAgICAgICAgICAgdG91Y2hEYXRhLmdsb2JhbC55ID0gdG91Y2hFdmVudC5jbGllbnRZO1xuICAgICAgICB9XG5cbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCB0aGlzLmludGVyYWN0aXZlSXRlbXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgIHZhciBpdGVtID0gdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zW2pdO1xuICAgICAgICAgICAgaWYgKGl0ZW0udG91Y2htb3ZlICYmIGl0ZW0uX190b3VjaERhdGEgJiYgaXRlbS5fX3RvdWNoRGF0YVt0b3VjaEV2ZW50LmlkZW50aWZpZXJdKSB7XG4gICAgICAgICAgICAgICAgaXRlbS50b3VjaG1vdmUodG91Y2hEYXRhKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn07XG5cbi8qKlxuICogSXMgY2FsbGVkIHdoZW4gYSB0b3VjaCBpcyBzdGFydGVkIG9uIHRoZSByZW5kZXJlciBlbGVtZW50XG4gKlxuICogQHBhcmFtIGV2ZW50IHtFdmVudH0gVGhlIERPTSBldmVudCBvZiBhIHRvdWNoIHN0YXJ0aW5nIG9uIHRoZSByZW5kZXJlciB2aWV3XG4gKiBAcHJpdmF0ZVxuICovXG5JbnRlcmFjdGlvbk1hbmFnZXIucHJvdG90eXBlLm9uVG91Y2hTdGFydCA9IGZ1bmN0aW9uIChldmVudCkge1xuICAgIGlmICh0aGlzLmRpcnR5KSB7XG4gICAgICAgIHRoaXMucmVidWlsZEludGVyYWN0aXZlR3JhcGgoKTtcbiAgICB9XG5cbiAgICB2YXIgcmVjdCA9IHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXG4gICAgaWYgKEFVVE9fUFJFVkVOVF9ERUZBVUxUKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuXG4gICAgdmFyIGNoYW5nZWRUb3VjaGVzID0gZXZlbnQuY2hhbmdlZFRvdWNoZXM7XG4gICAgZm9yICh2YXIgaT0wOyBpIDwgY2hhbmdlZFRvdWNoZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIHRvdWNoRXZlbnQgPSBjaGFuZ2VkVG91Y2hlc1tpXTtcblxuICAgICAgICB2YXIgdG91Y2hEYXRhID0gdGhpcy5wb29sLnBvcCgpO1xuICAgICAgICBpZiAoIXRvdWNoRGF0YSkge1xuICAgICAgICAgICAgdG91Y2hEYXRhID0gbmV3IEludGVyYWN0aW9uRGF0YSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdG91Y2hEYXRhLm9yaWdpbmFsRXZlbnQgPSBldmVudDtcblxuICAgICAgICB0aGlzLnRvdWNoZXNbdG91Y2hFdmVudC5pZGVudGlmaWVyXSA9IHRvdWNoRGF0YTtcbiAgICAgICAgdG91Y2hEYXRhLmdsb2JhbC54ID0gKCAodG91Y2hFdmVudC5jbGllbnRYIC0gcmVjdC5sZWZ0KSAqICh0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC53aWR0aCAvIHJlY3Qud2lkdGgpICkgLyB0aGlzLnJlc29sdXRpb247XG4gICAgICAgIHRvdWNoRGF0YS5nbG9iYWwueSA9ICggKHRvdWNoRXZlbnQuY2xpZW50WSAtIHJlY3QudG9wKSAgKiAodGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQuaGVpZ2h0IC8gcmVjdC5oZWlnaHQpICkgLyB0aGlzLnJlc29sdXRpb247XG4gICAgICAgIGlmIChuYXZpZ2F0b3IuaXNDb2Nvb25KUyAmJiAhcmVjdC5sZWZ0ICYmICFyZWN0LnRvcCAmJiAhZXZlbnQudGFyZ2V0LnN0eWxlLndpZHRoICYmICFldmVudC50YXJnZXQuc3R5bGUuaGVpZ2h0KSB7XG4gICAgICAgICAgICAvL1N1cHBvcnQgZm9yIENvY29vbkpTIGZ1bGxzY3JlZW4gc2NhbGUgbW9kZXNcbiAgICAgICAgICAgIHRvdWNoRGF0YS5nbG9iYWwueCA9IHRvdWNoRXZlbnQuY2xpZW50WDtcbiAgICAgICAgICAgIHRvdWNoRGF0YS5nbG9iYWwueSA9IHRvdWNoRXZlbnQuY2xpZW50WTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBsZW5ndGggPSB0aGlzLmludGVyYWN0aXZlSXRlbXMubGVuZ3RoO1xuXG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgbGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgIHZhciBpdGVtID0gdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zW2pdO1xuXG4gICAgICAgICAgICBpZiAoaXRlbS50b3VjaHN0YXJ0IHx8IGl0ZW0udGFwKSB7XG4gICAgICAgICAgICAgICAgaXRlbS5fX2hpdCA9IHRoaXMuaGl0VGVzdChpdGVtLCB0b3VjaERhdGEpO1xuXG4gICAgICAgICAgICAgICAgaWYgKGl0ZW0uX19oaXQpIHtcbiAgICAgICAgICAgICAgICAgICAgLy9jYWxsIHRoZSBmdW5jdGlvbiFcbiAgICAgICAgICAgICAgICAgICAgaWYgKGl0ZW0udG91Y2hzdGFydCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaXRlbS50b3VjaHN0YXJ0KHRvdWNoRGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBpdGVtLl9faXNEb3duID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgaXRlbS5fX3RvdWNoRGF0YSA9IGl0ZW0uX190b3VjaERhdGEgfHwge307XG4gICAgICAgICAgICAgICAgICAgIGl0ZW0uX190b3VjaERhdGFbdG91Y2hFdmVudC5pZGVudGlmaWVyXSA9IHRvdWNoRGF0YTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoIWl0ZW0uaW50ZXJhY3RpdmVDaGlsZHJlbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4vKipcbiAqIElzIGNhbGxlZCB3aGVuIGEgdG91Y2ggaXMgZW5kZWQgb24gdGhlIHJlbmRlcmVyIGVsZW1lbnRcbiAqXG4gKiBAcGFyYW0gZXZlbnQge0V2ZW50fSBUaGUgRE9NIGV2ZW50IG9mIGEgdG91Y2ggZW5kaW5nIG9uIHRoZSByZW5kZXJlciB2aWV3XG4gKiBAcHJpdmF0ZVxuICovXG5JbnRlcmFjdGlvbk1hbmFnZXIucHJvdG90eXBlLm9uVG91Y2hFbmQgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnJlYnVpbGRJbnRlcmFjdGl2ZUdyYXBoKCk7XG4gICAgfVxuXG4gICAgdmFyIHJlY3QgPSB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICB2YXIgY2hhbmdlZFRvdWNoZXMgPSBldmVudC5jaGFuZ2VkVG91Y2hlcztcblxuICAgIGZvciAodmFyIGk9MDsgaSA8IGNoYW5nZWRUb3VjaGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciB0b3VjaEV2ZW50ID0gY2hhbmdlZFRvdWNoZXNbaV07XG4gICAgICAgIHZhciB0b3VjaERhdGEgPSB0aGlzLnRvdWNoZXNbdG91Y2hFdmVudC5pZGVudGlmaWVyXTtcbiAgICAgICAgdmFyIHVwID0gZmFsc2U7XG4gICAgICAgIHRvdWNoRGF0YS5nbG9iYWwueCA9ICggKHRvdWNoRXZlbnQuY2xpZW50WCAtIHJlY3QubGVmdCkgKiAodGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQud2lkdGggLyByZWN0LndpZHRoKSApIC8gdGhpcy5yZXNvbHV0aW9uO1xuICAgICAgICB0b3VjaERhdGEuZ2xvYmFsLnkgPSAoICh0b3VjaEV2ZW50LmNsaWVudFkgLSByZWN0LnRvcCkgICogKHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LmhlaWdodCAvIHJlY3QuaGVpZ2h0KSApIC8gdGhpcy5yZXNvbHV0aW9uO1xuICAgICAgICBpZiAobmF2aWdhdG9yLmlzQ29jb29uSlMgJiYgIXJlY3QubGVmdCAmJiAhcmVjdC50b3AgJiYgIWV2ZW50LnRhcmdldC5zdHlsZS53aWR0aCAmJiAhZXZlbnQudGFyZ2V0LnN0eWxlLmhlaWdodCkge1xuICAgICAgICAgICAgLy9TdXBwb3J0IGZvciBDb2Nvb25KUyBmdWxsc2NyZWVuIHNjYWxlIG1vZGVzXG4gICAgICAgICAgICB0b3VjaERhdGEuZ2xvYmFsLnggPSB0b3VjaEV2ZW50LmNsaWVudFg7XG4gICAgICAgICAgICB0b3VjaERhdGEuZ2xvYmFsLnkgPSB0b3VjaEV2ZW50LmNsaWVudFk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgbGVuZ3RoID0gdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zLmxlbmd0aDtcbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBsZW5ndGg7IGorKykge1xuICAgICAgICAgICAgdmFyIGl0ZW0gPSB0aGlzLmludGVyYWN0aXZlSXRlbXNbal07XG5cbiAgICAgICAgICAgIGlmIChpdGVtLl9fdG91Y2hEYXRhICYmIGl0ZW0uX190b3VjaERhdGFbdG91Y2hFdmVudC5pZGVudGlmaWVyXSkge1xuXG4gICAgICAgICAgICAgICAgaXRlbS5fX2hpdCA9IHRoaXMuaGl0VGVzdChpdGVtLCBpdGVtLl9fdG91Y2hEYXRhW3RvdWNoRXZlbnQuaWRlbnRpZmllcl0pO1xuXG4gICAgICAgICAgICAgICAgLy8gc28gdGhpcyBvbmUgV0FTIGRvd24uLi5cbiAgICAgICAgICAgICAgICB0b3VjaERhdGEub3JpZ2luYWxFdmVudCA9IGV2ZW50O1xuICAgICAgICAgICAgICAgIC8vIGhpdFRlc3Q/P1xuXG4gICAgICAgICAgICAgICAgaWYgKGl0ZW0udG91Y2hlbmQgfHwgaXRlbS50YXApIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGl0ZW0uX19oaXQgJiYgIXVwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXRlbS50b3VjaGVuZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGl0ZW0udG91Y2hlbmQodG91Y2hEYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpdGVtLl9faXNEb3duICYmIGl0ZW0udGFwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaXRlbS50YXAodG91Y2hEYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghaXRlbS5pbnRlcmFjdGl2ZUNoaWxkcmVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdXAgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGl0ZW0uX19pc0Rvd24gJiYgaXRlbS50b3VjaGVuZG91dHNpZGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpdGVtLnRvdWNoZW5kb3V0c2lkZSh0b3VjaERhdGEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgaXRlbS5fX2lzRG93biA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGl0ZW0uX190b3VjaERhdGFbdG91Y2hFdmVudC5pZGVudGlmaWVyXSA9IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gcmVtb3ZlIHRoZSB0b3VjaC4uXG4gICAgICAgIHRoaXMucG9vbC5wdXNoKHRvdWNoRGF0YSk7XG4gICAgICAgIHRoaXMudG91Y2hlc1t0b3VjaEV2ZW50LmlkZW50aWZpZXJdID0gbnVsbDtcbiAgICB9XG59O1xuIiwiLyoqXG4gKiBAZmlsZSAgICAgICAgTWFpbiBleHBvcnQgb2YgdGhlIFBJWEkgaW50ZXJhY3Rpb25zIGxpYnJhcnlcbiAqIEBhdXRob3IgICAgICBNYXQgR3JvdmVzIDxtYXRAZ29vZGJveWRpZ2l0YWwuY29tPlxuICogQGNvcHlyaWdodCAgIDIwMTMtMjAxNSBHb29kQm95RGlnaXRhbFxuICogQGxpY2Vuc2UgICAgIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vR29vZEJveURpZ2l0YWwvcGl4aS5qcy9ibG9iL21hc3Rlci9MSUNFTlNFfE1JVCBMaWNlbnNlfVxuICovXG5cbi8qKlxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEludGVyYWN0aW9uRGF0YTogICAgcmVxdWlyZSgnLi9JbnRlcmFjdGlvbkRhdGEnKSxcbiAgICBJbnRlcmFjdGlvbk1hbmFnZXI6IHJlcXVpcmUoJy4vSW50ZXJhY3Rpb25NYW5hZ2VyJylcbn07XG4iLCJ2YXIgY29yZSA9IHJlcXVpcmUoJy4uL2NvcmUnKSxcbiAgICBJbWFnZUxvYWRlciA9IHJlcXVpcmUoJy4vSW1hZ2VMb2FkZXInKTtcblxuLyoqXG4gKiBUaGUgYXRsYXMgZmlsZSBsb2FkZXIgaXMgdXNlZCB0byBsb2FkIGluIFRleHR1cmUgQXRsYXMgZGF0YSBhbmQgcGFyc2UgaXQuIFdoZW4gbG9hZGVkIHRoaXMgY2xhc3Mgd2lsbCBkaXNwYXRjaCBhICdsb2FkZWQnIGV2ZW50LiBJZiBsb2FkaW5nIGZhaWxzIHRoaXMgY2xhc3Mgd2lsbCBkaXNwYXRjaCBhbiAnZXJyb3InIGV2ZW50LlxuICpcbiAqIFRvIGdlbmVyYXRlIHRoZSBkYXRhIHlvdSBjYW4gdXNlIGh0dHA6Ly93d3cuY29kZWFuZHdlYi5jb20vdGV4dHVyZXBhY2tlciBhbmQgcHVibGlzaCBpbiB0aGUgJ0pTT04nIGZvcm1hdC5cbiAqXG4gKiBJdCBpcyBoaWdobHkgcmVjb21tZW5kZWQgdG8gdXNlIHRleHR1cmUgYXRsYXNlcyAoYWxzbyBrbm93IGFzICdzcHJpdGUgc2hlZXRzJykgYXMgaXQgYWxsb3dlZCBzcHJpdGVzIHRvIGJlIGJhdGNoZWQgYW5kIGRyYXduIHRvZ2V0aGVyIGZvciBoaWdobHkgaW5jcmVhc2VkIHJlbmRlcmluZyBzcGVlZC5cbiAqIE9uY2UgdGhlIGRhdGEgaGFzIGJlZW4gbG9hZGVkIHRoZSBmcmFtZXMgYXJlIHN0b3JlZCBpbiB0aGUgUElYSSB0ZXh0dXJlIGNhY2hlIGFuZCBjYW4gYmUgYWNjZXNzZWQgdGhvdWdoIFRleHR1cmUuZnJvbUZyYW1lSWQoKSBhbmQgU3ByaXRlLmZyb21GcmFtZUlkKClcbiAqXG4gKiBAY2xhc3NcbiAqIEBtaXhlcyBldmVudFRhcmdldFxuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gdXJsIHtTdHJpbmd9IFRoZSB1cmwgb2YgdGhlIEpTT04gZmlsZVxuICogQHBhcmFtIGNyb3Nzb3JpZ2luIHtib29sZWFufSBXaGV0aGVyIHJlcXVlc3RzIHNob3VsZCBiZSB0cmVhdGVkIGFzIGNyb3Nzb3JpZ2luXG4gKi9cbmZ1bmN0aW9uIEF0bGFzTG9hZGVyKHVybCwgY3Jvc3NvcmlnaW4pIHtcbiAgICB0aGlzLnVybCA9IHVybDtcbiAgICB0aGlzLmJhc2VVcmwgPSB1cmwucmVwbGFjZSgvW15cXC9dKiQvLCAnJyk7XG4gICAgdGhpcy5jcm9zc29yaWdpbiA9IGNyb3Nzb3JpZ2luO1xuICAgIHRoaXMubG9hZGVkID0gZmFsc2U7XG59XG5cbkF0bGFzTG9hZGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEF0bGFzTG9hZGVyO1xubW9kdWxlLmV4cG9ydHMgPSBBdGxhc0xvYWRlcjtcblxuY29yZS51dGlscy5ldmVudFRhcmdldC5taXhpbihBdGxhc0xvYWRlci5wcm90b3R5cGUpO1xuXG4gLyoqXG4gKiBTdGFydHMgbG9hZGluZyB0aGUgSlNPTiBmaWxlXG4gKlxuICovXG5BdGxhc0xvYWRlci5wcm90b3R5cGUubG9hZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmFqYXhSZXF1ZXN0ID0gbmV3IGNvcmUudXRpbHMuQWpheFJlcXVlc3QoKTtcbiAgICB0aGlzLmFqYXhSZXF1ZXN0Lm9ucmVhZHlzdGF0ZWNoYW5nZSA9IHRoaXMub25BdGxhc0xvYWRlZC5iaW5kKHRoaXMpO1xuXG4gICAgdGhpcy5hamF4UmVxdWVzdC5vcGVuKCdHRVQnLCB0aGlzLnVybCwgdHJ1ZSk7XG5cbiAgICBpZiAodGhpcy5hamF4UmVxdWVzdC5vdmVycmlkZU1pbWVUeXBlKSB7XG4gICAgICAgIHRoaXMuYWpheFJlcXVlc3Qub3ZlcnJpZGVNaW1lVHlwZSgnYXBwbGljYXRpb24vanNvbicpO1xuICAgIH1cblxuICAgIHRoaXMuYWpheFJlcXVlc3Quc2VuZChudWxsKTtcbn07XG5cbi8qKlxuICogSW52b2tlZCB3aGVuIHRoZSBBdGxhcyBoYXMgZnVsbHkgbG9hZGVkLiBQYXJzZXMgdGhlIEpTT04gYW5kIGJ1aWxkcyB0aGUgdGV4dHVyZSBmcmFtZXMuXG4gKlxuICogQHByaXZhdGVcbiAqL1xuQXRsYXNMb2FkZXIucHJvdG90eXBlLm9uQXRsYXNMb2FkZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHRoaXMuYWpheFJlcXVlc3QucmVhZHlTdGF0ZSA9PT0gNCkge1xuICAgICAgICBpZiAodGhpcy5hamF4UmVxdWVzdC5zdGF0dXMgPT09IDIwMCB8fCB3aW5kb3cubG9jYXRpb24uaHJlZi5pbmRleE9mKCdodHRwJykgPT09IC0xKSB7XG4gICAgICAgICAgICB0aGlzLmF0bGFzID0ge1xuICAgICAgICAgICAgICAgIG1ldGEgOiB7XG4gICAgICAgICAgICAgICAgICAgIGltYWdlIDogW11cbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGZyYW1lcyA6IFtdXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHRoaXMuYWpheFJlcXVlc3QucmVzcG9uc2VUZXh0LnNwbGl0KC9cXHI/XFxuLyk7XG4gICAgICAgICAgICB2YXIgbGluZUNvdW50ID0gLTM7XG5cbiAgICAgICAgICAgIHZhciBjdXJyZW50SW1hZ2VJZCA9IDA7XG4gICAgICAgICAgICB2YXIgY3VycmVudEZyYW1lID0gbnVsbDtcbiAgICAgICAgICAgIHZhciBuYW1lSW5OZXh0TGluZSA9IGZhbHNlO1xuXG4gICAgICAgICAgICB2YXIgaSA9IDAsXG4gICAgICAgICAgICAgICAgaiA9IDAsXG4gICAgICAgICAgICAgICAgc2VsZk9uTG9hZGVkID0gdGhpcy5vbkxvYWRlZC5iaW5kKHRoaXMpO1xuXG4gICAgICAgICAgICAvLyBwYXJzZXIgd2l0aG91dCByb3RhdGlvbiBzdXBwb3J0IHlldCFcbiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCByZXN1bHQubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICByZXN1bHRbaV0gPSByZXN1bHRbaV0ucmVwbGFjZSgvXlxccyt8XFxzKyQvZywgJycpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHJlc3VsdFtpXSA9PT0gJycpIHtcbiAgICAgICAgICAgICAgICAgICAgbmFtZUluTmV4dExpbmUgPSBpKzE7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHJlc3VsdFtpXS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChuYW1lSW5OZXh0TGluZSA9PT0gaSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5hdGxhcy5tZXRhLmltYWdlLnB1c2gocmVzdWx0W2ldKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRJbWFnZUlkID0gdGhpcy5hdGxhcy5tZXRhLmltYWdlLmxlbmd0aCAtIDE7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmF0bGFzLmZyYW1lcy5wdXNoKHt9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxpbmVDb3VudCA9IC0zO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGxpbmVDb3VudCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChsaW5lQ291bnQgJSA3ID09PSAxKSB7IC8vIGZyYW1lIG5hbWVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3VycmVudEZyYW1lICE9IG51bGwpIHsgLy9qc2hpbnQgaWdub3JlOmxpbmVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5hdGxhcy5mcmFtZXNbY3VycmVudEltYWdlSWRdW2N1cnJlbnRGcmFtZS5uYW1lXSA9IGN1cnJlbnRGcmFtZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VycmVudEZyYW1lID0geyBuYW1lOiByZXN1bHRbaV0sIGZyYW1lIDoge30gfTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHRleHQgPSByZXN1bHRbaV0uc3BsaXQoJyAnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobGluZUNvdW50ICUgNyA9PT0gMykgeyAvLyBwb3NpdGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50RnJhbWUuZnJhbWUueCA9IE51bWJlcih0ZXh0WzFdLnJlcGxhY2UoJywnLCAnJykpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50RnJhbWUuZnJhbWUueSA9IE51bWJlcih0ZXh0WzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGxpbmVDb3VudCAlIDcgPT09IDQpIHsgLy8gc2l6ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50RnJhbWUuZnJhbWUudyA9IE51bWJlcih0ZXh0WzFdLnJlcGxhY2UoJywnLCAnJykpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50RnJhbWUuZnJhbWUuaCA9IE51bWJlcih0ZXh0WzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGxpbmVDb3VudCAlIDcgPT09IDUpIHsgLy8gcmVhbCBzaXplXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciByZWFsU2l6ZSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggOiAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA6IDAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3IDogTnVtYmVyKHRleHRbMV0ucmVwbGFjZSgnLCcsICcnKSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoIDogTnVtYmVyKHRleHRbMl0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJlYWxTaXplLncgPiBjdXJyZW50RnJhbWUuZnJhbWUudyB8fCByZWFsU2l6ZS5oID4gY3VycmVudEZyYW1lLmZyYW1lLmgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRGcmFtZS50cmltbWVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRGcmFtZS5yZWFsU2l6ZSA9IHJlYWxTaXplO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VycmVudEZyYW1lLnRyaW1tZWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBsaW5lQ291bnQrKztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChjdXJyZW50RnJhbWUgIT0gbnVsbCkgeyAvL2pzaGludCBpZ25vcmU6bGluZVxuICAgICAgICAgICAgICAgIHRoaXMuYXRsYXMuZnJhbWVzW2N1cnJlbnRJbWFnZUlkXVtjdXJyZW50RnJhbWUubmFtZV0gPSBjdXJyZW50RnJhbWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0aGlzLmF0bGFzLm1ldGEuaW1hZ2UubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHRoaXMuaW1hZ2VzID0gW107XG4gICAgICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IHRoaXMuYXRsYXMubWV0YS5pbWFnZS5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgICAgICAvLyBzcHJpdGUgc2hlZXRcbiAgICAgICAgICAgICAgICAgICAgdmFyIHRleHR1cmVVcmwgPSB0aGlzLmJhc2VVcmwgKyB0aGlzLmF0bGFzLm1ldGEuaW1hZ2Vbal07XG4gICAgICAgICAgICAgICAgICAgIHZhciBmcmFtZURhdGEgPSB0aGlzLmF0bGFzLmZyYW1lc1tqXTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5pbWFnZXMucHVzaChuZXcgSW1hZ2VMb2FkZXIodGV4dHVyZVVybCwgdGhpcy5jcm9zc29yaWdpbikpO1xuXG4gICAgICAgICAgICAgICAgICAgIGZvciAoaSBpbiBmcmFtZURhdGEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciByZWN0ID0gZnJhbWVEYXRhW2ldLmZyYW1lO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJlY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JlLnV0aWxzLlRleHR1cmVDYWNoZVtpXSA9IG5ldyBjb3JlLlRleHR1cmUodGhpcy5pbWFnZXNbal0udGV4dHVyZS5iYXNlVGV4dHVyZSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4OiByZWN0LngsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk6IHJlY3QueSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg6IHJlY3QudyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0OiByZWN0LmhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZnJhbWVEYXRhW2ldLnRyaW1tZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29yZS51dGlscy5UZXh0dXJlQ2FjaGVbaV0ucmVhbFNpemUgPSBmcmFtZURhdGFbaV0ucmVhbFNpemU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRyaW0gaW4gcGl4aSBub3Qgc3VwcG9ydGVkIHlldCwgdG9kbyB1cGRhdGUgdHJpbSBwcm9wZXJ0aWVzIGlmIGl0IGlzIGRvbmUgLi4uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmUudXRpbHMuVGV4dHVyZUNhY2hlW2ldLnRyaW0ueCA9IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmUudXRpbHMuVGV4dHVyZUNhY2hlW2ldLnRyaW0ueSA9IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdGhpcy5jdXJyZW50SW1hZ2VJZCA9IDA7XG4gICAgICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IHRoaXMuaW1hZ2VzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaW1hZ2VzW2pdLm9uKCdsb2FkZWQnLCBzZWxmT25Mb2FkZWQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLmltYWdlc1t0aGlzLmN1cnJlbnRJbWFnZUlkXS5sb2FkKCk7XG5cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5vbkxvYWRlZCgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLm9uRXJyb3IoKTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cbi8qKlxuICogSW52b2tlZCB3aGVuIGpzb24gZmlsZSBoYXMgbG9hZGVkLlxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkF0bGFzTG9hZGVyLnByb3RvdHlwZS5vbkxvYWRlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5pbWFnZXMubGVuZ3RoIC0gMSA+IHRoaXMuY3VycmVudEltYWdlSWQpIHtcbiAgICAgICAgdGhpcy5jdXJyZW50SW1hZ2VJZCsrO1xuICAgICAgICB0aGlzLmltYWdlc1t0aGlzLmN1cnJlbnRJbWFnZUlkXS5sb2FkKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5sb2FkZWQgPSB0cnVlO1xuICAgICAgICB0aGlzLmVtaXQoJ2xvYWRlZCcsIHsgY29udGVudDogdGhpcyB9KTtcbiAgICB9XG59O1xuXG4vKipcbiAqIEludm9rZWQgd2hlbiBhbiBlcnJvciBvY2N1cnMuXG4gKlxuICogQHByaXZhdGVcbiAqL1xuQXRsYXNMb2FkZXIucHJvdG90eXBlLm9uRXJyb3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5lbWl0KCdlcnJvcicsIHsgY29udGVudDogdGhpcyB9KTtcbn07XG4iLCJ2YXIgY29yZSA9IHJlcXVpcmUoJy4uL2NvcmUnKSxcbiAgICBJbWFnZUxvYWRlciA9IHJlcXVpcmUoJy4vSW1hZ2VMb2FkZXInKTtcblxuLyoqXG4gKiBUaGUgeG1sIGxvYWRlciBpcyB1c2VkIHRvIGxvYWQgaW4gWE1MIGJpdG1hcCBmb250IGRhdGEgKCd4bWwnIG9yICdmbnQnKVxuICogVG8gZ2VuZXJhdGUgdGhlIGRhdGEgeW91IGNhbiB1c2UgaHR0cDovL3d3dy5hbmdlbGNvZGUuY29tL3Byb2R1Y3RzL2JtZm9udC9cbiAqIFRoaXMgbG9hZGVyIHdpbGwgYWxzbyBsb2FkIHRoZSBpbWFnZSBmaWxlIGFzIHRoZSBkYXRhLlxuICogV2hlbiBsb2FkZWQgdGhpcyBjbGFzcyB3aWxsIGRpc3BhdGNoIGEgJ2xvYWRlZCcgZXZlbnRcbiAqXG4gKiBAY2xhc3NcbiAqIEBtaXhlcyBldmVudFRhcmdldFxuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gdXJsIHtTdHJpbmd9IFRoZSB1cmwgb2YgdGhlIHNwcml0ZSBzaGVldCBKU09OIGZpbGVcbiAqIEBwYXJhbSBjcm9zc29yaWdpbiB7Ym9vbGVhbn0gV2hldGhlciByZXF1ZXN0cyBzaG91bGQgYmUgdHJlYXRlZCBhcyBjcm9zc29yaWdpblxuICovXG5mdW5jdGlvbiBCaXRtYXBGb250TG9hZGVyKHVybCwgY3Jvc3NvcmlnaW4pIHtcbiAgICAvKipcbiAgICAgKiBUaGUgdXJsIG9mIHRoZSBiaXRtYXAgZm9udCBkYXRhXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtTdHJpbmd9XG4gICAgICovXG4gICAgdGhpcy51cmwgPSB1cmw7XG5cbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRoZSByZXF1ZXN0cyBzaG91bGQgYmUgdHJlYXRlZCBhcyBjcm9zcyBvcmlnaW5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5jcm9zc29yaWdpbiA9IGNyb3Nzb3JpZ2luO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGJhc2UgdXJsIG9mIHRoZSBiaXRtYXAgZm9udCBkYXRhXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtTdHJpbmd9XG4gICAgICogQHJlYWRPbmx5XG4gICAgICovXG4gICAgdGhpcy5iYXNlVXJsID0gdXJsLnJlcGxhY2UoL1teXFwvXSokLywgJycpO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHRleHR1cmUgb2YgdGhlIGJpdG1hcCBmb250XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtUZXh0dXJlfVxuICAgICAqL1xuICAgIHRoaXMudGV4dHVyZSA9IG51bGw7XG59XG5cbi8vIGNvbnN0cnVjdG9yXG5CaXRtYXBGb250TG9hZGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEJpdG1hcEZvbnRMb2FkZXI7XG5tb2R1bGUuZXhwb3J0cyA9IEJpdG1hcEZvbnRMb2FkZXI7XG5cbmNvcmUudXRpbHMuZXZlbnRUYXJnZXQubWl4aW4oQml0bWFwRm9udExvYWRlci5wcm90b3R5cGUpO1xuXG4vKipcbiAqIExvYWRzIHRoZSBYTUwgZm9udCBkYXRhXG4gKlxuICovXG5CaXRtYXBGb250TG9hZGVyLnByb3RvdHlwZS5sb2FkID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuYWpheFJlcXVlc3QgPSBuZXcgY29yZS51dGlscy5BamF4UmVxdWVzdCgpO1xuICAgIHRoaXMuYWpheFJlcXVlc3Qub25yZWFkeXN0YXRlY2hhbmdlID0gdGhpcy5vblhNTExvYWRlZC5iaW5kKHRoaXMpO1xuXG4gICAgdGhpcy5hamF4UmVxdWVzdC5vcGVuKCdHRVQnLCB0aGlzLnVybCwgdHJ1ZSk7XG5cbiAgICBpZiAodGhpcy5hamF4UmVxdWVzdC5vdmVycmlkZU1pbWVUeXBlKSB7XG4gICAgICAgIHRoaXMuYWpheFJlcXVlc3Qub3ZlcnJpZGVNaW1lVHlwZSgnYXBwbGljYXRpb24veG1sJyk7XG4gICAgfVxuXG4gICAgdGhpcy5hamF4UmVxdWVzdC5zZW5kKG51bGwpO1xufTtcblxuLyoqXG4gKiBJbnZva2VkIHdoZW4gdGhlIFhNTCBmaWxlIGlzIGxvYWRlZCwgcGFyc2VzIHRoZSBkYXRhLlxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkJpdG1hcEZvbnRMb2FkZXIucHJvdG90eXBlLm9uWE1MTG9hZGVkID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICh0aGlzLmFqYXhSZXF1ZXN0LnJlYWR5U3RhdGUgPT09IDQpIHtcbiAgICAgICAgaWYgKHRoaXMuYWpheFJlcXVlc3Quc3RhdHVzID09PSAyMDAgfHwgd2luZG93LmxvY2F0aW9uLnByb3RvY29sLmluZGV4T2YoJ2h0dHAnKSA9PT0gLTEpIHtcbiAgICAgICAgICAgIHZhciByZXNwb25zZVhNTCA9IHRoaXMuYWpheFJlcXVlc3QucmVzcG9uc2VYTUw7XG4gICAgICAgICAgICBpZiAoIXJlc3BvbnNlWE1MIHx8IC9NU0lFIDkvaS50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpIHx8IG5hdmlnYXRvci5pc0NvY29vbkpTKSB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZih3aW5kb3cuRE9NUGFyc2VyKSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZG9tcGFyc2VyID0gbmV3IERPTVBhcnNlcigpO1xuICAgICAgICAgICAgICAgICAgICByZXNwb25zZVhNTCA9IGRvbXBhcnNlci5wYXJzZUZyb21TdHJpbmcodGhpcy5hamF4UmVxdWVzdC5yZXNwb25zZVRleHQsICd0ZXh0L3htbCcpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkaXYgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICAgICAgICAgICAgICAgICAgZGl2LmlubmVySFRNTCA9IHRoaXMuYWpheFJlcXVlc3QucmVzcG9uc2VUZXh0O1xuICAgICAgICAgICAgICAgICAgICByZXNwb25zZVhNTCA9IGRpdjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciB0ZXh0dXJlVXJsID0gdGhpcy5iYXNlVXJsICsgcmVzcG9uc2VYTUwuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3BhZ2UnKVswXS5nZXRBdHRyaWJ1dGUoJ2ZpbGUnKTtcbiAgICAgICAgICAgIHZhciBpbWFnZSA9IG5ldyBJbWFnZUxvYWRlcih0ZXh0dXJlVXJsLCB0aGlzLmNyb3Nzb3JpZ2luKTtcbiAgICAgICAgICAgIHRoaXMudGV4dHVyZSA9IGltYWdlLnRleHR1cmUuYmFzZVRleHR1cmU7XG5cbiAgICAgICAgICAgIHZhciBkYXRhID0ge307XG4gICAgICAgICAgICB2YXIgaW5mbyA9IHJlc3BvbnNlWE1MLmdldEVsZW1lbnRzQnlUYWdOYW1lKCdpbmZvJylbMF07XG4gICAgICAgICAgICB2YXIgY29tbW9uID0gcmVzcG9uc2VYTUwuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2NvbW1vbicpWzBdO1xuICAgICAgICAgICAgZGF0YS5mb250ID0gaW5mby5nZXRBdHRyaWJ1dGUoJ2ZhY2UnKTtcbiAgICAgICAgICAgIGRhdGEuc2l6ZSA9IHBhcnNlSW50KGluZm8uZ2V0QXR0cmlidXRlKCdzaXplJyksIDEwKTtcbiAgICAgICAgICAgIGRhdGEubGluZUhlaWdodCA9IHBhcnNlSW50KGNvbW1vbi5nZXRBdHRyaWJ1dGUoJ2xpbmVIZWlnaHQnKSwgMTApO1xuICAgICAgICAgICAgZGF0YS5jaGFycyA9IHt9O1xuXG4gICAgICAgICAgICAvL3BhcnNlIGxldHRlcnNcbiAgICAgICAgICAgIHZhciBsZXR0ZXJzID0gcmVzcG9uc2VYTUwuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2NoYXInKTtcblxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZXR0ZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNoYXJDb2RlID0gcGFyc2VJbnQobGV0dGVyc1tpXS5nZXRBdHRyaWJ1dGUoJ2lkJyksIDEwKTtcblxuICAgICAgICAgICAgICAgIHZhciB0ZXh0dXJlUmVjdCA9IG5ldyBjb3JlLm1hdGguUmVjdGFuZ2xlKFxuICAgICAgICAgICAgICAgICAgICBwYXJzZUludChsZXR0ZXJzW2ldLmdldEF0dHJpYnV0ZSgneCcpLCAxMCksXG4gICAgICAgICAgICAgICAgICAgIHBhcnNlSW50KGxldHRlcnNbaV0uZ2V0QXR0cmlidXRlKCd5JyksIDEwKSxcbiAgICAgICAgICAgICAgICAgICAgcGFyc2VJbnQobGV0dGVyc1tpXS5nZXRBdHRyaWJ1dGUoJ3dpZHRoJyksIDEwKSxcbiAgICAgICAgICAgICAgICAgICAgcGFyc2VJbnQobGV0dGVyc1tpXS5nZXRBdHRyaWJ1dGUoJ2hlaWdodCcpLCAxMClcbiAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgZGF0YS5jaGFyc1tjaGFyQ29kZV0gPSB7XG4gICAgICAgICAgICAgICAgICAgIHhPZmZzZXQ6IHBhcnNlSW50KGxldHRlcnNbaV0uZ2V0QXR0cmlidXRlKCd4b2Zmc2V0JyksIDEwKSxcbiAgICAgICAgICAgICAgICAgICAgeU9mZnNldDogcGFyc2VJbnQobGV0dGVyc1tpXS5nZXRBdHRyaWJ1dGUoJ3lvZmZzZXQnKSwgMTApLFxuICAgICAgICAgICAgICAgICAgICB4QWR2YW5jZTogcGFyc2VJbnQobGV0dGVyc1tpXS5nZXRBdHRyaWJ1dGUoJ3hhZHZhbmNlJyksIDEwKSxcbiAgICAgICAgICAgICAgICAgICAga2VybmluZzoge30sXG4gICAgICAgICAgICAgICAgICAgIHRleHR1cmU6IGNvcmUudXRpbHMuVGV4dHVyZUNhY2hlW2NoYXJDb2RlXSA9IG5ldyBjb3JlLlRleHR1cmUodGhpcy50ZXh0dXJlLCB0ZXh0dXJlUmVjdClcblxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vcGFyc2Uga2VybmluZ3NcbiAgICAgICAgICAgIHZhciBrZXJuaW5ncyA9IHJlc3BvbnNlWE1MLmdldEVsZW1lbnRzQnlUYWdOYW1lKCdrZXJuaW5nJyk7XG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwga2VybmluZ3MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgZmlyc3QgPSBwYXJzZUludChrZXJuaW5nc1tpXS5nZXRBdHRyaWJ1dGUoJ2ZpcnN0JyksIDEwKTtcbiAgICAgICAgICAgICAgICB2YXIgc2Vjb25kID0gcGFyc2VJbnQoa2VybmluZ3NbaV0uZ2V0QXR0cmlidXRlKCdzZWNvbmQnKSwgMTApO1xuICAgICAgICAgICAgICAgIHZhciBhbW91bnQgPSBwYXJzZUludChrZXJuaW5nc1tpXS5nZXRBdHRyaWJ1dGUoJ2Ftb3VudCcpLCAxMCk7XG5cbiAgICAgICAgICAgICAgICBkYXRhLmNoYXJzW3NlY29uZF0ua2VybmluZ1tmaXJzdF0gPSBhbW91bnQ7XG5cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29yZS5CaXRtYXBUZXh0LmZvbnRzW2RhdGEuZm9udF0gPSBkYXRhO1xuXG4gICAgICAgICAgICBpbWFnZS5hZGRFdmVudExpc3RlbmVyKCdsb2FkZWQnLCB0aGlzLm9uTG9hZGVkLmJpbmQodGhpcykpO1xuICAgICAgICAgICAgaW1hZ2UubG9hZCgpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuLyoqXG4gKiBJbnZva2VkIHdoZW4gYWxsIGZpbGVzIGFyZSBsb2FkZWQgKHhtbC9mbnQgYW5kIHRleHR1cmUpXG4gKlxuICogQHByaXZhdGVcbiAqL1xuQml0bWFwRm9udExvYWRlci5wcm90b3R5cGUub25Mb2FkZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5lbWl0KCdsb2FkZWQnLCB7IGNvbnRlbnQ6IHRoaXMgfSk7XG59O1xuIiwidmFyIGNvcmUgPSByZXF1aXJlKCcuLi9jb3JlJyk7XG5cbi8qKlxuICogVGhlIGltYWdlIGxvYWRlciBjbGFzcyBpcyByZXNwb25zaWJsZSBmb3IgbG9hZGluZyBpbWFnZXMgZmlsZSBmb3JtYXRzICgnanBlZycsICdqcGcnLCAncG5nJyBhbmQgJ2dpZicpXG4gKiBPbmNlIHRoZSBpbWFnZSBoYXMgYmVlbiBsb2FkZWQgaXQgaXMgc3RvcmVkIGluIHRoZSBQSVhJIHRleHR1cmUgY2FjaGUgYW5kIGNhbiBiZSBhY2Nlc3NlZCB0aG91Z2ggVGV4dHVyZS5mcm9tRnJhbWUoKSBhbmQgU3ByaXRlLmZyb21GcmFtZSgpXG4gKiBXaGVuIGxvYWRlZCB0aGlzIGNsYXNzIHdpbGwgZGlzcGF0Y2ggYSAnbG9hZGVkJyBldmVudFxuICpcbiAqIEBjbGFzc1xuICogQG1peGVzIGV2ZW50VGFyZ2V0XG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSB1cmwge1N0cmluZ30gVGhlIHVybCBvZiB0aGUgaW1hZ2VcbiAqIEBwYXJhbSBjcm9zc29yaWdpbiB7Ym9vbGVhbn0gV2hldGhlciByZXF1ZXN0cyBzaG91bGQgYmUgdHJlYXRlZCBhcyBjcm9zc29yaWdpblxuICovXG5mdW5jdGlvbiBJbWFnZUxvYWRlcih1cmwsIGNyb3Nzb3JpZ2luKSB7XG4gICAgLyoqXG4gICAgICogVGhlIHRleHR1cmUgYmVpbmcgbG9hZGVkXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtUZXh0dXJlfVxuICAgICAqL1xuICAgIHRoaXMudGV4dHVyZSA9IGNvcmUuVGV4dHVyZS5mcm9tSW1hZ2UodXJsLCBjcm9zc29yaWdpbik7XG5cbiAgICAvKipcbiAgICAgKiBpZiB0aGUgaW1hZ2UgaXMgbG9hZGVkIHdpdGggbG9hZEZyYW1lZFNwcml0ZVNoZWV0XG4gICAgICogZnJhbWVzIHdpbGwgY29udGFpbiB0aGUgc3ByaXRlIHNoZWV0IGZyYW1lc1xuICAgICAqXG4gICAgICogQG1lbWJlciB7QXJyYXl9XG4gICAgICogQHJlYWRPbmx5XG4gICAgICovXG4gICAgdGhpcy5mcmFtZXMgPSBbXTtcbn1cblxuLy8gY29uc3RydWN0b3JcbkltYWdlTG9hZGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEltYWdlTG9hZGVyO1xubW9kdWxlLmV4cG9ydHMgPSBJbWFnZUxvYWRlcjtcblxuY29yZS51dGlscy5ldmVudFRhcmdldC5taXhpbihJbWFnZUxvYWRlci5wcm90b3R5cGUpO1xuXG4vKipcbiAqIExvYWRzIGltYWdlIG9yIHRha2VzIGl0IGZyb20gY2FjaGVcbiAqXG4gKi9cbkltYWdlTG9hZGVyLnByb3RvdHlwZS5sb2FkID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICghdGhpcy50ZXh0dXJlLmJhc2VUZXh0dXJlLmhhc0xvYWRlZCkge1xuICAgICAgICB0aGlzLnRleHR1cmUuYmFzZVRleHR1cmUub24oJ2xvYWRlZCcsIHRoaXMub25Mb2FkZWQuYmluZCh0aGlzKSk7XG4gICAgICAgIHRoaXMudGV4dHVyZS5iYXNlVGV4dHVyZS5vbignZXJyb3InLCB0aGlzLm9uRXJyb3IuYmluZCh0aGlzKSk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLm9uTG9hZGVkKCk7XG4gICAgfVxufTtcblxuLyoqXG4gKiBJbnZva2VkIHdoZW4gaW1hZ2UgZmlsZSBpcyBsb2FkZWQgb3IgaXQgaXMgYWxyZWFkeSBjYWNoZWQgYW5kIHJlYWR5IHRvIHVzZVxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkltYWdlTG9hZGVyLnByb3RvdHlwZS5vbkxvYWRlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmVtaXQoJ2xvYWRlZCcsIHsgY29udGVudDogdGhpcyB9KTtcbn07XG5cbi8qKlxuICogSW52b2tlZCB3aGVuIGltYWdlIGZpbGUgZmFpbGVkIGxvYWRpbmdcbiAqXG4gKiBAbWV0aG9kIG9uRXJyb3JcbiAqIEBwcml2YXRlXG4gKi9cbkltYWdlTG9hZGVyLnByb3RvdHlwZS5vbkVycm9yID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZW1pdCgnZXJyb3InLCB7IGNvbnRlbnQ6IHRoaXMgfSk7XG59O1xuXG4vKipcbiAqIExvYWRzIGltYWdlIGFuZCBzcGxpdCBpdCB0byB1bmlmb3JtIHNpemVkIGZyYW1lc1xuICpcbiAqIEBwYXJhbSBmcmFtZVdpZHRoIHtudW1iZXJ9IHdpZHRoIG9mIGVhY2ggZnJhbWVcbiAqIEBwYXJhbSBmcmFtZUhlaWdodCB7bnVtYmVyfSBoZWlnaHQgb2YgZWFjaCBmcmFtZVxuICogQHBhcmFtIHRleHR1cmVOYW1lIHtTdHJpbmd9IGlmIGdpdmVuLCB0aGUgZnJhbWVzIHdpbGwgYmUgY2FjaGVkIGluIDx0ZXh0dXJlTmFtZT4tPG9yZD4gZm9ybWF0XG4gKi9cbkltYWdlTG9hZGVyLnByb3RvdHlwZS5sb2FkRnJhbWVkU3ByaXRlU2hlZXQgPSBmdW5jdGlvbiAoZnJhbWVXaWR0aCwgZnJhbWVIZWlnaHQsIHRleHR1cmVOYW1lKSB7XG4gICAgdGhpcy5mcmFtZXMgPSBbXTtcblxuICAgIHZhciBjb2xzID0gTWF0aC5mbG9vcih0aGlzLnRleHR1cmUud2lkdGggLyBmcmFtZVdpZHRoKTtcbiAgICB2YXIgcm93cyA9IE1hdGguZmxvb3IodGhpcy50ZXh0dXJlLmhlaWdodCAvIGZyYW1lSGVpZ2h0KTtcblxuICAgIHZhciBpPTA7XG4gICAgZm9yICh2YXIgeSA9IDA7IHkgPCByb3dzOyArK3kpIHtcbiAgICAgICAgZm9yICh2YXIgeCA9IDA7IHggPCBjb2xzOyArK3gsICsraSkge1xuICAgICAgICAgICAgdmFyIHRleHR1cmUgPSBuZXcgY29yZS5UZXh0dXJlKFxuICAgICAgICAgICAgICAgIHRoaXMudGV4dHVyZS5iYXNlVGV4dHVyZSxcbiAgICAgICAgICAgICAgICBuZXcgY29yZS5tYXRoLlJlY3RhbmdsZShcbiAgICAgICAgICAgICAgICAgICAgeCAqIGZyYW1lV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgIHkgKiBmcmFtZUhlaWdodCxcbiAgICAgICAgICAgICAgICAgICAgZnJhbWVXaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgZnJhbWVIZWlnaHRcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB0aGlzLmZyYW1lcy5wdXNoKHRleHR1cmUpO1xuXG4gICAgICAgICAgICBpZiAodGV4dHVyZU5hbWUpIHtcbiAgICAgICAgICAgICAgICBjb3JlLnV0aWxzLlRleHR1cmVDYWNoZVt0ZXh0dXJlTmFtZSArICctJyArIGldID0gdGV4dHVyZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuXHR0aGlzLmxvYWQoKTtcbn07XG4iLCJ2YXIgY29yZSA9IHJlcXVpcmUoJy4uL2NvcmUnKSxcbiAgICBzcGluZSA9IHJlcXVpcmUoJy4uL3NwaW5lL1NwaW5lUnVudGltZScpLFxuICAgIEltYWdlTG9hZGVyID0gcmVxdWlyZSgnLi9JbWFnZUxvYWRlcicpLFxuICAgIFNwaW5lVGV4dHVyZUxvYWRlciA9IHJlcXVpcmUoJy4vU3BpbmVUZXh0dXJlTG9hZGVyJyk7XG5cbi8qKlxuICogVGhlIGpzb24gZmlsZSBsb2FkZXIgaXMgdXNlZCB0byBsb2FkIGluIEpTT04gZGF0YSBhbmQgcGFyc2UgaXRcbiAqIFdoZW4gbG9hZGVkIHRoaXMgY2xhc3Mgd2lsbCBkaXNwYXRjaCBhICdsb2FkZWQnIGV2ZW50XG4gKiBJZiBsb2FkaW5nIGZhaWxzIHRoaXMgY2xhc3Mgd2lsbCBkaXNwYXRjaCBhbiAnZXJyb3InIGV2ZW50XG4gKlxuICogQGNsYXNzXG4gKiBAbWl4ZXMgZXZlbnRUYXJnZXRcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHVybCB7U3RyaW5nfSBUaGUgdXJsIG9mIHRoZSBKU09OIGZpbGVcbiAqIEBwYXJhbSBjcm9zc29yaWdpbiB7Ym9vbGVhbn0gV2hldGhlciByZXF1ZXN0cyBzaG91bGQgYmUgdHJlYXRlZCBhcyBjcm9zc29yaWdpblxuICovXG5mdW5jdGlvbiBKc29uTG9hZGVyKHVybCwgY3Jvc3NvcmlnaW4pIHtcbiAgICAvKipcbiAgICAgKiBUaGUgdXJsIG9mIHRoZSBiaXRtYXAgZm9udCBkYXRhXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtTdHJpbmd9XG4gICAgICovXG4gICAgdGhpcy51cmwgPSB1cmw7XG5cbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRoZSByZXF1ZXN0cyBzaG91bGQgYmUgdHJlYXRlZCBhcyBjcm9zcyBvcmlnaW5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5jcm9zc29yaWdpbiA9IGNyb3Nzb3JpZ2luO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGJhc2UgdXJsIG9mIHRoZSBiaXRtYXAgZm9udCBkYXRhXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtTdHJpbmd9XG4gICAgICogQHJlYWRPbmx5XG4gICAgICovXG4gICAgdGhpcy5iYXNlVXJsID0gdXJsLnJlcGxhY2UoL1teXFwvXSokLywgJycpO1xuXG4gICAgLyoqXG4gICAgICogV2hldGhlciB0aGUgZGF0YSBoYXMgbG9hZGVkIHlldFxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAcmVhZE9ubHlcbiAgICAgKi9cbiAgICAgdGhpcy5sb2FkZWQgPSBmYWxzZTtcbn1cblxuLy8gY29uc3RydWN0b3Jcbkpzb25Mb2FkZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gSnNvbkxvYWRlcjtcbm1vZHVsZS5leHBvcnRzID0gSnNvbkxvYWRlcjtcblxuY29yZS51dGlscy5ldmVudFRhcmdldC5taXhpbihKc29uTG9hZGVyLnByb3RvdHlwZSk7XG5cbi8qKlxuICogTG9hZHMgdGhlIEpTT04gZGF0YVxuICpcbiAqL1xuSnNvbkxvYWRlci5wcm90b3R5cGUubG9hZCA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAod2luZG93LlhEb21haW5SZXF1ZXN0ICYmIHRoaXMuY3Jvc3NvcmlnaW4pIHtcbiAgICAgICAgdGhpcy5hamF4UmVxdWVzdCA9IG5ldyB3aW5kb3cuWERvbWFpblJlcXVlc3QoKTtcblxuICAgICAgICAvLyBYRG9tYWluUmVxdWVzdCBoYXMgYSBmZXcgcXVpcmtzLiBPY2Nhc2lvbmFsbHkgaXQgd2lsbCBhYm9ydCByZXF1ZXN0c1xuICAgICAgICAvLyBBIHdheSB0byBhdm9pZCB0aGlzIGlzIHRvIG1ha2Ugc3VyZSBBTEwgY2FsbGJhY2tzIGFyZSBzZXQgZXZlbiBpZiBub3QgdXNlZFxuICAgICAgICAvLyBNb3JlIGluZm8gaGVyZTogaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8xNTc4Njk2Ni94ZG9tYWlucmVxdWVzdC1hYm9ydHMtcG9zdC1vbi1pZS05XG4gICAgICAgIHRoaXMuYWpheFJlcXVlc3QudGltZW91dCA9IDMwMDA7XG5cbiAgICAgICAgdGhpcy5hamF4UmVxdWVzdC5vbmVycm9yID0gdGhpcy5vbkVycm9yLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuYWpheFJlcXVlc3Qub250aW1lb3V0ID0gdGhpcy5vbkVycm9yLmJpbmQodGhpcyk7XG5cbiAgICAgICAgdGhpcy5hamF4UmVxdWVzdC5vbnByb2dyZXNzID0gZnVuY3Rpb24gKCkge307XG5cbiAgICAgICAgdGhpcy5hamF4UmVxdWVzdC5vbmxvYWQgPSB0aGlzLm9uSlNPTkxvYWRlZC5iaW5kKHRoaXMpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgaWYgKHdpbmRvdy5YTUxIdHRwUmVxdWVzdCkge1xuICAgICAgICAgICAgdGhpcy5hamF4UmVxdWVzdCA9IG5ldyB3aW5kb3cuWE1MSHR0cFJlcXVlc3QoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuYWpheFJlcXVlc3QgPSBuZXcgd2luZG93LkFjdGl2ZVhPYmplY3QoJ01pY3Jvc29mdC5YTUxIVFRQJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmFqYXhSZXF1ZXN0Lm9ucmVhZHlzdGF0ZWNoYW5nZSA9IHRoaXMub25SZWFkeVN0YXRlQ2hhbmdlZC5iaW5kKHRoaXMpO1xuICAgIH1cblxuICAgIHRoaXMuYWpheFJlcXVlc3Qub3BlbignR0VUJyx0aGlzLnVybCx0cnVlKTtcblxuICAgIHRoaXMuYWpheFJlcXVlc3Quc2VuZCgpO1xufTtcblxuLyoqXG4gKiBCcmlkZ2UgZnVuY3Rpb24gdG8gYmUgYWJsZSB0byB1c2UgdGhlIG1vcmUgcmVsaWFibGUgb25yZWFkeXN0YXRlY2hhbmdlIGluIFhNTEh0dHBSZXF1ZXN0LlxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkpzb25Mb2FkZXIucHJvdG90eXBlLm9uUmVhZHlTdGF0ZUNoYW5nZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHRoaXMuYWpheFJlcXVlc3QucmVhZHlTdGF0ZSA9PT0gNCAmJiAodGhpcy5hamF4UmVxdWVzdC5zdGF0dXMgPT09IDIwMCB8fCB3aW5kb3cubG9jYXRpb24uaHJlZi5pbmRleE9mKCdodHRwJykgPT09IC0xKSkge1xuICAgICAgICB0aGlzLm9uSlNPTkxvYWRlZCgpO1xuICAgIH1cbn07XG5cbi8qKlxuICogSW52b2tlIHdoZW4gSlNPTiBmaWxlIGlzIGxvYWRlZFxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkpzb25Mb2FkZXIucHJvdG90eXBlLm9uSlNPTkxvYWRlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoIXRoaXMuYWpheFJlcXVlc3QucmVzcG9uc2VUZXh0KSB7XG4gICAgICAgIHRoaXMub25FcnJvcigpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5qc29uID0gSlNPTi5wYXJzZSh0aGlzLmFqYXhSZXF1ZXN0LnJlc3BvbnNlVGV4dCk7XG5cbiAgICBpZiAodGhpcy5qc29uLmZyYW1lcykge1xuICAgICAgICAvLyBzcHJpdGUgc2hlZXRcbiAgICAgICAgdmFyIHRleHR1cmVVcmwgPSB0aGlzLmJhc2VVcmwgKyB0aGlzLmpzb24ubWV0YS5pbWFnZTtcbiAgICAgICAgdmFyIGltYWdlID0gbmV3IEltYWdlTG9hZGVyKHRleHR1cmVVcmwsIHRoaXMuY3Jvc3NvcmlnaW4pO1xuICAgICAgICB2YXIgZnJhbWVEYXRhID0gdGhpcy5qc29uLmZyYW1lcztcblxuICAgICAgICB0aGlzLnRleHR1cmUgPSBpbWFnZS50ZXh0dXJlLmJhc2VUZXh0dXJlO1xuICAgICAgICBpbWFnZS5hZGRFdmVudExpc3RlbmVyKCdsb2FkZWQnLCB0aGlzLm9uTG9hZGVkLmJpbmQodGhpcykpO1xuICAgICAgICBpbWFnZS5hZGRFdmVudExpc3RlbmVyKCdlcnJvcicsIHRoaXMub25FcnJvci5iaW5kKHRoaXMpKTtcblxuICAgICAgICBmb3IgKHZhciBpIGluIGZyYW1lRGF0YSkge1xuICAgICAgICAgICAgdmFyIHJlY3QgPSBmcmFtZURhdGFbaV0uZnJhbWU7XG5cbiAgICAgICAgICAgIGlmIChyZWN0KSB7XG4gICAgICAgICAgICAgICAgdmFyIHRleHR1cmVTaXplID0gbmV3IGNvcmUubWF0aC5SZWN0YW5nbGUocmVjdC54LCByZWN0LnksIHJlY3QudywgcmVjdC5oKTtcbiAgICAgICAgICAgICAgICB2YXIgY3JvcCA9IHRleHR1cmVTaXplLmNsb25lKCk7XG4gICAgICAgICAgICAgICAgdmFyIHRyaW0gPSBudWxsO1xuXG4gICAgICAgICAgICAgICAgLy8gIENoZWNrIHRvIHNlZSBpZiB0aGUgc3ByaXRlIGlzIHRyaW1tZWRcbiAgICAgICAgICAgICAgICBpZiAoZnJhbWVEYXRhW2ldLnRyaW1tZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGFjdHVhbFNpemUgPSBmcmFtZURhdGFbaV0uc291cmNlU2l6ZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHJlYWxTaXplID0gZnJhbWVEYXRhW2ldLnNwcml0ZVNvdXJjZVNpemU7XG4gICAgICAgICAgICAgICAgICAgIHRyaW0gPSBuZXcgY29yZS5tYXRoLlJlY3RhbmdsZShyZWFsU2l6ZS54LCByZWFsU2l6ZS55LCBhY3R1YWxTaXplLncsIGFjdHVhbFNpemUuaCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvcmUudXRpbHMuVGV4dHVyZUNhY2hlW2ldID0gbmV3IGNvcmUuVGV4dHVyZSh0aGlzLnRleHR1cmUsIHRleHR1cmVTaXplLCBjcm9wLCB0cmltKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGltYWdlLmxvYWQoKTtcblxuICAgIH1cbiAgICBlbHNlIGlmICh0aGlzLmpzb24uYm9uZXMpIHtcblx0XHQvLyBjaGVjayBpZiB0aGUganNvbiB3YXMgbG9hZGVkIGJlZm9yZVxuXHRcdGlmIChjb3JlLnV0aWxzLkFuaW1DYWNoZVt0aGlzLnVybF0pIHtcblx0XHRcdHRoaXMub25Mb2FkZWQoKTtcblx0XHR9XG5cdFx0ZWxzZSB7XG5cdFx0XHQvKipcbiAgICAgICAgICAgICAqIHVzZSBhIGJpdCBvZiBoYWNrZXJ5IHRvIGxvYWQgdGhlIGF0bGFzIGZpbGUsIGhlcmUgd2UgYXNzdW1lIHRoYXQgdGhlIC5qc29uLCAuYXRsYXMgYW5kIC5wbmcgZmlsZXNcblx0XHRcdCAqIHRoYXQgY29ycmVzcG9uZCB0byB0aGUgc3BpbmUgZmlsZSBhcmUgaW4gdGhlIHNhbWUgYmFzZSBVUkwgYW5kIHRoYXQgdGhlIC5qc29uIGFuZCAuYXRsYXMgZmlsZXNcblx0XHRcdCAqIGhhdmUgdGhlIHNhbWUgbmFtZVxuXHRcdFx0ICovXG5cdFx0XHR2YXIgYXRsYXNQYXRoID0gdGhpcy51cmwuc3Vic3RyKDAsIHRoaXMudXJsLmxhc3RJbmRleE9mKCcuJykpICsgJy5hdGxhcyc7XG5cdFx0XHR2YXIgYXRsYXNMb2FkZXIgPSBuZXcgSnNvbkxvYWRlcihhdGxhc1BhdGgsIHRoaXMuY3Jvc3NvcmlnaW4pO1xuXHRcdFx0Ly8gc2F2ZSBhIGNvcHkgb2YgdGhlIGN1cnJlbnQgb2JqZWN0IGZvciBmdXR1cmUgcmVmZXJlbmNlIC8vXG5cdFx0XHR2YXIgb3JpZ2luYWxMb2FkZXIgPSB0aGlzO1xuXHRcdFx0Ly8gYmVmb3JlIGxvYWRpbmcgdGhlIGZpbGUsIHJlcGxhY2UgdGhlIFwib25KU09OTG9hZGVkXCIgZnVuY3Rpb24gZm9yIG91ciBvd24gLy9cblx0XHRcdGF0bGFzTG9hZGVyLm9uSlNPTkxvYWRlZCA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0Ly8gYXQgdGhpcyBwb2ludCBcInRoaXNcIiBwb2ludHMgYXQgdGhlIGF0bGFzTG9hZGVyIChKc29uTG9hZGVyKSBpbnN0YW5jZSAvL1xuXHRcdFx0XHRpZiAoIXRoaXMuYWpheFJlcXVlc3QucmVzcG9uc2VUZXh0KSB7XG5cdFx0XHRcdFx0dGhpcy5vbkVycm9yKCk7IC8vIEZJWE1FOiBobW0sIHRoaXMgaXMgZnVubnkgYmVjYXVzZSB3ZSBhcmUgbm90IHJlc3BvbmRpbmcgdG8gZXJyb3JzIHlldFxuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXHRcdFx0XHQvLyBjcmVhdGUgYSBuZXcgaW5zdGFuY2Ugb2YgYSBzcGluZSB0ZXh0dXJlIGxvYWRlciBmb3IgdGhpcyBzcGluZSBvYmplY3QgLy9cblx0XHRcdFx0dmFyIHRleHR1cmVMb2FkZXIgPSBuZXcgU3BpbmVUZXh0dXJlTG9hZGVyKHRoaXMudXJsLnN1YnN0cmluZygwLCB0aGlzLnVybC5sYXN0SW5kZXhPZignLycpKSk7XG5cdFx0XHRcdC8vIGNyZWF0ZSBhIHNwaW5lIGF0bGFzIHVzaW5nIHRoZSBsb2FkZWQgdGV4dCBhbmQgYSBzcGluZSB0ZXh0dXJlIGxvYWRlciBpbnN0YW5jZSAvL1xuXHRcdFx0XHR2YXIgc3BpbmVBdGxhcyA9IG5ldyBzcGluZS5BdGxhcyh0aGlzLmFqYXhSZXF1ZXN0LnJlc3BvbnNlVGV4dCwgdGV4dHVyZUxvYWRlcik7XG5cdFx0XHRcdC8vIG5vdyB3ZSB1c2UgYW4gYXRsYXMgYXR0YWNobWVudCBsb2FkZXIgLy9cblx0XHRcdFx0dmFyIGF0dGFjaG1lbnRMb2FkZXIgPSBuZXcgc3BpbmUuQXRsYXNBdHRhY2htZW50TG9hZGVyKHNwaW5lQXRsYXMpO1xuXHRcdFx0XHQvLyBzcGluZSBhbmltYXRpb25cblx0XHRcdFx0dmFyIHNwaW5lSnNvblBhcnNlciA9IG5ldyBzcGluZS5Ta2VsZXRvbkpzb24oYXR0YWNobWVudExvYWRlcik7XG5cdFx0XHRcdHZhciBza2VsZXRvbkRhdGEgPSBzcGluZUpzb25QYXJzZXIucmVhZFNrZWxldG9uRGF0YShvcmlnaW5hbExvYWRlci5qc29uKTtcblx0XHRcdFx0Y29yZS51dGlscy5BbmltQ2FjaGVbb3JpZ2luYWxMb2FkZXIudXJsXSA9IHNrZWxldG9uRGF0YTtcblx0XHRcdFx0b3JpZ2luYWxMb2FkZXIuc3BpbmUgPSBza2VsZXRvbkRhdGE7XG5cdFx0XHRcdG9yaWdpbmFsTG9hZGVyLnNwaW5lQXRsYXMgPSBzcGluZUF0bGFzO1xuXHRcdFx0XHRvcmlnaW5hbExvYWRlci5zcGluZUF0bGFzTG9hZGVyID0gYXRsYXNMb2FkZXI7XG5cdFx0XHRcdC8vIHdhaXQgZm9yIHRleHR1cmVzIHRvIGZpbmlzaCBsb2FkaW5nIGlmIG5lZWRlZFxuXHRcdFx0XHRpZiAodGV4dHVyZUxvYWRlci5sb2FkaW5nQ291bnQgPiAwKSB7XG5cdFx0XHRcdFx0dGV4dHVyZUxvYWRlci5hZGRFdmVudExpc3RlbmVyKCdsb2FkZWRCYXNlVGV4dHVyZScsIGZ1bmN0aW9uIChldnQpe1xuXHRcdFx0XHRcdFx0aWYgKGV2dC5jb250ZW50LmNvbnRlbnQubG9hZGluZ0NvdW50IDw9IDApIHtcblx0XHRcdFx0XHRcdFx0b3JpZ2luYWxMb2FkZXIub25Mb2FkZWQoKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRvcmlnaW5hbExvYWRlci5vbkxvYWRlZCgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9O1xuXHRcdFx0Ly8gc3RhcnQgdGhlIGxvYWRpbmcgLy9cblx0XHRcdGF0bGFzTG9hZGVyLmxvYWQoKTtcblx0XHR9XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLm9uTG9hZGVkKCk7XG4gICAgfVxufTtcblxuLyoqXG4gKiBJbnZva2Ugd2hlbiBqc29uIGZpbGUgbG9hZGVkXG4gKlxuICogQHByaXZhdGVcbiAqL1xuSnNvbkxvYWRlci5wcm90b3R5cGUub25Mb2FkZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5sb2FkZWQgPSB0cnVlO1xuICAgIHRoaXMuZGlzcGF0Y2hFdmVudCh7XG4gICAgICAgIHR5cGU6ICdsb2FkZWQnLFxuICAgICAgICBjb250ZW50OiB0aGlzXG4gICAgfSk7XG59O1xuXG4vKipcbiAqIEludm9rZSB3aGVuIGVycm9yIG9jY3VyZWRcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5Kc29uTG9hZGVyLnByb3RvdHlwZS5vbkVycm9yID0gZnVuY3Rpb24gKCkge1xuXG4gICAgdGhpcy5kaXNwYXRjaEV2ZW50KHtcbiAgICAgICAgdHlwZTogJ2Vycm9yJyxcbiAgICAgICAgY29udGVudDogdGhpc1xuICAgIH0pO1xufTtcbiIsInZhciBjb3JlID0gcmVxdWlyZSgnLi4vY29yZScpLFxuICAgIEpzb25Mb2FkZXIgPSByZXF1aXJlKCcuL0pzb25Mb2FkZXInKTtcblxuLyoqXG4gKiBAYXV0aG9yIE1hdCBHcm92ZXMgaHR0cDovL21hdGdyb3Zlcy5jb20vIEBEb29ybWF0MjNcbiAqIGJhc2VkIG9uIHBpeGkgaW1wYWN0IHNwaW5lIGltcGxlbWVudGF0aW9uIG1hZGUgYnkgRWVtZWxpIEtlbG9rb3JwaSAoQGVrZWxva29ycGkpIGh0dHBzOi8vZ2l0aHViLmNvbS9la2Vsb2tvcnBpXG4gKlxuICogQXdlc29tZSBKUyBydW4gdGltZSBwcm92aWRlZCBieSBFc290ZXJpY1NvZnR3YXJlXG4gKiBodHRwczovL2dpdGh1Yi5jb20vRXNvdGVyaWNTb2Z0d2FyZS9zcGluZS1ydW50aW1lc1xuICpcbiAqL1xuXG4vKipcbiAqIFRoZSBTcGluZSBsb2FkZXIgaXMgdXNlZCB0byBsb2FkIGluIEpTT04gc3BpbmUgZGF0YVxuICogVG8gZ2VuZXJhdGUgdGhlIGRhdGEgeW91IG5lZWQgdG8gdXNlIGh0dHA6Ly9lc290ZXJpY3NvZnR3YXJlLmNvbS8gYW5kIGV4cG9ydCBpbiB0aGUgXCJKU09OXCIgZm9ybWF0XG4gKiBEdWUgdG8gYSBjbGFzaCBvZiBuYW1lcyAgWW91IHdpbGwgbmVlZCB0byBjaGFuZ2UgdGhlIGV4dGVuc2lvbiBvZiB0aGUgc3BpbmUgZmlsZSBmcm9tICouanNvbiB0byAqLmFuaW0gZm9yIGl0IHRvIGxvYWRcbiAqIFNlZSBleGFtcGxlIDEyIChodHRwOi8vd3d3Lmdvb2Rib3lkaWdpdGFsLmNvbS9waXhpanMvZXhhbXBsZXMvMTIvKSB0byBzZWUgYSB3b3JraW5nIGV4YW1wbGUgYW5kIGNoZWNrIG91dCB0aGUgc291cmNlXG4gKiBZb3Ugd2lsbCBuZWVkIHRvIGdlbmVyYXRlIGEgc3ByaXRlIHNoZWV0IHRvIGFjY29tcGFueSB0aGUgc3BpbmUgZGF0YVxuICogV2hlbiBsb2FkZWQgdGhpcyBjbGFzcyB3aWxsIGRpc3BhdGNoIGEgXCJsb2FkZWRcIiBldmVudFxuICpcbiAqIEBjbGFzc1xuICogQG1peGVzIGV2ZW50VGFyZ2V0XG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSB1cmwge1N0cmluZ30gVGhlIHVybCBvZiB0aGUgSlNPTiBmaWxlXG4gKiBAcGFyYW0gY3Jvc3NvcmlnaW4ge2Jvb2xlYW59IFdoZXRoZXIgcmVxdWVzdHMgc2hvdWxkIGJlIHRyZWF0ZWQgYXMgY3Jvc3NvcmlnaW5cbiAqL1xuZnVuY3Rpb24gU3BpbmVMb2FkZXIodXJsLCBjcm9zc29yaWdpbikge1xuICAgIC8qKlxuICAgICAqIFRoZSB1cmwgb2YgdGhlIGJpdG1hcCBmb250IGRhdGFcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1N0cmluZ31cbiAgICAgKi9cbiAgICB0aGlzLnVybCA9IHVybDtcblxuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgdGhlIHJlcXVlc3RzIHNob3VsZCBiZSB0cmVhdGVkIGFzIGNyb3NzIG9yaWdpblxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLmNyb3Nzb3JpZ2luID0gY3Jvc3NvcmlnaW47XG5cbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRoZSBkYXRhIGhhcyBsb2FkZWQgeWV0XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqIEByZWFkT25seVxuICAgICAqL1xuICAgIHRoaXMubG9hZGVkID0gZmFsc2U7XG59XG5cblNwaW5lTG9hZGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFNwaW5lTG9hZGVyO1xubW9kdWxlLmV4cG9ydHMgPSBTcGluZUxvYWRlcjtcblxuY29yZS51dGlscy5ldmVudFRhcmdldC5taXhpbihTcGluZUxvYWRlci5wcm90b3R5cGUpO1xuXG4vKipcbiAqIExvYWRzIHRoZSBKU09OIGRhdGFcbiAqXG4gKi9cblNwaW5lTG9hZGVyLnByb3RvdHlwZS5sb2FkID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBzY29wZSA9IHRoaXM7XG4gICAgdmFyIGpzb25Mb2FkZXIgPSBuZXcgSnNvbkxvYWRlcih0aGlzLnVybCwgdGhpcy5jcm9zc29yaWdpbik7XG5cbiAgICBqc29uTG9hZGVyLm9uKCdsb2FkZWQnLCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgc2NvcGUuanNvbiA9IGV2ZW50LmRhdGEuY29udGVudC5qc29uO1xuICAgICAgICBzY29wZS5vbkxvYWRlZCgpO1xuICAgIH0pO1xuXG4gICAganNvbkxvYWRlci5sb2FkKCk7XG59O1xuXG4vKipcbiAqIEludm9rZWQgd2hlbiBKU09OIGZpbGUgaXMgbG9hZGVkLlxuICpcbiAqIEBwcml2YXRlXG4gKi9cblNwaW5lTG9hZGVyLnByb3RvdHlwZS5vbkxvYWRlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmxvYWRlZCA9IHRydWU7XG4gICAgdGhpcy5lbWl0KCdsb2FkZWQnLCB7IGNvbnRlbnQ6IHRoaXMgfSk7XG59O1xuIiwidmFyIGNvcmUgPSByZXF1aXJlKCcuLi9jb3JlJyk7XG5cbi8qKlxuICogU3VwcG9ydGluZyBjbGFzcyB0byBsb2FkIGltYWdlcyBmcm9tIHNwaW5lIGF0bGFzZXMgYXMgcGVyIHNwaW5lIHNwZWMuXG4gKlxuICogQGNsYXNzXG4gKiBAbWl4ZXMgZXZlbnRUYXJnZXRcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIGJhc2VQYXRoIHtzdHJpbmd9IFRoYSBiYXNlIHBhdGggd2hlcmUgdG8gbG9vayBmb3IgdGhlIGltYWdlcyB0byBiZSBsb2FkZWRcbiAqIEBwYXJhbSBjcm9zc29yaWdpbiB7Ym9vbGVhbn0gV2hldGhlciByZXF1ZXN0cyBzaG91bGQgYmUgdHJlYXRlZCBhcyBjcm9zc29yaWdpblxuICovXG5mdW5jdGlvbiBTcGluZVRleHR1cmVMb2FkZXIoYmFzZVBhdGgsIGNyb3Nzb3JpZ2luKSB7XG4gICAgdGhpcy5iYXNlUGF0aCA9IGJhc2VQYXRoO1xuICAgIHRoaXMuY3Jvc3NvcmlnaW4gPSBjcm9zc29yaWdpbjtcbiAgICB0aGlzLmxvYWRpbmdDb3VudCA9IDA7XG59XG5cblNwaW5lVGV4dHVyZUxvYWRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBTcGluZVRleHR1cmVMb2FkZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFNwaW5lVGV4dHVyZUxvYWRlcjtcblxuY29yZS51dGlscy5ldmVudFRhcmdldC5taXhpbihTcGluZVRleHR1cmVMb2FkZXIucHJvdG90eXBlKTtcblxuLyoqXG4gKiBTdGFydHMgbG9hZGluZyBhIGJhc2UgdGV4dHVyZSBhcyBwZXIgc3BpbmUgc3BlY2lmaWNhdGlvblxuICpcbiAqIEBwYXJhbSBwYWdlIHtzcGluZS5BdGxhc1BhZ2V9IEF0bGFzIHBhZ2UgdG8gd2hpY2ggdGV4dHVyZSBiZWxvbmdzXG4gKiBAcGFyYW0gZmlsZSB7c3RyaW5nfSBUaGUgZmlsZSB0byBsb2FkLCB0aGlzIGlzIGp1c3QgdGhlIGZpbGUgcGF0aCByZWxhdGl2ZSB0byB0aGUgYmFzZSBwYXRoIGNvbmZpZ3VyZWQgaW4gdGhlIGNvbnN0cnVjdG9yXG4gKi9cblNwaW5lVGV4dHVyZUxvYWRlci5wcm90b3R5cGUubG9hZCA9IGZ1bmN0aW9uIChwYWdlLCBmaWxlKSB7XG4gICAgcGFnZS5yZW5kZXJlck9iamVjdCA9IGNvcmUuQmFzZVRleHR1cmUuZnJvbUltYWdlKHRoaXMuYmFzZVBhdGggKyAnLycgKyBmaWxlLCB0aGlzLmNyb3Nzb3JpZ2luKTtcbiAgICBpZiAoIXBhZ2UucmVuZGVyZXJPYmplY3QuaGFzTG9hZGVkKSB7XG4gICAgICAgIHZhciBzY29wZSA9IHRoaXM7XG4gICAgICAgICsrc2NvcGUubG9hZGluZ0NvdW50O1xuICAgICAgICBwYWdlLnJlbmRlcmVyT2JqZWN0LmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWRlZCcsIGZ1bmN0aW9uICgpe1xuICAgICAgICAgICAgLS1zY29wZS5sb2FkaW5nQ291bnQ7XG4gICAgICAgICAgICBzY29wZS5kaXNwYXRjaEV2ZW50KHtcbiAgICAgICAgICAgICAgICB0eXBlOiAnbG9hZGVkQmFzZVRleHR1cmUnLFxuICAgICAgICAgICAgICAgIGNvbnRlbnQ6IHNjb3BlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfVxufTtcblxuLyoqXG4gKiBVbmxvYWRzIGEgcHJldmlvdXNseSBsb2FkZWQgdGV4dHVyZSBhcyBwZXIgc3BpbmUgc3BlY2lmaWNhdGlvblxuICpcbiAqIEBwYXJhbSB0ZXh0dXJlIHtCYXNlVGV4dHVyZX0gVGV4dHVyZSBvYmplY3QgdG8gZGVzdHJveVxuICovXG5TcGluZVRleHR1cmVMb2FkZXIucHJvdG90eXBlLnVubG9hZCA9IGZ1bmN0aW9uICh0ZXh0dXJlKSB7XG4gICAgdGV4dHVyZS5kZXN0cm95KHRydWUpO1xufTtcbiIsInZhciBjb3JlID0gcmVxdWlyZSgnLi4vY29yZScpLFxuICAgIEpzb25Mb2FkZXIgPSByZXF1aXJlKCcuL0pzb25Mb2FkZXInKTtcblxuLyoqXG4gKiBUaGUgc3ByaXRlIHNoZWV0IGxvYWRlciBpcyB1c2VkIHRvIGxvYWQgaW4gSlNPTiBzcHJpdGUgc2hlZXQgZGF0YVxuICogVG8gZ2VuZXJhdGUgdGhlIGRhdGEgeW91IGNhbiB1c2UgaHR0cDovL3d3dy5jb2RlYW5kd2ViLmNvbS90ZXh0dXJlcGFja2VyIGFuZCBwdWJsaXNoIGluIHRoZSAnSlNPTicgZm9ybWF0XG4gKiBUaGVyZSBpcyBhIGZyZWUgdmVyc2lvbiBzbyB0aGF0cyBuaWNlLCBhbHRob3VnaCB0aGUgcGFpZCB2ZXJzaW9uIGlzIGdyZWF0IHZhbHVlIGZvciBtb25leS5cbiAqIEl0IGlzIGhpZ2hseSByZWNvbW1lbmRlZCB0byB1c2UgU3ByaXRlIHNoZWV0cyAoYWxzbyBrbm93IGFzIGEgJ3RleHR1cmUgYXRsYXMnKSBhcyBpdCBtZWFucyBzcHJpdGVzIGNhbiBiZSBiYXRjaGVkIGFuZCBkcmF3biB0b2dldGhlciBmb3IgaGlnaGx5IGluY3JlYXNlZCByZW5kZXJpbmcgc3BlZWQuXG4gKiBPbmNlIHRoZSBkYXRhIGhhcyBiZWVuIGxvYWRlZCB0aGUgZnJhbWVzIGFyZSBzdG9yZWQgaW4gdGhlIFBJWEkgdGV4dHVyZSBjYWNoZSBhbmQgY2FuIGJlIGFjY2Vzc2VkIHRob3VnaCBUZXh0dXJlLmZyb21GcmFtZUlkKCkgYW5kIFNwcml0ZS5mcm9tRnJhbWVJZCgpXG4gKiBUaGlzIGxvYWRlciB3aWxsIGxvYWQgdGhlIGltYWdlIGZpbGUgdGhhdCB0aGUgU3ByaXRlc2hlZXQgcG9pbnRzIHRvIGFzIHdlbGwgYXMgdGhlIGRhdGEuXG4gKiBXaGVuIGxvYWRlZCB0aGlzIGNsYXNzIHdpbGwgZGlzcGF0Y2ggYSAnbG9hZGVkJyBldmVudFxuICpcbiAqIEBjbGFzc1xuICogQG1peGVzIGV2ZW50VGFyZ2V0XG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSB1cmwge1N0cmluZ30gVGhlIHVybCBvZiB0aGUgc3ByaXRlIHNoZWV0IEpTT04gZmlsZVxuICogQHBhcmFtIGNyb3Nzb3JpZ2luIHtib29sZWFufSBXaGV0aGVyIHJlcXVlc3RzIHNob3VsZCBiZSB0cmVhdGVkIGFzIGNyb3Nzb3JpZ2luXG4gKi9cbmZ1bmN0aW9uIFNwcml0ZVNoZWV0TG9hZGVyKHVybCwgY3Jvc3NvcmlnaW4pIHtcblxuICAgIC8qKlxuICAgICAqIFRoZSB1cmwgb2YgdGhlIGF0bGFzIGRhdGFcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1N0cmluZ31cbiAgICAgKi9cbiAgICB0aGlzLnVybCA9IHVybDtcblxuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgdGhlIHJlcXVlc3RzIHNob3VsZCBiZSB0cmVhdGVkIGFzIGNyb3NzIG9yaWdpblxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLmNyb3Nzb3JpZ2luID0gY3Jvc3NvcmlnaW47XG5cbiAgICAvKipcbiAgICAgKiBUaGUgYmFzZSB1cmwgb2YgdGhlIGJpdG1hcCBmb250IGRhdGFcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1N0cmluZ31cbiAgICAgKiBAcmVhZE9ubHlcbiAgICAgKi9cbiAgICB0aGlzLmJhc2VVcmwgPSB1cmwucmVwbGFjZSgvW15cXC9dKiQvLCAnJyk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdGV4dHVyZSBiZWluZyBsb2FkZWRcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1RleHR1cmV9XG4gICAgICovXG4gICAgdGhpcy50ZXh0dXJlID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBmcmFtZXMgb2YgdGhlIHNwcml0ZSBzaGVldFxuICAgICAqXG4gICAgICogQG1lbWJlciB7b2JqZWN0fVxuICAgICAqL1xuICAgIHRoaXMuZnJhbWVzID0ge307XG59XG5cbi8vIGNvbnN0cnVjdG9yXG5TcHJpdGVTaGVldExvYWRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBTcHJpdGVTaGVldExvYWRlcjtcbm1vZHVsZS5leHBvcnRzID0gU3ByaXRlU2hlZXRMb2FkZXI7XG5cbmNvcmUudXRpbHMuZXZlbnRUYXJnZXQubWl4aW4oU3ByaXRlU2hlZXRMb2FkZXIucHJvdG90eXBlKTtcblxuLyoqXG4gKiBUaGlzIHdpbGwgYmVnaW4gbG9hZGluZyB0aGUgSlNPTiBmaWxlXG4gKlxuICovXG5TcHJpdGVTaGVldExvYWRlci5wcm90b3R5cGUubG9hZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgc2NvcGUgPSB0aGlzO1xuICAgIHZhciBqc29uTG9hZGVyID0gbmV3IEpzb25Mb2FkZXIodGhpcy51cmwsIHRoaXMuY3Jvc3NvcmlnaW4pO1xuXG4gICAganNvbkxvYWRlci5vbignbG9hZGVkJywgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIHNjb3BlLmpzb24gPSBldmVudC5kYXRhLmNvbnRlbnQuanNvbjtcbiAgICAgICAgc2NvcGUub25Mb2FkZWQoKTtcbiAgICB9KTtcblxuICAgIGpzb25Mb2FkZXIubG9hZCgpO1xufTtcblxuLyoqXG4gKiBJbnZva2Ugd2hlbiBhbGwgZmlsZXMgYXJlIGxvYWRlZCAoanNvbiBhbmQgdGV4dHVyZSlcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5TcHJpdGVTaGVldExvYWRlci5wcm90b3R5cGUub25Mb2FkZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5lbWl0KCdsb2FkZWQnLCB7XG4gICAgICAgIGNvbnRlbnQ6IHRoaXNcbiAgICB9KTtcbn07XG4iLCIvKipcbiAqIEBmaWxlICAgICAgICBNYWluIGV4cG9ydCBvZiB0aGUgUElYSSBsb2FkZXJzIGxpYnJhcnlcbiAqIEBhdXRob3IgICAgICBNYXQgR3JvdmVzIDxtYXRAZ29vZGJveWRpZ2l0YWwuY29tPlxuICogQGNvcHlyaWdodCAgIDIwMTMtMjAxNSBHb29kQm95RGlnaXRhbFxuICogQGxpY2Vuc2UgICAgIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vR29vZEJveURpZ2l0YWwvcGl4aS5qcy9ibG9iL21hc3Rlci9MSUNFTlNFfE1JVCBMaWNlbnNlfVxuICovXG5cbi8qKlxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEF0bGFzTG9hZGVyOiAgICAgICAgcmVxdWlyZSgnLi9BdGxhc0xvYWRlcicpLFxuICAgIEJpdG1hcEZvbnRMb2FkZXI6ICAgcmVxdWlyZSgnLi9CaXRtYXBGb250TG9hZGVyJyksXG4gICAgSW1hZ2VMb2FkZXI6ICAgICAgICByZXF1aXJlKCcuL0ltYWdlTG9hZGVyJyksXG4gICAgSnNvbkxvYWRlcjogICAgICAgICByZXF1aXJlKCcuL0pzb25Mb2FkZXInKSxcbiAgICBTcGluZUxvYWRlcjogICAgICAgIHJlcXVpcmUoJy4vU3BpbmVMb2FkZXInKSxcbiAgICBTcHJpdGVTaGVldExvYWRlcjogIHJlcXVpcmUoJy4vU3ByaXRlU2hlZXRMb2FkZXInKVxufTtcbiIsInZhciBjb3JlID0gcmVxdWlyZSgnLi4vY29yZScpLFxuICAgIHNwaW5lID0gcmVxdWlyZSgnLi9TcGluZVJ1bnRpbWUnKTtcblxuLyogRXNvdGVyaWMgU29mdHdhcmUgU1BJTkUgd3JhcHBlciBmb3IgcGl4aS5qcyAqL1xuXG5zcGluZS5Cb25lLnlEb3duID0gdHJ1ZTtcblxuLyoqXG4gKiBBIGNsYXNzIHRoYXQgZW5hYmxlcyB0aGUgeW91IHRvIGltcG9ydCBhbmQgcnVuIHlvdXIgc3BpbmUgYW5pbWF0aW9ucyBpbiBwaXhpLlxuICogU3BpbmUgYW5pbWF0aW9uIGRhdGEgbmVlZHMgdG8gYmUgbG9hZGVkIHVzaW5nIHRoZSBBc3NldExvYWRlciBvciBTcGluZUxvYWRlciBiZWZvcmUgaXQgY2FuIGJlIHVzZWQgYnkgdGhpcyBjbGFzc1xuICogU2VlIGV4YW1wbGUgMTIgKGh0dHA6Ly93d3cuZ29vZGJveWRpZ2l0YWwuY29tL3BpeGlqcy9leGFtcGxlcy8xMi8pIHRvIHNlZSBhIHdvcmtpbmcgZXhhbXBsZSBhbmQgY2hlY2sgb3V0IHRoZSBzb3VyY2VcbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIERpc3BsYXlPYmplY3RDb250YWluZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHVybCB7c3RyaW5nfSBUaGUgdXJsIG9mIHRoZSBzcGluZSBhbmltIGZpbGUgdG8gYmUgdXNlZFxuICovXG5mdW5jdGlvbiBTcGluZSh1cmwpIHtcbiAgICBjb3JlLkRpc3BsYXlPYmplY3RDb250YWluZXIuY2FsbCh0aGlzKTtcblxuICAgIHRoaXMuc3BpbmVEYXRhID0gY29yZS51dGlscy5BbmltQ2FjaGVbdXJsXTtcblxuICAgIGlmICghdGhpcy5zcGluZURhdGEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTcGluZSBkYXRhIG11c3QgYmUgcHJlbG9hZGVkIHVzaW5nIFNwaW5lTG9hZGVyIG9yIEFzc2V0TG9hZGVyOiAnICsgdXJsKTtcbiAgICB9XG5cbiAgICB0aGlzLnNrZWxldG9uID0gbmV3IHNwaW5lLlNrZWxldG9uKHRoaXMuc3BpbmVEYXRhKTtcbiAgICB0aGlzLnNrZWxldG9uLnVwZGF0ZVdvcmxkVHJhbnNmb3JtKCk7XG5cbiAgICB0aGlzLnN0YXRlRGF0YSA9IG5ldyBzcGluZS5BbmltYXRpb25TdGF0ZURhdGEodGhpcy5zcGluZURhdGEpO1xuICAgIHRoaXMuc3RhdGUgPSBuZXcgc3BpbmUuQW5pbWF0aW9uU3RhdGUodGhpcy5zdGF0ZURhdGEpO1xuXG4gICAgdGhpcy5zbG90Q29udGFpbmVycyA9IFtdO1xuXG4gICAgZm9yICh2YXIgaSA9IDAsIG4gPSB0aGlzLnNrZWxldG9uLmRyYXdPcmRlci5sZW5ndGg7IGkgPCBuOyBpKyspIHtcbiAgICAgICAgdmFyIHNsb3QgPSB0aGlzLnNrZWxldG9uLmRyYXdPcmRlcltpXTtcbiAgICAgICAgdmFyIGF0dGFjaG1lbnQgPSBzbG90LmF0dGFjaG1lbnQ7XG4gICAgICAgIHZhciBzbG90Q29udGFpbmVyID0gbmV3IGNvcmUuRGlzcGxheU9iamVjdENvbnRhaW5lcigpO1xuICAgICAgICB0aGlzLnNsb3RDb250YWluZXJzLnB1c2goc2xvdENvbnRhaW5lcik7XG4gICAgICAgIHRoaXMuYWRkQ2hpbGQoc2xvdENvbnRhaW5lcik7XG5cbiAgICAgICAgaWYgKGF0dGFjaG1lbnQgaW5zdGFuY2VvZiBzcGluZS5SZWdpb25BdHRhY2htZW50KSB7XG4gICAgICAgICAgICB2YXIgc3ByaXRlTmFtZSA9IGF0dGFjaG1lbnQucmVuZGVyZXJPYmplY3QubmFtZTtcbiAgICAgICAgICAgIHZhciBzcHJpdGUgPSB0aGlzLmNyZWF0ZVNwcml0ZShzbG90LCBhdHRhY2htZW50KTtcbiAgICAgICAgICAgIHNsb3QuY3VycmVudFNwcml0ZSA9IHNwcml0ZTtcbiAgICAgICAgICAgIHNsb3QuY3VycmVudFNwcml0ZU5hbWUgPSBzcHJpdGVOYW1lO1xuICAgICAgICAgICAgc2xvdENvbnRhaW5lci5hZGRDaGlsZChzcHJpdGUpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGF0dGFjaG1lbnQgaW5zdGFuY2VvZiBzcGluZS5NZXNoQXR0YWNobWVudCkge1xuICAgICAgICAgICAgdmFyIG1lc2ggPSB0aGlzLmNyZWF0ZU1lc2goc2xvdCwgYXR0YWNobWVudCk7XG4gICAgICAgICAgICBzbG90LmN1cnJlbnRNZXNoID0gbWVzaDtcbiAgICAgICAgICAgIHNsb3QuY3VycmVudE1lc2hOYW1lID0gYXR0YWNobWVudC5uYW1lO1xuICAgICAgICAgICAgc2xvdENvbnRhaW5lci5hZGRDaGlsZChtZXNoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICB9XG5cbiAgICB0aGlzLmF1dG9VcGRhdGUgPSB0cnVlO1xufVxuXG5TcGluZS5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKGNvcmUuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUpO1xuU3BpbmUucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gU3BpbmU7XG5tb2R1bGUuZXhwb3J0cyA9IFNwaW5lO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhTcGluZS5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBJZiB0aGlzIGZsYWcgaXMgc2V0IHRvIHRydWUsIHRoZSBzcGluZSBhbmltYXRpb24gd2lsbCBiZSBhdXRvdXBkYXRlZCBldmVyeSB0aW1lXG4gICAgICogdGhlIG9iamVjdCBpZCBkcmF3bi4gVGhlIGRvd24gc2lkZSBvZiB0aGlzIGFwcHJvYWNoIGlzIHRoYXQgdGhlIGRlbHRhIHRpbWUgaXNcbiAgICAgKiBhdXRvbWF0aWNhbGx5IGNhbGN1bGF0ZWQgYW5kIHlvdSBjb3VsZCBtaXNzIG91dCBvbiBjb29sIGVmZmVjdHMgbGlrZSBzbG93IG1vdGlvbixcbiAgICAgKiBwYXVzZSwgc2tpcCBhaGVhZCBhbmQgdGhlIHNvcnRzLiBNb3N0IG9mIHRoZXNlIGVmZmVjdHMgY2FuIGJlIGFjaGlldmVkIGV2ZW4gd2l0aFxuICAgICAqIGF1dG91cGRhdGUgZW5hYmxlZCBidXQgYXJlIGhhcmRlciB0byBhY2hpZXZlLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAbWVtYmVyb2YgU3BpbmUjXG4gICAgICogQGRlZmF1bHQgdHJ1ZVxuICAgICAqL1xuICAgIGF1dG9VcGRhdGU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gKHRoaXMudXBkYXRlVHJhbnNmb3JtID09PSBTcGluZS5wcm90b3R5cGUuYXV0b1VwZGF0ZVRyYW5zZm9ybSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlVHJhbnNmb3JtID0gdmFsdWUgPyBTcGluZS5wcm90b3R5cGUuYXV0b1VwZGF0ZVRyYW5zZm9ybSA6IGNvcmUuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUudXBkYXRlVHJhbnNmb3JtO1xuICAgICAgICB9XG4gICAgfVxufSk7XG5cbi8qKlxuICogVXBkYXRlIHRoZSBzcGluZSBza2VsZXRvbiBhbmQgaXRzIGFuaW1hdGlvbnMgYnkgZGVsdGEgdGltZSAoZHQpXG4gKlxuICogQHBhcmFtIGR0IHtudW1iZXJ9IERlbHRhIHRpbWUuIFRpbWUgYnkgd2hpY2ggdGhlIGFuaW1hdGlvbiBzaG91bGQgYmUgdXBkYXRlZFxuICovXG5TcGluZS5wcm90b3R5cGUudXBkYXRlID0gZnVuY3Rpb24gKGR0KSB7XG4gICAgdGhpcy5zdGF0ZS51cGRhdGUoZHQpO1xuICAgIHRoaXMuc3RhdGUuYXBwbHkodGhpcy5za2VsZXRvbik7XG4gICAgdGhpcy5za2VsZXRvbi51cGRhdGVXb3JsZFRyYW5zZm9ybSgpO1xuXG4gICAgdmFyIGRyYXdPcmRlciA9IHRoaXMuc2tlbGV0b24uZHJhd09yZGVyO1xuICAgIGZvciAodmFyIGkgPSAwLCBuID0gZHJhd09yZGVyLmxlbmd0aDsgaSA8IG47IGkrKykge1xuICAgICAgICB2YXIgc2xvdCA9IGRyYXdPcmRlcltpXTtcbiAgICAgICAgdmFyIGF0dGFjaG1lbnQgPSBzbG90LmF0dGFjaG1lbnQ7XG4gICAgICAgIHZhciBzbG90Q29udGFpbmVyID0gdGhpcy5zbG90Q29udGFpbmVyc1tpXTtcblxuICAgICAgICBpZiAoIWF0dGFjaG1lbnQpIHtcbiAgICAgICAgICAgIHNsb3RDb250YWluZXIudmlzaWJsZSA9IGZhbHNlO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgdHlwZSA9IGF0dGFjaG1lbnQudHlwZTtcbiAgICAgICAgaWYgKHR5cGUgPT09IHNwaW5lLkF0dGFjaG1lbnRUeXBlLnJlZ2lvbikge1xuICAgICAgICAgICAgaWYgKGF0dGFjaG1lbnQucmVuZGVyZXJPYmplY3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXNsb3QuY3VycmVudFNwcml0ZU5hbWUgfHwgc2xvdC5jdXJyZW50U3ByaXRlTmFtZSAhPT0gYXR0YWNobWVudC5yZW5kZXJlck9iamVjdC5uYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBzcHJpdGVOYW1lID0gYXR0YWNobWVudC5yZW5kZXJlck9iamVjdC5uYW1lO1xuICAgICAgICAgICAgICAgICAgICBpZiAoc2xvdC5jdXJyZW50U3ByaXRlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNsb3QuY3VycmVudFNwcml0ZS52aXNpYmxlID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgc2xvdC5zcHJpdGVzID0gc2xvdC5zcHJpdGVzIHx8IHt9O1xuICAgICAgICAgICAgICAgICAgICBpZiAoc2xvdC5zcHJpdGVzW3Nwcml0ZU5hbWVdICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNsb3Quc3ByaXRlc1tzcHJpdGVOYW1lXS52aXNpYmxlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBzcHJpdGUgPSB0aGlzLmNyZWF0ZVNwcml0ZShzbG90LCBhdHRhY2htZW50KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNsb3RDb250YWluZXIuYWRkQ2hpbGQoc3ByaXRlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBzbG90LmN1cnJlbnRTcHJpdGUgPSBzbG90LnNwcml0ZXNbc3ByaXRlTmFtZV07XG4gICAgICAgICAgICAgICAgICAgIHNsb3QuY3VycmVudFNwcml0ZU5hbWUgPSBzcHJpdGVOYW1lO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGJvbmUgPSBzbG90LmJvbmU7XG5cbiAgICAgICAgICAgIHNsb3RDb250YWluZXIucG9zaXRpb24ueCA9IGJvbmUud29ybGRYICsgYXR0YWNobWVudC54ICogYm9uZS5tMDAgKyBhdHRhY2htZW50LnkgKiBib25lLm0wMTtcbiAgICAgICAgICAgIHNsb3RDb250YWluZXIucG9zaXRpb24ueSA9IGJvbmUud29ybGRZICsgYXR0YWNobWVudC54ICogYm9uZS5tMTAgKyBhdHRhY2htZW50LnkgKiBib25lLm0xMTtcbiAgICAgICAgICAgIHNsb3RDb250YWluZXIuc2NhbGUueCA9IGJvbmUud29ybGRTY2FsZVg7XG4gICAgICAgICAgICBzbG90Q29udGFpbmVyLnNjYWxlLnkgPSBib25lLndvcmxkU2NhbGVZO1xuXG4gICAgICAgICAgICBzbG90Q29udGFpbmVyLnJvdGF0aW9uID0gLShzbG90LmJvbmUud29ybGRSb3RhdGlvbiAqIHNwaW5lLmRlZ1JhZCk7XG5cbiAgICAgICAgICAgIHNsb3QuY3VycmVudFNwcml0ZS50aW50ID0gY29yZS51dGlscy5yZ2IyaGV4KFtzbG90LnIsc2xvdC5nLHNsb3QuYl0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHR5cGUgPT09IHNwaW5lLkF0dGFjaG1lbnRUeXBlLnNraW5uZWRtZXNoKSB7XG4gICAgICAgICAgICBpZiAoIXNsb3QuY3VycmVudE1lc2hOYW1lIHx8IHNsb3QuY3VycmVudE1lc2hOYW1lICE9PSBhdHRhY2htZW50Lm5hbWUpIHtcbiAgICAgICAgICAgICAgICB2YXIgbWVzaE5hbWUgPSBhdHRhY2htZW50Lm5hbWU7XG4gICAgICAgICAgICAgICAgaWYgKHNsb3QuY3VycmVudE1lc2ggIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgICBzbG90LmN1cnJlbnRNZXNoLnZpc2libGUgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBzbG90Lm1lc2hlcyA9IHNsb3QubWVzaGVzIHx8IHt9O1xuXG4gICAgICAgICAgICAgICAgaWYgKHNsb3QubWVzaGVzW21lc2hOYW1lXSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHNsb3QubWVzaGVzW21lc2hOYW1lXS52aXNpYmxlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBtZXNoID0gdGhpcy5jcmVhdGVNZXNoKHNsb3QsIGF0dGFjaG1lbnQpO1xuICAgICAgICAgICAgICAgICAgICBzbG90Q29udGFpbmVyLmFkZENoaWxkKG1lc2gpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHNsb3QuY3VycmVudE1lc2ggPSBzbG90Lm1lc2hlc1ttZXNoTmFtZV07XG4gICAgICAgICAgICAgICAgc2xvdC5jdXJyZW50TWVzaE5hbWUgPSBtZXNoTmFtZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgYXR0YWNobWVudC5jb21wdXRlV29ybGRWZXJ0aWNlcyhzbG90LmJvbmUuc2tlbGV0b24ueCwgc2xvdC5ib25lLnNrZWxldG9uLnksIHNsb3QsIHNsb3QuY3VycmVudE1lc2gudmVydGljZXMpO1xuXG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBzbG90Q29udGFpbmVyLnZpc2libGUgPSBmYWxzZTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIHNsb3RDb250YWluZXIudmlzaWJsZSA9IHRydWU7XG5cbiAgICAgICAgc2xvdENvbnRhaW5lci5hbHBoYSA9IHNsb3QuYTtcbiAgICB9XG59O1xuXG4vKipcbiAqIFdoZW4gYXV0b3VwZGF0ZSBpcyBzZXQgdG8geWVzIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCBhcyBwaXhpJ3MgdXBkYXRlVHJhbnNmb3JtIGZ1bmN0aW9uXG4gKlxuICogQHByaXZhdGVcbiAqL1xuU3BpbmUucHJvdG90eXBlLmF1dG9VcGRhdGVUcmFuc2Zvcm0gPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5sYXN0VGltZSA9IHRoaXMubGFzdFRpbWUgfHwgRGF0ZS5ub3coKTtcbiAgICB2YXIgdGltZURlbHRhID0gKERhdGUubm93KCkgLSB0aGlzLmxhc3RUaW1lKSAqIDAuMDAxO1xuICAgIHRoaXMubGFzdFRpbWUgPSBEYXRlLm5vdygpO1xuXG4gICAgdGhpcy51cGRhdGUodGltZURlbHRhKTtcblxuICAgIGNvcmUuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUudXBkYXRlVHJhbnNmb3JtLmNhbGwodGhpcyk7XG59O1xuXG4vKipcbiAqIENyZWF0ZSBhIG5ldyBzcHJpdGUgdG8gYmUgdXNlZCB3aXRoIHNwaW5lLlJlZ2lvbkF0dGFjaG1lbnRcbiAqXG4gKiBAcGFyYW0gc2xvdCB7c3BpbmUuU2xvdH0gVGhlIHNsb3QgdG8gd2hpY2ggdGhlIGF0dGFjaG1lbnQgaXMgcGFyZW50ZWRcbiAqIEBwYXJhbSBhdHRhY2htZW50IHtzcGluZS5SZWdpb25BdHRhY2htZW50fSBUaGUgYXR0YWNobWVudCB0aGF0IHRoZSBzcHJpdGUgd2lsbCByZXByZXNlbnRcbiAqIEBwcml2YXRlXG4gKi9cblNwaW5lLnByb3RvdHlwZS5jcmVhdGVTcHJpdGUgPSBmdW5jdGlvbiAoc2xvdCwgYXR0YWNobWVudCkge1xuICAgIHZhciBkZXNjcmlwdG9yID0gYXR0YWNobWVudC5yZW5kZXJlck9iamVjdDtcbiAgICB2YXIgYmFzZVRleHR1cmUgPSBkZXNjcmlwdG9yLnBhZ2UucmVuZGVyZXJPYmplY3Q7XG4gICAgdmFyIHNwcml0ZVJlY3QgPSBuZXcgY29yZS5tYXRoLlJlY3RhbmdsZShkZXNjcmlwdG9yLngsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRvci55LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0b3Iucm90YXRlID8gZGVzY3JpcHRvci5oZWlnaHQgOiBkZXNjcmlwdG9yLndpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0b3Iucm90YXRlID8gZGVzY3JpcHRvci53aWR0aCA6IGRlc2NyaXB0b3IuaGVpZ2h0KTtcbiAgICB2YXIgc3ByaXRlVGV4dHVyZSA9IG5ldyBjb3JlLlRleHR1cmUoYmFzZVRleHR1cmUsIHNwcml0ZVJlY3QpO1xuICAgIHZhciBzcHJpdGUgPSBuZXcgY29yZS5TcHJpdGUoc3ByaXRlVGV4dHVyZSk7XG5cbiAgICB2YXIgYmFzZVJvdGF0aW9uID0gZGVzY3JpcHRvci5yb3RhdGUgPyBNYXRoLlBJICogMC41IDogMC4wO1xuICAgIHNwcml0ZS5zY2FsZS5zZXQoZGVzY3JpcHRvci53aWR0aCAvIGRlc2NyaXB0b3Iub3JpZ2luYWxXaWR0aCwgZGVzY3JpcHRvci5oZWlnaHQgLyBkZXNjcmlwdG9yLm9yaWdpbmFsSGVpZ2h0KTtcbiAgICBzcHJpdGUucm90YXRpb24gPSBiYXNlUm90YXRpb24gLSAoYXR0YWNobWVudC5yb3RhdGlvbiAqIHNwaW5lLmRlZ1JhZCk7XG4gICAgc3ByaXRlLmFuY2hvci54ID0gc3ByaXRlLmFuY2hvci55ID0gMC41O1xuXG4gICAgc2xvdC5zcHJpdGVzID0gc2xvdC5zcHJpdGVzIHx8IHt9O1xuICAgIHNsb3Quc3ByaXRlc1tkZXNjcmlwdG9yLm5hbWVdID0gc3ByaXRlO1xuICAgIHJldHVybiBzcHJpdGU7XG59O1xuXG4vKipcbiAqXG4gKiBAcGFyYW0gc2xvdCB7c3BpbmUuU2xvdH0gVGhlIHNsb3QgdG8gd2hpY2ggdGhlIGF0dGFjaG1lbnQgaXMgcGFyZW50ZWRcbiAqIEBwYXJhbSBhdHRhY2htZW50IHtzcGluZS5SZWdpb25BdHRhY2htZW50fSBUaGUgYXR0YWNobWVudCB0aGF0IHRoZSBzcHJpdGUgd2lsbCByZXByZXNlbnRcbiAqIEBwcml2YXRlXG4gKi9cblNwaW5lLnByb3RvdHlwZS5jcmVhdGVNZXNoID0gZnVuY3Rpb24gKHNsb3QsIGF0dGFjaG1lbnQpIHtcbiAgICB2YXIgZGVzY3JpcHRvciA9IGF0dGFjaG1lbnQucmVuZGVyZXJPYmplY3Q7XG4gICAgdmFyIGJhc2VUZXh0dXJlID0gZGVzY3JpcHRvci5wYWdlLnJlbmRlcmVyT2JqZWN0O1xuICAgIHZhciB0ZXh0dXJlID0gbmV3IGNvcmUuVGV4dHVyZShiYXNlVGV4dHVyZSk7XG5cbiAgICB2YXIgc3RyaXAgPSBuZXcgY29yZS5TdHJpcCh0ZXh0dXJlKTtcbiAgICBzdHJpcC5kcmF3TW9kZSA9IGNvcmUuU3RyaXAuRHJhd01vZGVzLlRSSUFOR0xFUztcbiAgICBzdHJpcC5jYW52YXNQYWRkaW5nID0gMS41O1xuXG4gICAgc3RyaXAudmVydGljZXMgPSBuZXcgRmxvYXQzMkFycmF5KGF0dGFjaG1lbnQudXZzLmxlbmd0aCk7XG4gICAgc3RyaXAudXZzID0gYXR0YWNobWVudC51dnM7XG4gICAgc3RyaXAuaW5kaWNlcyA9IGF0dGFjaG1lbnQudHJpYW5nbGVzO1xuXG4gICAgc2xvdC5tZXNoZXMgPSBzbG90Lm1lc2hlcyB8fCB7fTtcbiAgICBzbG90Lm1lc2hlc1thdHRhY2htZW50Lm5hbWVdID0gc3RyaXA7XG5cbiAgICByZXR1cm4gc3RyaXA7XG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuICogU3BpbmUgUnVudGltZXMgU29mdHdhcmUgTGljZW5zZVxuICogVmVyc2lvbiAyLjFcbiAqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTMsIEVzb3RlcmljIFNvZnR3YXJlXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFlvdSBhcmUgZ3JhbnRlZCBhIHBlcnBldHVhbCwgbm9uLWV4Y2x1c2l2ZSwgbm9uLXN1YmxpY2Vuc2FibGUgYW5kXG4gKiBub24tdHJhbnNmZXJhYmxlIGxpY2Vuc2UgdG8gaW5zdGFsbCwgZXhlY3V0ZSBhbmQgcGVyZm9ybSB0aGUgU3BpbmUgUnVudGltZXNcbiAqIFNvZnR3YXJlICh0aGUgXCJTb2Z0d2FyZVwiKSBzb2xlbHkgZm9yIGludGVybmFsIHVzZS4gV2l0aG91dCB0aGUgd3JpdHRlblxuICogcGVybWlzc2lvbiBvZiBFc290ZXJpYyBTb2Z0d2FyZSAodHlwaWNhbGx5IGdyYW50ZWQgYnkgbGljZW5zaW5nIFNwaW5lKSwgeW91XG4gKiBtYXkgbm90IChhKSBtb2RpZnksIHRyYW5zbGF0ZSwgYWRhcHQgb3Igb3RoZXJ3aXNlIGNyZWF0ZSBkZXJpdmF0aXZlIHdvcmtzLFxuICogaW1wcm92ZW1lbnRzIG9mIHRoZSBTb2Z0d2FyZSBvciBkZXZlbG9wIG5ldyBhcHBsaWNhdGlvbnMgdXNpbmcgdGhlIFNvZnR3YXJlXG4gKiBvciAoYikgcmVtb3ZlLCBkZWxldGUsIGFsdGVyIG9yIG9ic2N1cmUgYW55IHRyYWRlbWFya3Mgb3IgYW55IGNvcHlyaWdodCxcbiAqIHRyYWRlbWFyaywgcGF0ZW50IG9yIG90aGVyIGludGVsbGVjdHVhbCBwcm9wZXJ0eSBvciBwcm9wcmlldGFyeSByaWdodHNcbiAqIG5vdGljZXMgb24gb3IgaW4gdGhlIFNvZnR3YXJlLCBpbmNsdWRpbmcgYW55IGNvcHkgdGhlcmVvZi4gUmVkaXN0cmlidXRpb25zXG4gKiBpbiBiaW5hcnkgb3Igc291cmNlIGZvcm0gbXVzdCBpbmNsdWRlIHRoaXMgbGljZW5zZSBhbmQgdGVybXMuXG4gKlxuICogVEhJUyBTT0ZUV0FSRSBJUyBQUk9WSURFRCBCWSBFU09URVJJQyBTT0ZUV0FSRSBcIkFTIElTXCIgQU5EIEFOWSBFWFBSRVNTIE9SXG4gKiBJTVBMSUVEIFdBUlJBTlRJRVMsIElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBUSEUgSU1QTElFRCBXQVJSQU5USUVTIE9GXG4gKiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFSRSBESVNDTEFJTUVELiBJTiBOT1xuICogRVZFTlQgU0hBTEwgRVNPVEVSSUMgU09GVEFSRSBCRSBMSUFCTEUgRk9SIEFOWSBESVJFQ1QsIElORElSRUNULCBJTkNJREVOVEFMLFxuICogU1BFQ0lBTCwgRVhFTVBMQVJZLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMgKElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLFxuICogUFJPQ1VSRU1FTlQgT0YgU1VCU1RJVFVURSBHT09EUyBPUiBTRVJWSUNFUzsgTE9TUyBPRiBVU0UsIERBVEEsIE9SIFBST0ZJVFM7XG4gKiBPUiBCVVNJTkVTUyBJTlRFUlJVUFRJT04pIEhPV0VWRVIgQ0FVU0VEIEFORCBPTiBBTlkgVEhFT1JZIE9GIExJQUJJTElUWSxcbiAqIFdIRVRIRVIgSU4gQ09OVFJBQ1QsIFNUUklDVCBMSUFCSUxJVFksIE9SIFRPUlQgKElOQ0xVRElORyBORUdMSUdFTkNFIE9SXG4gKiBPVEhFUldJU0UpIEFSSVNJTkcgSU4gQU5ZIFdBWSBPVVQgT0YgVEhFIFVTRSBPRiBUSElTIFNPRlRXQVJFLCBFVkVOIElGXG4gKiBBRFZJU0VEIE9GIFRIRSBQT1NTSUJJTElUWSBPRiBTVUNIIERBTUFHRS5cbiAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxudmFyIHNwaW5lID0gbW9kdWxlLmV4cG9ydHMgPSB7XG5cdHJhZERlZzogMTgwIC8gTWF0aC5QSSxcblx0ZGVnUmFkOiBNYXRoLlBJIC8gMTgwLFxuXHR0ZW1wOiBbXSxcbiAgICBGbG9hdDMyQXJyYXk6ICh0eXBlb2YoRmxvYXQzMkFycmF5KSA9PT0gJ3VuZGVmaW5lZCcpID8gQXJyYXkgOiBGbG9hdDMyQXJyYXksXG4gICAgVWludDE2QXJyYXk6ICh0eXBlb2YoVWludDE2QXJyYXkpID09PSAndW5kZWZpbmVkJykgPyBBcnJheSA6IFVpbnQxNkFycmF5XG59O1xuXG5zcGluZS5Cb25lRGF0YSA9IGZ1bmN0aW9uIChuYW1lLCBwYXJlbnQpIHtcblx0dGhpcy5uYW1lID0gbmFtZTtcblx0dGhpcy5wYXJlbnQgPSBwYXJlbnQ7XG59O1xuc3BpbmUuQm9uZURhdGEucHJvdG90eXBlID0ge1xuXHRsZW5ndGg6IDAsXG5cdHg6IDAsIHk6IDAsXG5cdHJvdGF0aW9uOiAwLFxuXHRzY2FsZVg6IDEsIHNjYWxlWTogMSxcblx0aW5oZXJpdFNjYWxlOiB0cnVlLFxuXHRpbmhlcml0Um90YXRpb246IHRydWUsXG5cdGZsaXBYOiBmYWxzZSwgZmxpcFk6IGZhbHNlXG59O1xuXG5zcGluZS5TbG90RGF0YSA9IGZ1bmN0aW9uIChuYW1lLCBib25lRGF0YSkge1xuXHR0aGlzLm5hbWUgPSBuYW1lO1xuXHR0aGlzLmJvbmVEYXRhID0gYm9uZURhdGE7XG59O1xuc3BpbmUuU2xvdERhdGEucHJvdG90eXBlID0ge1xuXHRyOiAxLCBnOiAxLCBiOiAxLCBhOiAxLFxuXHRhdHRhY2htZW50TmFtZTogbnVsbCxcblx0YWRkaXRpdmVCbGVuZGluZzogZmFsc2Vcbn07XG5cbnNwaW5lLklrQ29uc3RyYWludERhdGEgPSBmdW5jdGlvbiAobmFtZSkge1xuXHR0aGlzLm5hbWUgPSBuYW1lO1xuXHR0aGlzLmJvbmVzID0gW107XG59O1xuc3BpbmUuSWtDb25zdHJhaW50RGF0YS5wcm90b3R5cGUgPSB7XG5cdHRhcmdldDogbnVsbCxcblx0YmVuZERpcmVjdGlvbjogMSxcblx0bWl4OiAxXG59O1xuXG5zcGluZS5Cb25lID0gZnVuY3Rpb24gKGJvbmVEYXRhLCBza2VsZXRvbiwgcGFyZW50KSB7XG5cdHRoaXMuZGF0YSA9IGJvbmVEYXRhO1xuXHR0aGlzLnNrZWxldG9uID0gc2tlbGV0b247XG5cdHRoaXMucGFyZW50ID0gcGFyZW50O1xuXHR0aGlzLnNldFRvU2V0dXBQb3NlKCk7XG59O1xuc3BpbmUuQm9uZS55RG93biA9IGZhbHNlO1xuc3BpbmUuQm9uZS5wcm90b3R5cGUgPSB7XG5cdHg6IDAsIHk6IDAsXG5cdHJvdGF0aW9uOiAwLCByb3RhdGlvbklLOiAwLFxuXHRzY2FsZVg6IDEsIHNjYWxlWTogMSxcblx0ZmxpcFg6IGZhbHNlLCBmbGlwWTogZmFsc2UsXG5cdG0wMDogMCwgbTAxOiAwLCB3b3JsZFg6IDAsIC8vIGEgYiB4XG5cdG0xMDogMCwgbTExOiAwLCB3b3JsZFk6IDAsIC8vIGMgZCB5XG5cdHdvcmxkUm90YXRpb246IDAsXG5cdHdvcmxkU2NhbGVYOiAxLCB3b3JsZFNjYWxlWTogMSxcblx0d29ybGRGbGlwWDogZmFsc2UsIHdvcmxkRmxpcFk6IGZhbHNlLFxuXHR1cGRhdGVXb3JsZFRyYW5zZm9ybTogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBwYXJlbnQgPSB0aGlzLnBhcmVudDtcblx0XHRpZiAocGFyZW50KSB7XG5cdFx0XHR0aGlzLndvcmxkWCA9IHRoaXMueCAqIHBhcmVudC5tMDAgKyB0aGlzLnkgKiBwYXJlbnQubTAxICsgcGFyZW50LndvcmxkWDtcblx0XHRcdHRoaXMud29ybGRZID0gdGhpcy54ICogcGFyZW50Lm0xMCArIHRoaXMueSAqIHBhcmVudC5tMTEgKyBwYXJlbnQud29ybGRZO1xuXHRcdFx0aWYgKHRoaXMuZGF0YS5pbmhlcml0U2NhbGUpIHtcblx0XHRcdFx0dGhpcy53b3JsZFNjYWxlWCA9IHBhcmVudC53b3JsZFNjYWxlWCAqIHRoaXMuc2NhbGVYO1xuXHRcdFx0XHR0aGlzLndvcmxkU2NhbGVZID0gcGFyZW50LndvcmxkU2NhbGVZICogdGhpcy5zY2FsZVk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzLndvcmxkU2NhbGVYID0gdGhpcy5zY2FsZVg7XG5cdFx0XHRcdHRoaXMud29ybGRTY2FsZVkgPSB0aGlzLnNjYWxlWTtcblx0XHRcdH1cblx0XHRcdHRoaXMud29ybGRSb3RhdGlvbiA9IHRoaXMuZGF0YS5pbmhlcml0Um90YXRpb24gPyAocGFyZW50LndvcmxkUm90YXRpb24gKyB0aGlzLnJvdGF0aW9uSUspIDogdGhpcy5yb3RhdGlvbklLO1xuXHRcdFx0dGhpcy53b3JsZEZsaXBYID0gcGFyZW50LndvcmxkRmxpcFggIT0gdGhpcy5mbGlwWDtcblx0XHRcdHRoaXMud29ybGRGbGlwWSA9IHBhcmVudC53b3JsZEZsaXBZICE9IHRoaXMuZmxpcFk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHZhciBza2VsZXRvbkZsaXBYID0gdGhpcy5za2VsZXRvbi5mbGlwWCwgc2tlbGV0b25GbGlwWSA9IHRoaXMuc2tlbGV0b24uZmxpcFk7XG5cdFx0XHR0aGlzLndvcmxkWCA9IHNrZWxldG9uRmxpcFggPyAtdGhpcy54IDogdGhpcy54O1xuXHRcdFx0dGhpcy53b3JsZFkgPSAoc2tlbGV0b25GbGlwWSAhPSBzcGluZS5Cb25lLnlEb3duKSA/IC10aGlzLnkgOiB0aGlzLnk7XG5cdFx0XHR0aGlzLndvcmxkU2NhbGVYID0gdGhpcy5zY2FsZVg7XG5cdFx0XHR0aGlzLndvcmxkU2NhbGVZID0gdGhpcy5zY2FsZVk7XG5cdFx0XHR0aGlzLndvcmxkUm90YXRpb24gPSB0aGlzLnJvdGF0aW9uSUs7XG5cdFx0XHR0aGlzLndvcmxkRmxpcFggPSBza2VsZXRvbkZsaXBYICE9IHRoaXMuZmxpcFg7XG5cdFx0XHR0aGlzLndvcmxkRmxpcFkgPSBza2VsZXRvbkZsaXBZICE9IHRoaXMuZmxpcFk7XG5cdFx0fVxuXHRcdHZhciByYWRpYW5zID0gdGhpcy53b3JsZFJvdGF0aW9uICogc3BpbmUuZGVnUmFkO1xuXHRcdHZhciBjb3MgPSBNYXRoLmNvcyhyYWRpYW5zKTtcblx0XHR2YXIgc2luID0gTWF0aC5zaW4ocmFkaWFucyk7XG5cdFx0aWYgKHRoaXMud29ybGRGbGlwWCkge1xuXHRcdFx0dGhpcy5tMDAgPSAtY29zICogdGhpcy53b3JsZFNjYWxlWDtcblx0XHRcdHRoaXMubTAxID0gc2luICogdGhpcy53b3JsZFNjYWxlWTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5tMDAgPSBjb3MgKiB0aGlzLndvcmxkU2NhbGVYO1xuXHRcdFx0dGhpcy5tMDEgPSAtc2luICogdGhpcy53b3JsZFNjYWxlWTtcblx0XHR9XG5cdFx0aWYgKHRoaXMud29ybGRGbGlwWSAhPSBzcGluZS5Cb25lLnlEb3duKSB7XG5cdFx0XHR0aGlzLm0xMCA9IC1zaW4gKiB0aGlzLndvcmxkU2NhbGVYO1xuXHRcdFx0dGhpcy5tMTEgPSAtY29zICogdGhpcy53b3JsZFNjYWxlWTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5tMTAgPSBzaW4gKiB0aGlzLndvcmxkU2NhbGVYO1xuXHRcdFx0dGhpcy5tMTEgPSBjb3MgKiB0aGlzLndvcmxkU2NhbGVZO1xuXHRcdH1cblx0fSxcblx0c2V0VG9TZXR1cFBvc2U6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgZGF0YSA9IHRoaXMuZGF0YTtcblx0XHR0aGlzLnggPSBkYXRhLng7XG5cdFx0dGhpcy55ID0gZGF0YS55O1xuXHRcdHRoaXMucm90YXRpb24gPSBkYXRhLnJvdGF0aW9uO1xuXHRcdHRoaXMucm90YXRpb25JSyA9IHRoaXMucm90YXRpb247XG5cdFx0dGhpcy5zY2FsZVggPSBkYXRhLnNjYWxlWDtcblx0XHR0aGlzLnNjYWxlWSA9IGRhdGEuc2NhbGVZO1xuXHRcdHRoaXMuZmxpcFggPSBkYXRhLmZsaXBYO1xuXHRcdHRoaXMuZmxpcFkgPSBkYXRhLmZsaXBZO1xuXHR9LFxuXHR3b3JsZFRvTG9jYWw6IGZ1bmN0aW9uICh3b3JsZCkge1xuXHRcdHZhciBkeCA9IHdvcmxkWzBdIC0gdGhpcy53b3JsZFgsIGR5ID0gd29ybGRbMV0gLSB0aGlzLndvcmxkWTtcblx0XHR2YXIgbTAwID0gdGhpcy5tMDAsIG0xMCA9IHRoaXMubTEwLCBtMDEgPSB0aGlzLm0wMSwgbTExID0gdGhpcy5tMTE7XG5cdFx0aWYgKHRoaXMud29ybGRGbGlwWCAhPSAodGhpcy53b3JsZEZsaXBZICE9IHNwaW5lLkJvbmUueURvd24pKSB7XG5cdFx0XHRtMDAgPSAtbTAwO1xuXHRcdFx0bTExID0gLW0xMTtcblx0XHR9XG5cdFx0dmFyIGludkRldCA9IDEgLyAobTAwICogbTExIC0gbTAxICogbTEwKTtcblx0XHR3b3JsZFswXSA9IGR4ICogbTAwICogaW52RGV0IC0gZHkgKiBtMDEgKiBpbnZEZXQ7XG5cdFx0d29ybGRbMV0gPSBkeSAqIG0xMSAqIGludkRldCAtIGR4ICogbTEwICogaW52RGV0O1xuXHR9LFxuXHRsb2NhbFRvV29ybGQ6IGZ1bmN0aW9uIChsb2NhbCkge1xuXHRcdHZhciBsb2NhbFggPSBsb2NhbFswXSwgbG9jYWxZID0gbG9jYWxbMV07XG5cdFx0bG9jYWxbMF0gPSBsb2NhbFggKiB0aGlzLm0wMCArIGxvY2FsWSAqIHRoaXMubTAxICsgdGhpcy53b3JsZFg7XG5cdFx0bG9jYWxbMV0gPSBsb2NhbFggKiB0aGlzLm0xMCArIGxvY2FsWSAqIHRoaXMubTExICsgdGhpcy53b3JsZFk7XG5cdH1cbn07XG5cbnNwaW5lLlNsb3QgPSBmdW5jdGlvbiAoc2xvdERhdGEsIGJvbmUpIHtcblx0dGhpcy5kYXRhID0gc2xvdERhdGE7XG5cdHRoaXMuYm9uZSA9IGJvbmU7XG5cdHRoaXMuc2V0VG9TZXR1cFBvc2UoKTtcbn07XG5zcGluZS5TbG90LnByb3RvdHlwZSA9IHtcblx0cjogMSwgZzogMSwgYjogMSwgYTogMSxcblx0X2F0dGFjaG1lbnRUaW1lOiAwLFxuXHRhdHRhY2htZW50OiBudWxsLFxuXHRhdHRhY2htZW50VmVydGljZXM6IFtdLFxuXHRzZXRBdHRhY2htZW50OiBmdW5jdGlvbiAoYXR0YWNobWVudCkge1xuXHRcdHRoaXMuYXR0YWNobWVudCA9IGF0dGFjaG1lbnQ7XG5cdFx0dGhpcy5fYXR0YWNobWVudFRpbWUgPSB0aGlzLmJvbmUuc2tlbGV0b24udGltZTtcblx0XHR0aGlzLmF0dGFjaG1lbnRWZXJ0aWNlcy5sZW5ndGggPSAwO1xuXHR9LFxuXHRzZXRBdHRhY2htZW50VGltZTogZnVuY3Rpb24gKHRpbWUpIHtcblx0XHR0aGlzLl9hdHRhY2htZW50VGltZSA9IHRoaXMuYm9uZS5za2VsZXRvbi50aW1lIC0gdGltZTtcblx0fSxcblx0Z2V0QXR0YWNobWVudFRpbWU6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5ib25lLnNrZWxldG9uLnRpbWUgLSB0aGlzLl9hdHRhY2htZW50VGltZTtcblx0fSxcblx0c2V0VG9TZXR1cFBvc2U6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgZGF0YSA9IHRoaXMuZGF0YTtcblx0XHR0aGlzLnIgPSBkYXRhLnI7XG5cdFx0dGhpcy5nID0gZGF0YS5nO1xuXHRcdHRoaXMuYiA9IGRhdGEuYjtcblx0XHR0aGlzLmEgPSBkYXRhLmE7XG5cblx0XHR2YXIgc2xvdERhdGFzID0gdGhpcy5ib25lLnNrZWxldG9uLmRhdGEuc2xvdHM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBzbG90RGF0YXMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRpZiAoc2xvdERhdGFzW2ldID09IGRhdGEpIHtcblx0XHRcdFx0dGhpcy5zZXRBdHRhY2htZW50KCFkYXRhLmF0dGFjaG1lbnROYW1lID8gbnVsbCA6IHRoaXMuYm9uZS5za2VsZXRvbi5nZXRBdHRhY2htZW50QnlTbG90SW5kZXgoaSwgZGF0YS5hdHRhY2htZW50TmFtZSkpO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdH1cblx0XHR9XG5cdH1cbn07XG5cbnNwaW5lLklrQ29uc3RyYWludCA9IGZ1bmN0aW9uIChkYXRhLCBza2VsZXRvbikge1xuXHR0aGlzLmRhdGEgPSBkYXRhO1xuXHR0aGlzLm1peCA9IGRhdGEubWl4O1xuXHR0aGlzLmJlbmREaXJlY3Rpb24gPSBkYXRhLmJlbmREaXJlY3Rpb247XG5cblx0dGhpcy5ib25lcyA9IFtdO1xuXHRmb3IgKHZhciBpID0gMCwgbiA9IGRhdGEuYm9uZXMubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdHRoaXMuYm9uZXMucHVzaChza2VsZXRvbi5maW5kQm9uZShkYXRhLmJvbmVzW2ldLm5hbWUpKTtcblx0dGhpcy50YXJnZXQgPSBza2VsZXRvbi5maW5kQm9uZShkYXRhLnRhcmdldC5uYW1lKTtcbn07XG5zcGluZS5Ja0NvbnN0cmFpbnQucHJvdG90eXBlID0ge1xuXHRhcHBseTogZnVuY3Rpb24gKCkge1xuXHRcdHZhciB0YXJnZXQgPSB0aGlzLnRhcmdldDtcblx0XHR2YXIgYm9uZXMgPSB0aGlzLmJvbmVzO1xuXHRcdHN3aXRjaCAoYm9uZXMubGVuZ3RoKSB7XG5cdFx0Y2FzZSAxOlxuXHRcdFx0c3BpbmUuSWtDb25zdHJhaW50LmFwcGx5MShib25lc1swXSwgdGFyZ2V0LndvcmxkWCwgdGFyZ2V0LndvcmxkWSwgdGhpcy5taXgpO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAyOlxuXHRcdFx0c3BpbmUuSWtDb25zdHJhaW50LmFwcGx5Mihib25lc1swXSwgYm9uZXNbMV0sIHRhcmdldC53b3JsZFgsIHRhcmdldC53b3JsZFksIHRoaXMuYmVuZERpcmVjdGlvbiwgdGhpcy5taXgpO1xuXHRcdFx0YnJlYWs7XG5cdFx0fVxuXHR9XG59O1xuLyoqIEFkanVzdHMgdGhlIGJvbmUgcm90YXRpb24gc28gdGhlIHRpcCBpcyBhcyBjbG9zZSB0byB0aGUgdGFyZ2V0IHBvc2l0aW9uIGFzIHBvc3NpYmxlLiBUaGUgdGFyZ2V0IGlzIHNwZWNpZmllZCBpbiB0aGUgd29ybGRcbiAqIGNvb3JkaW5hdGUgc3lzdGVtLiAqL1xuc3BpbmUuSWtDb25zdHJhaW50LmFwcGx5MSA9IGZ1bmN0aW9uIChib25lLCB0YXJnZXRYLCB0YXJnZXRZLCBhbHBoYSkge1xuXHR2YXIgcGFyZW50Um90YXRpb24gPSAoIWJvbmUuZGF0YS5pbmhlcml0Um90YXRpb24gfHwgIWJvbmUucGFyZW50KSA/IDAgOiBib25lLnBhcmVudC53b3JsZFJvdGF0aW9uO1xuXHR2YXIgcm90YXRpb24gPSBib25lLnJvdGF0aW9uO1xuXHR2YXIgcm90YXRpb25JSyA9IE1hdGguYXRhbjIodGFyZ2V0WSAtIGJvbmUud29ybGRZLCB0YXJnZXRYIC0gYm9uZS53b3JsZFgpICogc3BpbmUucmFkRGVnIC0gcGFyZW50Um90YXRpb247XG5cdGJvbmUucm90YXRpb25JSyA9IHJvdGF0aW9uICsgKHJvdGF0aW9uSUsgLSByb3RhdGlvbikgKiBhbHBoYTtcbn07XG4vKiogQWRqdXN0cyB0aGUgcGFyZW50IGFuZCBjaGlsZCBib25lIHJvdGF0aW9ucyBzbyB0aGUgdGlwIG9mIHRoZSBjaGlsZCBpcyBhcyBjbG9zZSB0byB0aGUgdGFyZ2V0IHBvc2l0aW9uIGFzIHBvc3NpYmxlLiBUaGVcbiAqIHRhcmdldCBpcyBzcGVjaWZpZWQgaW4gdGhlIHdvcmxkIGNvb3JkaW5hdGUgc3lzdGVtLlxuICogQHBhcmFtIGNoaWxkIEFueSBkZXNjZW5kYW50IGJvbmUgb2YgdGhlIHBhcmVudC4gKi9cbnNwaW5lLklrQ29uc3RyYWludC5hcHBseTIgPSBmdW5jdGlvbiAocGFyZW50LCBjaGlsZCwgdGFyZ2V0WCwgdGFyZ2V0WSwgYmVuZERpcmVjdGlvbiwgYWxwaGEpIHtcblx0dmFyIGNoaWxkUm90YXRpb24gPSBjaGlsZC5yb3RhdGlvbiwgcGFyZW50Um90YXRpb24gPSBwYXJlbnQucm90YXRpb247XG5cdGlmICghYWxwaGEpIHtcblx0XHRjaGlsZC5yb3RhdGlvbklLID0gY2hpbGRSb3RhdGlvbjtcblx0XHRwYXJlbnQucm90YXRpb25JSyA9IHBhcmVudFJvdGF0aW9uO1xuXHRcdHJldHVybjtcblx0fVxuXHR2YXIgcG9zaXRpb25YLCBwb3NpdGlvblksIHRlbXBQb3NpdGlvbiA9IHNwaW5lLnRlbXA7XG5cdHZhciBwYXJlbnRQYXJlbnQgPSBwYXJlbnQucGFyZW50O1xuXHRpZiAocGFyZW50UGFyZW50KSB7XG5cdFx0dGVtcFBvc2l0aW9uWzBdID0gdGFyZ2V0WDtcblx0XHR0ZW1wUG9zaXRpb25bMV0gPSB0YXJnZXRZO1xuXHRcdHBhcmVudFBhcmVudC53b3JsZFRvTG9jYWwodGVtcFBvc2l0aW9uKTtcblx0XHR0YXJnZXRYID0gKHRlbXBQb3NpdGlvblswXSAtIHBhcmVudC54KSAqIHBhcmVudFBhcmVudC53b3JsZFNjYWxlWDtcblx0XHR0YXJnZXRZID0gKHRlbXBQb3NpdGlvblsxXSAtIHBhcmVudC55KSAqIHBhcmVudFBhcmVudC53b3JsZFNjYWxlWTtcblx0fSBlbHNlIHtcblx0XHR0YXJnZXRYIC09IHBhcmVudC54O1xuXHRcdHRhcmdldFkgLT0gcGFyZW50Lnk7XG5cdH1cblx0aWYgKGNoaWxkLnBhcmVudCA9PSBwYXJlbnQpIHtcblx0XHRwb3NpdGlvblggPSBjaGlsZC54O1xuXHRcdHBvc2l0aW9uWSA9IGNoaWxkLnk7XG5cdH0gZWxzZSB7XG5cdFx0dGVtcFBvc2l0aW9uWzBdID0gY2hpbGQueDtcblx0XHR0ZW1wUG9zaXRpb25bMV0gPSBjaGlsZC55O1xuXHRcdGNoaWxkLnBhcmVudC5sb2NhbFRvV29ybGQodGVtcFBvc2l0aW9uKTtcblx0XHRwYXJlbnQud29ybGRUb0xvY2FsKHRlbXBQb3NpdGlvbik7XG5cdFx0cG9zaXRpb25YID0gdGVtcFBvc2l0aW9uWzBdO1xuXHRcdHBvc2l0aW9uWSA9IHRlbXBQb3NpdGlvblsxXTtcblx0fVxuXHR2YXIgY2hpbGRYID0gcG9zaXRpb25YICogcGFyZW50LndvcmxkU2NhbGVYLCBjaGlsZFkgPSBwb3NpdGlvblkgKiBwYXJlbnQud29ybGRTY2FsZVk7XG5cdHZhciBvZmZzZXQgPSBNYXRoLmF0YW4yKGNoaWxkWSwgY2hpbGRYKTtcblx0dmFyIGxlbjEgPSBNYXRoLnNxcnQoY2hpbGRYICogY2hpbGRYICsgY2hpbGRZICogY2hpbGRZKSwgbGVuMiA9IGNoaWxkLmRhdGEubGVuZ3RoICogY2hpbGQud29ybGRTY2FsZVg7XG5cdC8vIEJhc2VkIG9uIGNvZGUgYnkgUnlhbiBKdWNrZXR0IHdpdGggcGVybWlzc2lvbjogQ29weXJpZ2h0IChjKSAyMDA4LTIwMDkgUnlhbiBKdWNrZXR0LCBodHRwOi8vd3d3LnJ5YW5qdWNrZXR0LmNvbS9cblx0dmFyIGNvc0Rlbm9tID0gMiAqIGxlbjEgKiBsZW4yO1xuXHRpZiAoY29zRGVub20gPCAwLjAwMDEpIHtcblx0XHRjaGlsZC5yb3RhdGlvbklLID0gY2hpbGRSb3RhdGlvbiArIChNYXRoLmF0YW4yKHRhcmdldFksIHRhcmdldFgpICogc3BpbmUucmFkRGVnIC0gcGFyZW50Um90YXRpb24gLSBjaGlsZFJvdGF0aW9uKSAqIGFscGhhO1xuXHRcdHJldHVybjtcblx0fVxuXHR2YXIgY29zID0gKHRhcmdldFggKiB0YXJnZXRYICsgdGFyZ2V0WSAqIHRhcmdldFkgLSBsZW4xICogbGVuMSAtIGxlbjIgKiBsZW4yKSAvIGNvc0Rlbm9tO1xuXHRpZiAoY29zIDwgLTEpXG5cdFx0Y29zID0gLTE7XG5cdGVsc2UgaWYgKGNvcyA+IDEpXG5cdFx0Y29zID0gMTtcblx0dmFyIGNoaWxkQW5nbGUgPSBNYXRoLmFjb3MoY29zKSAqIGJlbmREaXJlY3Rpb247XG5cdHZhciBhZGphY2VudCA9IGxlbjEgKyBsZW4yICogY29zLCBvcHBvc2l0ZSA9IGxlbjIgKiBNYXRoLnNpbihjaGlsZEFuZ2xlKTtcblx0dmFyIHBhcmVudEFuZ2xlID0gTWF0aC5hdGFuMih0YXJnZXRZICogYWRqYWNlbnQgLSB0YXJnZXRYICogb3Bwb3NpdGUsIHRhcmdldFggKiBhZGphY2VudCArIHRhcmdldFkgKiBvcHBvc2l0ZSk7XG5cdHZhciByb3RhdGlvbiA9IChwYXJlbnRBbmdsZSAtIG9mZnNldCkgKiBzcGluZS5yYWREZWcgLSBwYXJlbnRSb3RhdGlvbjtcblx0aWYgKHJvdGF0aW9uID4gMTgwKVxuXHRcdHJvdGF0aW9uIC09IDM2MDtcblx0ZWxzZSBpZiAocm90YXRpb24gPCAtMTgwKSAvL1xuXHRcdHJvdGF0aW9uICs9IDM2MDtcblx0cGFyZW50LnJvdGF0aW9uSUsgPSBwYXJlbnRSb3RhdGlvbiArIHJvdGF0aW9uICogYWxwaGE7XG5cdHJvdGF0aW9uID0gKGNoaWxkQW5nbGUgKyBvZmZzZXQpICogc3BpbmUucmFkRGVnIC0gY2hpbGRSb3RhdGlvbjtcblx0aWYgKHJvdGF0aW9uID4gMTgwKVxuXHRcdHJvdGF0aW9uIC09IDM2MDtcblx0ZWxzZSBpZiAocm90YXRpb24gPCAtMTgwKSAvL1xuXHRcdHJvdGF0aW9uICs9IDM2MDtcblx0Y2hpbGQucm90YXRpb25JSyA9IGNoaWxkUm90YXRpb24gKyAocm90YXRpb24gKyBwYXJlbnQud29ybGRSb3RhdGlvbiAtIGNoaWxkLnBhcmVudC53b3JsZFJvdGF0aW9uKSAqIGFscGhhO1xufTtcblxuc3BpbmUuU2tpbiA9IGZ1bmN0aW9uIChuYW1lKSB7XG5cdHRoaXMubmFtZSA9IG5hbWU7XG5cdHRoaXMuYXR0YWNobWVudHMgPSB7fTtcbn07XG5zcGluZS5Ta2luLnByb3RvdHlwZSA9IHtcblx0YWRkQXR0YWNobWVudDogZnVuY3Rpb24gKHNsb3RJbmRleCwgbmFtZSwgYXR0YWNobWVudCkge1xuXHRcdHRoaXMuYXR0YWNobWVudHNbc2xvdEluZGV4ICsgXCI6XCIgKyBuYW1lXSA9IGF0dGFjaG1lbnQ7XG5cdH0sXG5cdGdldEF0dGFjaG1lbnQ6IGZ1bmN0aW9uIChzbG90SW5kZXgsIG5hbWUpIHtcblx0XHRyZXR1cm4gdGhpcy5hdHRhY2htZW50c1tzbG90SW5kZXggKyBcIjpcIiArIG5hbWVdO1xuXHR9LFxuXHRfYXR0YWNoQWxsOiBmdW5jdGlvbiAoc2tlbGV0b24sIG9sZFNraW4pIHtcblx0XHRmb3IgKHZhciBrZXkgaW4gb2xkU2tpbi5hdHRhY2htZW50cykge1xuXHRcdFx0dmFyIGNvbG9uID0ga2V5LmluZGV4T2YoXCI6XCIpO1xuXHRcdFx0dmFyIHNsb3RJbmRleCA9IHBhcnNlSW50KGtleS5zdWJzdHJpbmcoMCwgY29sb24pKTtcblx0XHRcdHZhciBuYW1lID0ga2V5LnN1YnN0cmluZyhjb2xvbiArIDEpO1xuXHRcdFx0dmFyIHNsb3QgPSBza2VsZXRvbi5zbG90c1tzbG90SW5kZXhdO1xuXHRcdFx0aWYgKHNsb3QuYXR0YWNobWVudCAmJiBzbG90LmF0dGFjaG1lbnQubmFtZSA9PSBuYW1lKSB7XG5cdFx0XHRcdHZhciBhdHRhY2htZW50ID0gdGhpcy5nZXRBdHRhY2htZW50KHNsb3RJbmRleCwgbmFtZSk7XG5cdFx0XHRcdGlmIChhdHRhY2htZW50KSBzbG90LnNldEF0dGFjaG1lbnQoYXR0YWNobWVudCk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG59O1xuXG5zcGluZS5BbmltYXRpb24gPSBmdW5jdGlvbiAobmFtZSwgdGltZWxpbmVzLCBkdXJhdGlvbikge1xuXHR0aGlzLm5hbWUgPSBuYW1lO1xuXHR0aGlzLnRpbWVsaW5lcyA9IHRpbWVsaW5lcztcblx0dGhpcy5kdXJhdGlvbiA9IGR1cmF0aW9uO1xufTtcbnNwaW5lLkFuaW1hdGlvbi5wcm90b3R5cGUgPSB7XG5cdGFwcGx5OiBmdW5jdGlvbiAoc2tlbGV0b24sIGxhc3RUaW1lLCB0aW1lLCBsb29wLCBldmVudHMpIHtcblx0XHRpZiAobG9vcCAmJiB0aGlzLmR1cmF0aW9uICE9IDApIHtcblx0XHRcdHRpbWUgJT0gdGhpcy5kdXJhdGlvbjtcblx0XHRcdGxhc3RUaW1lICU9IHRoaXMuZHVyYXRpb247XG5cdFx0fVxuXHRcdHZhciB0aW1lbGluZXMgPSB0aGlzLnRpbWVsaW5lcztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHRpbWVsaW5lcy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHR0aW1lbGluZXNbaV0uYXBwbHkoc2tlbGV0b24sIGxhc3RUaW1lLCB0aW1lLCBldmVudHMsIDEpO1xuXHR9LFxuXHRtaXg6IGZ1bmN0aW9uIChza2VsZXRvbiwgbGFzdFRpbWUsIHRpbWUsIGxvb3AsIGV2ZW50cywgYWxwaGEpIHtcblx0XHRpZiAobG9vcCAmJiB0aGlzLmR1cmF0aW9uICE9IDApIHtcblx0XHRcdHRpbWUgJT0gdGhpcy5kdXJhdGlvbjtcblx0XHRcdGxhc3RUaW1lICU9IHRoaXMuZHVyYXRpb247XG5cdFx0fVxuXHRcdHZhciB0aW1lbGluZXMgPSB0aGlzLnRpbWVsaW5lcztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHRpbWVsaW5lcy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHR0aW1lbGluZXNbaV0uYXBwbHkoc2tlbGV0b24sIGxhc3RUaW1lLCB0aW1lLCBldmVudHMsIGFscGhhKTtcblx0fVxufTtcbnNwaW5lLkFuaW1hdGlvbi5iaW5hcnlTZWFyY2ggPSBmdW5jdGlvbiAodmFsdWVzLCB0YXJnZXQsIHN0ZXApIHtcblx0dmFyIGxvdyA9IDA7XG5cdHZhciBoaWdoID0gTWF0aC5mbG9vcih2YWx1ZXMubGVuZ3RoIC8gc3RlcCkgLSAyO1xuXHRpZiAoIWhpZ2gpIHJldHVybiBzdGVwO1xuXHR2YXIgY3VycmVudCA9IGhpZ2ggPj4+IDE7XG5cdHdoaWxlICh0cnVlKSB7XG5cdFx0aWYgKHZhbHVlc1soY3VycmVudCArIDEpICogc3RlcF0gPD0gdGFyZ2V0KVxuXHRcdFx0bG93ID0gY3VycmVudCArIDE7XG5cdFx0ZWxzZVxuXHRcdFx0aGlnaCA9IGN1cnJlbnQ7XG5cdFx0aWYgKGxvdyA9PSBoaWdoKSByZXR1cm4gKGxvdyArIDEpICogc3RlcDtcblx0XHRjdXJyZW50ID0gKGxvdyArIGhpZ2gpID4+PiAxO1xuXHR9XG59O1xuc3BpbmUuQW5pbWF0aW9uLmJpbmFyeVNlYXJjaDEgPSBmdW5jdGlvbiAodmFsdWVzLCB0YXJnZXQpIHtcblx0dmFyIGxvdyA9IDA7XG5cdHZhciBoaWdoID0gdmFsdWVzLmxlbmd0aCAtIDI7XG5cdGlmICghaGlnaCkgcmV0dXJuIDE7XG5cdHZhciBjdXJyZW50ID0gaGlnaCA+Pj4gMTtcblx0d2hpbGUgKHRydWUpIHtcblx0XHRpZiAodmFsdWVzW2N1cnJlbnQgKyAxXSA8PSB0YXJnZXQpXG5cdFx0XHRsb3cgPSBjdXJyZW50ICsgMTtcblx0XHRlbHNlXG5cdFx0XHRoaWdoID0gY3VycmVudDtcblx0XHRpZiAobG93ID09IGhpZ2gpIHJldHVybiBsb3cgKyAxO1xuXHRcdGN1cnJlbnQgPSAobG93ICsgaGlnaCkgPj4+IDE7XG5cdH1cbn07XG5zcGluZS5BbmltYXRpb24ubGluZWFyU2VhcmNoID0gZnVuY3Rpb24gKHZhbHVlcywgdGFyZ2V0LCBzdGVwKSB7XG5cdGZvciAodmFyIGkgPSAwLCBsYXN0ID0gdmFsdWVzLmxlbmd0aCAtIHN0ZXA7IGkgPD0gbGFzdDsgaSArPSBzdGVwKVxuXHRcdGlmICh2YWx1ZXNbaV0gPiB0YXJnZXQpIHJldHVybiBpO1xuXHRyZXR1cm4gLTE7XG59O1xuXG5zcGluZS5DdXJ2ZXMgPSBmdW5jdGlvbiAoZnJhbWVDb3VudCkge1xuXHR0aGlzLmN1cnZlcyA9IFtdOyAvLyB0eXBlLCB4LCB5LCAuLi5cblx0Ly90aGlzLmN1cnZlcy5sZW5ndGggPSAoZnJhbWVDb3VudCAtIDEpICogMTkvKkJFWklFUl9TSVpFKi87XG59O1xuc3BpbmUuQ3VydmVzLnByb3RvdHlwZSA9IHtcblx0c2V0TGluZWFyOiBmdW5jdGlvbiAoZnJhbWVJbmRleCkge1xuXHRcdHRoaXMuY3VydmVzW2ZyYW1lSW5kZXggKiAxOS8qQkVaSUVSX1NJWkUqL10gPSAwLypMSU5FQVIqLztcblx0fSxcblx0c2V0U3RlcHBlZDogZnVuY3Rpb24gKGZyYW1lSW5kZXgpIHtcblx0XHR0aGlzLmN1cnZlc1tmcmFtZUluZGV4ICogMTkvKkJFWklFUl9TSVpFKi9dID0gMS8qU1RFUFBFRCovO1xuXHR9LFxuXHQvKiogU2V0cyB0aGUgY29udHJvbCBoYW5kbGUgcG9zaXRpb25zIGZvciBhbiBpbnRlcnBvbGF0aW9uIGJlemllciBjdXJ2ZSB1c2VkIHRvIHRyYW5zaXRpb24gZnJvbSB0aGlzIGtleWZyYW1lIHRvIHRoZSBuZXh0LlxuXHQgKiBjeDEgYW5kIGN4MiBhcmUgZnJvbSAwIHRvIDEsIHJlcHJlc2VudGluZyB0aGUgcGVyY2VudCBvZiB0aW1lIGJldHdlZW4gdGhlIHR3byBrZXlmcmFtZXMuIGN5MSBhbmQgY3kyIGFyZSB0aGUgcGVyY2VudCBvZlxuXHQgKiB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBrZXlmcmFtZSdzIHZhbHVlcy4gKi9cblx0c2V0Q3VydmU6IGZ1bmN0aW9uIChmcmFtZUluZGV4LCBjeDEsIGN5MSwgY3gyLCBjeTIpIHtcblx0XHR2YXIgc3ViZGl2MSA9IDEgLyAxMC8qQkVaSUVSX1NFR01FTlRTKi8sIHN1YmRpdjIgPSBzdWJkaXYxICogc3ViZGl2MSwgc3ViZGl2MyA9IHN1YmRpdjIgKiBzdWJkaXYxO1xuXHRcdHZhciBwcmUxID0gMyAqIHN1YmRpdjEsIHByZTIgPSAzICogc3ViZGl2MiwgcHJlNCA9IDYgKiBzdWJkaXYyLCBwcmU1ID0gNiAqIHN1YmRpdjM7XG5cdFx0dmFyIHRtcDF4ID0gLWN4MSAqIDIgKyBjeDIsIHRtcDF5ID0gLWN5MSAqIDIgKyBjeTIsIHRtcDJ4ID0gKGN4MSAtIGN4MikgKiAzICsgMSwgdG1wMnkgPSAoY3kxIC0gY3kyKSAqIDMgKyAxO1xuXHRcdHZhciBkZnggPSBjeDEgKiBwcmUxICsgdG1wMXggKiBwcmUyICsgdG1wMnggKiBzdWJkaXYzLCBkZnkgPSBjeTEgKiBwcmUxICsgdG1wMXkgKiBwcmUyICsgdG1wMnkgKiBzdWJkaXYzO1xuXHRcdHZhciBkZGZ4ID0gdG1wMXggKiBwcmU0ICsgdG1wMnggKiBwcmU1LCBkZGZ5ID0gdG1wMXkgKiBwcmU0ICsgdG1wMnkgKiBwcmU1O1xuXHRcdHZhciBkZGRmeCA9IHRtcDJ4ICogcHJlNSwgZGRkZnkgPSB0bXAyeSAqIHByZTU7XG5cblx0XHR2YXIgaSA9IGZyYW1lSW5kZXggKiAxOS8qQkVaSUVSX1NJWkUqLztcblx0XHR2YXIgY3VydmVzID0gdGhpcy5jdXJ2ZXM7XG5cdFx0Y3VydmVzW2krK10gPSAyLypCRVpJRVIqLztcblxuXHRcdHZhciB4ID0gZGZ4LCB5ID0gZGZ5O1xuXHRcdGZvciAodmFyIG4gPSBpICsgMTkvKkJFWklFUl9TSVpFKi8gLSAxOyBpIDwgbjsgaSArPSAyKSB7XG5cdFx0XHRjdXJ2ZXNbaV0gPSB4O1xuXHRcdFx0Y3VydmVzW2kgKyAxXSA9IHk7XG5cdFx0XHRkZnggKz0gZGRmeDtcblx0XHRcdGRmeSArPSBkZGZ5O1xuXHRcdFx0ZGRmeCArPSBkZGRmeDtcblx0XHRcdGRkZnkgKz0gZGRkZnk7XG5cdFx0XHR4ICs9IGRmeDtcblx0XHRcdHkgKz0gZGZ5O1xuXHRcdH1cblx0fSxcblx0Z2V0Q3VydmVQZXJjZW50OiBmdW5jdGlvbiAoZnJhbWVJbmRleCwgcGVyY2VudCkge1xuXHRcdHBlcmNlbnQgPSBwZXJjZW50IDwgMCA/IDAgOiAocGVyY2VudCA+IDEgPyAxIDogcGVyY2VudCk7XG5cdFx0dmFyIGN1cnZlcyA9IHRoaXMuY3VydmVzO1xuXHRcdHZhciBpID0gZnJhbWVJbmRleCAqIDE5LypCRVpJRVJfU0laRSovO1xuXHRcdHZhciB0eXBlID0gY3VydmVzW2ldO1xuXHRcdGlmICh0eXBlID09PSAwLypMSU5FQVIqLykgcmV0dXJuIHBlcmNlbnQ7XG5cdFx0aWYgKHR5cGUgPT0gMS8qU1RFUFBFRCovKSByZXR1cm4gMDtcblx0XHRpKys7XG5cdFx0dmFyIHggPSAwO1xuXHRcdGZvciAodmFyIHN0YXJ0ID0gaSwgbiA9IGkgKyAxOS8qQkVaSUVSX1NJWkUqLyAtIDE7IGkgPCBuOyBpICs9IDIpIHtcblx0XHRcdHggPSBjdXJ2ZXNbaV07XG5cdFx0XHRpZiAoeCA+PSBwZXJjZW50KSB7XG5cdFx0XHRcdHZhciBwcmV2WCwgcHJldlk7XG5cdFx0XHRcdGlmIChpID09IHN0YXJ0KSB7XG5cdFx0XHRcdFx0cHJldlggPSAwO1xuXHRcdFx0XHRcdHByZXZZID0gMDtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRwcmV2WCA9IGN1cnZlc1tpIC0gMl07XG5cdFx0XHRcdFx0cHJldlkgPSBjdXJ2ZXNbaSAtIDFdO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBwcmV2WSArIChjdXJ2ZXNbaSArIDFdIC0gcHJldlkpICogKHBlcmNlbnQgLSBwcmV2WCkgLyAoeCAtIHByZXZYKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0dmFyIHkgPSBjdXJ2ZXNbaSAtIDFdO1xuXHRcdHJldHVybiB5ICsgKDEgLSB5KSAqIChwZXJjZW50IC0geCkgLyAoMSAtIHgpOyAvLyBMYXN0IHBvaW50IGlzIDEsMS5cblx0fVxufTtcblxuc3BpbmUuUm90YXRlVGltZWxpbmUgPSBmdW5jdGlvbiAoZnJhbWVDb3VudCkge1xuXHR0aGlzLmN1cnZlcyA9IG5ldyBzcGluZS5DdXJ2ZXMoZnJhbWVDb3VudCk7XG5cdHRoaXMuZnJhbWVzID0gW107IC8vIHRpbWUsIGFuZ2xlLCAuLi5cblx0dGhpcy5mcmFtZXMubGVuZ3RoID0gZnJhbWVDb3VudCAqIDI7XG59O1xuc3BpbmUuUm90YXRlVGltZWxpbmUucHJvdG90eXBlID0ge1xuXHRib25lSW5kZXg6IDAsXG5cdGdldEZyYW1lQ291bnQ6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5mcmFtZXMubGVuZ3RoIC8gMjtcblx0fSxcblx0c2V0RnJhbWU6IGZ1bmN0aW9uIChmcmFtZUluZGV4LCB0aW1lLCBhbmdsZSkge1xuXHRcdGZyYW1lSW5kZXggKj0gMjtcblx0XHR0aGlzLmZyYW1lc1tmcmFtZUluZGV4XSA9IHRpbWU7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleCArIDFdID0gYW5nbGU7XG5cdH0sXG5cdGFwcGx5OiBmdW5jdGlvbiAoc2tlbGV0b24sIGxhc3RUaW1lLCB0aW1lLCBmaXJlZEV2ZW50cywgYWxwaGEpIHtcblx0XHR2YXIgZnJhbWVzID0gdGhpcy5mcmFtZXM7XG5cdFx0aWYgKHRpbWUgPCBmcmFtZXNbMF0pIHJldHVybjsgLy8gVGltZSBpcyBiZWZvcmUgZmlyc3QgZnJhbWUuXG5cblx0XHR2YXIgYm9uZSA9IHNrZWxldG9uLmJvbmVzW3RoaXMuYm9uZUluZGV4XTtcblxuXHRcdGlmICh0aW1lID49IGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMl0pIHsgLy8gVGltZSBpcyBhZnRlciBsYXN0IGZyYW1lLlxuXHRcdFx0dmFyIGFtb3VudCA9IGJvbmUuZGF0YS5yb3RhdGlvbiArIGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMV0gLSBib25lLnJvdGF0aW9uO1xuXHRcdFx0d2hpbGUgKGFtb3VudCA+IDE4MClcblx0XHRcdFx0YW1vdW50IC09IDM2MDtcblx0XHRcdHdoaWxlIChhbW91bnQgPCAtMTgwKVxuXHRcdFx0XHRhbW91bnQgKz0gMzYwO1xuXHRcdFx0Ym9uZS5yb3RhdGlvbiArPSBhbW91bnQgKiBhbHBoYTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBJbnRlcnBvbGF0ZSBiZXR3ZWVuIHRoZSBwcmV2aW91cyBmcmFtZSBhbmQgdGhlIGN1cnJlbnQgZnJhbWUuXG5cdFx0dmFyIGZyYW1lSW5kZXggPSBzcGluZS5BbmltYXRpb24uYmluYXJ5U2VhcmNoKGZyYW1lcywgdGltZSwgMik7XG5cdFx0dmFyIHByZXZGcmFtZVZhbHVlID0gZnJhbWVzW2ZyYW1lSW5kZXggLSAxXTtcblx0XHR2YXIgZnJhbWVUaW1lID0gZnJhbWVzW2ZyYW1lSW5kZXhdO1xuXHRcdHZhciBwZXJjZW50ID0gMSAtICh0aW1lIC0gZnJhbWVUaW1lKSAvIChmcmFtZXNbZnJhbWVJbmRleCAtIDIvKlBSRVZfRlJBTUVfVElNRSovXSAtIGZyYW1lVGltZSk7XG5cdFx0cGVyY2VudCA9IHRoaXMuY3VydmVzLmdldEN1cnZlUGVyY2VudChmcmFtZUluZGV4IC8gMiAtIDEsIHBlcmNlbnQpO1xuXG5cdFx0dmFyIGFtb3VudCA9IGZyYW1lc1tmcmFtZUluZGV4ICsgMS8qRlJBTUVfVkFMVUUqL10gLSBwcmV2RnJhbWVWYWx1ZTtcblx0XHR3aGlsZSAoYW1vdW50ID4gMTgwKVxuXHRcdFx0YW1vdW50IC09IDM2MDtcblx0XHR3aGlsZSAoYW1vdW50IDwgLTE4MClcblx0XHRcdGFtb3VudCArPSAzNjA7XG5cdFx0YW1vdW50ID0gYm9uZS5kYXRhLnJvdGF0aW9uICsgKHByZXZGcmFtZVZhbHVlICsgYW1vdW50ICogcGVyY2VudCkgLSBib25lLnJvdGF0aW9uO1xuXHRcdHdoaWxlIChhbW91bnQgPiAxODApXG5cdFx0XHRhbW91bnQgLT0gMzYwO1xuXHRcdHdoaWxlIChhbW91bnQgPCAtMTgwKVxuXHRcdFx0YW1vdW50ICs9IDM2MDtcblx0XHRib25lLnJvdGF0aW9uICs9IGFtb3VudCAqIGFscGhhO1xuXHR9XG59O1xuXG5zcGluZS5UcmFuc2xhdGVUaW1lbGluZSA9IGZ1bmN0aW9uIChmcmFtZUNvdW50KSB7XG5cdHRoaXMuY3VydmVzID0gbmV3IHNwaW5lLkN1cnZlcyhmcmFtZUNvdW50KTtcblx0dGhpcy5mcmFtZXMgPSBbXTsgLy8gdGltZSwgeCwgeSwgLi4uXG5cdHRoaXMuZnJhbWVzLmxlbmd0aCA9IGZyYW1lQ291bnQgKiAzO1xufTtcbnNwaW5lLlRyYW5zbGF0ZVRpbWVsaW5lLnByb3RvdHlwZSA9IHtcblx0Ym9uZUluZGV4OiAwLFxuXHRnZXRGcmFtZUNvdW50OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZnJhbWVzLmxlbmd0aCAvIDM7XG5cdH0sXG5cdHNldEZyYW1lOiBmdW5jdGlvbiAoZnJhbWVJbmRleCwgdGltZSwgeCwgeSkge1xuXHRcdGZyYW1lSW5kZXggKj0gMztcblx0XHR0aGlzLmZyYW1lc1tmcmFtZUluZGV4XSA9IHRpbWU7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleCArIDFdID0geDtcblx0XHR0aGlzLmZyYW1lc1tmcmFtZUluZGV4ICsgMl0gPSB5O1xuXHR9LFxuXHRhcHBseTogZnVuY3Rpb24gKHNrZWxldG9uLCBsYXN0VGltZSwgdGltZSwgZmlyZWRFdmVudHMsIGFscGhhKSB7XG5cdFx0dmFyIGZyYW1lcyA9IHRoaXMuZnJhbWVzO1xuXHRcdGlmICh0aW1lIDwgZnJhbWVzWzBdKSByZXR1cm47IC8vIFRpbWUgaXMgYmVmb3JlIGZpcnN0IGZyYW1lLlxuXG5cdFx0dmFyIGJvbmUgPSBza2VsZXRvbi5ib25lc1t0aGlzLmJvbmVJbmRleF07XG5cblx0XHRpZiAodGltZSA+PSBmcmFtZXNbZnJhbWVzLmxlbmd0aCAtIDNdKSB7IC8vIFRpbWUgaXMgYWZ0ZXIgbGFzdCBmcmFtZS5cblx0XHRcdGJvbmUueCArPSAoYm9uZS5kYXRhLnggKyBmcmFtZXNbZnJhbWVzLmxlbmd0aCAtIDJdIC0gYm9uZS54KSAqIGFscGhhO1xuXHRcdFx0Ym9uZS55ICs9IChib25lLmRhdGEueSArIGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMV0gLSBib25lLnkpICogYWxwaGE7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gSW50ZXJwb2xhdGUgYmV0d2VlbiB0aGUgcHJldmlvdXMgZnJhbWUgYW5kIHRoZSBjdXJyZW50IGZyYW1lLlxuXHRcdHZhciBmcmFtZUluZGV4ID0gc3BpbmUuQW5pbWF0aW9uLmJpbmFyeVNlYXJjaChmcmFtZXMsIHRpbWUsIDMpO1xuXHRcdHZhciBwcmV2RnJhbWVYID0gZnJhbWVzW2ZyYW1lSW5kZXggLSAyXTtcblx0XHR2YXIgcHJldkZyYW1lWSA9IGZyYW1lc1tmcmFtZUluZGV4IC0gMV07XG5cdFx0dmFyIGZyYW1lVGltZSA9IGZyYW1lc1tmcmFtZUluZGV4XTtcblx0XHR2YXIgcGVyY2VudCA9IDEgLSAodGltZSAtIGZyYW1lVGltZSkgLyAoZnJhbWVzW2ZyYW1lSW5kZXggKyAtMy8qUFJFVl9GUkFNRV9USU1FKi9dIC0gZnJhbWVUaW1lKTtcblx0XHRwZXJjZW50ID0gdGhpcy5jdXJ2ZXMuZ2V0Q3VydmVQZXJjZW50KGZyYW1lSW5kZXggLyAzIC0gMSwgcGVyY2VudCk7XG5cblx0XHRib25lLnggKz0gKGJvbmUuZGF0YS54ICsgcHJldkZyYW1lWCArIChmcmFtZXNbZnJhbWVJbmRleCArIDEvKkZSQU1FX1gqL10gLSBwcmV2RnJhbWVYKSAqIHBlcmNlbnQgLSBib25lLngpICogYWxwaGE7XG5cdFx0Ym9uZS55ICs9IChib25lLmRhdGEueSArIHByZXZGcmFtZVkgKyAoZnJhbWVzW2ZyYW1lSW5kZXggKyAyLypGUkFNRV9ZKi9dIC0gcHJldkZyYW1lWSkgKiBwZXJjZW50IC0gYm9uZS55KSAqIGFscGhhO1xuXHR9XG59O1xuXG5zcGluZS5TY2FsZVRpbWVsaW5lID0gZnVuY3Rpb24gKGZyYW1lQ291bnQpIHtcblx0dGhpcy5jdXJ2ZXMgPSBuZXcgc3BpbmUuQ3VydmVzKGZyYW1lQ291bnQpO1xuXHR0aGlzLmZyYW1lcyA9IFtdOyAvLyB0aW1lLCB4LCB5LCAuLi5cblx0dGhpcy5mcmFtZXMubGVuZ3RoID0gZnJhbWVDb3VudCAqIDM7XG59O1xuc3BpbmUuU2NhbGVUaW1lbGluZS5wcm90b3R5cGUgPSB7XG5cdGJvbmVJbmRleDogMCxcblx0Z2V0RnJhbWVDb3VudDogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLmZyYW1lcy5sZW5ndGggLyAzO1xuXHR9LFxuXHRzZXRGcmFtZTogZnVuY3Rpb24gKGZyYW1lSW5kZXgsIHRpbWUsIHgsIHkpIHtcblx0XHRmcmFtZUluZGV4ICo9IDM7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleF0gPSB0aW1lO1xuXHRcdHRoaXMuZnJhbWVzW2ZyYW1lSW5kZXggKyAxXSA9IHg7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleCArIDJdID0geTtcblx0fSxcblx0YXBwbHk6IGZ1bmN0aW9uIChza2VsZXRvbiwgbGFzdFRpbWUsIHRpbWUsIGZpcmVkRXZlbnRzLCBhbHBoYSkge1xuXHRcdHZhciBmcmFtZXMgPSB0aGlzLmZyYW1lcztcblx0XHRpZiAodGltZSA8IGZyYW1lc1swXSkgcmV0dXJuOyAvLyBUaW1lIGlzIGJlZm9yZSBmaXJzdCBmcmFtZS5cblxuXHRcdHZhciBib25lID0gc2tlbGV0b24uYm9uZXNbdGhpcy5ib25lSW5kZXhdO1xuXG5cdFx0aWYgKHRpbWUgPj0gZnJhbWVzW2ZyYW1lcy5sZW5ndGggLSAzXSkgeyAvLyBUaW1lIGlzIGFmdGVyIGxhc3QgZnJhbWUuXG5cdFx0XHRib25lLnNjYWxlWCArPSAoYm9uZS5kYXRhLnNjYWxlWCAqIGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMl0gLSBib25lLnNjYWxlWCkgKiBhbHBoYTtcblx0XHRcdGJvbmUuc2NhbGVZICs9IChib25lLmRhdGEuc2NhbGVZICogZnJhbWVzW2ZyYW1lcy5sZW5ndGggLSAxXSAtIGJvbmUuc2NhbGVZKSAqIGFscGhhO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIEludGVycG9sYXRlIGJldHdlZW4gdGhlIHByZXZpb3VzIGZyYW1lIGFuZCB0aGUgY3VycmVudCBmcmFtZS5cblx0XHR2YXIgZnJhbWVJbmRleCA9IHNwaW5lLkFuaW1hdGlvbi5iaW5hcnlTZWFyY2goZnJhbWVzLCB0aW1lLCAzKTtcblx0XHR2YXIgcHJldkZyYW1lWCA9IGZyYW1lc1tmcmFtZUluZGV4IC0gMl07XG5cdFx0dmFyIHByZXZGcmFtZVkgPSBmcmFtZXNbZnJhbWVJbmRleCAtIDFdO1xuXHRcdHZhciBmcmFtZVRpbWUgPSBmcmFtZXNbZnJhbWVJbmRleF07XG5cdFx0dmFyIHBlcmNlbnQgPSAxIC0gKHRpbWUgLSBmcmFtZVRpbWUpIC8gKGZyYW1lc1tmcmFtZUluZGV4ICsgLTMvKlBSRVZfRlJBTUVfVElNRSovXSAtIGZyYW1lVGltZSk7XG5cdFx0cGVyY2VudCA9IHRoaXMuY3VydmVzLmdldEN1cnZlUGVyY2VudChmcmFtZUluZGV4IC8gMyAtIDEsIHBlcmNlbnQpO1xuXG5cdFx0Ym9uZS5zY2FsZVggKz0gKGJvbmUuZGF0YS5zY2FsZVggKiAocHJldkZyYW1lWCArIChmcmFtZXNbZnJhbWVJbmRleCArIDEvKkZSQU1FX1gqL10gLSBwcmV2RnJhbWVYKSAqIHBlcmNlbnQpIC0gYm9uZS5zY2FsZVgpICogYWxwaGE7XG5cdFx0Ym9uZS5zY2FsZVkgKz0gKGJvbmUuZGF0YS5zY2FsZVkgKiAocHJldkZyYW1lWSArIChmcmFtZXNbZnJhbWVJbmRleCArIDIvKkZSQU1FX1kqL10gLSBwcmV2RnJhbWVZKSAqIHBlcmNlbnQpIC0gYm9uZS5zY2FsZVkpICogYWxwaGE7XG5cdH1cbn07XG5cbnNwaW5lLkNvbG9yVGltZWxpbmUgPSBmdW5jdGlvbiAoZnJhbWVDb3VudCkge1xuXHR0aGlzLmN1cnZlcyA9IG5ldyBzcGluZS5DdXJ2ZXMoZnJhbWVDb3VudCk7XG5cdHRoaXMuZnJhbWVzID0gW107IC8vIHRpbWUsIHIsIGcsIGIsIGEsIC4uLlxuXHR0aGlzLmZyYW1lcy5sZW5ndGggPSBmcmFtZUNvdW50ICogNTtcbn07XG5zcGluZS5Db2xvclRpbWVsaW5lLnByb3RvdHlwZSA9IHtcblx0c2xvdEluZGV4OiAwLFxuXHRnZXRGcmFtZUNvdW50OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZnJhbWVzLmxlbmd0aCAvIDU7XG5cdH0sXG5cdHNldEZyYW1lOiBmdW5jdGlvbiAoZnJhbWVJbmRleCwgdGltZSwgciwgZywgYiwgYSkge1xuXHRcdGZyYW1lSW5kZXggKj0gNTtcblx0XHR0aGlzLmZyYW1lc1tmcmFtZUluZGV4XSA9IHRpbWU7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleCArIDFdID0gcjtcblx0XHR0aGlzLmZyYW1lc1tmcmFtZUluZGV4ICsgMl0gPSBnO1xuXHRcdHRoaXMuZnJhbWVzW2ZyYW1lSW5kZXggKyAzXSA9IGI7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleCArIDRdID0gYTtcblx0fSxcblx0YXBwbHk6IGZ1bmN0aW9uIChza2VsZXRvbiwgbGFzdFRpbWUsIHRpbWUsIGZpcmVkRXZlbnRzLCBhbHBoYSkge1xuXHRcdHZhciBmcmFtZXMgPSB0aGlzLmZyYW1lcztcblx0XHRpZiAodGltZSA8IGZyYW1lc1swXSkgcmV0dXJuOyAvLyBUaW1lIGlzIGJlZm9yZSBmaXJzdCBmcmFtZS5cblxuXHRcdHZhciByLCBnLCBiLCBhO1xuXHRcdGlmICh0aW1lID49IGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gNV0pIHtcblx0XHRcdC8vIFRpbWUgaXMgYWZ0ZXIgbGFzdCBmcmFtZS5cblx0XHRcdHZhciBpID0gZnJhbWVzLmxlbmd0aCAtIDE7XG5cdFx0XHRyID0gZnJhbWVzW2kgLSAzXTtcblx0XHRcdGcgPSBmcmFtZXNbaSAtIDJdO1xuXHRcdFx0YiA9IGZyYW1lc1tpIC0gMV07XG5cdFx0XHRhID0gZnJhbWVzW2ldO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBJbnRlcnBvbGF0ZSBiZXR3ZWVuIHRoZSBwcmV2aW91cyBmcmFtZSBhbmQgdGhlIGN1cnJlbnQgZnJhbWUuXG5cdFx0XHR2YXIgZnJhbWVJbmRleCA9IHNwaW5lLkFuaW1hdGlvbi5iaW5hcnlTZWFyY2goZnJhbWVzLCB0aW1lLCA1KTtcblx0XHRcdHZhciBwcmV2RnJhbWVSID0gZnJhbWVzW2ZyYW1lSW5kZXggLSA0XTtcblx0XHRcdHZhciBwcmV2RnJhbWVHID0gZnJhbWVzW2ZyYW1lSW5kZXggLSAzXTtcblx0XHRcdHZhciBwcmV2RnJhbWVCID0gZnJhbWVzW2ZyYW1lSW5kZXggLSAyXTtcblx0XHRcdHZhciBwcmV2RnJhbWVBID0gZnJhbWVzW2ZyYW1lSW5kZXggLSAxXTtcblx0XHRcdHZhciBmcmFtZVRpbWUgPSBmcmFtZXNbZnJhbWVJbmRleF07XG5cdFx0XHR2YXIgcGVyY2VudCA9IDEgLSAodGltZSAtIGZyYW1lVGltZSkgLyAoZnJhbWVzW2ZyYW1lSW5kZXggLSA1LypQUkVWX0ZSQU1FX1RJTUUqL10gLSBmcmFtZVRpbWUpO1xuXHRcdFx0cGVyY2VudCA9IHRoaXMuY3VydmVzLmdldEN1cnZlUGVyY2VudChmcmFtZUluZGV4IC8gNSAtIDEsIHBlcmNlbnQpO1xuXG5cdFx0XHRyID0gcHJldkZyYW1lUiArIChmcmFtZXNbZnJhbWVJbmRleCArIDEvKkZSQU1FX1IqL10gLSBwcmV2RnJhbWVSKSAqIHBlcmNlbnQ7XG5cdFx0XHRnID0gcHJldkZyYW1lRyArIChmcmFtZXNbZnJhbWVJbmRleCArIDIvKkZSQU1FX0cqL10gLSBwcmV2RnJhbWVHKSAqIHBlcmNlbnQ7XG5cdFx0XHRiID0gcHJldkZyYW1lQiArIChmcmFtZXNbZnJhbWVJbmRleCArIDMvKkZSQU1FX0IqL10gLSBwcmV2RnJhbWVCKSAqIHBlcmNlbnQ7XG5cdFx0XHRhID0gcHJldkZyYW1lQSArIChmcmFtZXNbZnJhbWVJbmRleCArIDQvKkZSQU1FX0EqL10gLSBwcmV2RnJhbWVBKSAqIHBlcmNlbnQ7XG5cdFx0fVxuXHRcdHZhciBzbG90ID0gc2tlbGV0b24uc2xvdHNbdGhpcy5zbG90SW5kZXhdO1xuXHRcdGlmIChhbHBoYSA8IDEpIHtcblx0XHRcdHNsb3QuciArPSAociAtIHNsb3QucikgKiBhbHBoYTtcblx0XHRcdHNsb3QuZyArPSAoZyAtIHNsb3QuZykgKiBhbHBoYTtcblx0XHRcdHNsb3QuYiArPSAoYiAtIHNsb3QuYikgKiBhbHBoYTtcblx0XHRcdHNsb3QuYSArPSAoYSAtIHNsb3QuYSkgKiBhbHBoYTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0c2xvdC5yID0gcjtcblx0XHRcdHNsb3QuZyA9IGc7XG5cdFx0XHRzbG90LmIgPSBiO1xuXHRcdFx0c2xvdC5hID0gYTtcblx0XHR9XG5cdH1cbn07XG5cbnNwaW5lLkF0dGFjaG1lbnRUaW1lbGluZSA9IGZ1bmN0aW9uIChmcmFtZUNvdW50KSB7XG5cdHRoaXMuY3VydmVzID0gbmV3IHNwaW5lLkN1cnZlcyhmcmFtZUNvdW50KTtcblx0dGhpcy5mcmFtZXMgPSBbXTsgLy8gdGltZSwgLi4uXG5cdHRoaXMuZnJhbWVzLmxlbmd0aCA9IGZyYW1lQ291bnQ7XG5cdHRoaXMuYXR0YWNobWVudE5hbWVzID0gW107XG5cdHRoaXMuYXR0YWNobWVudE5hbWVzLmxlbmd0aCA9IGZyYW1lQ291bnQ7XG59O1xuc3BpbmUuQXR0YWNobWVudFRpbWVsaW5lLnByb3RvdHlwZSA9IHtcblx0c2xvdEluZGV4OiAwLFxuXHRnZXRGcmFtZUNvdW50OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZnJhbWVzLmxlbmd0aDtcblx0fSxcblx0c2V0RnJhbWU6IGZ1bmN0aW9uIChmcmFtZUluZGV4LCB0aW1lLCBhdHRhY2htZW50TmFtZSkge1xuXHRcdHRoaXMuZnJhbWVzW2ZyYW1lSW5kZXhdID0gdGltZTtcblx0XHR0aGlzLmF0dGFjaG1lbnROYW1lc1tmcmFtZUluZGV4XSA9IGF0dGFjaG1lbnROYW1lO1xuXHR9LFxuXHRhcHBseTogZnVuY3Rpb24gKHNrZWxldG9uLCBsYXN0VGltZSwgdGltZSwgZmlyZWRFdmVudHMsIGFscGhhKSB7XG5cdFx0dmFyIGZyYW1lcyA9IHRoaXMuZnJhbWVzO1xuXHRcdGlmICh0aW1lIDwgZnJhbWVzWzBdKSB7XG5cdFx0XHRpZiAobGFzdFRpbWUgPiB0aW1lKSB0aGlzLmFwcGx5KHNrZWxldG9uLCBsYXN0VGltZSwgTnVtYmVyLk1BWF9WQUxVRSwgbnVsbCwgMCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fSBlbHNlIGlmIChsYXN0VGltZSA+IHRpbWUpIC8vXG5cdFx0XHRsYXN0VGltZSA9IC0xO1xuXG5cdFx0dmFyIGZyYW1lSW5kZXggPSB0aW1lID49IGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMV0gPyBmcmFtZXMubGVuZ3RoIC0gMSA6IHNwaW5lLkFuaW1hdGlvbi5iaW5hcnlTZWFyY2gxKGZyYW1lcywgdGltZSkgLSAxO1xuXHRcdGlmIChmcmFtZXNbZnJhbWVJbmRleF0gPCBsYXN0VGltZSkgcmV0dXJuO1xuXG5cdFx0dmFyIGF0dGFjaG1lbnROYW1lID0gdGhpcy5hdHRhY2htZW50TmFtZXNbZnJhbWVJbmRleF07XG5cdFx0c2tlbGV0b24uc2xvdHNbdGhpcy5zbG90SW5kZXhdLnNldEF0dGFjaG1lbnQoXG5cdFx0XHQhYXR0YWNobWVudE5hbWUgPyBudWxsIDogc2tlbGV0b24uZ2V0QXR0YWNobWVudEJ5U2xvdEluZGV4KHRoaXMuc2xvdEluZGV4LCBhdHRhY2htZW50TmFtZSkpO1xuXHR9XG59O1xuXG5zcGluZS5FdmVudFRpbWVsaW5lID0gZnVuY3Rpb24gKGZyYW1lQ291bnQpIHtcblx0dGhpcy5mcmFtZXMgPSBbXTsgLy8gdGltZSwgLi4uXG5cdHRoaXMuZnJhbWVzLmxlbmd0aCA9IGZyYW1lQ291bnQ7XG5cdHRoaXMuZXZlbnRzID0gW107XG5cdHRoaXMuZXZlbnRzLmxlbmd0aCA9IGZyYW1lQ291bnQ7XG59O1xuc3BpbmUuRXZlbnRUaW1lbGluZS5wcm90b3R5cGUgPSB7XG5cdGdldEZyYW1lQ291bnQ6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5mcmFtZXMubGVuZ3RoO1xuXHR9LFxuXHRzZXRGcmFtZTogZnVuY3Rpb24gKGZyYW1lSW5kZXgsIHRpbWUsIGV2ZW50KSB7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleF0gPSB0aW1lO1xuXHRcdHRoaXMuZXZlbnRzW2ZyYW1lSW5kZXhdID0gZXZlbnQ7XG5cdH0sXG5cdC8qKiBGaXJlcyBldmVudHMgZm9yIGZyYW1lcyA+IGxhc3RUaW1lIGFuZCA8PSB0aW1lLiAqL1xuXHRhcHBseTogZnVuY3Rpb24gKHNrZWxldG9uLCBsYXN0VGltZSwgdGltZSwgZmlyZWRFdmVudHMsIGFscGhhKSB7XG5cdFx0aWYgKCFmaXJlZEV2ZW50cykgcmV0dXJuO1xuXG5cdFx0dmFyIGZyYW1lcyA9IHRoaXMuZnJhbWVzO1xuXHRcdHZhciBmcmFtZUNvdW50ID0gZnJhbWVzLmxlbmd0aDtcblxuXHRcdGlmIChsYXN0VGltZSA+IHRpbWUpIHsgLy8gRmlyZSBldmVudHMgYWZ0ZXIgbGFzdCB0aW1lIGZvciBsb29wZWQgYW5pbWF0aW9ucy5cblx0XHRcdHRoaXMuYXBwbHkoc2tlbGV0b24sIGxhc3RUaW1lLCBOdW1iZXIuTUFYX1ZBTFVFLCBmaXJlZEV2ZW50cywgYWxwaGEpO1xuXHRcdFx0bGFzdFRpbWUgPSAtMTtcblx0XHR9IGVsc2UgaWYgKGxhc3RUaW1lID49IGZyYW1lc1tmcmFtZUNvdW50IC0gMV0pIC8vIExhc3QgdGltZSBpcyBhZnRlciBsYXN0IGZyYW1lLlxuXHRcdFx0cmV0dXJuO1xuXHRcdGlmICh0aW1lIDwgZnJhbWVzWzBdKSByZXR1cm47IC8vIFRpbWUgaXMgYmVmb3JlIGZpcnN0IGZyYW1lLlxuXG5cdFx0dmFyIGZyYW1lSW5kZXg7XG5cdFx0aWYgKGxhc3RUaW1lIDwgZnJhbWVzWzBdKVxuXHRcdFx0ZnJhbWVJbmRleCA9IDA7XG5cdFx0ZWxzZSB7XG5cdFx0XHRmcmFtZUluZGV4ID0gc3BpbmUuQW5pbWF0aW9uLmJpbmFyeVNlYXJjaDEoZnJhbWVzLCBsYXN0VGltZSk7XG5cdFx0XHR2YXIgZnJhbWUgPSBmcmFtZXNbZnJhbWVJbmRleF07XG5cdFx0XHR3aGlsZSAoZnJhbWVJbmRleCA+IDApIHsgLy8gRmlyZSBtdWx0aXBsZSBldmVudHMgd2l0aCB0aGUgc2FtZSBmcmFtZS5cblx0XHRcdFx0aWYgKGZyYW1lc1tmcmFtZUluZGV4IC0gMV0gIT0gZnJhbWUpIGJyZWFrO1xuXHRcdFx0XHRmcmFtZUluZGV4LS07XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHZhciBldmVudHMgPSB0aGlzLmV2ZW50cztcblx0XHRmb3IgKDsgZnJhbWVJbmRleCA8IGZyYW1lQ291bnQgJiYgdGltZSA+PSBmcmFtZXNbZnJhbWVJbmRleF07IGZyYW1lSW5kZXgrKylcblx0XHRcdGZpcmVkRXZlbnRzLnB1c2goZXZlbnRzW2ZyYW1lSW5kZXhdKTtcblx0fVxufTtcblxuc3BpbmUuRHJhd09yZGVyVGltZWxpbmUgPSBmdW5jdGlvbiAoZnJhbWVDb3VudCkge1xuXHR0aGlzLmZyYW1lcyA9IFtdOyAvLyB0aW1lLCAuLi5cblx0dGhpcy5mcmFtZXMubGVuZ3RoID0gZnJhbWVDb3VudDtcblx0dGhpcy5kcmF3T3JkZXJzID0gW107XG5cdHRoaXMuZHJhd09yZGVycy5sZW5ndGggPSBmcmFtZUNvdW50O1xufTtcbnNwaW5lLkRyYXdPcmRlclRpbWVsaW5lLnByb3RvdHlwZSA9IHtcblx0Z2V0RnJhbWVDb3VudDogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLmZyYW1lcy5sZW5ndGg7XG5cdH0sXG5cdHNldEZyYW1lOiBmdW5jdGlvbiAoZnJhbWVJbmRleCwgdGltZSwgZHJhd09yZGVyKSB7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleF0gPSB0aW1lO1xuXHRcdHRoaXMuZHJhd09yZGVyc1tmcmFtZUluZGV4XSA9IGRyYXdPcmRlcjtcblx0fSxcblx0YXBwbHk6IGZ1bmN0aW9uIChza2VsZXRvbiwgbGFzdFRpbWUsIHRpbWUsIGZpcmVkRXZlbnRzLCBhbHBoYSkge1xuXHRcdHZhciBmcmFtZXMgPSB0aGlzLmZyYW1lcztcblx0XHRpZiAodGltZSA8IGZyYW1lc1swXSkgcmV0dXJuOyAvLyBUaW1lIGlzIGJlZm9yZSBmaXJzdCBmcmFtZS5cblxuXHRcdHZhciBmcmFtZUluZGV4O1xuXHRcdGlmICh0aW1lID49IGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMV0pIC8vIFRpbWUgaXMgYWZ0ZXIgbGFzdCBmcmFtZS5cblx0XHRcdGZyYW1lSW5kZXggPSBmcmFtZXMubGVuZ3RoIC0gMTtcblx0XHRlbHNlXG5cdFx0XHRmcmFtZUluZGV4ID0gc3BpbmUuQW5pbWF0aW9uLmJpbmFyeVNlYXJjaDEoZnJhbWVzLCB0aW1lKSAtIDE7XG5cblx0XHR2YXIgZHJhd09yZGVyID0gc2tlbGV0b24uZHJhd09yZGVyO1xuXHRcdHZhciBzbG90cyA9IHNrZWxldG9uLnNsb3RzO1xuXHRcdHZhciBkcmF3T3JkZXJUb1NldHVwSW5kZXggPSB0aGlzLmRyYXdPcmRlcnNbZnJhbWVJbmRleF07XG5cdFx0aWYgKCFkcmF3T3JkZXJUb1NldHVwSW5kZXgpIHtcblx0XHRcdGZvciAodmFyIGkgPSAwLCBuID0gc2xvdHMubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0XHRkcmF3T3JkZXJbaV0gPSBzbG90c1tpXTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBkcmF3T3JkZXJUb1NldHVwSW5kZXgubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0XHRkcmF3T3JkZXJbaV0gPSBza2VsZXRvbi5zbG90c1tkcmF3T3JkZXJUb1NldHVwSW5kZXhbaV1dO1xuXHRcdH1cblxuXHR9XG59O1xuXG5zcGluZS5GZmRUaW1lbGluZSA9IGZ1bmN0aW9uIChmcmFtZUNvdW50KSB7XG5cdHRoaXMuY3VydmVzID0gbmV3IHNwaW5lLkN1cnZlcyhmcmFtZUNvdW50KTtcblx0dGhpcy5mcmFtZXMgPSBbXTtcblx0dGhpcy5mcmFtZXMubGVuZ3RoID0gZnJhbWVDb3VudDtcblx0dGhpcy5mcmFtZVZlcnRpY2VzID0gW107XG5cdHRoaXMuZnJhbWVWZXJ0aWNlcy5sZW5ndGggPSBmcmFtZUNvdW50O1xufTtcbnNwaW5lLkZmZFRpbWVsaW5lLnByb3RvdHlwZSA9IHtcblx0c2xvdEluZGV4OiAwLFxuXHRhdHRhY2htZW50OiAwLFxuXHRnZXRGcmFtZUNvdW50OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZnJhbWVzLmxlbmd0aDtcblx0fSxcblx0c2V0RnJhbWU6IGZ1bmN0aW9uIChmcmFtZUluZGV4LCB0aW1lLCB2ZXJ0aWNlcykge1xuXHRcdHRoaXMuZnJhbWVzW2ZyYW1lSW5kZXhdID0gdGltZTtcblx0XHR0aGlzLmZyYW1lVmVydGljZXNbZnJhbWVJbmRleF0gPSB2ZXJ0aWNlcztcblx0fSxcblx0YXBwbHk6IGZ1bmN0aW9uIChza2VsZXRvbiwgbGFzdFRpbWUsIHRpbWUsIGZpcmVkRXZlbnRzLCBhbHBoYSkge1xuXHRcdHZhciBzbG90ID0gc2tlbGV0b24uc2xvdHNbdGhpcy5zbG90SW5kZXhdO1xuXHRcdGlmIChzbG90LmF0dGFjaG1lbnQgIT0gdGhpcy5hdHRhY2htZW50KSByZXR1cm47XG5cblx0XHR2YXIgZnJhbWVzID0gdGhpcy5mcmFtZXM7XG5cdFx0aWYgKHRpbWUgPCBmcmFtZXNbMF0pIHJldHVybjsgLy8gVGltZSBpcyBiZWZvcmUgZmlyc3QgZnJhbWUuXG5cblx0XHR2YXIgZnJhbWVWZXJ0aWNlcyA9IHRoaXMuZnJhbWVWZXJ0aWNlcztcblx0XHR2YXIgdmVydGV4Q291bnQgPSBmcmFtZVZlcnRpY2VzWzBdLmxlbmd0aDtcblxuXHRcdHZhciB2ZXJ0aWNlcyA9IHNsb3QuYXR0YWNobWVudFZlcnRpY2VzO1xuXHRcdGlmICh2ZXJ0aWNlcy5sZW5ndGggIT0gdmVydGV4Q291bnQpIGFscGhhID0gMTtcblx0XHR2ZXJ0aWNlcy5sZW5ndGggPSB2ZXJ0ZXhDb3VudDtcblxuXHRcdGlmICh0aW1lID49IGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMV0pIHsgLy8gVGltZSBpcyBhZnRlciBsYXN0IGZyYW1lLlxuXHRcdFx0dmFyIGxhc3RWZXJ0aWNlcyA9IGZyYW1lVmVydGljZXNbZnJhbWVzLmxlbmd0aCAtIDFdO1xuXHRcdFx0aWYgKGFscGhhIDwgMSkge1xuXHRcdFx0XHRmb3IgKHZhciBpID0gMDsgaSA8IHZlcnRleENvdW50OyBpKyspXG5cdFx0XHRcdFx0dmVydGljZXNbaV0gKz0gKGxhc3RWZXJ0aWNlc1tpXSAtIHZlcnRpY2VzW2ldKSAqIGFscGhhO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCB2ZXJ0ZXhDb3VudDsgaSsrKVxuXHRcdFx0XHRcdHZlcnRpY2VzW2ldID0gbGFzdFZlcnRpY2VzW2ldO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIEludGVycG9sYXRlIGJldHdlZW4gdGhlIHByZXZpb3VzIGZyYW1lIGFuZCB0aGUgY3VycmVudCBmcmFtZS5cblx0XHR2YXIgZnJhbWVJbmRleCA9IHNwaW5lLkFuaW1hdGlvbi5iaW5hcnlTZWFyY2gxKGZyYW1lcywgdGltZSk7XG5cdFx0dmFyIGZyYW1lVGltZSA9IGZyYW1lc1tmcmFtZUluZGV4XTtcblx0XHR2YXIgcGVyY2VudCA9IDEgLSAodGltZSAtIGZyYW1lVGltZSkgLyAoZnJhbWVzW2ZyYW1lSW5kZXggLSAxXSAtIGZyYW1lVGltZSk7XG5cdFx0cGVyY2VudCA9IHRoaXMuY3VydmVzLmdldEN1cnZlUGVyY2VudChmcmFtZUluZGV4IC0gMSwgcGVyY2VudCA8IDAgPyAwIDogKHBlcmNlbnQgPiAxID8gMSA6IHBlcmNlbnQpKTtcblxuXHRcdHZhciBwcmV2VmVydGljZXMgPSBmcmFtZVZlcnRpY2VzW2ZyYW1lSW5kZXggLSAxXTtcblx0XHR2YXIgbmV4dFZlcnRpY2VzID0gZnJhbWVWZXJ0aWNlc1tmcmFtZUluZGV4XTtcblxuXHRcdGlmIChhbHBoYSA8IDEpIHtcblx0XHRcdGZvciAodmFyIGkgPSAwOyBpIDwgdmVydGV4Q291bnQ7IGkrKykge1xuXHRcdFx0XHR2YXIgcHJldiA9IHByZXZWZXJ0aWNlc1tpXTtcblx0XHRcdFx0dmVydGljZXNbaV0gKz0gKHByZXYgKyAobmV4dFZlcnRpY2VzW2ldIC0gcHJldikgKiBwZXJjZW50IC0gdmVydGljZXNbaV0pICogYWxwaGE7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdGZvciAodmFyIGkgPSAwOyBpIDwgdmVydGV4Q291bnQ7IGkrKykge1xuXHRcdFx0XHR2YXIgcHJldiA9IHByZXZWZXJ0aWNlc1tpXTtcblx0XHRcdFx0dmVydGljZXNbaV0gPSBwcmV2ICsgKG5leHRWZXJ0aWNlc1tpXSAtIHByZXYpICogcGVyY2VudDtcblx0XHRcdH1cblx0XHR9XG5cdH1cbn07XG5cbnNwaW5lLklrQ29uc3RyYWludFRpbWVsaW5lID0gZnVuY3Rpb24gKGZyYW1lQ291bnQpIHtcblx0dGhpcy5jdXJ2ZXMgPSBuZXcgc3BpbmUuQ3VydmVzKGZyYW1lQ291bnQpO1xuXHR0aGlzLmZyYW1lcyA9IFtdOyAvLyB0aW1lLCBtaXgsIGJlbmREaXJlY3Rpb24sIC4uLlxuXHR0aGlzLmZyYW1lcy5sZW5ndGggPSBmcmFtZUNvdW50ICogMztcbn07XG5zcGluZS5Ja0NvbnN0cmFpbnRUaW1lbGluZS5wcm90b3R5cGUgPSB7XG5cdGlrQ29uc3RyYWludEluZGV4OiAwLFxuXHRnZXRGcmFtZUNvdW50OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZnJhbWVzLmxlbmd0aCAvIDM7XG5cdH0sXG5cdHNldEZyYW1lOiBmdW5jdGlvbiAoZnJhbWVJbmRleCwgdGltZSwgbWl4LCBiZW5kRGlyZWN0aW9uKSB7XG5cdFx0ZnJhbWVJbmRleCAqPSAzO1xuXHRcdHRoaXMuZnJhbWVzW2ZyYW1lSW5kZXhdID0gdGltZTtcblx0XHR0aGlzLmZyYW1lc1tmcmFtZUluZGV4ICsgMV0gPSBtaXg7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleCArIDJdID0gYmVuZERpcmVjdGlvbjtcblx0fSxcblx0YXBwbHk6IGZ1bmN0aW9uIChza2VsZXRvbiwgbGFzdFRpbWUsIHRpbWUsIGZpcmVkRXZlbnRzLCBhbHBoYSkge1xuXHRcdHZhciBmcmFtZXMgPSB0aGlzLmZyYW1lcztcblx0XHRpZiAodGltZSA8IGZyYW1lc1swXSkgcmV0dXJuOyAvLyBUaW1lIGlzIGJlZm9yZSBmaXJzdCBmcmFtZS5cblxuXHRcdHZhciBpa0NvbnN0cmFpbnQgPSBza2VsZXRvbi5pa0NvbnN0cmFpbnRzW3RoaXMuaWtDb25zdHJhaW50SW5kZXhdO1xuXG5cdFx0aWYgKHRpbWUgPj0gZnJhbWVzW2ZyYW1lcy5sZW5ndGggLSAzXSkgeyAvLyBUaW1lIGlzIGFmdGVyIGxhc3QgZnJhbWUuXG5cdFx0XHRpa0NvbnN0cmFpbnQubWl4ICs9IChmcmFtZXNbZnJhbWVzLmxlbmd0aCAtIDJdIC0gaWtDb25zdHJhaW50Lm1peCkgKiBhbHBoYTtcblx0XHRcdGlrQ29uc3RyYWludC5iZW5kRGlyZWN0aW9uID0gZnJhbWVzW2ZyYW1lcy5sZW5ndGggLSAxXTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBJbnRlcnBvbGF0ZSBiZXR3ZWVuIHRoZSBwcmV2aW91cyBmcmFtZSBhbmQgdGhlIGN1cnJlbnQgZnJhbWUuXG5cdFx0dmFyIGZyYW1lSW5kZXggPSBzcGluZS5BbmltYXRpb24uYmluYXJ5U2VhcmNoKGZyYW1lcywgdGltZSwgMyk7XG5cdFx0dmFyIHByZXZGcmFtZU1peCA9IGZyYW1lc1tmcmFtZUluZGV4ICsgLTIvKlBSRVZfRlJBTUVfTUlYKi9dO1xuXHRcdHZhciBmcmFtZVRpbWUgPSBmcmFtZXNbZnJhbWVJbmRleF07XG5cdFx0dmFyIHBlcmNlbnQgPSAxIC0gKHRpbWUgLSBmcmFtZVRpbWUpIC8gKGZyYW1lc1tmcmFtZUluZGV4ICsgLTMvKlBSRVZfRlJBTUVfVElNRSovXSAtIGZyYW1lVGltZSk7XG5cdFx0cGVyY2VudCA9IHRoaXMuY3VydmVzLmdldEN1cnZlUGVyY2VudChmcmFtZUluZGV4IC8gMyAtIDEsIHBlcmNlbnQpO1xuXG5cdFx0dmFyIG1peCA9IHByZXZGcmFtZU1peCArIChmcmFtZXNbZnJhbWVJbmRleCArIDEvKkZSQU1FX01JWCovXSAtIHByZXZGcmFtZU1peCkgKiBwZXJjZW50O1xuXHRcdGlrQ29uc3RyYWludC5taXggKz0gKG1peCAtIGlrQ29uc3RyYWludC5taXgpICogYWxwaGE7XG5cdFx0aWtDb25zdHJhaW50LmJlbmREaXJlY3Rpb24gPSBmcmFtZXNbZnJhbWVJbmRleCArIC0xLypQUkVWX0ZSQU1FX0JFTkRfRElSRUNUSU9OKi9dO1xuXHR9XG59O1xuXG5zcGluZS5GbGlwWFRpbWVsaW5lID0gZnVuY3Rpb24gKGZyYW1lQ291bnQpIHtcblx0dGhpcy5jdXJ2ZXMgPSBuZXcgc3BpbmUuQ3VydmVzKGZyYW1lQ291bnQpO1xuXHR0aGlzLmZyYW1lcyA9IFtdOyAvLyB0aW1lLCBmbGlwLCAuLi5cblx0dGhpcy5mcmFtZXMubGVuZ3RoID0gZnJhbWVDb3VudCAqIDI7XG59O1xuc3BpbmUuRmxpcFhUaW1lbGluZS5wcm90b3R5cGUgPSB7XG5cdGJvbmVJbmRleDogMCxcblx0Z2V0RnJhbWVDb3VudDogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLmZyYW1lcy5sZW5ndGggLyAyO1xuXHR9LFxuXHRzZXRGcmFtZTogZnVuY3Rpb24gKGZyYW1lSW5kZXgsIHRpbWUsIGZsaXApIHtcblx0XHRmcmFtZUluZGV4ICo9IDI7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleF0gPSB0aW1lO1xuXHRcdHRoaXMuZnJhbWVzW2ZyYW1lSW5kZXggKyAxXSA9IGZsaXAgPyAxIDogMDtcblx0fSxcblx0YXBwbHk6IGZ1bmN0aW9uIChza2VsZXRvbiwgbGFzdFRpbWUsIHRpbWUsIGZpcmVkRXZlbnRzLCBhbHBoYSkge1xuXHRcdHZhciBmcmFtZXMgPSB0aGlzLmZyYW1lcztcblx0XHRpZiAodGltZSA8IGZyYW1lc1swXSkge1xuXHRcdFx0aWYgKGxhc3RUaW1lID4gdGltZSkgdGhpcy5hcHBseShza2VsZXRvbiwgbGFzdFRpbWUsIE51bWJlci5NQVhfVkFMVUUsIG51bGwsIDApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH0gZWxzZSBpZiAobGFzdFRpbWUgPiB0aW1lKSAvL1xuXHRcdFx0bGFzdFRpbWUgPSAtMTtcblx0XHR2YXIgZnJhbWVJbmRleCA9ICh0aW1lID49IGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMl0gPyBmcmFtZXMubGVuZ3RoIDogc3BpbmUuQW5pbWF0aW9uLmJpbmFyeVNlYXJjaChmcmFtZXMsIHRpbWUsIDIpKSAtIDI7XG5cdFx0aWYgKGZyYW1lc1tmcmFtZUluZGV4XSA8IGxhc3RUaW1lKSByZXR1cm47XG5cdFx0c2tlbGV0b24uYm9uZXNbYm9uZUluZGV4XS5mbGlwWCA9IGZyYW1lc1tmcmFtZUluZGV4ICsgMV0gIT0gMDtcblx0fVxufTtcblxuc3BpbmUuRmxpcFlUaW1lbGluZSA9IGZ1bmN0aW9uIChmcmFtZUNvdW50KSB7XG5cdHRoaXMuY3VydmVzID0gbmV3IHNwaW5lLkN1cnZlcyhmcmFtZUNvdW50KTtcblx0dGhpcy5mcmFtZXMgPSBbXTsgLy8gdGltZSwgZmxpcCwgLi4uXG5cdHRoaXMuZnJhbWVzLmxlbmd0aCA9IGZyYW1lQ291bnQgKiAyO1xufTtcbnNwaW5lLkZsaXBZVGltZWxpbmUucHJvdG90eXBlID0ge1xuXHRib25lSW5kZXg6IDAsXG5cdGdldEZyYW1lQ291bnQ6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5mcmFtZXMubGVuZ3RoIC8gMjtcblx0fSxcblx0c2V0RnJhbWU6IGZ1bmN0aW9uIChmcmFtZUluZGV4LCB0aW1lLCBmbGlwKSB7XG5cdFx0ZnJhbWVJbmRleCAqPSAyO1xuXHRcdHRoaXMuZnJhbWVzW2ZyYW1lSW5kZXhdID0gdGltZTtcblx0XHR0aGlzLmZyYW1lc1tmcmFtZUluZGV4ICsgMV0gPSBmbGlwID8gMSA6IDA7XG5cdH0sXG5cdGFwcGx5OiBmdW5jdGlvbiAoc2tlbGV0b24sIGxhc3RUaW1lLCB0aW1lLCBmaXJlZEV2ZW50cywgYWxwaGEpIHtcblx0XHR2YXIgZnJhbWVzID0gdGhpcy5mcmFtZXM7XG5cdFx0aWYgKHRpbWUgPCBmcmFtZXNbMF0pIHtcblx0XHRcdGlmIChsYXN0VGltZSA+IHRpbWUpIHRoaXMuYXBwbHkoc2tlbGV0b24sIGxhc3RUaW1lLCBOdW1iZXIuTUFYX1ZBTFVFLCBudWxsLCAwKTtcblx0XHRcdHJldHVybjtcblx0XHR9IGVsc2UgaWYgKGxhc3RUaW1lID4gdGltZSkgLy9cblx0XHRcdGxhc3RUaW1lID0gLTE7XG5cdFx0dmFyIGZyYW1lSW5kZXggPSAodGltZSA+PSBmcmFtZXNbZnJhbWVzLmxlbmd0aCAtIDJdID8gZnJhbWVzLmxlbmd0aCA6IHNwaW5lLkFuaW1hdGlvbi5iaW5hcnlTZWFyY2goZnJhbWVzLCB0aW1lLCAyKSkgLSAyO1xuXHRcdGlmIChmcmFtZXNbZnJhbWVJbmRleF0gPCBsYXN0VGltZSkgcmV0dXJuO1xuXHRcdHNrZWxldG9uLmJvbmVzW2JvbmVJbmRleF0uZmxpcFkgPSBmcmFtZXNbZnJhbWVJbmRleCArIDFdICE9IDA7XG5cdH1cbn07XG5cbnNwaW5lLlNrZWxldG9uRGF0YSA9IGZ1bmN0aW9uICgpIHtcblx0dGhpcy5ib25lcyA9IFtdO1xuXHR0aGlzLnNsb3RzID0gW107XG5cdHRoaXMuc2tpbnMgPSBbXTtcblx0dGhpcy5ldmVudHMgPSBbXTtcblx0dGhpcy5hbmltYXRpb25zID0gW107XG5cdHRoaXMuaWtDb25zdHJhaW50cyA9IFtdO1xufTtcbnNwaW5lLlNrZWxldG9uRGF0YS5wcm90b3R5cGUgPSB7XG5cdG5hbWU6IG51bGwsXG5cdGRlZmF1bHRTa2luOiBudWxsLFxuXHR3aWR0aDogMCwgaGVpZ2h0OiAwLFxuXHR2ZXJzaW9uOiBudWxsLCBoYXNoOiBudWxsLFxuXHQvKiogQHJldHVybiBNYXkgYmUgbnVsbC4gKi9cblx0ZmluZEJvbmU6IGZ1bmN0aW9uIChib25lTmFtZSkge1xuXHRcdHZhciBib25lcyA9IHRoaXMuYm9uZXM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBib25lcy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRpZiAoYm9uZXNbaV0ubmFtZSA9PSBib25lTmFtZSkgcmV0dXJuIGJvbmVzW2ldO1xuXHRcdHJldHVybiBudWxsO1xuXHR9LFxuXHQvKiogQHJldHVybiAtMSBpZiB0aGUgYm9uZSB3YXMgbm90IGZvdW5kLiAqL1xuXHRmaW5kQm9uZUluZGV4OiBmdW5jdGlvbiAoYm9uZU5hbWUpIHtcblx0XHR2YXIgYm9uZXMgPSB0aGlzLmJvbmVzO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gYm9uZXMubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0aWYgKGJvbmVzW2ldLm5hbWUgPT0gYm9uZU5hbWUpIHJldHVybiBpO1xuXHRcdHJldHVybiAtMTtcblx0fSxcblx0LyoqIEByZXR1cm4gTWF5IGJlIG51bGwuICovXG5cdGZpbmRTbG90OiBmdW5jdGlvbiAoc2xvdE5hbWUpIHtcblx0XHR2YXIgc2xvdHMgPSB0aGlzLnNsb3RzO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gc2xvdHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRpZiAoc2xvdHNbaV0ubmFtZSA9PSBzbG90TmFtZSkgcmV0dXJuIHNsb3RbaV07XG5cdFx0fVxuXHRcdHJldHVybiBudWxsO1xuXHR9LFxuXHQvKiogQHJldHVybiAtMSBpZiB0aGUgYm9uZSB3YXMgbm90IGZvdW5kLiAqL1xuXHRmaW5kU2xvdEluZGV4OiBmdW5jdGlvbiAoc2xvdE5hbWUpIHtcblx0XHR2YXIgc2xvdHMgPSB0aGlzLnNsb3RzO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gc2xvdHMubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0aWYgKHNsb3RzW2ldLm5hbWUgPT0gc2xvdE5hbWUpIHJldHVybiBpO1xuXHRcdHJldHVybiAtMTtcblx0fSxcblx0LyoqIEByZXR1cm4gTWF5IGJlIG51bGwuICovXG5cdGZpbmRTa2luOiBmdW5jdGlvbiAoc2tpbk5hbWUpIHtcblx0XHR2YXIgc2tpbnMgPSB0aGlzLnNraW5zO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gc2tpbnMubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0aWYgKHNraW5zW2ldLm5hbWUgPT0gc2tpbk5hbWUpIHJldHVybiBza2luc1tpXTtcblx0XHRyZXR1cm4gbnVsbDtcblx0fSxcblx0LyoqIEByZXR1cm4gTWF5IGJlIG51bGwuICovXG5cdGZpbmRFdmVudDogZnVuY3Rpb24gKGV2ZW50TmFtZSkge1xuXHRcdHZhciBldmVudHMgPSB0aGlzLmV2ZW50cztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IGV2ZW50cy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRpZiAoZXZlbnRzW2ldLm5hbWUgPT0gZXZlbnROYW1lKSByZXR1cm4gZXZlbnRzW2ldO1xuXHRcdHJldHVybiBudWxsO1xuXHR9LFxuXHQvKiogQHJldHVybiBNYXkgYmUgbnVsbC4gKi9cblx0ZmluZEFuaW1hdGlvbjogZnVuY3Rpb24gKGFuaW1hdGlvbk5hbWUpIHtcblx0XHR2YXIgYW5pbWF0aW9ucyA9IHRoaXMuYW5pbWF0aW9ucztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IGFuaW1hdGlvbnMubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0aWYgKGFuaW1hdGlvbnNbaV0ubmFtZSA9PSBhbmltYXRpb25OYW1lKSByZXR1cm4gYW5pbWF0aW9uc1tpXTtcblx0XHRyZXR1cm4gbnVsbDtcblx0fSxcblx0LyoqIEByZXR1cm4gTWF5IGJlIG51bGwuICovXG5cdGZpbmRJa0NvbnN0cmFpbnQ6IGZ1bmN0aW9uIChpa0NvbnN0cmFpbnROYW1lKSB7XG5cdFx0dmFyIGlrQ29uc3RyYWludHMgPSB0aGlzLmlrQ29uc3RyYWludHM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBpa0NvbnN0cmFpbnRzLmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdGlmIChpa0NvbnN0cmFpbnRzW2ldLm5hbWUgPT0gaWtDb25zdHJhaW50TmFtZSkgcmV0dXJuIGlrQ29uc3RyYWludHNbaV07XG5cdFx0cmV0dXJuIG51bGw7XG5cdH1cbn07XG5cbnNwaW5lLlNrZWxldG9uID0gZnVuY3Rpb24gKHNrZWxldG9uRGF0YSkge1xuXHR0aGlzLmRhdGEgPSBza2VsZXRvbkRhdGE7XG5cblx0dGhpcy5ib25lcyA9IFtdO1xuXHRmb3IgKHZhciBpID0gMCwgbiA9IHNrZWxldG9uRGF0YS5ib25lcy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcblx0XHR2YXIgYm9uZURhdGEgPSBza2VsZXRvbkRhdGEuYm9uZXNbaV07XG5cdFx0dmFyIHBhcmVudCA9ICFib25lRGF0YS5wYXJlbnQgPyBudWxsIDogdGhpcy5ib25lc1tza2VsZXRvbkRhdGEuYm9uZXMuaW5kZXhPZihib25lRGF0YS5wYXJlbnQpXTtcblx0XHR0aGlzLmJvbmVzLnB1c2gobmV3IHNwaW5lLkJvbmUoYm9uZURhdGEsIHRoaXMsIHBhcmVudCkpO1xuXHR9XG5cblx0dGhpcy5zbG90cyA9IFtdO1xuXHR0aGlzLmRyYXdPcmRlciA9IFtdO1xuXHRmb3IgKHZhciBpID0gMCwgbiA9IHNrZWxldG9uRGF0YS5zbG90cy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcblx0XHR2YXIgc2xvdERhdGEgPSBza2VsZXRvbkRhdGEuc2xvdHNbaV07XG5cdFx0dmFyIGJvbmUgPSB0aGlzLmJvbmVzW3NrZWxldG9uRGF0YS5ib25lcy5pbmRleE9mKHNsb3REYXRhLmJvbmVEYXRhKV07XG5cdFx0dmFyIHNsb3QgPSBuZXcgc3BpbmUuU2xvdChzbG90RGF0YSwgYm9uZSk7XG5cdFx0dGhpcy5zbG90cy5wdXNoKHNsb3QpO1xuXHRcdHRoaXMuZHJhd09yZGVyLnB1c2goc2xvdCk7XG5cdH1cblxuXHR0aGlzLmlrQ29uc3RyYWludHMgPSBbXTtcblx0Zm9yICh2YXIgaSA9IDAsIG4gPSBza2VsZXRvbkRhdGEuaWtDb25zdHJhaW50cy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0dGhpcy5pa0NvbnN0cmFpbnRzLnB1c2gobmV3IHNwaW5lLklrQ29uc3RyYWludChza2VsZXRvbkRhdGEuaWtDb25zdHJhaW50c1tpXSwgdGhpcykpO1xuXG5cdHRoaXMuYm9uZUNhY2hlID0gW107XG5cdHRoaXMudXBkYXRlQ2FjaGUoKTtcbn07XG5zcGluZS5Ta2VsZXRvbi5wcm90b3R5cGUgPSB7XG5cdHg6IDAsIHk6IDAsXG5cdHNraW46IG51bGwsXG5cdHI6IDEsIGc6IDEsIGI6IDEsIGE6IDEsXG5cdHRpbWU6IDAsXG5cdGZsaXBYOiBmYWxzZSwgZmxpcFk6IGZhbHNlLFxuXHQvKiogQ2FjaGVzIGluZm9ybWF0aW9uIGFib3V0IGJvbmVzIGFuZCBJSyBjb25zdHJhaW50cy4gTXVzdCBiZSBjYWxsZWQgaWYgYm9uZXMgb3IgSUsgY29uc3RyYWludHMgYXJlIGFkZGVkIG9yIHJlbW92ZWQuICovXG5cdHVwZGF0ZUNhY2hlOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGlrQ29uc3RyYWludHMgPSB0aGlzLmlrQ29uc3RyYWludHM7XG5cdFx0dmFyIGlrQ29uc3RyYWludHNDb3VudCA9IGlrQ29uc3RyYWludHMubGVuZ3RoO1xuXG5cdFx0dmFyIGFycmF5Q291bnQgPSBpa0NvbnN0cmFpbnRzQ291bnQgKyAxO1xuXHRcdHZhciBib25lQ2FjaGUgPSB0aGlzLmJvbmVDYWNoZTtcblx0XHRpZiAoYm9uZUNhY2hlLmxlbmd0aCA+IGFycmF5Q291bnQpIGJvbmVDYWNoZS5sZW5ndGggPSBhcnJheUNvdW50O1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gYm9uZUNhY2hlLmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdGJvbmVDYWNoZVtpXS5sZW5ndGggPSAwO1xuXHRcdHdoaWxlIChib25lQ2FjaGUubGVuZ3RoIDwgYXJyYXlDb3VudClcblx0XHRcdGJvbmVDYWNoZVtib25lQ2FjaGUubGVuZ3RoXSA9IFtdO1xuXG5cdFx0dmFyIG5vbklrQm9uZXMgPSBib25lQ2FjaGVbMF07XG5cdFx0dmFyIGJvbmVzID0gdGhpcy5ib25lcztcblxuXHRcdG91dGVyOlxuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gYm9uZXMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHR2YXIgYm9uZSA9IGJvbmVzW2ldO1xuXHRcdFx0dmFyIGN1cnJlbnQgPSBib25lO1xuXHRcdFx0ZG8ge1xuXHRcdFx0XHRmb3IgKHZhciBpaSA9IDA7IGlpIDwgaWtDb25zdHJhaW50c0NvdW50OyBpaSsrKSB7XG5cdFx0XHRcdFx0dmFyIGlrQ29uc3RyYWludCA9IGlrQ29uc3RyYWludHNbaWldO1xuXHRcdFx0XHRcdHZhciBwYXJlbnQgPSBpa0NvbnN0cmFpbnQuYm9uZXNbMF07XG5cdFx0XHRcdFx0dmFyIGNoaWxkPSBpa0NvbnN0cmFpbnQuYm9uZXNbaWtDb25zdHJhaW50LmJvbmVzLmxlbmd0aCAtIDFdO1xuXHRcdFx0XHRcdHdoaWxlICh0cnVlKSB7XG5cdFx0XHRcdFx0XHRpZiAoY3VycmVudCA9PSBjaGlsZCkge1xuXHRcdFx0XHRcdFx0XHRib25lQ2FjaGVbaWldLnB1c2goYm9uZSk7XG5cdFx0XHRcdFx0XHRcdGJvbmVDYWNoZVtpaSArIDFdLnB1c2goYm9uZSk7XG5cdFx0XHRcdFx0XHRcdGNvbnRpbnVlIG91dGVyO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aWYgKGNoaWxkID09IHBhcmVudCkgYnJlYWs7XG5cdFx0XHRcdFx0XHRjaGlsZCA9IGNoaWxkLnBhcmVudDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0Y3VycmVudCA9IGN1cnJlbnQucGFyZW50O1xuXHRcdFx0fSB3aGlsZSAoY3VycmVudCk7XG5cdFx0XHRub25Ja0JvbmVzW25vbklrQm9uZXMubGVuZ3RoXSA9IGJvbmU7XG5cdFx0fVxuXHR9LFxuXHQvKiogVXBkYXRlcyB0aGUgd29ybGQgdHJhbnNmb3JtIGZvciBlYWNoIGJvbmUuICovXG5cdHVwZGF0ZVdvcmxkVHJhbnNmb3JtOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGJvbmVzID0gdGhpcy5ib25lcztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IGJvbmVzLmxlbmd0aDsgaSA8IG47IGkrKykge1xuXHRcdFx0dmFyIGJvbmUgPSBib25lc1tpXTtcblx0XHRcdGJvbmUucm90YXRpb25JSyA9IGJvbmUucm90YXRpb247XG5cdFx0fVxuXHRcdHZhciBpID0gMCwgbGFzdCA9IHRoaXMuYm9uZUNhY2hlLmxlbmd0aCAtIDE7XG5cdFx0d2hpbGUgKHRydWUpIHtcblx0XHRcdHZhciBjYWNoZUJvbmVzID0gdGhpcy5ib25lQ2FjaGVbaV07XG5cdFx0XHRmb3IgKHZhciBpaSA9IDAsIG5uID0gY2FjaGVCb25lcy5sZW5ndGg7IGlpIDwgbm47IGlpKyspXG5cdFx0XHRcdGNhY2hlQm9uZXNbaWldLnVwZGF0ZVdvcmxkVHJhbnNmb3JtKCk7XG5cdFx0XHRpZiAoaSA9PSBsYXN0KSBicmVhaztcblx0XHRcdHRoaXMuaWtDb25zdHJhaW50c1tpXS5hcHBseSgpO1xuXHRcdFx0aSsrO1xuXHRcdH1cblx0fSxcblx0LyoqIFNldHMgdGhlIGJvbmVzIGFuZCBzbG90cyB0byB0aGVpciBzZXR1cCBwb3NlIHZhbHVlcy4gKi9cblx0c2V0VG9TZXR1cFBvc2U6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLnNldEJvbmVzVG9TZXR1cFBvc2UoKTtcblx0XHR0aGlzLnNldFNsb3RzVG9TZXR1cFBvc2UoKTtcblx0fSxcblx0c2V0Qm9uZXNUb1NldHVwUG9zZTogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBib25lcyA9IHRoaXMuYm9uZXM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBib25lcy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRib25lc1tpXS5zZXRUb1NldHVwUG9zZSgpO1xuXG5cdFx0dmFyIGlrQ29uc3RyYWludHMgPSB0aGlzLmlrQ29uc3RyYWludHM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBpa0NvbnN0cmFpbnRzLmxlbmd0aDsgaSA8IG47IGkrKykge1xuXHRcdFx0dmFyIGlrQ29uc3RyYWludCA9IGlrQ29uc3RyYWludHNbaV07XG5cdFx0XHRpa0NvbnN0cmFpbnQuYmVuZERpcmVjdGlvbiA9IGlrQ29uc3RyYWludC5kYXRhLmJlbmREaXJlY3Rpb247XG5cdFx0XHRpa0NvbnN0cmFpbnQubWl4ID0gaWtDb25zdHJhaW50LmRhdGEubWl4O1xuXHRcdH1cblx0fSxcblx0c2V0U2xvdHNUb1NldHVwUG9zZTogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBzbG90cyA9IHRoaXMuc2xvdHM7XG5cdFx0dmFyIGRyYXdPcmRlciA9IHRoaXMuZHJhd09yZGVyO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gc2xvdHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRkcmF3T3JkZXJbaV0gPSBzbG90c1tpXTtcblx0XHRcdHNsb3RzW2ldLnNldFRvU2V0dXBQb3NlKGkpO1xuXHRcdH1cblx0fSxcblx0LyoqIEByZXR1cm4gTWF5IHJldHVybiBudWxsLiAqL1xuXHRnZXRSb290Qm9uZTogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLmJvbmVzLmxlbmd0aCA/IHRoaXMuYm9uZXNbMF0gOiBudWxsO1xuXHR9LFxuXHQvKiogQHJldHVybiBNYXkgYmUgbnVsbC4gKi9cblx0ZmluZEJvbmU6IGZ1bmN0aW9uIChib25lTmFtZSkge1xuXHRcdHZhciBib25lcyA9IHRoaXMuYm9uZXM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBib25lcy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRpZiAoYm9uZXNbaV0uZGF0YS5uYW1lID09IGJvbmVOYW1lKSByZXR1cm4gYm9uZXNbaV07XG5cdFx0cmV0dXJuIG51bGw7XG5cdH0sXG5cdC8qKiBAcmV0dXJuIC0xIGlmIHRoZSBib25lIHdhcyBub3QgZm91bmQuICovXG5cdGZpbmRCb25lSW5kZXg6IGZ1bmN0aW9uIChib25lTmFtZSkge1xuXHRcdHZhciBib25lcyA9IHRoaXMuYm9uZXM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBib25lcy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRpZiAoYm9uZXNbaV0uZGF0YS5uYW1lID09IGJvbmVOYW1lKSByZXR1cm4gaTtcblx0XHRyZXR1cm4gLTE7XG5cdH0sXG5cdC8qKiBAcmV0dXJuIE1heSBiZSBudWxsLiAqL1xuXHRmaW5kU2xvdDogZnVuY3Rpb24gKHNsb3ROYW1lKSB7XG5cdFx0dmFyIHNsb3RzID0gdGhpcy5zbG90cztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHNsb3RzLmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdGlmIChzbG90c1tpXS5kYXRhLm5hbWUgPT0gc2xvdE5hbWUpIHJldHVybiBzbG90c1tpXTtcblx0XHRyZXR1cm4gbnVsbDtcblx0fSxcblx0LyoqIEByZXR1cm4gLTEgaWYgdGhlIGJvbmUgd2FzIG5vdCBmb3VuZC4gKi9cblx0ZmluZFNsb3RJbmRleDogZnVuY3Rpb24gKHNsb3ROYW1lKSB7XG5cdFx0dmFyIHNsb3RzID0gdGhpcy5zbG90cztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHNsb3RzLmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdGlmIChzbG90c1tpXS5kYXRhLm5hbWUgPT0gc2xvdE5hbWUpIHJldHVybiBpO1xuXHRcdHJldHVybiAtMTtcblx0fSxcblx0c2V0U2tpbkJ5TmFtZTogZnVuY3Rpb24gKHNraW5OYW1lKSB7XG5cdFx0dmFyIHNraW4gPSB0aGlzLmRhdGEuZmluZFNraW4oc2tpbk5hbWUpO1xuXHRcdGlmICghc2tpbikgdGhyb3cgXCJTa2luIG5vdCBmb3VuZDogXCIgKyBza2luTmFtZTtcblx0XHR0aGlzLnNldFNraW4oc2tpbik7XG5cdH0sXG5cdC8qKiBTZXRzIHRoZSBza2luIHVzZWQgdG8gbG9vayB1cCBhdHRhY2htZW50cyBiZWZvcmUgbG9va2luZyBpbiB0aGUge0BsaW5rIFNrZWxldG9uRGF0YSNnZXREZWZhdWx0U2tpbigpIGRlZmF1bHQgc2tpbn0uXG5cdCAqIEF0dGFjaG1lbnRzIGZyb20gdGhlIG5ldyBza2luIGFyZSBhdHRhY2hlZCBpZiB0aGUgY29ycmVzcG9uZGluZyBhdHRhY2htZW50IGZyb20gdGhlIG9sZCBza2luIHdhcyBhdHRhY2hlZC4gSWYgdGhlcmUgd2FzXG5cdCAqIG5vIG9sZCBza2luLCBlYWNoIHNsb3QncyBzZXR1cCBtb2RlIGF0dGFjaG1lbnQgaXMgYXR0YWNoZWQgZnJvbSB0aGUgbmV3IHNraW4uXG5cdCAqIEBwYXJhbSBuZXdTa2luIE1heSBiZSBudWxsLiAqL1xuXHRzZXRTa2luOiBmdW5jdGlvbiAobmV3U2tpbikge1xuXHRcdGlmIChuZXdTa2luKSB7XG5cdFx0XHRpZiAodGhpcy5za2luKVxuXHRcdFx0XHRuZXdTa2luLl9hdHRhY2hBbGwodGhpcywgdGhpcy5za2luKTtcblx0XHRcdGVsc2Uge1xuXHRcdFx0XHR2YXIgc2xvdHMgPSB0aGlzLnNsb3RzO1xuXHRcdFx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHNsb3RzLmxlbmd0aDsgaSA8IG47IGkrKykge1xuXHRcdFx0XHRcdHZhciBzbG90ID0gc2xvdHNbaV07XG5cdFx0XHRcdFx0dmFyIG5hbWUgPSBzbG90LmRhdGEuYXR0YWNobWVudE5hbWU7XG5cdFx0XHRcdFx0aWYgKG5hbWUpIHtcblx0XHRcdFx0XHRcdHZhciBhdHRhY2htZW50ID0gbmV3U2tpbi5nZXRBdHRhY2htZW50KGksIG5hbWUpO1xuXHRcdFx0XHRcdFx0aWYgKGF0dGFjaG1lbnQpIHNsb3Quc2V0QXR0YWNobWVudChhdHRhY2htZW50KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdFx0dGhpcy5za2luID0gbmV3U2tpbjtcblx0fSxcblx0LyoqIEByZXR1cm4gTWF5IGJlIG51bGwuICovXG5cdGdldEF0dGFjaG1lbnRCeVNsb3ROYW1lOiBmdW5jdGlvbiAoc2xvdE5hbWUsIGF0dGFjaG1lbnROYW1lKSB7XG5cdFx0cmV0dXJuIHRoaXMuZ2V0QXR0YWNobWVudEJ5U2xvdEluZGV4KHRoaXMuZGF0YS5maW5kU2xvdEluZGV4KHNsb3ROYW1lKSwgYXR0YWNobWVudE5hbWUpO1xuXHR9LFxuXHQvKiogQHJldHVybiBNYXkgYmUgbnVsbC4gKi9cblx0Z2V0QXR0YWNobWVudEJ5U2xvdEluZGV4OiBmdW5jdGlvbiAoc2xvdEluZGV4LCBhdHRhY2htZW50TmFtZSkge1xuXHRcdGlmICh0aGlzLnNraW4pIHtcblx0XHRcdHZhciBhdHRhY2htZW50ID0gdGhpcy5za2luLmdldEF0dGFjaG1lbnQoc2xvdEluZGV4LCBhdHRhY2htZW50TmFtZSk7XG5cdFx0XHRpZiAoYXR0YWNobWVudCkgcmV0dXJuIGF0dGFjaG1lbnQ7XG5cdFx0fVxuXHRcdGlmICh0aGlzLmRhdGEuZGVmYXVsdFNraW4pIHJldHVybiB0aGlzLmRhdGEuZGVmYXVsdFNraW4uZ2V0QXR0YWNobWVudChzbG90SW5kZXgsIGF0dGFjaG1lbnROYW1lKTtcblx0XHRyZXR1cm4gbnVsbDtcblx0fSxcblx0LyoqIEBwYXJhbSBhdHRhY2htZW50TmFtZSBNYXkgYmUgbnVsbC4gKi9cblx0c2V0QXR0YWNobWVudDogZnVuY3Rpb24gKHNsb3ROYW1lLCBhdHRhY2htZW50TmFtZSkge1xuXHRcdHZhciBzbG90cyA9IHRoaXMuc2xvdHM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBzbG90cy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcblx0XHRcdHZhciBzbG90ID0gc2xvdHNbaV07XG5cdFx0XHRpZiAoc2xvdC5kYXRhLm5hbWUgPT0gc2xvdE5hbWUpIHtcblx0XHRcdFx0dmFyIGF0dGFjaG1lbnQgPSBudWxsO1xuXHRcdFx0XHRpZiAoYXR0YWNobWVudE5hbWUpIHtcblx0XHRcdFx0XHRhdHRhY2htZW50ID0gdGhpcy5nZXRBdHRhY2htZW50QnlTbG90SW5kZXgoaSwgYXR0YWNobWVudE5hbWUpO1xuXHRcdFx0XHRcdGlmICghYXR0YWNobWVudCkgdGhyb3cgXCJBdHRhY2htZW50IG5vdCBmb3VuZDogXCIgKyBhdHRhY2htZW50TmFtZSArIFwiLCBmb3Igc2xvdDogXCIgKyBzbG90TmFtZTtcblx0XHRcdFx0fVxuXHRcdFx0XHRzbG90LnNldEF0dGFjaG1lbnQoYXR0YWNobWVudCk7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblx0XHR9XG5cdFx0dGhyb3cgXCJTbG90IG5vdCBmb3VuZDogXCIgKyBzbG90TmFtZTtcblx0fSxcblx0LyoqIEByZXR1cm4gTWF5IGJlIG51bGwuICovXG5cdGZpbmRJa0NvbnN0cmFpbnQ6IGZ1bmN0aW9uIChpa0NvbnN0cmFpbnROYW1lKSB7XG5cdFx0dmFyIGlrQ29uc3RyYWludHMgPSB0aGlzLmlrQ29uc3RyYWludHM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBpa0NvbnN0cmFpbnRzLmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdGlmIChpa0NvbnN0cmFpbnRzW2ldLmRhdGEubmFtZSA9PSBpa0NvbnN0cmFpbnROYW1lKSByZXR1cm4gaWtDb25zdHJhaW50c1tpXTtcblx0XHRyZXR1cm4gbnVsbDtcblx0fSxcblx0dXBkYXRlOiBmdW5jdGlvbiAoZGVsdGEpIHtcblx0XHR0aGlzLnRpbWUgKz0gZGVsdGE7XG5cdH1cbn07XG5cbnNwaW5lLkV2ZW50RGF0YSA9IGZ1bmN0aW9uIChuYW1lKSB7XG5cdHRoaXMubmFtZSA9IG5hbWU7XG59O1xuc3BpbmUuRXZlbnREYXRhLnByb3RvdHlwZSA9IHtcblx0aW50VmFsdWU6IDAsXG5cdGZsb2F0VmFsdWU6IDAsXG5cdHN0cmluZ1ZhbHVlOiBudWxsXG59O1xuXG5zcGluZS5FdmVudCA9IGZ1bmN0aW9uIChkYXRhKSB7XG5cdHRoaXMuZGF0YSA9IGRhdGE7XG59O1xuc3BpbmUuRXZlbnQucHJvdG90eXBlID0ge1xuXHRpbnRWYWx1ZTogMCxcblx0ZmxvYXRWYWx1ZTogMCxcblx0c3RyaW5nVmFsdWU6IG51bGxcbn07XG5cbnNwaW5lLkF0dGFjaG1lbnRUeXBlID0ge1xuXHRyZWdpb246IDAsXG5cdGJvdW5kaW5nYm94OiAxLFxuXHRtZXNoOiAyLFxuXHRza2lubmVkbWVzaDogM1xufTtcblxuc3BpbmUuUmVnaW9uQXR0YWNobWVudCA9IGZ1bmN0aW9uIChuYW1lKSB7XG5cdHRoaXMubmFtZSA9IG5hbWU7XG5cdHRoaXMub2Zmc2V0ID0gW107XG5cdHRoaXMub2Zmc2V0Lmxlbmd0aCA9IDg7XG5cdHRoaXMudXZzID0gW107XG5cdHRoaXMudXZzLmxlbmd0aCA9IDg7XG59O1xuc3BpbmUuUmVnaW9uQXR0YWNobWVudC5wcm90b3R5cGUgPSB7XG5cdHR5cGU6IHNwaW5lLkF0dGFjaG1lbnRUeXBlLnJlZ2lvbixcblx0eDogMCwgeTogMCxcblx0cm90YXRpb246IDAsXG5cdHNjYWxlWDogMSwgc2NhbGVZOiAxLFxuXHR3aWR0aDogMCwgaGVpZ2h0OiAwLFxuXHRyOiAxLCBnOiAxLCBiOiAxLCBhOiAxLFxuXHRwYXRoOiBudWxsLFxuXHRyZW5kZXJlck9iamVjdDogbnVsbCxcblx0cmVnaW9uT2Zmc2V0WDogMCwgcmVnaW9uT2Zmc2V0WTogMCxcblx0cmVnaW9uV2lkdGg6IDAsIHJlZ2lvbkhlaWdodDogMCxcblx0cmVnaW9uT3JpZ2luYWxXaWR0aDogMCwgcmVnaW9uT3JpZ2luYWxIZWlnaHQ6IDAsXG5cdHNldFVWczogZnVuY3Rpb24gKHUsIHYsIHUyLCB2Miwgcm90YXRlKSB7XG5cdFx0dmFyIHV2cyA9IHRoaXMudXZzO1xuXHRcdGlmIChyb3RhdGUpIHtcblx0XHRcdHV2c1syLypYMiovXSA9IHU7XG5cdFx0XHR1dnNbMy8qWTIqL10gPSB2Mjtcblx0XHRcdHV2c1s0LypYMyovXSA9IHU7XG5cdFx0XHR1dnNbNS8qWTMqL10gPSB2O1xuXHRcdFx0dXZzWzYvKlg0Ki9dID0gdTI7XG5cdFx0XHR1dnNbNy8qWTQqL10gPSB2O1xuXHRcdFx0dXZzWzAvKlgxKi9dID0gdTI7XG5cdFx0XHR1dnNbMS8qWTEqL10gPSB2Mjtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dXZzWzAvKlgxKi9dID0gdTtcblx0XHRcdHV2c1sxLypZMSovXSA9IHYyO1xuXHRcdFx0dXZzWzIvKlgyKi9dID0gdTtcblx0XHRcdHV2c1szLypZMiovXSA9IHY7XG5cdFx0XHR1dnNbNC8qWDMqL10gPSB1Mjtcblx0XHRcdHV2c1s1LypZMyovXSA9IHY7XG5cdFx0XHR1dnNbNi8qWDQqL10gPSB1Mjtcblx0XHRcdHV2c1s3LypZNCovXSA9IHYyO1xuXHRcdH1cblx0fSxcblx0dXBkYXRlT2Zmc2V0OiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIHJlZ2lvblNjYWxlWCA9IHRoaXMud2lkdGggLyB0aGlzLnJlZ2lvbk9yaWdpbmFsV2lkdGggKiB0aGlzLnNjYWxlWDtcblx0XHR2YXIgcmVnaW9uU2NhbGVZID0gdGhpcy5oZWlnaHQgLyB0aGlzLnJlZ2lvbk9yaWdpbmFsSGVpZ2h0ICogdGhpcy5zY2FsZVk7XG5cdFx0dmFyIGxvY2FsWCA9IC10aGlzLndpZHRoIC8gMiAqIHRoaXMuc2NhbGVYICsgdGhpcy5yZWdpb25PZmZzZXRYICogcmVnaW9uU2NhbGVYO1xuXHRcdHZhciBsb2NhbFkgPSAtdGhpcy5oZWlnaHQgLyAyICogdGhpcy5zY2FsZVkgKyB0aGlzLnJlZ2lvbk9mZnNldFkgKiByZWdpb25TY2FsZVk7XG5cdFx0dmFyIGxvY2FsWDIgPSBsb2NhbFggKyB0aGlzLnJlZ2lvbldpZHRoICogcmVnaW9uU2NhbGVYO1xuXHRcdHZhciBsb2NhbFkyID0gbG9jYWxZICsgdGhpcy5yZWdpb25IZWlnaHQgKiByZWdpb25TY2FsZVk7XG5cdFx0dmFyIHJhZGlhbnMgPSB0aGlzLnJvdGF0aW9uICogc3BpbmUuZGVnUmFkO1xuXHRcdHZhciBjb3MgPSBNYXRoLmNvcyhyYWRpYW5zKTtcblx0XHR2YXIgc2luID0gTWF0aC5zaW4ocmFkaWFucyk7XG5cdFx0dmFyIGxvY2FsWENvcyA9IGxvY2FsWCAqIGNvcyArIHRoaXMueDtcblx0XHR2YXIgbG9jYWxYU2luID0gbG9jYWxYICogc2luO1xuXHRcdHZhciBsb2NhbFlDb3MgPSBsb2NhbFkgKiBjb3MgKyB0aGlzLnk7XG5cdFx0dmFyIGxvY2FsWVNpbiA9IGxvY2FsWSAqIHNpbjtcblx0XHR2YXIgbG9jYWxYMkNvcyA9IGxvY2FsWDIgKiBjb3MgKyB0aGlzLng7XG5cdFx0dmFyIGxvY2FsWDJTaW4gPSBsb2NhbFgyICogc2luO1xuXHRcdHZhciBsb2NhbFkyQ29zID0gbG9jYWxZMiAqIGNvcyArIHRoaXMueTtcblx0XHR2YXIgbG9jYWxZMlNpbiA9IGxvY2FsWTIgKiBzaW47XG5cdFx0dmFyIG9mZnNldCA9IHRoaXMub2Zmc2V0O1xuXHRcdG9mZnNldFswLypYMSovXSA9IGxvY2FsWENvcyAtIGxvY2FsWVNpbjtcblx0XHRvZmZzZXRbMS8qWTEqL10gPSBsb2NhbFlDb3MgKyBsb2NhbFhTaW47XG5cdFx0b2Zmc2V0WzIvKlgyKi9dID0gbG9jYWxYQ29zIC0gbG9jYWxZMlNpbjtcblx0XHRvZmZzZXRbMy8qWTIqL10gPSBsb2NhbFkyQ29zICsgbG9jYWxYU2luO1xuXHRcdG9mZnNldFs0LypYMyovXSA9IGxvY2FsWDJDb3MgLSBsb2NhbFkyU2luO1xuXHRcdG9mZnNldFs1LypZMyovXSA9IGxvY2FsWTJDb3MgKyBsb2NhbFgyU2luO1xuXHRcdG9mZnNldFs2LypYNCovXSA9IGxvY2FsWDJDb3MgLSBsb2NhbFlTaW47XG5cdFx0b2Zmc2V0WzcvKlk0Ki9dID0gbG9jYWxZQ29zICsgbG9jYWxYMlNpbjtcblx0fSxcblx0Y29tcHV0ZVZlcnRpY2VzOiBmdW5jdGlvbiAoeCwgeSwgYm9uZSwgdmVydGljZXMpIHtcblx0XHR4ICs9IGJvbmUud29ybGRYO1xuXHRcdHkgKz0gYm9uZS53b3JsZFk7XG5cdFx0dmFyIG0wMCA9IGJvbmUubTAwLCBtMDEgPSBib25lLm0wMSwgbTEwID0gYm9uZS5tMTAsIG0xMSA9IGJvbmUubTExO1xuXHRcdHZhciBvZmZzZXQgPSB0aGlzLm9mZnNldDtcblx0XHR2ZXJ0aWNlc1swLypYMSovXSA9IG9mZnNldFswLypYMSovXSAqIG0wMCArIG9mZnNldFsxLypZMSovXSAqIG0wMSArIHg7XG5cdFx0dmVydGljZXNbMS8qWTEqL10gPSBvZmZzZXRbMC8qWDEqL10gKiBtMTAgKyBvZmZzZXRbMS8qWTEqL10gKiBtMTEgKyB5O1xuXHRcdHZlcnRpY2VzWzIvKlgyKi9dID0gb2Zmc2V0WzIvKlgyKi9dICogbTAwICsgb2Zmc2V0WzMvKlkyKi9dICogbTAxICsgeDtcblx0XHR2ZXJ0aWNlc1szLypZMiovXSA9IG9mZnNldFsyLypYMiovXSAqIG0xMCArIG9mZnNldFszLypZMiovXSAqIG0xMSArIHk7XG5cdFx0dmVydGljZXNbNC8qWDMqL10gPSBvZmZzZXRbNC8qWDMqL10gKiBtMDAgKyBvZmZzZXRbNS8qWDMqL10gKiBtMDEgKyB4O1xuXHRcdHZlcnRpY2VzWzUvKlgzKi9dID0gb2Zmc2V0WzQvKlgzKi9dICogbTEwICsgb2Zmc2V0WzUvKlgzKi9dICogbTExICsgeTtcblx0XHR2ZXJ0aWNlc1s2LypYNCovXSA9IG9mZnNldFs2LypYNCovXSAqIG0wMCArIG9mZnNldFs3LypZNCovXSAqIG0wMSArIHg7XG5cdFx0dmVydGljZXNbNy8qWTQqL10gPSBvZmZzZXRbNi8qWDQqL10gKiBtMTAgKyBvZmZzZXRbNy8qWTQqL10gKiBtMTEgKyB5O1xuXHR9XG59O1xuXG5zcGluZS5NZXNoQXR0YWNobWVudCA9IGZ1bmN0aW9uIChuYW1lKSB7XG5cdHRoaXMubmFtZSA9IG5hbWU7XG59O1xuc3BpbmUuTWVzaEF0dGFjaG1lbnQucHJvdG90eXBlID0ge1xuXHR0eXBlOiBzcGluZS5BdHRhY2htZW50VHlwZS5tZXNoLFxuXHR2ZXJ0aWNlczogbnVsbCxcblx0dXZzOiBudWxsLFxuXHRyZWdpb25VVnM6IG51bGwsXG5cdHRyaWFuZ2xlczogbnVsbCxcblx0aHVsbExlbmd0aDogMCxcblx0cjogMSwgZzogMSwgYjogMSwgYTogMSxcblx0cGF0aDogbnVsbCxcblx0cmVuZGVyZXJPYmplY3Q6IG51bGwsXG5cdHJlZ2lvblU6IDAsIHJlZ2lvblY6IDAsIHJlZ2lvblUyOiAwLCByZWdpb25WMjogMCwgcmVnaW9uUm90YXRlOiBmYWxzZSxcblx0cmVnaW9uT2Zmc2V0WDogMCwgcmVnaW9uT2Zmc2V0WTogMCxcblx0cmVnaW9uV2lkdGg6IDAsIHJlZ2lvbkhlaWdodDogMCxcblx0cmVnaW9uT3JpZ2luYWxXaWR0aDogMCwgcmVnaW9uT3JpZ2luYWxIZWlnaHQ6IDAsXG5cdGVkZ2VzOiBudWxsLFxuXHR3aWR0aDogMCwgaGVpZ2h0OiAwLFxuXHR1cGRhdGVVVnM6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgd2lkdGggPSB0aGlzLnJlZ2lvblUyIC0gdGhpcy5yZWdpb25VLCBoZWlnaHQgPSB0aGlzLnJlZ2lvblYyIC0gdGhpcy5yZWdpb25WO1xuXHRcdHZhciBuID0gdGhpcy5yZWdpb25VVnMubGVuZ3RoO1xuXHRcdGlmICghdGhpcy51dnMgfHwgdGhpcy51dnMubGVuZ3RoICE9IG4pIHtcbiAgICAgICAgICAgIHRoaXMudXZzID0gbmV3IHNwaW5lLkZsb2F0MzJBcnJheShuKTtcblx0XHR9XG5cdFx0aWYgKHRoaXMucmVnaW9uUm90YXRlKSB7XG5cdFx0XHRmb3IgKHZhciBpID0gMDsgaSA8IG47IGkgKz0gMikge1xuICAgICAgICAgICAgICAgIHRoaXMudXZzW2ldID0gdGhpcy5yZWdpb25VICsgdGhpcy5yZWdpb25VVnNbaSArIDFdICogd2lkdGg7XG4gICAgICAgICAgICAgICAgdGhpcy51dnNbaSArIDFdID0gdGhpcy5yZWdpb25WICsgaGVpZ2h0IC0gdGhpcy5yZWdpb25VVnNbaV0gKiBoZWlnaHQ7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdGZvciAodmFyIGkgPSAwOyBpIDwgbjsgaSArPSAyKSB7XG4gICAgICAgICAgICAgICAgdGhpcy51dnNbaV0gPSB0aGlzLnJlZ2lvblUgKyB0aGlzLnJlZ2lvblVWc1tpXSAqIHdpZHRoO1xuICAgICAgICAgICAgICAgIHRoaXMudXZzW2kgKyAxXSA9IHRoaXMucmVnaW9uViArIHRoaXMucmVnaW9uVVZzW2kgKyAxXSAqIGhlaWdodDtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cdGNvbXB1dGVXb3JsZFZlcnRpY2VzOiBmdW5jdGlvbiAoeCwgeSwgc2xvdCwgd29ybGRWZXJ0aWNlcykge1xuXHRcdHZhciBib25lID0gc2xvdC5ib25lO1xuXHRcdHggKz0gYm9uZS53b3JsZFg7XG5cdFx0eSArPSBib25lLndvcmxkWTtcblx0XHR2YXIgbTAwID0gYm9uZS5tMDAsIG0wMSA9IGJvbmUubTAxLCBtMTAgPSBib25lLm0xMCwgbTExID0gYm9uZS5tMTE7XG5cdFx0dmFyIHZlcnRpY2VzID0gdGhpcy52ZXJ0aWNlcztcblx0XHR2YXIgdmVydGljZXNDb3VudCA9IHZlcnRpY2VzLmxlbmd0aDtcblx0XHRpZiAoc2xvdC5hdHRhY2htZW50VmVydGljZXMubGVuZ3RoID09IHZlcnRpY2VzQ291bnQpIHZlcnRpY2VzID0gc2xvdC5hdHRhY2htZW50VmVydGljZXM7XG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCB2ZXJ0aWNlc0NvdW50OyBpICs9IDIpIHtcblx0XHRcdHZhciB2eCA9IHZlcnRpY2VzW2ldO1xuXHRcdFx0dmFyIHZ5ID0gdmVydGljZXNbaSArIDFdO1xuXHRcdFx0d29ybGRWZXJ0aWNlc1tpXSA9IHZ4ICogbTAwICsgdnkgKiBtMDEgKyB4O1xuXHRcdFx0d29ybGRWZXJ0aWNlc1tpICsgMV0gPSB2eCAqIG0xMCArIHZ5ICogbTExICsgeTtcblx0XHR9XG5cdH1cbn07XG5cbnNwaW5lLlNraW5uZWRNZXNoQXR0YWNobWVudCA9IGZ1bmN0aW9uIChuYW1lKSB7XG5cdHRoaXMubmFtZSA9IG5hbWU7XG59O1xuc3BpbmUuU2tpbm5lZE1lc2hBdHRhY2htZW50LnByb3RvdHlwZSA9IHtcblx0dHlwZTogc3BpbmUuQXR0YWNobWVudFR5cGUuc2tpbm5lZG1lc2gsXG5cdGJvbmVzOiBudWxsLFxuXHR3ZWlnaHRzOiBudWxsLFxuXHR1dnM6IG51bGwsXG5cdHJlZ2lvblVWczogbnVsbCxcblx0dHJpYW5nbGVzOiBudWxsLFxuXHRodWxsTGVuZ3RoOiAwLFxuXHRyOiAxLCBnOiAxLCBiOiAxLCBhOiAxLFxuXHRwYXRoOiBudWxsLFxuXHRyZW5kZXJlck9iamVjdDogbnVsbCxcblx0cmVnaW9uVTogMCwgcmVnaW9uVjogMCwgcmVnaW9uVTI6IDAsIHJlZ2lvblYyOiAwLCByZWdpb25Sb3RhdGU6IGZhbHNlLFxuXHRyZWdpb25PZmZzZXRYOiAwLCByZWdpb25PZmZzZXRZOiAwLFxuXHRyZWdpb25XaWR0aDogMCwgcmVnaW9uSGVpZ2h0OiAwLFxuXHRyZWdpb25PcmlnaW5hbFdpZHRoOiAwLCByZWdpb25PcmlnaW5hbEhlaWdodDogMCxcblx0ZWRnZXM6IG51bGwsXG5cdHdpZHRoOiAwLCBoZWlnaHQ6IDAsXG5cdHVwZGF0ZVVWczogZnVuY3Rpb24gKHUsIHYsIHUyLCB2Miwgcm90YXRlKSB7XG5cdFx0dmFyIHdpZHRoID0gdGhpcy5yZWdpb25VMiAtIHRoaXMucmVnaW9uVSwgaGVpZ2h0ID0gdGhpcy5yZWdpb25WMiAtIHRoaXMucmVnaW9uVjtcblx0XHR2YXIgbiA9IHRoaXMucmVnaW9uVVZzLmxlbmd0aDtcblx0XHRpZiAoIXRoaXMudXZzIHx8IHRoaXMudXZzLmxlbmd0aCAhPSBuKSB7XG4gICAgICAgICAgICB0aGlzLnV2cyA9IG5ldyBzcGluZS5GbG9hdDMyQXJyYXkobik7XG5cdFx0fVxuXHRcdGlmICh0aGlzLnJlZ2lvblJvdGF0ZSkge1xuXHRcdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBuOyBpICs9IDIpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnV2c1tpXSA9IHRoaXMucmVnaW9uVSArIHRoaXMucmVnaW9uVVZzW2kgKyAxXSAqIHdpZHRoO1xuICAgICAgICAgICAgICAgIHRoaXMudXZzW2kgKyAxXSA9IHRoaXMucmVnaW9uViArIGhlaWdodCAtIHRoaXMucmVnaW9uVVZzW2ldICogaGVpZ2h0O1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHRmb3IgKHZhciBpID0gMDsgaSA8IG47IGkgKz0gMikge1xuICAgICAgICAgICAgICAgIHRoaXMudXZzW2ldID0gdGhpcy5yZWdpb25VICsgdGhpcy5yZWdpb25VVnNbaV0gKiB3aWR0aDtcbiAgICAgICAgICAgICAgICB0aGlzLnV2c1tpICsgMV0gPSB0aGlzLnJlZ2lvblYgKyB0aGlzLnJlZ2lvblVWc1tpICsgMV0gKiBoZWlnaHQ7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXHRjb21wdXRlV29ybGRWZXJ0aWNlczogZnVuY3Rpb24gKHgsIHksIHNsb3QsIHdvcmxkVmVydGljZXMpIHtcblx0XHR2YXIgc2tlbGV0b25Cb25lcyA9IHNsb3QuYm9uZS5za2VsZXRvbi5ib25lcztcblx0XHR2YXIgd2VpZ2h0cyA9IHRoaXMud2VpZ2h0cztcblx0XHR2YXIgYm9uZXMgPSB0aGlzLmJvbmVzO1xuXG5cdFx0dmFyIHcgPSAwLCB2ID0gMCwgYiA9IDAsIGYgPSAwLCBuID0gYm9uZXMubGVuZ3RoLCBubjtcblx0XHR2YXIgd3gsIHd5LCBib25lLCB2eCwgdnksIHdlaWdodDtcblx0XHRpZiAoIXNsb3QuYXR0YWNobWVudFZlcnRpY2VzLmxlbmd0aCkge1xuXHRcdFx0Zm9yICg7IHYgPCBuOyB3ICs9IDIpIHtcblx0XHRcdFx0d3ggPSAwO1xuXHRcdFx0XHR3eSA9IDA7XG5cdFx0XHRcdG5uID0gYm9uZXNbdisrXSArIHY7XG5cdFx0XHRcdGZvciAoOyB2IDwgbm47IHYrKywgYiArPSAzKSB7XG5cdFx0XHRcdFx0Ym9uZSA9IHNrZWxldG9uQm9uZXNbYm9uZXNbdl1dO1xuXHRcdFx0XHRcdHZ4ID0gd2VpZ2h0c1tiXTtcblx0XHRcdFx0XHR2eSA9IHdlaWdodHNbYiArIDFdO1xuXHRcdFx0XHRcdHdlaWdodCA9IHdlaWdodHNbYiArIDJdO1xuXHRcdFx0XHRcdHd4ICs9ICh2eCAqIGJvbmUubTAwICsgdnkgKiBib25lLm0wMSArIGJvbmUud29ybGRYKSAqIHdlaWdodDtcblx0XHRcdFx0XHR3eSArPSAodnggKiBib25lLm0xMCArIHZ5ICogYm9uZS5tMTEgKyBib25lLndvcmxkWSkgKiB3ZWlnaHQ7XG5cdFx0XHRcdH1cblx0XHRcdFx0d29ybGRWZXJ0aWNlc1t3XSA9IHd4ICsgeDtcblx0XHRcdFx0d29ybGRWZXJ0aWNlc1t3ICsgMV0gPSB3eSArIHk7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdHZhciBmZmQgPSBzbG90LmF0dGFjaG1lbnRWZXJ0aWNlcztcblx0XHRcdGZvciAoOyB2IDwgbjsgdyArPSAyKSB7XG5cdFx0XHRcdHd4ID0gMDtcblx0XHRcdFx0d3kgPSAwO1xuXHRcdFx0XHRubiA9IGJvbmVzW3YrK10gKyB2O1xuXHRcdFx0XHRmb3IgKDsgdiA8IG5uOyB2KyssIGIgKz0gMywgZiArPSAyKSB7XG5cdFx0XHRcdFx0Ym9uZSA9IHNrZWxldG9uQm9uZXNbYm9uZXNbdl1dO1xuXHRcdFx0XHRcdHZ4ID0gd2VpZ2h0c1tiXSArIGZmZFtmXTtcblx0XHRcdFx0XHR2eSA9IHdlaWdodHNbYiArIDFdICsgZmZkW2YgKyAxXTtcblx0XHRcdFx0XHR3ZWlnaHQgPSB3ZWlnaHRzW2IgKyAyXTtcblx0XHRcdFx0XHR3eCArPSAodnggKiBib25lLm0wMCArIHZ5ICogYm9uZS5tMDEgKyBib25lLndvcmxkWCkgKiB3ZWlnaHQ7XG5cdFx0XHRcdFx0d3kgKz0gKHZ4ICogYm9uZS5tMTAgKyB2eSAqIGJvbmUubTExICsgYm9uZS53b3JsZFkpICogd2VpZ2h0O1xuXHRcdFx0XHR9XG5cdFx0XHRcdHdvcmxkVmVydGljZXNbd10gPSB3eCArIHg7XG5cdFx0XHRcdHdvcmxkVmVydGljZXNbdyArIDFdID0gd3kgKyB5O1xuXHRcdFx0fVxuXHRcdH1cblx0fVxufTtcblxuc3BpbmUuQm91bmRpbmdCb3hBdHRhY2htZW50ID0gZnVuY3Rpb24gKG5hbWUpIHtcblx0dGhpcy5uYW1lID0gbmFtZTtcblx0dGhpcy52ZXJ0aWNlcyA9IFtdO1xufTtcbnNwaW5lLkJvdW5kaW5nQm94QXR0YWNobWVudC5wcm90b3R5cGUgPSB7XG5cdHR5cGU6IHNwaW5lLkF0dGFjaG1lbnRUeXBlLmJvdW5kaW5nYm94LFxuXHRjb21wdXRlV29ybGRWZXJ0aWNlczogZnVuY3Rpb24gKHgsIHksIGJvbmUsIHdvcmxkVmVydGljZXMpIHtcblx0XHR4ICs9IGJvbmUud29ybGRYO1xuXHRcdHkgKz0gYm9uZS53b3JsZFk7XG5cdFx0dmFyIG0wMCA9IGJvbmUubTAwLCBtMDEgPSBib25lLm0wMSwgbTEwID0gYm9uZS5tMTAsIG0xMSA9IGJvbmUubTExO1xuXHRcdHZhciB2ZXJ0aWNlcyA9IHRoaXMudmVydGljZXM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSB2ZXJ0aWNlcy5sZW5ndGg7IGkgPCBuOyBpICs9IDIpIHtcblx0XHRcdHZhciBweCA9IHZlcnRpY2VzW2ldO1xuXHRcdFx0dmFyIHB5ID0gdmVydGljZXNbaSArIDFdO1xuXHRcdFx0d29ybGRWZXJ0aWNlc1tpXSA9IHB4ICogbTAwICsgcHkgKiBtMDEgKyB4O1xuXHRcdFx0d29ybGRWZXJ0aWNlc1tpICsgMV0gPSBweCAqIG0xMCArIHB5ICogbTExICsgeTtcblx0XHR9XG5cdH1cbn07XG5cbnNwaW5lLkFuaW1hdGlvblN0YXRlRGF0YSA9IGZ1bmN0aW9uIChza2VsZXRvbkRhdGEpIHtcblx0dGhpcy5za2VsZXRvbkRhdGEgPSBza2VsZXRvbkRhdGE7XG5cdHRoaXMuYW5pbWF0aW9uVG9NaXhUaW1lID0ge307XG59O1xuc3BpbmUuQW5pbWF0aW9uU3RhdGVEYXRhLnByb3RvdHlwZSA9IHtcblx0ZGVmYXVsdE1peDogMCxcblx0c2V0TWl4QnlOYW1lOiBmdW5jdGlvbiAoZnJvbU5hbWUsIHRvTmFtZSwgZHVyYXRpb24pIHtcblx0XHR2YXIgZnJvbSA9IHRoaXMuc2tlbGV0b25EYXRhLmZpbmRBbmltYXRpb24oZnJvbU5hbWUpO1xuXHRcdGlmICghZnJvbSkgdGhyb3cgXCJBbmltYXRpb24gbm90IGZvdW5kOiBcIiArIGZyb21OYW1lO1xuXHRcdHZhciB0byA9IHRoaXMuc2tlbGV0b25EYXRhLmZpbmRBbmltYXRpb24odG9OYW1lKTtcblx0XHRpZiAoIXRvKSB0aHJvdyBcIkFuaW1hdGlvbiBub3QgZm91bmQ6IFwiICsgdG9OYW1lO1xuXHRcdHRoaXMuc2V0TWl4KGZyb20sIHRvLCBkdXJhdGlvbik7XG5cdH0sXG5cdHNldE1peDogZnVuY3Rpb24gKGZyb20sIHRvLCBkdXJhdGlvbikge1xuXHRcdHRoaXMuYW5pbWF0aW9uVG9NaXhUaW1lW2Zyb20ubmFtZSArIFwiOlwiICsgdG8ubmFtZV0gPSBkdXJhdGlvbjtcblx0fSxcblx0Z2V0TWl4OiBmdW5jdGlvbiAoZnJvbSwgdG8pIHtcblx0XHR2YXIga2V5ID0gZnJvbS5uYW1lICsgXCI6XCIgKyB0by5uYW1lO1xuXHRcdHJldHVybiB0aGlzLmFuaW1hdGlvblRvTWl4VGltZS5oYXNPd25Qcm9wZXJ0eShrZXkpID8gdGhpcy5hbmltYXRpb25Ub01peFRpbWVba2V5XSA6IHRoaXMuZGVmYXVsdE1peDtcblx0fVxufTtcblxuc3BpbmUuVHJhY2tFbnRyeSA9IGZ1bmN0aW9uICgpIHt9O1xuc3BpbmUuVHJhY2tFbnRyeS5wcm90b3R5cGUgPSB7XG5cdG5leHQ6IG51bGwsIHByZXZpb3VzOiBudWxsLFxuXHRhbmltYXRpb246IG51bGwsXG5cdGxvb3A6IGZhbHNlLFxuXHRkZWxheTogMCwgdGltZTogMCwgbGFzdFRpbWU6IC0xLCBlbmRUaW1lOiAwLFxuXHR0aW1lU2NhbGU6IDEsXG5cdG1peFRpbWU6IDAsIG1peER1cmF0aW9uOiAwLCBtaXg6IDEsXG5cdG9uU3RhcnQ6IG51bGwsIG9uRW5kOiBudWxsLCBvbkNvbXBsZXRlOiBudWxsLCBvbkV2ZW50OiBudWxsXG59O1xuXG5zcGluZS5BbmltYXRpb25TdGF0ZSA9IGZ1bmN0aW9uIChzdGF0ZURhdGEpIHtcblx0dGhpcy5kYXRhID0gc3RhdGVEYXRhO1xuXHR0aGlzLnRyYWNrcyA9IFtdO1xuXHR0aGlzLmV2ZW50cyA9IFtdO1xufTtcbnNwaW5lLkFuaW1hdGlvblN0YXRlLnByb3RvdHlwZSA9IHtcblx0b25TdGFydDogbnVsbCxcblx0b25FbmQ6IG51bGwsXG5cdG9uQ29tcGxldGU6IG51bGwsXG5cdG9uRXZlbnQ6IG51bGwsXG5cdHRpbWVTY2FsZTogMSxcblx0dXBkYXRlOiBmdW5jdGlvbiAoZGVsdGEpIHtcblx0XHRkZWx0YSAqPSB0aGlzLnRpbWVTY2FsZTtcblx0XHRmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMudHJhY2tzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHR2YXIgY3VycmVudCA9IHRoaXMudHJhY2tzW2ldO1xuXHRcdFx0aWYgKCFjdXJyZW50KSBjb250aW51ZTtcblxuXHRcdFx0Y3VycmVudC50aW1lICs9IGRlbHRhICogY3VycmVudC50aW1lU2NhbGU7XG5cdFx0XHRpZiAoY3VycmVudC5wcmV2aW91cykge1xuXHRcdFx0XHR2YXIgcHJldmlvdXNEZWx0YSA9IGRlbHRhICogY3VycmVudC5wcmV2aW91cy50aW1lU2NhbGU7XG5cdFx0XHRcdGN1cnJlbnQucHJldmlvdXMudGltZSArPSBwcmV2aW91c0RlbHRhO1xuXHRcdFx0XHRjdXJyZW50Lm1peFRpbWUgKz0gcHJldmlvdXNEZWx0YTtcblx0XHRcdH1cblxuXHRcdFx0dmFyIG5leHQgPSBjdXJyZW50Lm5leHQ7XG5cdFx0XHRpZiAobmV4dCkge1xuXHRcdFx0XHRuZXh0LnRpbWUgPSBjdXJyZW50Lmxhc3RUaW1lIC0gbmV4dC5kZWxheTtcblx0XHRcdFx0aWYgKG5leHQudGltZSA+PSAwKSB0aGlzLnNldEN1cnJlbnQoaSwgbmV4dCk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHQvLyBFbmQgbm9uLWxvb3BpbmcgYW5pbWF0aW9uIHdoZW4gaXQgcmVhY2hlcyBpdHMgZW5kIHRpbWUgYW5kIHRoZXJlIGlzIG5vIG5leHQgZW50cnkuXG5cdFx0XHRcdGlmICghY3VycmVudC5sb29wICYmIGN1cnJlbnQubGFzdFRpbWUgPj0gY3VycmVudC5lbmRUaW1lKSB0aGlzLmNsZWFyVHJhY2soaSk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXHRhcHBseTogZnVuY3Rpb24gKHNrZWxldG9uKSB7XG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnRyYWNrcy5sZW5ndGg7IGkrKykge1xuXHRcdFx0dmFyIGN1cnJlbnQgPSB0aGlzLnRyYWNrc1tpXTtcblx0XHRcdGlmICghY3VycmVudCkgY29udGludWU7XG5cblx0XHRcdHRoaXMuZXZlbnRzLmxlbmd0aCA9IDA7XG5cblx0XHRcdHZhciB0aW1lID0gY3VycmVudC50aW1lO1xuXHRcdFx0dmFyIGxhc3RUaW1lID0gY3VycmVudC5sYXN0VGltZTtcblx0XHRcdHZhciBlbmRUaW1lID0gY3VycmVudC5lbmRUaW1lO1xuXHRcdFx0dmFyIGxvb3AgPSBjdXJyZW50Lmxvb3A7XG5cdFx0XHRpZiAoIWxvb3AgJiYgdGltZSA+IGVuZFRpbWUpIHRpbWUgPSBlbmRUaW1lO1xuXG5cdFx0XHR2YXIgcHJldmlvdXMgPSBjdXJyZW50LnByZXZpb3VzO1xuXHRcdFx0aWYgKCFwcmV2aW91cykge1xuXHRcdFx0XHRpZiAoY3VycmVudC5taXggPT0gMSlcblx0XHRcdFx0XHRjdXJyZW50LmFuaW1hdGlvbi5hcHBseShza2VsZXRvbiwgY3VycmVudC5sYXN0VGltZSwgdGltZSwgbG9vcCwgdGhpcy5ldmVudHMpO1xuXHRcdFx0XHRlbHNlXG5cdFx0XHRcdFx0Y3VycmVudC5hbmltYXRpb24ubWl4KHNrZWxldG9uLCBjdXJyZW50Lmxhc3RUaW1lLCB0aW1lLCBsb29wLCB0aGlzLmV2ZW50cywgY3VycmVudC5taXgpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dmFyIHByZXZpb3VzVGltZSA9IHByZXZpb3VzLnRpbWU7XG5cdFx0XHRcdGlmICghcHJldmlvdXMubG9vcCAmJiBwcmV2aW91c1RpbWUgPiBwcmV2aW91cy5lbmRUaW1lKSBwcmV2aW91c1RpbWUgPSBwcmV2aW91cy5lbmRUaW1lO1xuXHRcdFx0XHRwcmV2aW91cy5hbmltYXRpb24uYXBwbHkoc2tlbGV0b24sIHByZXZpb3VzVGltZSwgcHJldmlvdXNUaW1lLCBwcmV2aW91cy5sb29wLCBudWxsKTtcblxuXHRcdFx0XHR2YXIgYWxwaGEgPSBjdXJyZW50Lm1peFRpbWUgLyBjdXJyZW50Lm1peER1cmF0aW9uICogY3VycmVudC5taXg7XG5cdFx0XHRcdGlmIChhbHBoYSA+PSAxKSB7XG5cdFx0XHRcdFx0YWxwaGEgPSAxO1xuXHRcdFx0XHRcdGN1cnJlbnQucHJldmlvdXMgPSBudWxsO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGN1cnJlbnQuYW5pbWF0aW9uLm1peChza2VsZXRvbiwgY3VycmVudC5sYXN0VGltZSwgdGltZSwgbG9vcCwgdGhpcy5ldmVudHMsIGFscGhhKTtcblx0XHRcdH1cblxuXHRcdFx0Zm9yICh2YXIgaWkgPSAwLCBubiA9IHRoaXMuZXZlbnRzLmxlbmd0aDsgaWkgPCBubjsgaWkrKykge1xuXHRcdFx0XHR2YXIgZXZlbnQgPSB0aGlzLmV2ZW50c1tpaV07XG5cdFx0XHRcdGlmIChjdXJyZW50Lm9uRXZlbnQpIGN1cnJlbnQub25FdmVudChpLCBldmVudCk7XG5cdFx0XHRcdGlmICh0aGlzLm9uRXZlbnQpIHRoaXMub25FdmVudChpLCBldmVudCk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIENoZWNrIGlmIGNvbXBsZXRlZCB0aGUgYW5pbWF0aW9uIG9yIGEgbG9vcCBpdGVyYXRpb24uXG5cdFx0XHRpZiAobG9vcCA/IChsYXN0VGltZSAlIGVuZFRpbWUgPiB0aW1lICUgZW5kVGltZSkgOiAobGFzdFRpbWUgPCBlbmRUaW1lICYmIHRpbWUgPj0gZW5kVGltZSkpIHtcblx0XHRcdFx0dmFyIGNvdW50ID0gTWF0aC5mbG9vcih0aW1lIC8gZW5kVGltZSk7XG5cdFx0XHRcdGlmIChjdXJyZW50Lm9uQ29tcGxldGUpIGN1cnJlbnQub25Db21wbGV0ZShpLCBjb3VudCk7XG5cdFx0XHRcdGlmICh0aGlzLm9uQ29tcGxldGUpIHRoaXMub25Db21wbGV0ZShpLCBjb3VudCk7XG5cdFx0XHR9XG5cblx0XHRcdGN1cnJlbnQubGFzdFRpbWUgPSBjdXJyZW50LnRpbWU7XG5cdFx0fVxuXHR9LFxuXHRjbGVhclRyYWNrczogZnVuY3Rpb24gKCkge1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gdGhpcy50cmFja3MubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0dGhpcy5jbGVhclRyYWNrKGkpO1xuXHRcdHRoaXMudHJhY2tzLmxlbmd0aCA9IDA7XG5cdH0sXG5cdGNsZWFyVHJhY2s6IGZ1bmN0aW9uICh0cmFja0luZGV4KSB7XG5cdFx0aWYgKHRyYWNrSW5kZXggPj0gdGhpcy50cmFja3MubGVuZ3RoKSByZXR1cm47XG5cdFx0dmFyIGN1cnJlbnQgPSB0aGlzLnRyYWNrc1t0cmFja0luZGV4XTtcblx0XHRpZiAoIWN1cnJlbnQpIHJldHVybjtcblxuXHRcdGlmIChjdXJyZW50Lm9uRW5kKSBjdXJyZW50Lm9uRW5kKHRyYWNrSW5kZXgpO1xuXHRcdGlmICh0aGlzLm9uRW5kKSB0aGlzLm9uRW5kKHRyYWNrSW5kZXgpO1xuXG5cdFx0dGhpcy50cmFja3NbdHJhY2tJbmRleF0gPSBudWxsO1xuXHR9LFxuXHRfZXhwYW5kVG9JbmRleDogZnVuY3Rpb24gKGluZGV4KSB7XG5cdFx0aWYgKGluZGV4IDwgdGhpcy50cmFja3MubGVuZ3RoKSByZXR1cm4gdGhpcy50cmFja3NbaW5kZXhdO1xuXHRcdHdoaWxlIChpbmRleCA+PSB0aGlzLnRyYWNrcy5sZW5ndGgpXG5cdFx0XHR0aGlzLnRyYWNrcy5wdXNoKG51bGwpO1xuXHRcdHJldHVybiBudWxsO1xuXHR9LFxuXHRzZXRDdXJyZW50OiBmdW5jdGlvbiAoaW5kZXgsIGVudHJ5KSB7XG5cdFx0dmFyIGN1cnJlbnQgPSB0aGlzLl9leHBhbmRUb0luZGV4KGluZGV4KTtcblx0XHRpZiAoY3VycmVudCkge1xuXHRcdFx0dmFyIHByZXZpb3VzID0gY3VycmVudC5wcmV2aW91cztcblx0XHRcdGN1cnJlbnQucHJldmlvdXMgPSBudWxsO1xuXG5cdFx0XHRpZiAoY3VycmVudC5vbkVuZCkgY3VycmVudC5vbkVuZChpbmRleCk7XG5cdFx0XHRpZiAodGhpcy5vbkVuZCkgdGhpcy5vbkVuZChpbmRleCk7XG5cblx0XHRcdGVudHJ5Lm1peER1cmF0aW9uID0gdGhpcy5kYXRhLmdldE1peChjdXJyZW50LmFuaW1hdGlvbiwgZW50cnkuYW5pbWF0aW9uKTtcblx0XHRcdGlmIChlbnRyeS5taXhEdXJhdGlvbiA+IDApIHtcblx0XHRcdFx0ZW50cnkubWl4VGltZSA9IDA7XG5cdFx0XHRcdC8vIElmIGEgbWl4IGlzIGluIHByb2dyZXNzLCBtaXggZnJvbSB0aGUgY2xvc2VzdCBhbmltYXRpb24uXG5cdFx0XHRcdGlmIChwcmV2aW91cyAmJiBjdXJyZW50Lm1peFRpbWUgLyBjdXJyZW50Lm1peER1cmF0aW9uIDwgMC41KVxuXHRcdFx0XHRcdGVudHJ5LnByZXZpb3VzID0gcHJldmlvdXM7XG5cdFx0XHRcdGVsc2Vcblx0XHRcdFx0XHRlbnRyeS5wcmV2aW91cyA9IGN1cnJlbnQ7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy50cmFja3NbaW5kZXhdID0gZW50cnk7XG5cblx0XHRpZiAoZW50cnkub25TdGFydCkgZW50cnkub25TdGFydChpbmRleCk7XG5cdFx0aWYgKHRoaXMub25TdGFydCkgdGhpcy5vblN0YXJ0KGluZGV4KTtcblx0fSxcblx0c2V0QW5pbWF0aW9uQnlOYW1lOiBmdW5jdGlvbiAodHJhY2tJbmRleCwgYW5pbWF0aW9uTmFtZSwgbG9vcCkge1xuXHRcdHZhciBhbmltYXRpb24gPSB0aGlzLmRhdGEuc2tlbGV0b25EYXRhLmZpbmRBbmltYXRpb24oYW5pbWF0aW9uTmFtZSk7XG5cdFx0aWYgKCFhbmltYXRpb24pIHRocm93IFwiQW5pbWF0aW9uIG5vdCBmb3VuZDogXCIgKyBhbmltYXRpb25OYW1lO1xuXHRcdHJldHVybiB0aGlzLnNldEFuaW1hdGlvbih0cmFja0luZGV4LCBhbmltYXRpb24sIGxvb3ApO1xuXHR9LFxuXHQvKiogU2V0IHRoZSBjdXJyZW50IGFuaW1hdGlvbi4gQW55IHF1ZXVlZCBhbmltYXRpb25zIGFyZSBjbGVhcmVkLiAqL1xuXHRzZXRBbmltYXRpb246IGZ1bmN0aW9uICh0cmFja0luZGV4LCBhbmltYXRpb24sIGxvb3ApIHtcblx0XHR2YXIgZW50cnkgPSBuZXcgc3BpbmUuVHJhY2tFbnRyeSgpO1xuXHRcdGVudHJ5LmFuaW1hdGlvbiA9IGFuaW1hdGlvbjtcblx0XHRlbnRyeS5sb29wID0gbG9vcDtcblx0XHRlbnRyeS5lbmRUaW1lID0gYW5pbWF0aW9uLmR1cmF0aW9uO1xuXHRcdHRoaXMuc2V0Q3VycmVudCh0cmFja0luZGV4LCBlbnRyeSk7XG5cdFx0cmV0dXJuIGVudHJ5O1xuXHR9LFxuXHRhZGRBbmltYXRpb25CeU5hbWU6IGZ1bmN0aW9uICh0cmFja0luZGV4LCBhbmltYXRpb25OYW1lLCBsb29wLCBkZWxheSkge1xuXHRcdHZhciBhbmltYXRpb24gPSB0aGlzLmRhdGEuc2tlbGV0b25EYXRhLmZpbmRBbmltYXRpb24oYW5pbWF0aW9uTmFtZSk7XG5cdFx0aWYgKCFhbmltYXRpb24pIHRocm93IFwiQW5pbWF0aW9uIG5vdCBmb3VuZDogXCIgKyBhbmltYXRpb25OYW1lO1xuXHRcdHJldHVybiB0aGlzLmFkZEFuaW1hdGlvbih0cmFja0luZGV4LCBhbmltYXRpb24sIGxvb3AsIGRlbGF5KTtcblx0fSxcblx0LyoqIEFkZHMgYW4gYW5pbWF0aW9uIHRvIGJlIHBsYXllZCBkZWxheSBzZWNvbmRzIGFmdGVyIHRoZSBjdXJyZW50IG9yIGxhc3QgcXVldWVkIGFuaW1hdGlvbi5cblx0ICogQHBhcmFtIGRlbGF5IE1heSBiZSA8PSAwIHRvIHVzZSBkdXJhdGlvbiBvZiBwcmV2aW91cyBhbmltYXRpb24gbWludXMgYW55IG1peCBkdXJhdGlvbiBwbHVzIHRoZSBuZWdhdGl2ZSBkZWxheS4gKi9cblx0YWRkQW5pbWF0aW9uOiBmdW5jdGlvbiAodHJhY2tJbmRleCwgYW5pbWF0aW9uLCBsb29wLCBkZWxheSkge1xuXHRcdHZhciBlbnRyeSA9IG5ldyBzcGluZS5UcmFja0VudHJ5KCk7XG5cdFx0ZW50cnkuYW5pbWF0aW9uID0gYW5pbWF0aW9uO1xuXHRcdGVudHJ5Lmxvb3AgPSBsb29wO1xuXHRcdGVudHJ5LmVuZFRpbWUgPSBhbmltYXRpb24uZHVyYXRpb247XG5cblx0XHR2YXIgbGFzdCA9IHRoaXMuX2V4cGFuZFRvSW5kZXgodHJhY2tJbmRleCk7XG5cdFx0aWYgKGxhc3QpIHtcblx0XHRcdHdoaWxlIChsYXN0Lm5leHQpXG5cdFx0XHRcdGxhc3QgPSBsYXN0Lm5leHQ7XG5cdFx0XHRsYXN0Lm5leHQgPSBlbnRyeTtcblx0XHR9IGVsc2Vcblx0XHRcdHRoaXMudHJhY2tzW3RyYWNrSW5kZXhdID0gZW50cnk7XG5cblx0XHRpZiAoZGVsYXkgPD0gMCkge1xuXHRcdFx0aWYgKGxhc3QpXG5cdFx0XHRcdGRlbGF5ICs9IGxhc3QuZW5kVGltZSAtIHRoaXMuZGF0YS5nZXRNaXgobGFzdC5hbmltYXRpb24sIGFuaW1hdGlvbik7XG5cdFx0XHRlbHNlXG5cdFx0XHRcdGRlbGF5ID0gMDtcblx0XHR9XG5cdFx0ZW50cnkuZGVsYXkgPSBkZWxheTtcblxuXHRcdHJldHVybiBlbnRyeTtcblx0fSxcblx0LyoqIE1heSBiZSBudWxsLiAqL1xuXHRnZXRDdXJyZW50OiBmdW5jdGlvbiAodHJhY2tJbmRleCkge1xuXHRcdGlmICh0cmFja0luZGV4ID49IHRoaXMudHJhY2tzLmxlbmd0aCkgcmV0dXJuIG51bGw7XG5cdFx0cmV0dXJuIHRoaXMudHJhY2tzW3RyYWNrSW5kZXhdO1xuXHR9XG59O1xuXG5zcGluZS5Ta2VsZXRvbkpzb24gPSBmdW5jdGlvbiAoYXR0YWNobWVudExvYWRlcikge1xuXHR0aGlzLmF0dGFjaG1lbnRMb2FkZXIgPSBhdHRhY2htZW50TG9hZGVyO1xufTtcbnNwaW5lLlNrZWxldG9uSnNvbi5wcm90b3R5cGUgPSB7XG5cdHNjYWxlOiAxLFxuXHRyZWFkU2tlbGV0b25EYXRhOiBmdW5jdGlvbiAocm9vdCwgbmFtZSkge1xuXHRcdHZhciBza2VsZXRvbkRhdGEgPSBuZXcgc3BpbmUuU2tlbGV0b25EYXRhKCk7XG5cdFx0c2tlbGV0b25EYXRhLm5hbWUgPSBuYW1lO1xuXG5cdFx0Ly8gU2tlbGV0b24uXG5cdFx0dmFyIHNrZWxldG9uTWFwID0gcm9vdFtcInNrZWxldG9uXCJdO1xuXHRcdGlmIChza2VsZXRvbk1hcCkge1xuXHRcdFx0c2tlbGV0b25EYXRhLmhhc2ggPSBza2VsZXRvbk1hcFtcImhhc2hcIl07XG5cdFx0XHRza2VsZXRvbkRhdGEudmVyc2lvbiA9IHNrZWxldG9uTWFwW1wic3BpbmVcIl07XG5cdFx0XHRza2VsZXRvbkRhdGEud2lkdGggPSBza2VsZXRvbk1hcFtcIndpZHRoXCJdIHx8IDA7XG5cdFx0XHRza2VsZXRvbkRhdGEuaGVpZ2h0ID0gc2tlbGV0b25NYXBbXCJoZWlnaHRcIl0gfHwgMDtcblx0XHR9XG5cblx0XHQvLyBCb25lcy5cblx0XHR2YXIgYm9uZXMgPSByb290W1wiYm9uZXNcIl07XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBib25lcy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcblx0XHRcdHZhciBib25lTWFwID0gYm9uZXNbaV07XG5cdFx0XHR2YXIgcGFyZW50ID0gbnVsbDtcblx0XHRcdGlmIChib25lTWFwW1wicGFyZW50XCJdKSB7XG5cdFx0XHRcdHBhcmVudCA9IHNrZWxldG9uRGF0YS5maW5kQm9uZShib25lTWFwW1wicGFyZW50XCJdKTtcblx0XHRcdFx0aWYgKCFwYXJlbnQpIHRocm93IFwiUGFyZW50IGJvbmUgbm90IGZvdW5kOiBcIiArIGJvbmVNYXBbXCJwYXJlbnRcIl07XG5cdFx0XHR9XG5cdFx0XHR2YXIgYm9uZURhdGEgPSBuZXcgc3BpbmUuQm9uZURhdGEoYm9uZU1hcFtcIm5hbWVcIl0sIHBhcmVudCk7XG5cdFx0XHRib25lRGF0YS5sZW5ndGggPSAoYm9uZU1hcFtcImxlbmd0aFwiXSB8fCAwKSAqIHRoaXMuc2NhbGU7XG5cdFx0XHRib25lRGF0YS54ID0gKGJvbmVNYXBbXCJ4XCJdIHx8IDApICogdGhpcy5zY2FsZTtcblx0XHRcdGJvbmVEYXRhLnkgPSAoYm9uZU1hcFtcInlcIl0gfHwgMCkgKiB0aGlzLnNjYWxlO1xuXHRcdFx0Ym9uZURhdGEucm90YXRpb24gPSAoYm9uZU1hcFtcInJvdGF0aW9uXCJdIHx8IDApO1xuXHRcdFx0Ym9uZURhdGEuc2NhbGVYID0gYm9uZU1hcC5oYXNPd25Qcm9wZXJ0eShcInNjYWxlWFwiKSA/IGJvbmVNYXBbXCJzY2FsZVhcIl0gOiAxO1xuXHRcdFx0Ym9uZURhdGEuc2NhbGVZID0gYm9uZU1hcC5oYXNPd25Qcm9wZXJ0eShcInNjYWxlWVwiKSA/IGJvbmVNYXBbXCJzY2FsZVlcIl0gOiAxO1xuXHRcdFx0Ym9uZURhdGEuaW5oZXJpdFNjYWxlID0gYm9uZU1hcC5oYXNPd25Qcm9wZXJ0eShcImluaGVyaXRTY2FsZVwiKSA/IGJvbmVNYXBbXCJpbmhlcml0U2NhbGVcIl0gOiB0cnVlO1xuXHRcdFx0Ym9uZURhdGEuaW5oZXJpdFJvdGF0aW9uID0gYm9uZU1hcC5oYXNPd25Qcm9wZXJ0eShcImluaGVyaXRSb3RhdGlvblwiKSA/IGJvbmVNYXBbXCJpbmhlcml0Um90YXRpb25cIl0gOiB0cnVlO1xuXHRcdFx0c2tlbGV0b25EYXRhLmJvbmVzLnB1c2goYm9uZURhdGEpO1xuXHRcdH1cblxuXHRcdC8vIElLIGNvbnN0cmFpbnRzLlxuXHRcdHZhciBpayA9IHJvb3RbXCJpa1wiXTtcblx0XHRpZiAoaWspIHtcblx0XHRcdGZvciAodmFyIGkgPSAwLCBuID0gaWsubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRcdHZhciBpa01hcCA9IGlrW2ldO1xuXHRcdFx0XHR2YXIgaWtDb25zdHJhaW50RGF0YSA9IG5ldyBzcGluZS5Ja0NvbnN0cmFpbnREYXRhKGlrTWFwW1wibmFtZVwiXSk7XG5cblx0XHRcdFx0dmFyIGJvbmVzID0gaWtNYXBbXCJib25lc1wiXTtcblx0XHRcdFx0Zm9yICh2YXIgaWkgPSAwLCBubiA9IGJvbmVzLmxlbmd0aDsgaWkgPCBubjsgaWkrKykge1xuXHRcdFx0XHRcdHZhciBib25lID0gc2tlbGV0b25EYXRhLmZpbmRCb25lKGJvbmVzW2lpXSk7XG5cdFx0XHRcdFx0aWYgKCFib25lKSB0aHJvdyBcIklLIGJvbmUgbm90IGZvdW5kOiBcIiArIGJvbmVzW2lpXTtcblx0XHRcdFx0XHRpa0NvbnN0cmFpbnREYXRhLmJvbmVzLnB1c2goYm9uZSk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpa0NvbnN0cmFpbnREYXRhLnRhcmdldCA9IHNrZWxldG9uRGF0YS5maW5kQm9uZShpa01hcFtcInRhcmdldFwiXSk7XG5cdFx0XHRcdGlmICghaWtDb25zdHJhaW50RGF0YS50YXJnZXQpIHRocm93IFwiVGFyZ2V0IGJvbmUgbm90IGZvdW5kOiBcIiArIGlrTWFwW1widGFyZ2V0XCJdO1xuXG5cdFx0XHRcdGlrQ29uc3RyYWludERhdGEuYmVuZERpcmVjdGlvbiA9ICghaWtNYXAuaGFzT3duUHJvcGVydHkoXCJiZW5kUG9zaXRpdmVcIikgfHwgaWtNYXBbXCJiZW5kUG9zaXRpdmVcIl0pID8gMSA6IC0xO1xuXHRcdFx0XHRpa0NvbnN0cmFpbnREYXRhLm1peCA9IGlrTWFwLmhhc093blByb3BlcnR5KFwibWl4XCIpID8gaWtNYXBbXCJtaXhcIl0gOiAxO1xuXG5cdFx0XHRcdHNrZWxldG9uRGF0YS5pa0NvbnN0cmFpbnRzLnB1c2goaWtDb25zdHJhaW50RGF0YSk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gU2xvdHMuXG5cdFx0dmFyIHNsb3RzID0gcm9vdFtcInNsb3RzXCJdO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gc2xvdHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHR2YXIgc2xvdE1hcCA9IHNsb3RzW2ldO1xuXHRcdFx0dmFyIGJvbmVEYXRhID0gc2tlbGV0b25EYXRhLmZpbmRCb25lKHNsb3RNYXBbXCJib25lXCJdKTtcblx0XHRcdGlmICghYm9uZURhdGEpIHRocm93IFwiU2xvdCBib25lIG5vdCBmb3VuZDogXCIgKyBzbG90TWFwW1wiYm9uZVwiXTtcblx0XHRcdHZhciBzbG90RGF0YSA9IG5ldyBzcGluZS5TbG90RGF0YShzbG90TWFwW1wibmFtZVwiXSwgYm9uZURhdGEpO1xuXG5cdFx0XHR2YXIgY29sb3IgPSBzbG90TWFwW1wiY29sb3JcIl07XG5cdFx0XHRpZiAoY29sb3IpIHtcblx0XHRcdFx0c2xvdERhdGEuciA9IHRoaXMudG9Db2xvcihjb2xvciwgMCk7XG5cdFx0XHRcdHNsb3REYXRhLmcgPSB0aGlzLnRvQ29sb3IoY29sb3IsIDEpO1xuXHRcdFx0XHRzbG90RGF0YS5iID0gdGhpcy50b0NvbG9yKGNvbG9yLCAyKTtcblx0XHRcdFx0c2xvdERhdGEuYSA9IHRoaXMudG9Db2xvcihjb2xvciwgMyk7XG5cdFx0XHR9XG5cblx0XHRcdHNsb3REYXRhLmF0dGFjaG1lbnROYW1lID0gc2xvdE1hcFtcImF0dGFjaG1lbnRcIl07XG5cdFx0XHRzbG90RGF0YS5hZGRpdGl2ZUJsZW5kaW5nID0gc2xvdE1hcFtcImFkZGl0aXZlXCJdICYmIHNsb3RNYXBbXCJhZGRpdGl2ZVwiXSA9PSBcInRydWVcIjtcblxuXHRcdFx0c2tlbGV0b25EYXRhLnNsb3RzLnB1c2goc2xvdERhdGEpO1xuXHRcdH1cblxuXHRcdC8vIFNraW5zLlxuXHRcdHZhciBza2lucyA9IHJvb3RbXCJza2luc1wiXTtcblx0XHRmb3IgKHZhciBza2luTmFtZSBpbiBza2lucykge1xuXHRcdFx0aWYgKCFza2lucy5oYXNPd25Qcm9wZXJ0eShza2luTmFtZSkpIGNvbnRpbnVlO1xuXHRcdFx0dmFyIHNraW5NYXAgPSBza2luc1tza2luTmFtZV07XG5cdFx0XHR2YXIgc2tpbiA9IG5ldyBzcGluZS5Ta2luKHNraW5OYW1lKTtcblx0XHRcdGZvciAodmFyIHNsb3ROYW1lIGluIHNraW5NYXApIHtcblx0XHRcdFx0aWYgKCFza2luTWFwLmhhc093blByb3BlcnR5KHNsb3ROYW1lKSkgY29udGludWU7XG5cdFx0XHRcdHZhciBzbG90SW5kZXggPSBza2VsZXRvbkRhdGEuZmluZFNsb3RJbmRleChzbG90TmFtZSk7XG5cdFx0XHRcdHZhciBzbG90RW50cnkgPSBza2luTWFwW3Nsb3ROYW1lXTtcblx0XHRcdFx0Zm9yICh2YXIgYXR0YWNobWVudE5hbWUgaW4gc2xvdEVudHJ5KSB7XG5cdFx0XHRcdFx0aWYgKCFzbG90RW50cnkuaGFzT3duUHJvcGVydHkoYXR0YWNobWVudE5hbWUpKSBjb250aW51ZTtcblx0XHRcdFx0XHR2YXIgYXR0YWNobWVudCA9IHRoaXMucmVhZEF0dGFjaG1lbnQoc2tpbiwgYXR0YWNobWVudE5hbWUsIHNsb3RFbnRyeVthdHRhY2htZW50TmFtZV0pO1xuXHRcdFx0XHRcdGlmIChhdHRhY2htZW50KSBza2luLmFkZEF0dGFjaG1lbnQoc2xvdEluZGV4LCBhdHRhY2htZW50TmFtZSwgYXR0YWNobWVudCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHNrZWxldG9uRGF0YS5za2lucy5wdXNoKHNraW4pO1xuXHRcdFx0aWYgKHNraW4ubmFtZSA9PSBcImRlZmF1bHRcIikgc2tlbGV0b25EYXRhLmRlZmF1bHRTa2luID0gc2tpbjtcblx0XHR9XG5cblx0XHQvLyBFdmVudHMuXG5cdFx0dmFyIGV2ZW50cyA9IHJvb3RbXCJldmVudHNcIl07XG5cdFx0Zm9yICh2YXIgZXZlbnROYW1lIGluIGV2ZW50cykge1xuXHRcdFx0aWYgKCFldmVudHMuaGFzT3duUHJvcGVydHkoZXZlbnROYW1lKSkgY29udGludWU7XG5cdFx0XHR2YXIgZXZlbnRNYXAgPSBldmVudHNbZXZlbnROYW1lXTtcblx0XHRcdHZhciBldmVudERhdGEgPSBuZXcgc3BpbmUuRXZlbnREYXRhKGV2ZW50TmFtZSk7XG5cdFx0XHRldmVudERhdGEuaW50VmFsdWUgPSBldmVudE1hcFtcImludFwiXSB8fCAwO1xuXHRcdFx0ZXZlbnREYXRhLmZsb2F0VmFsdWUgPSBldmVudE1hcFtcImZsb2F0XCJdIHx8IDA7XG5cdFx0XHRldmVudERhdGEuc3RyaW5nVmFsdWUgPSBldmVudE1hcFtcInN0cmluZ1wiXSB8fCBudWxsO1xuXHRcdFx0c2tlbGV0b25EYXRhLmV2ZW50cy5wdXNoKGV2ZW50RGF0YSk7XG5cdFx0fVxuXG5cdFx0Ly8gQW5pbWF0aW9ucy5cblx0XHR2YXIgYW5pbWF0aW9ucyA9IHJvb3RbXCJhbmltYXRpb25zXCJdO1xuXHRcdGZvciAodmFyIGFuaW1hdGlvbk5hbWUgaW4gYW5pbWF0aW9ucykge1xuXHRcdFx0aWYgKCFhbmltYXRpb25zLmhhc093blByb3BlcnR5KGFuaW1hdGlvbk5hbWUpKSBjb250aW51ZTtcblx0XHRcdHRoaXMucmVhZEFuaW1hdGlvbihhbmltYXRpb25OYW1lLCBhbmltYXRpb25zW2FuaW1hdGlvbk5hbWVdLCBza2VsZXRvbkRhdGEpO1xuXHRcdH1cblxuXHRcdHJldHVybiBza2VsZXRvbkRhdGE7XG5cdH0sXG5cdHJlYWRBdHRhY2htZW50OiBmdW5jdGlvbiAoc2tpbiwgbmFtZSwgbWFwKSB7XG5cdFx0bmFtZSA9IG1hcFtcIm5hbWVcIl0gfHwgbmFtZTtcblxuXHRcdHZhciB0eXBlID0gc3BpbmUuQXR0YWNobWVudFR5cGVbbWFwW1widHlwZVwiXSB8fCBcInJlZ2lvblwiXTtcblx0XHR2YXIgcGF0aCA9IG1hcFtcInBhdGhcIl0gfHwgbmFtZTtcblxuXHRcdHZhciBzY2FsZSA9IHRoaXMuc2NhbGU7XG5cdFx0aWYgKHR5cGUgPT0gc3BpbmUuQXR0YWNobWVudFR5cGUucmVnaW9uKSB7XG5cdFx0XHR2YXIgcmVnaW9uID0gdGhpcy5hdHRhY2htZW50TG9hZGVyLm5ld1JlZ2lvbkF0dGFjaG1lbnQoc2tpbiwgbmFtZSwgcGF0aCk7XG5cdFx0XHRpZiAoIXJlZ2lvbikgcmV0dXJuIG51bGw7XG5cdFx0XHRyZWdpb24ucGF0aCA9IHBhdGg7XG5cdFx0XHRyZWdpb24ueCA9IChtYXBbXCJ4XCJdIHx8IDApICogc2NhbGU7XG5cdFx0XHRyZWdpb24ueSA9IChtYXBbXCJ5XCJdIHx8IDApICogc2NhbGU7XG5cdFx0XHRyZWdpb24uc2NhbGVYID0gbWFwLmhhc093blByb3BlcnR5KFwic2NhbGVYXCIpID8gbWFwW1wic2NhbGVYXCJdIDogMTtcblx0XHRcdHJlZ2lvbi5zY2FsZVkgPSBtYXAuaGFzT3duUHJvcGVydHkoXCJzY2FsZVlcIikgPyBtYXBbXCJzY2FsZVlcIl0gOiAxO1xuXHRcdFx0cmVnaW9uLnJvdGF0aW9uID0gbWFwW1wicm90YXRpb25cIl0gfHwgMDtcblx0XHRcdHJlZ2lvbi53aWR0aCA9IChtYXBbXCJ3aWR0aFwiXSB8fCAwKSAqIHNjYWxlO1xuXHRcdFx0cmVnaW9uLmhlaWdodCA9IChtYXBbXCJoZWlnaHRcIl0gfHwgMCkgKiBzY2FsZTtcblxuXHRcdFx0dmFyIGNvbG9yID0gbWFwW1wiY29sb3JcIl07XG5cdFx0XHRpZiAoY29sb3IpIHtcblx0XHRcdFx0cmVnaW9uLnIgPSB0aGlzLnRvQ29sb3IoY29sb3IsIDApO1xuXHRcdFx0XHRyZWdpb24uZyA9IHRoaXMudG9Db2xvcihjb2xvciwgMSk7XG5cdFx0XHRcdHJlZ2lvbi5iID0gdGhpcy50b0NvbG9yKGNvbG9yLCAyKTtcblx0XHRcdFx0cmVnaW9uLmEgPSB0aGlzLnRvQ29sb3IoY29sb3IsIDMpO1xuXHRcdFx0fVxuXG5cdFx0XHRyZWdpb24udXBkYXRlT2Zmc2V0KCk7XG5cdFx0XHRyZXR1cm4gcmVnaW9uO1xuXHRcdH0gZWxzZSBpZiAodHlwZSA9PSBzcGluZS5BdHRhY2htZW50VHlwZS5tZXNoKSB7XG5cdFx0XHR2YXIgbWVzaCA9IHRoaXMuYXR0YWNobWVudExvYWRlci5uZXdNZXNoQXR0YWNobWVudChza2luLCBuYW1lLCBwYXRoKTtcblx0XHRcdGlmICghbWVzaCkgcmV0dXJuIG51bGw7XG5cdFx0XHRtZXNoLnBhdGggPSBwYXRoO1xuXHRcdFx0bWVzaC52ZXJ0aWNlcyA9IHRoaXMuZ2V0RmxvYXRBcnJheShtYXAsIFwidmVydGljZXNcIiwgc2NhbGUpO1xuXHRcdFx0bWVzaC50cmlhbmdsZXMgPSB0aGlzLmdldEludEFycmF5KG1hcCwgXCJ0cmlhbmdsZXNcIik7XG5cdFx0XHRtZXNoLnJlZ2lvblVWcyA9IHRoaXMuZ2V0RmxvYXRBcnJheShtYXAsIFwidXZzXCIsIDEpO1xuXHRcdFx0bWVzaC51cGRhdGVVVnMoKTtcblxuXHRcdFx0Y29sb3IgPSBtYXBbXCJjb2xvclwiXTtcblx0XHRcdGlmIChjb2xvcikge1xuXHRcdFx0XHRtZXNoLnIgPSB0aGlzLnRvQ29sb3IoY29sb3IsIDApO1xuXHRcdFx0XHRtZXNoLmcgPSB0aGlzLnRvQ29sb3IoY29sb3IsIDEpO1xuXHRcdFx0XHRtZXNoLmIgPSB0aGlzLnRvQ29sb3IoY29sb3IsIDIpO1xuXHRcdFx0XHRtZXNoLmEgPSB0aGlzLnRvQ29sb3IoY29sb3IsIDMpO1xuXHRcdFx0fVxuXG5cdFx0XHRtZXNoLmh1bGxMZW5ndGggPSAobWFwW1wiaHVsbFwiXSB8fCAwKSAqIDI7XG5cdFx0XHRpZiAobWFwW1wiZWRnZXNcIl0pIG1lc2guZWRnZXMgPSB0aGlzLmdldEludEFycmF5KG1hcCwgXCJlZGdlc1wiKTtcblx0XHRcdG1lc2gud2lkdGggPSAobWFwW1wid2lkdGhcIl0gfHwgMCkgKiBzY2FsZTtcblx0XHRcdG1lc2guaGVpZ2h0ID0gKG1hcFtcImhlaWdodFwiXSB8fCAwKSAqIHNjYWxlO1xuXHRcdFx0cmV0dXJuIG1lc2g7XG5cdFx0fSBlbHNlIGlmICh0eXBlID09IHNwaW5lLkF0dGFjaG1lbnRUeXBlLnNraW5uZWRtZXNoKSB7XG5cdFx0XHR2YXIgbWVzaCA9IHRoaXMuYXR0YWNobWVudExvYWRlci5uZXdTa2lubmVkTWVzaEF0dGFjaG1lbnQoc2tpbiwgbmFtZSwgcGF0aCk7XG5cdFx0XHRpZiAoIW1lc2gpIHJldHVybiBudWxsO1xuXHRcdFx0bWVzaC5wYXRoID0gcGF0aDtcblxuXHRcdFx0dmFyIHV2cyA9IHRoaXMuZ2V0RmxvYXRBcnJheShtYXAsIFwidXZzXCIsIDEpO1xuXHRcdFx0dmFyIHZlcnRpY2VzID0gdGhpcy5nZXRGbG9hdEFycmF5KG1hcCwgXCJ2ZXJ0aWNlc1wiLCAxKTtcblx0XHRcdHZhciB3ZWlnaHRzID0gW107XG5cdFx0XHR2YXIgYm9uZXMgPSBbXTtcblx0XHRcdGZvciAodmFyIGkgPSAwLCBuID0gdmVydGljZXMubGVuZ3RoOyBpIDwgbjsgKSB7XG5cdFx0XHRcdHZhciBib25lQ291bnQgPSB2ZXJ0aWNlc1tpKytdIHwgMDtcblx0XHRcdFx0Ym9uZXNbYm9uZXMubGVuZ3RoXSA9IGJvbmVDb3VudDtcblx0XHRcdFx0Zm9yICh2YXIgbm4gPSBpICsgYm9uZUNvdW50ICogNDsgaSA8IG5uOyApIHtcblx0XHRcdFx0XHRib25lc1tib25lcy5sZW5ndGhdID0gdmVydGljZXNbaV07XG5cdFx0XHRcdFx0d2VpZ2h0c1t3ZWlnaHRzLmxlbmd0aF0gPSB2ZXJ0aWNlc1tpICsgMV0gKiBzY2FsZTtcblx0XHRcdFx0XHR3ZWlnaHRzW3dlaWdodHMubGVuZ3RoXSA9IHZlcnRpY2VzW2kgKyAyXSAqIHNjYWxlO1xuXHRcdFx0XHRcdHdlaWdodHNbd2VpZ2h0cy5sZW5ndGhdID0gdmVydGljZXNbaSArIDNdO1xuXHRcdFx0XHRcdGkgKz0gNDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0bWVzaC5ib25lcyA9IGJvbmVzO1xuXHRcdFx0bWVzaC53ZWlnaHRzID0gd2VpZ2h0cztcblx0XHRcdG1lc2gudHJpYW5nbGVzID0gdGhpcy5nZXRJbnRBcnJheShtYXAsIFwidHJpYW5nbGVzXCIpO1xuXHRcdFx0bWVzaC5yZWdpb25VVnMgPSB1dnM7XG5cdFx0XHRtZXNoLnVwZGF0ZVVWcygpO1xuXG5cdFx0XHRjb2xvciA9IG1hcFtcImNvbG9yXCJdO1xuXHRcdFx0aWYgKGNvbG9yKSB7XG5cdFx0XHRcdG1lc2guciA9IHRoaXMudG9Db2xvcihjb2xvciwgMCk7XG5cdFx0XHRcdG1lc2guZyA9IHRoaXMudG9Db2xvcihjb2xvciwgMSk7XG5cdFx0XHRcdG1lc2guYiA9IHRoaXMudG9Db2xvcihjb2xvciwgMik7XG5cdFx0XHRcdG1lc2guYSA9IHRoaXMudG9Db2xvcihjb2xvciwgMyk7XG5cdFx0XHR9XG5cblx0XHRcdG1lc2guaHVsbExlbmd0aCA9IChtYXBbXCJodWxsXCJdIHx8IDApICogMjtcblx0XHRcdGlmIChtYXBbXCJlZGdlc1wiXSkgbWVzaC5lZGdlcyA9IHRoaXMuZ2V0SW50QXJyYXkobWFwLCBcImVkZ2VzXCIpO1xuXHRcdFx0bWVzaC53aWR0aCA9IChtYXBbXCJ3aWR0aFwiXSB8fCAwKSAqIHNjYWxlO1xuXHRcdFx0bWVzaC5oZWlnaHQgPSAobWFwW1wiaGVpZ2h0XCJdIHx8IDApICogc2NhbGU7XG5cdFx0XHRyZXR1cm4gbWVzaDtcblx0XHR9IGVsc2UgaWYgKHR5cGUgPT0gc3BpbmUuQXR0YWNobWVudFR5cGUuYm91bmRpbmdib3gpIHtcblx0XHRcdHZhciBhdHRhY2htZW50ID0gdGhpcy5hdHRhY2htZW50TG9hZGVyLm5ld0JvdW5kaW5nQm94QXR0YWNobWVudChza2luLCBuYW1lKTtcblx0XHRcdHZhciB2ZXJ0aWNlcyA9IG1hcFtcInZlcnRpY2VzXCJdO1xuXHRcdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSB2ZXJ0aWNlcy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRcdGF0dGFjaG1lbnQudmVydGljZXMucHVzaCh2ZXJ0aWNlc1tpXSAqIHNjYWxlKTtcblx0XHRcdHJldHVybiBhdHRhY2htZW50O1xuXHRcdH1cblx0XHR0aHJvdyBcIlVua25vd24gYXR0YWNobWVudCB0eXBlOiBcIiArIHR5cGU7XG5cdH0sXG5cdHJlYWRBbmltYXRpb246IGZ1bmN0aW9uIChuYW1lLCBtYXAsIHNrZWxldG9uRGF0YSkge1xuXHRcdHZhciB0aW1lbGluZXMgPSBbXTtcblx0XHR2YXIgZHVyYXRpb24gPSAwO1xuXG5cdFx0dmFyIHNsb3RzID0gbWFwW1wic2xvdHNcIl07XG5cdFx0Zm9yICh2YXIgc2xvdE5hbWUgaW4gc2xvdHMpIHtcblx0XHRcdGlmICghc2xvdHMuaGFzT3duUHJvcGVydHkoc2xvdE5hbWUpKSBjb250aW51ZTtcblx0XHRcdHZhciBzbG90TWFwID0gc2xvdHNbc2xvdE5hbWVdO1xuXHRcdFx0dmFyIHNsb3RJbmRleCA9IHNrZWxldG9uRGF0YS5maW5kU2xvdEluZGV4KHNsb3ROYW1lKTtcblxuXHRcdFx0Zm9yICh2YXIgdGltZWxpbmVOYW1lIGluIHNsb3RNYXApIHtcblx0XHRcdFx0aWYgKCFzbG90TWFwLmhhc093blByb3BlcnR5KHRpbWVsaW5lTmFtZSkpIGNvbnRpbnVlO1xuXHRcdFx0XHR2YXIgdmFsdWVzID0gc2xvdE1hcFt0aW1lbGluZU5hbWVdO1xuXHRcdFx0XHRpZiAodGltZWxpbmVOYW1lID09IFwiY29sb3JcIikge1xuXHRcdFx0XHRcdHZhciB0aW1lbGluZSA9IG5ldyBzcGluZS5Db2xvclRpbWVsaW5lKHZhbHVlcy5sZW5ndGgpO1xuXHRcdFx0XHRcdHRpbWVsaW5lLnNsb3RJbmRleCA9IHNsb3RJbmRleDtcblxuXHRcdFx0XHRcdHZhciBmcmFtZUluZGV4ID0gMDtcblx0XHRcdFx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHZhbHVlcy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcblx0XHRcdFx0XHRcdHZhciB2YWx1ZU1hcCA9IHZhbHVlc1tpXTtcblx0XHRcdFx0XHRcdHZhciBjb2xvciA9IHZhbHVlTWFwW1wiY29sb3JcIl07XG5cdFx0XHRcdFx0XHR2YXIgciA9IHRoaXMudG9Db2xvcihjb2xvciwgMCk7XG5cdFx0XHRcdFx0XHR2YXIgZyA9IHRoaXMudG9Db2xvcihjb2xvciwgMSk7XG5cdFx0XHRcdFx0XHR2YXIgYiA9IHRoaXMudG9Db2xvcihjb2xvciwgMik7XG5cdFx0XHRcdFx0XHR2YXIgYSA9IHRoaXMudG9Db2xvcihjb2xvciwgMyk7XG5cdFx0XHRcdFx0XHR0aW1lbGluZS5zZXRGcmFtZShmcmFtZUluZGV4LCB2YWx1ZU1hcFtcInRpbWVcIl0sIHIsIGcsIGIsIGEpO1xuXHRcdFx0XHRcdFx0dGhpcy5yZWFkQ3VydmUodGltZWxpbmUsIGZyYW1lSW5kZXgsIHZhbHVlTWFwKTtcblx0XHRcdFx0XHRcdGZyYW1lSW5kZXgrKztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dGltZWxpbmVzLnB1c2godGltZWxpbmUpO1xuXHRcdFx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoZHVyYXRpb24sIHRpbWVsaW5lLmZyYW1lc1t0aW1lbGluZS5nZXRGcmFtZUNvdW50KCkgKiA1IC0gNV0pO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAodGltZWxpbmVOYW1lID09IFwiYXR0YWNobWVudFwiKSB7XG5cdFx0XHRcdFx0dmFyIHRpbWVsaW5lID0gbmV3IHNwaW5lLkF0dGFjaG1lbnRUaW1lbGluZSh2YWx1ZXMubGVuZ3RoKTtcblx0XHRcdFx0XHR0aW1lbGluZS5zbG90SW5kZXggPSBzbG90SW5kZXg7XG5cblx0XHRcdFx0XHR2YXIgZnJhbWVJbmRleCA9IDA7XG5cdFx0XHRcdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSB2YWx1ZXMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRcdFx0XHR2YXIgdmFsdWVNYXAgPSB2YWx1ZXNbaV07XG5cdFx0XHRcdFx0XHR0aW1lbGluZS5zZXRGcmFtZShmcmFtZUluZGV4KyssIHZhbHVlTWFwW1widGltZVwiXSwgdmFsdWVNYXBbXCJuYW1lXCJdKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dGltZWxpbmVzLnB1c2godGltZWxpbmUpO1xuXHRcdFx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoZHVyYXRpb24sIHRpbWVsaW5lLmZyYW1lc1t0aW1lbGluZS5nZXRGcmFtZUNvdW50KCkgLSAxXSk7XG5cblx0XHRcdFx0fSBlbHNlXG5cdFx0XHRcdFx0dGhyb3cgXCJJbnZhbGlkIHRpbWVsaW5lIHR5cGUgZm9yIGEgc2xvdDogXCIgKyB0aW1lbGluZU5hbWUgKyBcIiAoXCIgKyBzbG90TmFtZSArIFwiKVwiO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHZhciBib25lcyA9IG1hcFtcImJvbmVzXCJdO1xuXHRcdGZvciAodmFyIGJvbmVOYW1lIGluIGJvbmVzKSB7XG5cdFx0XHRpZiAoIWJvbmVzLmhhc093blByb3BlcnR5KGJvbmVOYW1lKSkgY29udGludWU7XG5cdFx0XHR2YXIgYm9uZUluZGV4ID0gc2tlbGV0b25EYXRhLmZpbmRCb25lSW5kZXgoYm9uZU5hbWUpO1xuXHRcdFx0aWYgKGJvbmVJbmRleCA9PSAtMSkgdGhyb3cgXCJCb25lIG5vdCBmb3VuZDogXCIgKyBib25lTmFtZTtcblx0XHRcdHZhciBib25lTWFwID0gYm9uZXNbYm9uZU5hbWVdO1xuXG5cdFx0XHRmb3IgKHZhciB0aW1lbGluZU5hbWUgaW4gYm9uZU1hcCkge1xuXHRcdFx0XHRpZiAoIWJvbmVNYXAuaGFzT3duUHJvcGVydHkodGltZWxpbmVOYW1lKSkgY29udGludWU7XG5cdFx0XHRcdHZhciB2YWx1ZXMgPSBib25lTWFwW3RpbWVsaW5lTmFtZV07XG5cdFx0XHRcdGlmICh0aW1lbGluZU5hbWUgPT0gXCJyb3RhdGVcIikge1xuXHRcdFx0XHRcdHZhciB0aW1lbGluZSA9IG5ldyBzcGluZS5Sb3RhdGVUaW1lbGluZSh2YWx1ZXMubGVuZ3RoKTtcblx0XHRcdFx0XHR0aW1lbGluZS5ib25lSW5kZXggPSBib25lSW5kZXg7XG5cblx0XHRcdFx0XHR2YXIgZnJhbWVJbmRleCA9IDA7XG5cdFx0XHRcdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSB2YWx1ZXMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRcdFx0XHR2YXIgdmFsdWVNYXAgPSB2YWx1ZXNbaV07XG5cdFx0XHRcdFx0XHR0aW1lbGluZS5zZXRGcmFtZShmcmFtZUluZGV4LCB2YWx1ZU1hcFtcInRpbWVcIl0sIHZhbHVlTWFwW1wiYW5nbGVcIl0pO1xuXHRcdFx0XHRcdFx0dGhpcy5yZWFkQ3VydmUodGltZWxpbmUsIGZyYW1lSW5kZXgsIHZhbHVlTWFwKTtcblx0XHRcdFx0XHRcdGZyYW1lSW5kZXgrKztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dGltZWxpbmVzLnB1c2godGltZWxpbmUpO1xuXHRcdFx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoZHVyYXRpb24sIHRpbWVsaW5lLmZyYW1lc1t0aW1lbGluZS5nZXRGcmFtZUNvdW50KCkgKiAyIC0gMl0pO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAodGltZWxpbmVOYW1lID09IFwidHJhbnNsYXRlXCIgfHwgdGltZWxpbmVOYW1lID09IFwic2NhbGVcIikge1xuXHRcdFx0XHRcdHZhciB0aW1lbGluZTtcblx0XHRcdFx0XHR2YXIgdGltZWxpbmVTY2FsZSA9IDE7XG5cdFx0XHRcdFx0aWYgKHRpbWVsaW5lTmFtZSA9PSBcInNjYWxlXCIpXG5cdFx0XHRcdFx0XHR0aW1lbGluZSA9IG5ldyBzcGluZS5TY2FsZVRpbWVsaW5lKHZhbHVlcy5sZW5ndGgpO1xuXHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0dGltZWxpbmUgPSBuZXcgc3BpbmUuVHJhbnNsYXRlVGltZWxpbmUodmFsdWVzLmxlbmd0aCk7XG5cdFx0XHRcdFx0XHR0aW1lbGluZVNjYWxlID0gdGhpcy5zY2FsZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dGltZWxpbmUuYm9uZUluZGV4ID0gYm9uZUluZGV4O1xuXG5cdFx0XHRcdFx0dmFyIGZyYW1lSW5kZXggPSAwO1xuXHRcdFx0XHRcdGZvciAodmFyIGkgPSAwLCBuID0gdmFsdWVzLmxlbmd0aDsgaSA8IG47IGkrKykge1xuXHRcdFx0XHRcdFx0dmFyIHZhbHVlTWFwID0gdmFsdWVzW2ldO1xuXHRcdFx0XHRcdFx0dmFyIHggPSAodmFsdWVNYXBbXCJ4XCJdIHx8IDApICogdGltZWxpbmVTY2FsZTtcblx0XHRcdFx0XHRcdHZhciB5ID0gKHZhbHVlTWFwW1wieVwiXSB8fCAwKSAqIHRpbWVsaW5lU2NhbGU7XG5cdFx0XHRcdFx0XHR0aW1lbGluZS5zZXRGcmFtZShmcmFtZUluZGV4LCB2YWx1ZU1hcFtcInRpbWVcIl0sIHgsIHkpO1xuXHRcdFx0XHRcdFx0dGhpcy5yZWFkQ3VydmUodGltZWxpbmUsIGZyYW1lSW5kZXgsIHZhbHVlTWFwKTtcblx0XHRcdFx0XHRcdGZyYW1lSW5kZXgrKztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dGltZWxpbmVzLnB1c2godGltZWxpbmUpO1xuXHRcdFx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoZHVyYXRpb24sIHRpbWVsaW5lLmZyYW1lc1t0aW1lbGluZS5nZXRGcmFtZUNvdW50KCkgKiAzIC0gM10pO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAodGltZWxpbmVOYW1lID09IFwiZmxpcFhcIiB8fCB0aW1lbGluZU5hbWUgPT0gXCJmbGlwWVwiKSB7XG5cdFx0XHRcdFx0dmFyIHggPSB0aW1lbGluZU5hbWUgPT0gXCJmbGlwWFwiO1xuXHRcdFx0XHRcdHZhciB0aW1lbGluZSA9IHggPyBuZXcgc3BpbmUuRmxpcFhUaW1lbGluZSh2YWx1ZXMubGVuZ3RoKSA6IG5ldyBzcGluZS5GbGlwWVRpbWVsaW5lKHZhbHVlcy5sZW5ndGgpO1xuXHRcdFx0XHRcdHRpbWVsaW5lLmJvbmVJbmRleCA9IGJvbmVJbmRleDtcblxuXHRcdFx0XHRcdHZhciBmaWVsZCA9IHggPyBcInhcIiA6IFwieVwiO1xuXHRcdFx0XHRcdHZhciBmcmFtZUluZGV4ID0gMDtcblx0XHRcdFx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHZhbHVlcy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcblx0XHRcdFx0XHRcdHZhciB2YWx1ZU1hcCA9IHZhbHVlc1tpXTtcblx0XHRcdFx0XHRcdHRpbWVsaW5lLnNldEZyYW1lKGZyYW1lSW5kZXgsIHZhbHVlTWFwW1widGltZVwiXSwgdmFsdWVNYXBbZmllbGRdIHx8IGZhbHNlKTtcblx0XHRcdFx0XHRcdGZyYW1lSW5kZXgrKztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dGltZWxpbmVzLnB1c2godGltZWxpbmUpO1xuXHRcdFx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoZHVyYXRpb24sIHRpbWVsaW5lLmZyYW1lc1t0aW1lbGluZS5nZXRGcmFtZUNvdW50KCkgKiAyIC0gMl0pO1xuXHRcdFx0XHR9IGVsc2Vcblx0XHRcdFx0XHR0aHJvdyBcIkludmFsaWQgdGltZWxpbmUgdHlwZSBmb3IgYSBib25lOiBcIiArIHRpbWVsaW5lTmFtZSArIFwiIChcIiArIGJvbmVOYW1lICsgXCIpXCI7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dmFyIGlrTWFwID0gbWFwW1wiaWtcIl07XG5cdFx0Zm9yICh2YXIgaWtDb25zdHJhaW50TmFtZSBpbiBpa01hcCkge1xuXHRcdFx0aWYgKCFpa01hcC5oYXNPd25Qcm9wZXJ0eShpa0NvbnN0cmFpbnROYW1lKSkgY29udGludWU7XG5cdFx0XHR2YXIgaWtDb25zdHJhaW50ID0gc2tlbGV0b25EYXRhLmZpbmRJa0NvbnN0cmFpbnQoaWtDb25zdHJhaW50TmFtZSk7XG5cdFx0XHR2YXIgdmFsdWVzID0gaWtNYXBbaWtDb25zdHJhaW50TmFtZV07XG5cdFx0XHR2YXIgdGltZWxpbmUgPSBuZXcgc3BpbmUuSWtDb25zdHJhaW50VGltZWxpbmUodmFsdWVzLmxlbmd0aCk7XG5cdFx0XHR0aW1lbGluZS5pa0NvbnN0cmFpbnRJbmRleCA9IHNrZWxldG9uRGF0YS5pa0NvbnN0cmFpbnRzLmluZGV4T2YoaWtDb25zdHJhaW50KTtcblx0XHRcdHZhciBmcmFtZUluZGV4ID0gMDtcblx0XHRcdGZvciAodmFyIGkgPSAwLCBuID0gdmFsdWVzLmxlbmd0aDsgaSA8IG47IGkrKykge1xuXHRcdFx0XHR2YXIgdmFsdWVNYXAgPSB2YWx1ZXNbaV07XG5cdFx0XHRcdHZhciBtaXggPSB2YWx1ZU1hcC5oYXNPd25Qcm9wZXJ0eShcIm1peFwiKSA/IHZhbHVlTWFwW1wibWl4XCJdIDogMTtcblx0XHRcdFx0dmFyIGJlbmREaXJlY3Rpb24gPSAoIXZhbHVlTWFwLmhhc093blByb3BlcnR5KFwiYmVuZFBvc2l0aXZlXCIpIHx8IHZhbHVlTWFwW1wiYmVuZFBvc2l0aXZlXCJdKSA/IDEgOiAtMTtcblx0XHRcdFx0dGltZWxpbmUuc2V0RnJhbWUoZnJhbWVJbmRleCwgdmFsdWVNYXBbXCJ0aW1lXCJdLCBtaXgsIGJlbmREaXJlY3Rpb24pO1xuXHRcdFx0XHR0aGlzLnJlYWRDdXJ2ZSh0aW1lbGluZSwgZnJhbWVJbmRleCwgdmFsdWVNYXApO1xuXHRcdFx0XHRmcmFtZUluZGV4Kys7XG5cdFx0XHR9XG5cdFx0XHR0aW1lbGluZXMucHVzaCh0aW1lbGluZSk7XG5cdFx0XHRkdXJhdGlvbiA9IE1hdGgubWF4KGR1cmF0aW9uLCB0aW1lbGluZS5mcmFtZXNbdGltZWxpbmUuZnJhbWVDb3VudCAqIDMgLSAzXSk7XG5cdFx0fVxuXG5cdFx0dmFyIGZmZCA9IG1hcFtcImZmZFwiXTtcblx0XHRmb3IgKHZhciBza2luTmFtZSBpbiBmZmQpIHtcblx0XHRcdHZhciBza2luID0gc2tlbGV0b25EYXRhLmZpbmRTa2luKHNraW5OYW1lKTtcblx0XHRcdHZhciBzbG90TWFwID0gZmZkW3NraW5OYW1lXTtcblx0XHRcdGZvciAoc2xvdE5hbWUgaW4gc2xvdE1hcCkge1xuXHRcdFx0XHR2YXIgc2xvdEluZGV4ID0gc2tlbGV0b25EYXRhLmZpbmRTbG90SW5kZXgoc2xvdE5hbWUpO1xuXHRcdFx0XHR2YXIgbWVzaE1hcCA9IHNsb3RNYXBbc2xvdE5hbWVdO1xuXHRcdFx0XHRmb3IgKHZhciBtZXNoTmFtZSBpbiBtZXNoTWFwKSB7XG5cdFx0XHRcdFx0dmFyIHZhbHVlcyA9IG1lc2hNYXBbbWVzaE5hbWVdO1xuXHRcdFx0XHRcdHZhciB0aW1lbGluZSA9IG5ldyBzcGluZS5GZmRUaW1lbGluZSh2YWx1ZXMubGVuZ3RoKTtcblx0XHRcdFx0XHR2YXIgYXR0YWNobWVudCA9IHNraW4uZ2V0QXR0YWNobWVudChzbG90SW5kZXgsIG1lc2hOYW1lKTtcblx0XHRcdFx0XHRpZiAoIWF0dGFjaG1lbnQpIHRocm93IFwiRkZEIGF0dGFjaG1lbnQgbm90IGZvdW5kOiBcIiArIG1lc2hOYW1lO1xuXHRcdFx0XHRcdHRpbWVsaW5lLnNsb3RJbmRleCA9IHNsb3RJbmRleDtcblx0XHRcdFx0XHR0aW1lbGluZS5hdHRhY2htZW50ID0gYXR0YWNobWVudDtcblxuXHRcdFx0XHRcdHZhciBpc01lc2ggPSBhdHRhY2htZW50LnR5cGUgPT0gc3BpbmUuQXR0YWNobWVudFR5cGUubWVzaDtcblx0XHRcdFx0XHR2YXIgdmVydGV4Q291bnQ7XG5cdFx0XHRcdFx0aWYgKGlzTWVzaClcblx0XHRcdFx0XHRcdHZlcnRleENvdW50ID0gYXR0YWNobWVudC52ZXJ0aWNlcy5sZW5ndGg7XG5cdFx0XHRcdFx0ZWxzZVxuXHRcdFx0XHRcdFx0dmVydGV4Q291bnQgPSBhdHRhY2htZW50LndlaWdodHMubGVuZ3RoIC8gMyAqIDI7XG5cblx0XHRcdFx0XHR2YXIgZnJhbWVJbmRleCA9IDA7XG5cdFx0XHRcdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSB2YWx1ZXMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRcdFx0XHR2YXIgdmFsdWVNYXAgPSB2YWx1ZXNbaV07XG5cdFx0XHRcdFx0XHR2YXIgdmVydGljZXM7XG5cdFx0XHRcdFx0XHRpZiAoIXZhbHVlTWFwW1widmVydGljZXNcIl0pIHtcblx0XHRcdFx0XHRcdFx0aWYgKGlzTWVzaClcblx0XHRcdFx0XHRcdFx0XHR2ZXJ0aWNlcyA9IGF0dGFjaG1lbnQudmVydGljZXM7XG5cdFx0XHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdHZlcnRpY2VzID0gW107XG5cdFx0XHRcdFx0XHRcdFx0dmVydGljZXMubGVuZ3RoID0gdmVydGV4Q291bnQ7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdHZhciB2ZXJ0aWNlc1ZhbHVlID0gdmFsdWVNYXBbXCJ2ZXJ0aWNlc1wiXTtcblx0XHRcdFx0XHRcdFx0dmFyIHZlcnRpY2VzID0gW107XG5cdFx0XHRcdFx0XHRcdHZlcnRpY2VzLmxlbmd0aCA9IHZlcnRleENvdW50O1xuXHRcdFx0XHRcdFx0XHR2YXIgc3RhcnQgPSB2YWx1ZU1hcFtcIm9mZnNldFwiXSB8fCAwO1xuXHRcdFx0XHRcdFx0XHR2YXIgbm4gPSB2ZXJ0aWNlc1ZhbHVlLmxlbmd0aDtcblx0XHRcdFx0XHRcdFx0aWYgKHRoaXMuc2NhbGUgPT0gMSkge1xuXHRcdFx0XHRcdFx0XHRcdGZvciAodmFyIGlpID0gMDsgaWkgPCBubjsgaWkrKylcblx0XHRcdFx0XHRcdFx0XHRcdHZlcnRpY2VzW2lpICsgc3RhcnRdID0gdmVydGljZXNWYWx1ZVtpaV07XG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0Zm9yICh2YXIgaWkgPSAwOyBpaSA8IG5uOyBpaSsrKVxuXHRcdFx0XHRcdFx0XHRcdFx0dmVydGljZXNbaWkgKyBzdGFydF0gPSB2ZXJ0aWNlc1ZhbHVlW2lpXSAqIHRoaXMuc2NhbGU7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0aWYgKGlzTWVzaCkge1xuXHRcdFx0XHRcdFx0XHRcdHZhciBtZXNoVmVydGljZXMgPSBhdHRhY2htZW50LnZlcnRpY2VzO1xuXHRcdFx0XHRcdFx0XHRcdGZvciAodmFyIGlpID0gMCwgbm4gPSB2ZXJ0aWNlcy5sZW5ndGg7IGlpIDwgbm47IGlpKyspXG5cdFx0XHRcdFx0XHRcdFx0XHR2ZXJ0aWNlc1tpaV0gKz0gbWVzaFZlcnRpY2VzW2lpXTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR0aW1lbGluZS5zZXRGcmFtZShmcmFtZUluZGV4LCB2YWx1ZU1hcFtcInRpbWVcIl0sIHZlcnRpY2VzKTtcblx0XHRcdFx0XHRcdHRoaXMucmVhZEN1cnZlKHRpbWVsaW5lLCBmcmFtZUluZGV4LCB2YWx1ZU1hcCk7XG5cdFx0XHRcdFx0XHRmcmFtZUluZGV4Kys7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHRpbWVsaW5lc1t0aW1lbGluZXMubGVuZ3RoXSA9IHRpbWVsaW5lO1xuXHRcdFx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoZHVyYXRpb24sIHRpbWVsaW5lLmZyYW1lc1t0aW1lbGluZS5mcmFtZUNvdW50IC0gMV0pO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dmFyIGRyYXdPcmRlclZhbHVlcyA9IG1hcFtcImRyYXdPcmRlclwiXTtcblx0XHRpZiAoIWRyYXdPcmRlclZhbHVlcykgZHJhd09yZGVyVmFsdWVzID0gbWFwW1wiZHJhd29yZGVyXCJdO1xuXHRcdGlmIChkcmF3T3JkZXJWYWx1ZXMpIHtcblx0XHRcdHZhciB0aW1lbGluZSA9IG5ldyBzcGluZS5EcmF3T3JkZXJUaW1lbGluZShkcmF3T3JkZXJWYWx1ZXMubGVuZ3RoKTtcblx0XHRcdHZhciBzbG90Q291bnQgPSBza2VsZXRvbkRhdGEuc2xvdHMubGVuZ3RoO1xuXHRcdFx0dmFyIGZyYW1lSW5kZXggPSAwO1xuXHRcdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBkcmF3T3JkZXJWYWx1ZXMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRcdHZhciBkcmF3T3JkZXJNYXAgPSBkcmF3T3JkZXJWYWx1ZXNbaV07XG5cdFx0XHRcdHZhciBkcmF3T3JkZXIgPSBudWxsO1xuXHRcdFx0XHRpZiAoZHJhd09yZGVyTWFwW1wib2Zmc2V0c1wiXSkge1xuXHRcdFx0XHRcdGRyYXdPcmRlciA9IFtdO1xuXHRcdFx0XHRcdGRyYXdPcmRlci5sZW5ndGggPSBzbG90Q291bnQ7XG5cdFx0XHRcdFx0Zm9yICh2YXIgaWkgPSBzbG90Q291bnQgLSAxOyBpaSA+PSAwOyBpaS0tKVxuXHRcdFx0XHRcdFx0ZHJhd09yZGVyW2lpXSA9IC0xO1xuXHRcdFx0XHRcdHZhciBvZmZzZXRzID0gZHJhd09yZGVyTWFwW1wib2Zmc2V0c1wiXTtcblx0XHRcdFx0XHR2YXIgdW5jaGFuZ2VkID0gW107XG5cdFx0XHRcdFx0dW5jaGFuZ2VkLmxlbmd0aCA9IHNsb3RDb3VudCAtIG9mZnNldHMubGVuZ3RoO1xuXHRcdFx0XHRcdHZhciBvcmlnaW5hbEluZGV4ID0gMCwgdW5jaGFuZ2VkSW5kZXggPSAwO1xuXHRcdFx0XHRcdGZvciAodmFyIGlpID0gMCwgbm4gPSBvZmZzZXRzLmxlbmd0aDsgaWkgPCBubjsgaWkrKykge1xuXHRcdFx0XHRcdFx0dmFyIG9mZnNldE1hcCA9IG9mZnNldHNbaWldO1xuXHRcdFx0XHRcdFx0dmFyIHNsb3RJbmRleCA9IHNrZWxldG9uRGF0YS5maW5kU2xvdEluZGV4KG9mZnNldE1hcFtcInNsb3RcIl0pO1xuXHRcdFx0XHRcdFx0aWYgKHNsb3RJbmRleCA9PSAtMSkgdGhyb3cgXCJTbG90IG5vdCBmb3VuZDogXCIgKyBvZmZzZXRNYXBbXCJzbG90XCJdO1xuXHRcdFx0XHRcdFx0Ly8gQ29sbGVjdCB1bmNoYW5nZWQgaXRlbXMuXG5cdFx0XHRcdFx0XHR3aGlsZSAob3JpZ2luYWxJbmRleCAhPSBzbG90SW5kZXgpXG5cdFx0XHRcdFx0XHRcdHVuY2hhbmdlZFt1bmNoYW5nZWRJbmRleCsrXSA9IG9yaWdpbmFsSW5kZXgrKztcblx0XHRcdFx0XHRcdC8vIFNldCBjaGFuZ2VkIGl0ZW1zLlxuXHRcdFx0XHRcdFx0ZHJhd09yZGVyW29yaWdpbmFsSW5kZXggKyBvZmZzZXRNYXBbXCJvZmZzZXRcIl1dID0gb3JpZ2luYWxJbmRleCsrO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHQvLyBDb2xsZWN0IHJlbWFpbmluZyB1bmNoYW5nZWQgaXRlbXMuXG5cdFx0XHRcdFx0d2hpbGUgKG9yaWdpbmFsSW5kZXggPCBzbG90Q291bnQpXG5cdFx0XHRcdFx0XHR1bmNoYW5nZWRbdW5jaGFuZ2VkSW5kZXgrK10gPSBvcmlnaW5hbEluZGV4Kys7XG5cdFx0XHRcdFx0Ly8gRmlsbCBpbiB1bmNoYW5nZWQgaXRlbXMuXG5cdFx0XHRcdFx0Zm9yICh2YXIgaWkgPSBzbG90Q291bnQgLSAxOyBpaSA+PSAwOyBpaS0tKVxuXHRcdFx0XHRcdFx0aWYgKGRyYXdPcmRlcltpaV0gPT0gLTEpIGRyYXdPcmRlcltpaV0gPSB1bmNoYW5nZWRbLS11bmNoYW5nZWRJbmRleF07XG5cdFx0XHRcdH1cblx0XHRcdFx0dGltZWxpbmUuc2V0RnJhbWUoZnJhbWVJbmRleCsrLCBkcmF3T3JkZXJNYXBbXCJ0aW1lXCJdLCBkcmF3T3JkZXIpO1xuXHRcdFx0fVxuXHRcdFx0dGltZWxpbmVzLnB1c2godGltZWxpbmUpO1xuXHRcdFx0ZHVyYXRpb24gPSBNYXRoLm1heChkdXJhdGlvbiwgdGltZWxpbmUuZnJhbWVzW3RpbWVsaW5lLmdldEZyYW1lQ291bnQoKSAtIDFdKTtcblx0XHR9XG5cblx0XHR2YXIgZXZlbnRzID0gbWFwW1wiZXZlbnRzXCJdO1xuXHRcdGlmIChldmVudHMpIHtcblx0XHRcdHZhciB0aW1lbGluZSA9IG5ldyBzcGluZS5FdmVudFRpbWVsaW5lKGV2ZW50cy5sZW5ndGgpO1xuXHRcdFx0dmFyIGZyYW1lSW5kZXggPSAwO1xuXHRcdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBldmVudHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRcdHZhciBldmVudE1hcCA9IGV2ZW50c1tpXTtcblx0XHRcdFx0dmFyIGV2ZW50RGF0YSA9IHNrZWxldG9uRGF0YS5maW5kRXZlbnQoZXZlbnRNYXBbXCJuYW1lXCJdKTtcblx0XHRcdFx0aWYgKCFldmVudERhdGEpIHRocm93IFwiRXZlbnQgbm90IGZvdW5kOiBcIiArIGV2ZW50TWFwW1wibmFtZVwiXTtcblx0XHRcdFx0dmFyIGV2ZW50ID0gbmV3IHNwaW5lLkV2ZW50KGV2ZW50RGF0YSk7XG5cdFx0XHRcdGV2ZW50LmludFZhbHVlID0gZXZlbnRNYXAuaGFzT3duUHJvcGVydHkoXCJpbnRcIikgPyBldmVudE1hcFtcImludFwiXSA6IGV2ZW50RGF0YS5pbnRWYWx1ZTtcblx0XHRcdFx0ZXZlbnQuZmxvYXRWYWx1ZSA9IGV2ZW50TWFwLmhhc093blByb3BlcnR5KFwiZmxvYXRcIikgPyBldmVudE1hcFtcImZsb2F0XCJdIDogZXZlbnREYXRhLmZsb2F0VmFsdWU7XG5cdFx0XHRcdGV2ZW50LnN0cmluZ1ZhbHVlID0gZXZlbnRNYXAuaGFzT3duUHJvcGVydHkoXCJzdHJpbmdcIikgPyBldmVudE1hcFtcInN0cmluZ1wiXSA6IGV2ZW50RGF0YS5zdHJpbmdWYWx1ZTtcblx0XHRcdFx0dGltZWxpbmUuc2V0RnJhbWUoZnJhbWVJbmRleCsrLCBldmVudE1hcFtcInRpbWVcIl0sIGV2ZW50KTtcblx0XHRcdH1cblx0XHRcdHRpbWVsaW5lcy5wdXNoKHRpbWVsaW5lKTtcblx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoZHVyYXRpb24sIHRpbWVsaW5lLmZyYW1lc1t0aW1lbGluZS5nZXRGcmFtZUNvdW50KCkgLSAxXSk7XG5cdFx0fVxuXG5cdFx0c2tlbGV0b25EYXRhLmFuaW1hdGlvbnMucHVzaChuZXcgc3BpbmUuQW5pbWF0aW9uKG5hbWUsIHRpbWVsaW5lcywgZHVyYXRpb24pKTtcblx0fSxcblx0cmVhZEN1cnZlOiBmdW5jdGlvbiAodGltZWxpbmUsIGZyYW1lSW5kZXgsIHZhbHVlTWFwKSB7XG5cdFx0dmFyIGN1cnZlID0gdmFsdWVNYXBbXCJjdXJ2ZVwiXTtcblx0XHRpZiAoIWN1cnZlKVxuXHRcdFx0dGltZWxpbmUuY3VydmVzLnNldExpbmVhcihmcmFtZUluZGV4KTtcblx0XHRlbHNlIGlmIChjdXJ2ZSA9PSBcInN0ZXBwZWRcIilcblx0XHRcdHRpbWVsaW5lLmN1cnZlcy5zZXRTdGVwcGVkKGZyYW1lSW5kZXgpO1xuXHRcdGVsc2UgaWYgKGN1cnZlIGluc3RhbmNlb2YgQXJyYXkpXG5cdFx0XHR0aW1lbGluZS5jdXJ2ZXMuc2V0Q3VydmUoZnJhbWVJbmRleCwgY3VydmVbMF0sIGN1cnZlWzFdLCBjdXJ2ZVsyXSwgY3VydmVbM10pO1xuXHR9LFxuXHR0b0NvbG9yOiBmdW5jdGlvbiAoaGV4U3RyaW5nLCBjb2xvckluZGV4KSB7XG5cdFx0aWYgKGhleFN0cmluZy5sZW5ndGggIT0gOCkgdGhyb3cgXCJDb2xvciBoZXhpZGVjaW1hbCBsZW5ndGggbXVzdCBiZSA4LCByZWNpZXZlZDogXCIgKyBoZXhTdHJpbmc7XG5cdFx0cmV0dXJuIHBhcnNlSW50KGhleFN0cmluZy5zdWJzdHJpbmcoY29sb3JJbmRleCAqIDIsIChjb2xvckluZGV4ICogMikgKyAyKSwgMTYpIC8gMjU1O1xuXHR9LFxuXHRnZXRGbG9hdEFycmF5OiBmdW5jdGlvbiAobWFwLCBuYW1lLCBzY2FsZSkge1xuXHRcdHZhciBsaXN0ID0gbWFwW25hbWVdO1xuXHRcdHZhciB2YWx1ZXMgPSBuZXcgc3BpbmUuRmxvYXQzMkFycmF5KGxpc3QubGVuZ3RoKTtcblx0XHR2YXIgaSA9IDAsIG4gPSBsaXN0Lmxlbmd0aDtcblx0XHRpZiAoc2NhbGUgPT0gMSkge1xuXHRcdFx0Zm9yICg7IGkgPCBuOyBpKyspXG5cdFx0XHRcdHZhbHVlc1tpXSA9IGxpc3RbaV07XG5cdFx0fSBlbHNlIHtcblx0XHRcdGZvciAoOyBpIDwgbjsgaSsrKVxuXHRcdFx0XHR2YWx1ZXNbaV0gPSBsaXN0W2ldICogc2NhbGU7XG5cdFx0fVxuXHRcdHJldHVybiB2YWx1ZXM7XG5cdH0sXG5cdGdldEludEFycmF5OiBmdW5jdGlvbiAobWFwLCBuYW1lKSB7XG5cdFx0dmFyIGxpc3QgPSBtYXBbbmFtZV07XG5cdFx0dmFyIHZhbHVlcyA9IG5ldyBzcGluZS5VaW50MTZBcnJheShsaXN0Lmxlbmd0aCk7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBsaXN0Lmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdHZhbHVlc1tpXSA9IGxpc3RbaV0gfCAwO1xuXHRcdHJldHVybiB2YWx1ZXM7XG5cdH1cbn07XG5cbnNwaW5lLkF0bGFzID0gZnVuY3Rpb24gKGF0bGFzVGV4dCwgdGV4dHVyZUxvYWRlcikge1xuXHR0aGlzLnRleHR1cmVMb2FkZXIgPSB0ZXh0dXJlTG9hZGVyO1xuXHR0aGlzLnBhZ2VzID0gW107XG5cdHRoaXMucmVnaW9ucyA9IFtdO1xuXG5cdHZhciByZWFkZXIgPSBuZXcgc3BpbmUuQXRsYXNSZWFkZXIoYXRsYXNUZXh0KTtcblx0dmFyIHR1cGxlID0gW107XG5cdHR1cGxlLmxlbmd0aCA9IDQ7XG5cdHZhciBwYWdlID0gbnVsbDtcblx0d2hpbGUgKHRydWUpIHtcblx0XHR2YXIgbGluZSA9IHJlYWRlci5yZWFkTGluZSgpO1xuXHRcdGlmIChsaW5lID09PSBudWxsKSBicmVhaztcblx0XHRsaW5lID0gcmVhZGVyLnRyaW0obGluZSk7XG5cdFx0aWYgKCFsaW5lLmxlbmd0aClcblx0XHRcdHBhZ2UgPSBudWxsO1xuXHRcdGVsc2UgaWYgKCFwYWdlKSB7XG5cdFx0XHRwYWdlID0gbmV3IHNwaW5lLkF0bGFzUGFnZSgpO1xuXHRcdFx0cGFnZS5uYW1lID0gbGluZTtcblxuXHRcdFx0aWYgKHJlYWRlci5yZWFkVHVwbGUodHVwbGUpID09IDIpIHsgLy8gc2l6ZSBpcyBvbmx5IG9wdGlvbmFsIGZvciBhbiBhdGxhcyBwYWNrZWQgd2l0aCBhbiBvbGQgVGV4dHVyZVBhY2tlci5cblx0XHRcdFx0cGFnZS53aWR0aCA9IHBhcnNlSW50KHR1cGxlWzBdKTtcblx0XHRcdFx0cGFnZS5oZWlnaHQgPSBwYXJzZUludCh0dXBsZVsxXSk7XG5cdFx0XHRcdHJlYWRlci5yZWFkVHVwbGUodHVwbGUpO1xuXHRcdFx0fVxuXHRcdFx0cGFnZS5mb3JtYXQgPSBzcGluZS5BdGxhcy5Gb3JtYXRbdHVwbGVbMF1dO1xuXG5cdFx0XHRyZWFkZXIucmVhZFR1cGxlKHR1cGxlKTtcblx0XHRcdHBhZ2UubWluRmlsdGVyID0gc3BpbmUuQXRsYXMuVGV4dHVyZUZpbHRlclt0dXBsZVswXV07XG5cdFx0XHRwYWdlLm1hZ0ZpbHRlciA9IHNwaW5lLkF0bGFzLlRleHR1cmVGaWx0ZXJbdHVwbGVbMV1dO1xuXG5cdFx0XHR2YXIgZGlyZWN0aW9uID0gcmVhZGVyLnJlYWRWYWx1ZSgpO1xuXHRcdFx0cGFnZS51V3JhcCA9IHNwaW5lLkF0bGFzLlRleHR1cmVXcmFwLmNsYW1wVG9FZGdlO1xuXHRcdFx0cGFnZS52V3JhcCA9IHNwaW5lLkF0bGFzLlRleHR1cmVXcmFwLmNsYW1wVG9FZGdlO1xuXHRcdFx0aWYgKGRpcmVjdGlvbiA9PSBcInhcIilcblx0XHRcdFx0cGFnZS51V3JhcCA9IHNwaW5lLkF0bGFzLlRleHR1cmVXcmFwLnJlcGVhdDtcblx0XHRcdGVsc2UgaWYgKGRpcmVjdGlvbiA9PSBcInlcIilcblx0XHRcdFx0cGFnZS52V3JhcCA9IHNwaW5lLkF0bGFzLlRleHR1cmVXcmFwLnJlcGVhdDtcblx0XHRcdGVsc2UgaWYgKGRpcmVjdGlvbiA9PSBcInh5XCIpXG5cdFx0XHRcdHBhZ2UudVdyYXAgPSBwYWdlLnZXcmFwID0gc3BpbmUuQXRsYXMuVGV4dHVyZVdyYXAucmVwZWF0O1xuXG5cdFx0XHR0ZXh0dXJlTG9hZGVyLmxvYWQocGFnZSwgbGluZSwgdGhpcyk7XG5cblx0XHRcdHRoaXMucGFnZXMucHVzaChwYWdlKTtcblxuXHRcdH0gZWxzZSB7XG5cdFx0XHR2YXIgcmVnaW9uID0gbmV3IHNwaW5lLkF0bGFzUmVnaW9uKCk7XG5cdFx0XHRyZWdpb24ubmFtZSA9IGxpbmU7XG5cdFx0XHRyZWdpb24ucGFnZSA9IHBhZ2U7XG5cblx0XHRcdHJlZ2lvbi5yb3RhdGUgPSByZWFkZXIucmVhZFZhbHVlKCkgPT0gXCJ0cnVlXCI7XG5cblx0XHRcdHJlYWRlci5yZWFkVHVwbGUodHVwbGUpO1xuXHRcdFx0dmFyIHggPSBwYXJzZUludCh0dXBsZVswXSk7XG5cdFx0XHR2YXIgeSA9IHBhcnNlSW50KHR1cGxlWzFdKTtcblxuXHRcdFx0cmVhZGVyLnJlYWRUdXBsZSh0dXBsZSk7XG5cdFx0XHR2YXIgd2lkdGggPSBwYXJzZUludCh0dXBsZVswXSk7XG5cdFx0XHR2YXIgaGVpZ2h0ID0gcGFyc2VJbnQodHVwbGVbMV0pO1xuXG5cdFx0XHRyZWdpb24udSA9IHggLyBwYWdlLndpZHRoO1xuXHRcdFx0cmVnaW9uLnYgPSB5IC8gcGFnZS5oZWlnaHQ7XG5cdFx0XHRpZiAocmVnaW9uLnJvdGF0ZSkge1xuXHRcdFx0XHRyZWdpb24udTIgPSAoeCArIGhlaWdodCkgLyBwYWdlLndpZHRoO1xuXHRcdFx0XHRyZWdpb24udjIgPSAoeSArIHdpZHRoKSAvIHBhZ2UuaGVpZ2h0O1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cmVnaW9uLnUyID0gKHggKyB3aWR0aCkgLyBwYWdlLndpZHRoO1xuXHRcdFx0XHRyZWdpb24udjIgPSAoeSArIGhlaWdodCkgLyBwYWdlLmhlaWdodDtcblx0XHRcdH1cblx0XHRcdHJlZ2lvbi54ID0geDtcblx0XHRcdHJlZ2lvbi55ID0geTtcblx0XHRcdHJlZ2lvbi53aWR0aCA9IE1hdGguYWJzKHdpZHRoKTtcblx0XHRcdHJlZ2lvbi5oZWlnaHQgPSBNYXRoLmFicyhoZWlnaHQpO1xuXG5cdFx0XHRpZiAocmVhZGVyLnJlYWRUdXBsZSh0dXBsZSkgPT0gNCkgeyAvLyBzcGxpdCBpcyBvcHRpb25hbFxuXHRcdFx0XHRyZWdpb24uc3BsaXRzID0gW3BhcnNlSW50KHR1cGxlWzBdKSwgcGFyc2VJbnQodHVwbGVbMV0pLCBwYXJzZUludCh0dXBsZVsyXSksIHBhcnNlSW50KHR1cGxlWzNdKV07XG5cblx0XHRcdFx0aWYgKHJlYWRlci5yZWFkVHVwbGUodHVwbGUpID09IDQpIHsgLy8gcGFkIGlzIG9wdGlvbmFsLCBidXQgb25seSBwcmVzZW50IHdpdGggc3BsaXRzXG5cdFx0XHRcdFx0cmVnaW9uLnBhZHMgPSBbcGFyc2VJbnQodHVwbGVbMF0pLCBwYXJzZUludCh0dXBsZVsxXSksIHBhcnNlSW50KHR1cGxlWzJdKSwgcGFyc2VJbnQodHVwbGVbM10pXTtcblxuXHRcdFx0XHRcdHJlYWRlci5yZWFkVHVwbGUodHVwbGUpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdHJlZ2lvbi5vcmlnaW5hbFdpZHRoID0gcGFyc2VJbnQodHVwbGVbMF0pO1xuXHRcdFx0cmVnaW9uLm9yaWdpbmFsSGVpZ2h0ID0gcGFyc2VJbnQodHVwbGVbMV0pO1xuXG5cdFx0XHRyZWFkZXIucmVhZFR1cGxlKHR1cGxlKTtcblx0XHRcdHJlZ2lvbi5vZmZzZXRYID0gcGFyc2VJbnQodHVwbGVbMF0pO1xuXHRcdFx0cmVnaW9uLm9mZnNldFkgPSBwYXJzZUludCh0dXBsZVsxXSk7XG5cblx0XHRcdHJlZ2lvbi5pbmRleCA9IHBhcnNlSW50KHJlYWRlci5yZWFkVmFsdWUoKSk7XG5cblx0XHRcdHRoaXMucmVnaW9ucy5wdXNoKHJlZ2lvbik7XG5cdFx0fVxuXHR9XG59O1xuc3BpbmUuQXRsYXMucHJvdG90eXBlID0ge1xuXHRmaW5kUmVnaW9uOiBmdW5jdGlvbiAobmFtZSkge1xuXHRcdHZhciByZWdpb25zID0gdGhpcy5yZWdpb25zO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gcmVnaW9ucy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRpZiAocmVnaW9uc1tpXS5uYW1lID09IG5hbWUpIHJldHVybiByZWdpb25zW2ldO1xuXHRcdHJldHVybiBudWxsO1xuXHR9LFxuXHRkaXNwb3NlOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIHBhZ2VzID0gdGhpcy5wYWdlcztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHBhZ2VzLmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdHRoaXMudGV4dHVyZUxvYWRlci51bmxvYWQocGFnZXNbaV0ucmVuZGVyZXJPYmplY3QpO1xuXHR9LFxuXHR1cGRhdGVVVnM6IGZ1bmN0aW9uIChwYWdlKSB7XG5cdFx0dmFyIHJlZ2lvbnMgPSB0aGlzLnJlZ2lvbnM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSByZWdpb25zLmxlbmd0aDsgaSA8IG47IGkrKykge1xuXHRcdFx0dmFyIHJlZ2lvbiA9IHJlZ2lvbnNbaV07XG5cdFx0XHRpZiAocmVnaW9uLnBhZ2UgIT0gcGFnZSkgY29udGludWU7XG5cdFx0XHRyZWdpb24udSA9IHJlZ2lvbi54IC8gcGFnZS53aWR0aDtcblx0XHRcdHJlZ2lvbi52ID0gcmVnaW9uLnkgLyBwYWdlLmhlaWdodDtcblx0XHRcdGlmIChyZWdpb24ucm90YXRlKSB7XG5cdFx0XHRcdHJlZ2lvbi51MiA9IChyZWdpb24ueCArIHJlZ2lvbi5oZWlnaHQpIC8gcGFnZS53aWR0aDtcblx0XHRcdFx0cmVnaW9uLnYyID0gKHJlZ2lvbi55ICsgcmVnaW9uLndpZHRoKSAvIHBhZ2UuaGVpZ2h0O1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cmVnaW9uLnUyID0gKHJlZ2lvbi54ICsgcmVnaW9uLndpZHRoKSAvIHBhZ2Uud2lkdGg7XG5cdFx0XHRcdHJlZ2lvbi52MiA9IChyZWdpb24ueSArIHJlZ2lvbi5oZWlnaHQpIC8gcGFnZS5oZWlnaHQ7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG59O1xuXG5zcGluZS5BdGxhcy5Gb3JtYXQgPSB7XG5cdGFscGhhOiAwLFxuXHRpbnRlbnNpdHk6IDEsXG5cdGx1bWluYW5jZUFscGhhOiAyLFxuXHRyZ2I1NjU6IDMsXG5cdHJnYmE0NDQ0OiA0LFxuXHRyZ2I4ODg6IDUsXG5cdHJnYmE4ODg4OiA2XG59O1xuXG5zcGluZS5BdGxhcy5UZXh0dXJlRmlsdGVyID0ge1xuXHRuZWFyZXN0OiAwLFxuXHRsaW5lYXI6IDEsXG5cdG1pcE1hcDogMixcblx0bWlwTWFwTmVhcmVzdE5lYXJlc3Q6IDMsXG5cdG1pcE1hcExpbmVhck5lYXJlc3Q6IDQsXG5cdG1pcE1hcE5lYXJlc3RMaW5lYXI6IDUsXG5cdG1pcE1hcExpbmVhckxpbmVhcjogNlxufTtcblxuc3BpbmUuQXRsYXMuVGV4dHVyZVdyYXAgPSB7XG5cdG1pcnJvcmVkUmVwZWF0OiAwLFxuXHRjbGFtcFRvRWRnZTogMSxcblx0cmVwZWF0OiAyXG59O1xuXG5zcGluZS5BdGxhc1BhZ2UgPSBmdW5jdGlvbiAoKSB7fTtcbnNwaW5lLkF0bGFzUGFnZS5wcm90b3R5cGUgPSB7XG5cdG5hbWU6IG51bGwsXG5cdGZvcm1hdDogbnVsbCxcblx0bWluRmlsdGVyOiBudWxsLFxuXHRtYWdGaWx0ZXI6IG51bGwsXG5cdHVXcmFwOiBudWxsLFxuXHR2V3JhcDogbnVsbCxcblx0cmVuZGVyZXJPYmplY3Q6IG51bGwsXG5cdHdpZHRoOiAwLFxuXHRoZWlnaHQ6IDBcbn07XG5cbnNwaW5lLkF0bGFzUmVnaW9uID0gZnVuY3Rpb24gKCkge307XG5zcGluZS5BdGxhc1JlZ2lvbi5wcm90b3R5cGUgPSB7XG5cdHBhZ2U6IG51bGwsXG5cdG5hbWU6IG51bGwsXG5cdHg6IDAsIHk6IDAsXG5cdHdpZHRoOiAwLCBoZWlnaHQ6IDAsXG5cdHU6IDAsIHY6IDAsIHUyOiAwLCB2MjogMCxcblx0b2Zmc2V0WDogMCwgb2Zmc2V0WTogMCxcblx0b3JpZ2luYWxXaWR0aDogMCwgb3JpZ2luYWxIZWlnaHQ6IDAsXG5cdGluZGV4OiAwLFxuXHRyb3RhdGU6IGZhbHNlLFxuXHRzcGxpdHM6IG51bGwsXG5cdHBhZHM6IG51bGxcbn07XG5cbnNwaW5lLkF0bGFzUmVhZGVyID0gZnVuY3Rpb24gKHRleHQpIHtcblx0dGhpcy5saW5lcyA9IHRleHQuc3BsaXQoL1xcclxcbnxcXHJ8XFxuLyk7XG59O1xuc3BpbmUuQXRsYXNSZWFkZXIucHJvdG90eXBlID0ge1xuXHRpbmRleDogMCxcblx0dHJpbTogZnVuY3Rpb24gKHZhbHVlKSB7XG5cdFx0cmV0dXJuIHZhbHVlLnJlcGxhY2UoL15cXHMrfFxccyskL2csIFwiXCIpO1xuXHR9LFxuXHRyZWFkTGluZTogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLmluZGV4ID49IHRoaXMubGluZXMubGVuZ3RoKSByZXR1cm4gbnVsbDtcblx0XHRyZXR1cm4gdGhpcy5saW5lc1t0aGlzLmluZGV4KytdO1xuXHR9LFxuXHRyZWFkVmFsdWU6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgbGluZSA9IHRoaXMucmVhZExpbmUoKTtcblx0XHR2YXIgY29sb24gPSBsaW5lLmluZGV4T2YoXCI6XCIpO1xuXHRcdGlmIChjb2xvbiA9PSAtMSkgdGhyb3cgXCJJbnZhbGlkIGxpbmU6IFwiICsgbGluZTtcblx0XHRyZXR1cm4gdGhpcy50cmltKGxpbmUuc3Vic3RyaW5nKGNvbG9uICsgMSkpO1xuXHR9LFxuXHQvKiogUmV0dXJucyB0aGUgbnVtYmVyIG9mIHR1cGxlIHZhbHVlcyByZWFkICgxLCAyIG9yIDQpLiAqL1xuXHRyZWFkVHVwbGU6IGZ1bmN0aW9uICh0dXBsZSkge1xuXHRcdHZhciBsaW5lID0gdGhpcy5yZWFkTGluZSgpO1xuXHRcdHZhciBjb2xvbiA9IGxpbmUuaW5kZXhPZihcIjpcIik7XG5cdFx0aWYgKGNvbG9uID09IC0xKSB0aHJvdyBcIkludmFsaWQgbGluZTogXCIgKyBsaW5lO1xuXHRcdHZhciBpID0gMCwgbGFzdE1hdGNoID0gY29sb24gKyAxO1xuXHRcdGZvciAoOyBpIDwgMzsgaSsrKSB7XG5cdFx0XHR2YXIgY29tbWEgPSBsaW5lLmluZGV4T2YoXCIsXCIsIGxhc3RNYXRjaCk7XG5cdFx0XHRpZiAoY29tbWEgPT0gLTEpIGJyZWFrO1xuXHRcdFx0dHVwbGVbaV0gPSB0aGlzLnRyaW0obGluZS5zdWJzdHIobGFzdE1hdGNoLCBjb21tYSAtIGxhc3RNYXRjaCkpO1xuXHRcdFx0bGFzdE1hdGNoID0gY29tbWEgKyAxO1xuXHRcdH1cblx0XHR0dXBsZVtpXSA9IHRoaXMudHJpbShsaW5lLnN1YnN0cmluZyhsYXN0TWF0Y2gpKTtcblx0XHRyZXR1cm4gaSArIDE7XG5cdH1cbn07XG5cbnNwaW5lLkF0bGFzQXR0YWNobWVudExvYWRlciA9IGZ1bmN0aW9uIChhdGxhcykge1xuXHR0aGlzLmF0bGFzID0gYXRsYXM7XG59O1xuc3BpbmUuQXRsYXNBdHRhY2htZW50TG9hZGVyLnByb3RvdHlwZSA9IHtcblx0bmV3UmVnaW9uQXR0YWNobWVudDogZnVuY3Rpb24gKHNraW4sIG5hbWUsIHBhdGgpIHtcblx0XHR2YXIgcmVnaW9uID0gdGhpcy5hdGxhcy5maW5kUmVnaW9uKHBhdGgpO1xuXHRcdGlmICghcmVnaW9uKSB0aHJvdyBcIlJlZ2lvbiBub3QgZm91bmQgaW4gYXRsYXM6IFwiICsgcGF0aCArIFwiIChyZWdpb24gYXR0YWNobWVudDogXCIgKyBuYW1lICsgXCIpXCI7XG5cdFx0dmFyIGF0dGFjaG1lbnQgPSBuZXcgc3BpbmUuUmVnaW9uQXR0YWNobWVudChuYW1lKTtcblx0XHRhdHRhY2htZW50LnJlbmRlcmVyT2JqZWN0ID0gcmVnaW9uO1xuXHRcdGF0dGFjaG1lbnQuc2V0VVZzKHJlZ2lvbi51LCByZWdpb24udiwgcmVnaW9uLnUyLCByZWdpb24udjIsIHJlZ2lvbi5yb3RhdGUpO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT2Zmc2V0WCA9IHJlZ2lvbi5vZmZzZXRYO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT2Zmc2V0WSA9IHJlZ2lvbi5vZmZzZXRZO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uV2lkdGggPSByZWdpb24ud2lkdGg7XG5cdFx0YXR0YWNobWVudC5yZWdpb25IZWlnaHQgPSByZWdpb24uaGVpZ2h0O1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT3JpZ2luYWxXaWR0aCA9IHJlZ2lvbi5vcmlnaW5hbFdpZHRoO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT3JpZ2luYWxIZWlnaHQgPSByZWdpb24ub3JpZ2luYWxIZWlnaHQ7XG5cdFx0cmV0dXJuIGF0dGFjaG1lbnQ7XG5cdH0sXG5cdG5ld01lc2hBdHRhY2htZW50OiBmdW5jdGlvbiAoc2tpbiwgbmFtZSwgcGF0aCkge1xuXHRcdHZhciByZWdpb24gPSB0aGlzLmF0bGFzLmZpbmRSZWdpb24ocGF0aCk7XG5cdFx0aWYgKCFyZWdpb24pIHRocm93IFwiUmVnaW9uIG5vdCBmb3VuZCBpbiBhdGxhczogXCIgKyBwYXRoICsgXCIgKG1lc2ggYXR0YWNobWVudDogXCIgKyBuYW1lICsgXCIpXCI7XG5cdFx0dmFyIGF0dGFjaG1lbnQgPSBuZXcgc3BpbmUuTWVzaEF0dGFjaG1lbnQobmFtZSk7XG5cdFx0YXR0YWNobWVudC5yZW5kZXJlck9iamVjdCA9IHJlZ2lvbjtcblx0XHRhdHRhY2htZW50LnJlZ2lvblUgPSByZWdpb24udTtcblx0XHRhdHRhY2htZW50LnJlZ2lvblYgPSByZWdpb24udjtcblx0XHRhdHRhY2htZW50LnJlZ2lvblUyID0gcmVnaW9uLnUyO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uVjIgPSByZWdpb24udjI7XG5cdFx0YXR0YWNobWVudC5yZWdpb25Sb3RhdGUgPSByZWdpb24ucm90YXRlO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT2Zmc2V0WCA9IHJlZ2lvbi5vZmZzZXRYO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT2Zmc2V0WSA9IHJlZ2lvbi5vZmZzZXRZO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uV2lkdGggPSByZWdpb24ud2lkdGg7XG5cdFx0YXR0YWNobWVudC5yZWdpb25IZWlnaHQgPSByZWdpb24uaGVpZ2h0O1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT3JpZ2luYWxXaWR0aCA9IHJlZ2lvbi5vcmlnaW5hbFdpZHRoO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT3JpZ2luYWxIZWlnaHQgPSByZWdpb24ub3JpZ2luYWxIZWlnaHQ7XG5cdFx0cmV0dXJuIGF0dGFjaG1lbnQ7XG5cdH0sXG5cdG5ld1NraW5uZWRNZXNoQXR0YWNobWVudDogZnVuY3Rpb24gKHNraW4sIG5hbWUsIHBhdGgpIHtcblx0XHR2YXIgcmVnaW9uID0gdGhpcy5hdGxhcy5maW5kUmVnaW9uKHBhdGgpO1xuXHRcdGlmICghcmVnaW9uKSB0aHJvdyBcIlJlZ2lvbiBub3QgZm91bmQgaW4gYXRsYXM6IFwiICsgcGF0aCArIFwiIChza2lubmVkIG1lc2ggYXR0YWNobWVudDogXCIgKyBuYW1lICsgXCIpXCI7XG5cdFx0dmFyIGF0dGFjaG1lbnQgPSBuZXcgc3BpbmUuU2tpbm5lZE1lc2hBdHRhY2htZW50KG5hbWUpO1xuXHRcdGF0dGFjaG1lbnQucmVuZGVyZXJPYmplY3QgPSByZWdpb247XG5cdFx0YXR0YWNobWVudC5yZWdpb25VID0gcmVnaW9uLnU7XG5cdFx0YXR0YWNobWVudC5yZWdpb25WID0gcmVnaW9uLnY7XG5cdFx0YXR0YWNobWVudC5yZWdpb25VMiA9IHJlZ2lvbi51Mjtcblx0XHRhdHRhY2htZW50LnJlZ2lvblYyID0gcmVnaW9uLnYyO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uUm90YXRlID0gcmVnaW9uLnJvdGF0ZTtcblx0XHRhdHRhY2htZW50LnJlZ2lvbk9mZnNldFggPSByZWdpb24ub2Zmc2V0WDtcblx0XHRhdHRhY2htZW50LnJlZ2lvbk9mZnNldFkgPSByZWdpb24ub2Zmc2V0WTtcblx0XHRhdHRhY2htZW50LnJlZ2lvbldpZHRoID0gcmVnaW9uLndpZHRoO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uSGVpZ2h0ID0gcmVnaW9uLmhlaWdodDtcblx0XHRhdHRhY2htZW50LnJlZ2lvbk9yaWdpbmFsV2lkdGggPSByZWdpb24ub3JpZ2luYWxXaWR0aDtcblx0XHRhdHRhY2htZW50LnJlZ2lvbk9yaWdpbmFsSGVpZ2h0ID0gcmVnaW9uLm9yaWdpbmFsSGVpZ2h0O1xuXHRcdHJldHVybiBhdHRhY2htZW50O1xuXHR9LFxuXHRuZXdCb3VuZGluZ0JveEF0dGFjaG1lbnQ6IGZ1bmN0aW9uIChza2luLCBuYW1lKSB7XG5cdFx0cmV0dXJuIG5ldyBzcGluZS5Cb3VuZGluZ0JveEF0dGFjaG1lbnQobmFtZSk7XG5cdH1cbn07XG5cbnNwaW5lLlNrZWxldG9uQm91bmRzID0gZnVuY3Rpb24gKCkge1xuXHR0aGlzLnBvbHlnb25Qb29sID0gW107XG5cdHRoaXMucG9seWdvbnMgPSBbXTtcblx0dGhpcy5ib3VuZGluZ0JveGVzID0gW107XG59O1xuc3BpbmUuU2tlbGV0b25Cb3VuZHMucHJvdG90eXBlID0ge1xuXHRtaW5YOiAwLCBtaW5ZOiAwLCBtYXhYOiAwLCBtYXhZOiAwLFxuXHR1cGRhdGU6IGZ1bmN0aW9uIChza2VsZXRvbiwgdXBkYXRlQWFiYikge1xuXHRcdHZhciBzbG90cyA9IHNrZWxldG9uLnNsb3RzO1xuXHRcdHZhciBzbG90Q291bnQgPSBzbG90cy5sZW5ndGg7XG5cdFx0dmFyIHggPSBza2VsZXRvbi54LCB5ID0gc2tlbGV0b24ueTtcblx0XHR2YXIgYm91bmRpbmdCb3hlcyA9IHRoaXMuYm91bmRpbmdCb3hlcztcblx0XHR2YXIgcG9seWdvblBvb2wgPSB0aGlzLnBvbHlnb25Qb29sO1xuXHRcdHZhciBwb2x5Z29ucyA9IHRoaXMucG9seWdvbnM7XG5cblx0XHRib3VuZGluZ0JveGVzLmxlbmd0aCA9IDA7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBwb2x5Z29ucy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRwb2x5Z29uUG9vbC5wdXNoKHBvbHlnb25zW2ldKTtcblx0XHRwb2x5Z29ucy5sZW5ndGggPSAwO1xuXG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBzbG90Q291bnQ7IGkrKykge1xuXHRcdFx0dmFyIHNsb3QgPSBzbG90c1tpXTtcblx0XHRcdHZhciBib3VuZGluZ0JveCA9IHNsb3QuYXR0YWNobWVudDtcblx0XHRcdGlmIChib3VuZGluZ0JveC50eXBlICE9IHNwaW5lLkF0dGFjaG1lbnRUeXBlLmJvdW5kaW5nYm94KSBjb250aW51ZTtcblx0XHRcdGJvdW5kaW5nQm94ZXMucHVzaChib3VuZGluZ0JveCk7XG5cblx0XHRcdHZhciBwb29sQ291bnQgPSBwb2x5Z29uUG9vbC5sZW5ndGgsIHBvbHlnb247XG5cdFx0XHRpZiAocG9vbENvdW50ID4gMCkge1xuXHRcdFx0XHRwb2x5Z29uID0gcG9seWdvblBvb2xbcG9vbENvdW50IC0gMV07XG5cdFx0XHRcdHBvbHlnb25Qb29sLnNwbGljZShwb29sQ291bnQgLSAxLCAxKTtcblx0XHRcdH0gZWxzZVxuXHRcdFx0XHRwb2x5Z29uID0gW107XG5cdFx0XHRwb2x5Z29ucy5wdXNoKHBvbHlnb24pO1xuXG5cdFx0XHRwb2x5Z29uLmxlbmd0aCA9IGJvdW5kaW5nQm94LnZlcnRpY2VzLmxlbmd0aDtcblx0XHRcdGJvdW5kaW5nQm94LmNvbXB1dGVXb3JsZFZlcnRpY2VzKHgsIHksIHNsb3QuYm9uZSwgcG9seWdvbik7XG5cdFx0fVxuXG5cdFx0aWYgKHVwZGF0ZUFhYmIpIHRoaXMuYWFiYkNvbXB1dGUoKTtcblx0fSxcblx0YWFiYkNvbXB1dGU6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgcG9seWdvbnMgPSB0aGlzLnBvbHlnb25zO1xuXHRcdHZhciBtaW5YID0gTnVtYmVyLk1BWF9WQUxVRSwgbWluWSA9IE51bWJlci5NQVhfVkFMVUUsIG1heFggPSBOdW1iZXIuTUlOX1ZBTFVFLCBtYXhZID0gTnVtYmVyLk1JTl9WQUxVRTtcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHBvbHlnb25zLmxlbmd0aDsgaSA8IG47IGkrKykge1xuXHRcdFx0dmFyIHZlcnRpY2VzID0gcG9seWdvbnNbaV07XG5cdFx0XHRmb3IgKHZhciBpaSA9IDAsIG5uID0gdmVydGljZXMubGVuZ3RoOyBpaSA8IG5uOyBpaSArPSAyKSB7XG5cdFx0XHRcdHZhciB4ID0gdmVydGljZXNbaWldO1xuXHRcdFx0XHR2YXIgeSA9IHZlcnRpY2VzW2lpICsgMV07XG5cdFx0XHRcdG1pblggPSBNYXRoLm1pbihtaW5YLCB4KTtcblx0XHRcdFx0bWluWSA9IE1hdGgubWluKG1pblksIHkpO1xuXHRcdFx0XHRtYXhYID0gTWF0aC5tYXgobWF4WCwgeCk7XG5cdFx0XHRcdG1heFkgPSBNYXRoLm1heChtYXhZLCB5KTtcblx0XHRcdH1cblx0XHR9XG5cdFx0dGhpcy5taW5YID0gbWluWDtcblx0XHR0aGlzLm1pblkgPSBtaW5ZO1xuXHRcdHRoaXMubWF4WCA9IG1heFg7XG5cdFx0dGhpcy5tYXhZID0gbWF4WTtcblx0fSxcblx0LyoqIFJldHVybnMgdHJ1ZSBpZiB0aGUgYXhpcyBhbGlnbmVkIGJvdW5kaW5nIGJveCBjb250YWlucyB0aGUgcG9pbnQuICovXG5cdGFhYmJDb250YWluc1BvaW50OiBmdW5jdGlvbiAoeCwgeSkge1xuXHRcdHJldHVybiB4ID49IHRoaXMubWluWCAmJiB4IDw9IHRoaXMubWF4WCAmJiB5ID49IHRoaXMubWluWSAmJiB5IDw9IHRoaXMubWF4WTtcblx0fSxcblx0LyoqIFJldHVybnMgdHJ1ZSBpZiB0aGUgYXhpcyBhbGlnbmVkIGJvdW5kaW5nIGJveCBpbnRlcnNlY3RzIHRoZSBsaW5lIHNlZ21lbnQuICovXG5cdGFhYmJJbnRlcnNlY3RzU2VnbWVudDogZnVuY3Rpb24gKHgxLCB5MSwgeDIsIHkyKSB7XG5cdFx0dmFyIG1pblggPSB0aGlzLm1pblgsIG1pblkgPSB0aGlzLm1pblksIG1heFggPSB0aGlzLm1heFgsIG1heFkgPSB0aGlzLm1heFk7XG5cdFx0aWYgKCh4MSA8PSBtaW5YICYmIHgyIDw9IG1pblgpIHx8ICh5MSA8PSBtaW5ZICYmIHkyIDw9IG1pblkpIHx8ICh4MSA+PSBtYXhYICYmIHgyID49IG1heFgpIHx8ICh5MSA+PSBtYXhZICYmIHkyID49IG1heFkpKVxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdHZhciBtID0gKHkyIC0geTEpIC8gKHgyIC0geDEpO1xuXHRcdHZhciB5ID0gbSAqIChtaW5YIC0geDEpICsgeTE7XG5cdFx0aWYgKHkgPiBtaW5ZICYmIHkgPCBtYXhZKSByZXR1cm4gdHJ1ZTtcblx0XHR5ID0gbSAqIChtYXhYIC0geDEpICsgeTE7XG5cdFx0aWYgKHkgPiBtaW5ZICYmIHkgPCBtYXhZKSByZXR1cm4gdHJ1ZTtcblx0XHR2YXIgeCA9IChtaW5ZIC0geTEpIC8gbSArIHgxO1xuXHRcdGlmICh4ID4gbWluWCAmJiB4IDwgbWF4WCkgcmV0dXJuIHRydWU7XG5cdFx0eCA9IChtYXhZIC0geTEpIC8gbSArIHgxO1xuXHRcdGlmICh4ID4gbWluWCAmJiB4IDwgbWF4WCkgcmV0dXJuIHRydWU7XG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9LFxuXHQvKiogUmV0dXJucyB0cnVlIGlmIHRoZSBheGlzIGFsaWduZWQgYm91bmRpbmcgYm94IGludGVyc2VjdHMgdGhlIGF4aXMgYWxpZ25lZCBib3VuZGluZyBib3ggb2YgdGhlIHNwZWNpZmllZCBib3VuZHMuICovXG5cdGFhYmJJbnRlcnNlY3RzU2tlbGV0b246IGZ1bmN0aW9uIChib3VuZHMpIHtcblx0XHRyZXR1cm4gdGhpcy5taW5YIDwgYm91bmRzLm1heFggJiYgdGhpcy5tYXhYID4gYm91bmRzLm1pblggJiYgdGhpcy5taW5ZIDwgYm91bmRzLm1heFkgJiYgdGhpcy5tYXhZID4gYm91bmRzLm1pblk7XG5cdH0sXG5cdC8qKiBSZXR1cm5zIHRoZSBmaXJzdCBib3VuZGluZyBib3ggYXR0YWNobWVudCB0aGF0IGNvbnRhaW5zIHRoZSBwb2ludCwgb3IgbnVsbC4gV2hlbiBkb2luZyBtYW55IGNoZWNrcywgaXQgaXMgdXN1YWxseSBtb3JlXG5cdCAqIGVmZmljaWVudCB0byBvbmx5IGNhbGwgdGhpcyBtZXRob2QgaWYge0BsaW5rICNhYWJiQ29udGFpbnNQb2ludChmbG9hdCwgZmxvYXQpfSByZXR1cm5zIHRydWUuICovXG5cdGNvbnRhaW5zUG9pbnQ6IGZ1bmN0aW9uICh4LCB5KSB7XG5cdFx0dmFyIHBvbHlnb25zID0gdGhpcy5wb2x5Z29ucztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHBvbHlnb25zLmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdGlmICh0aGlzLnBvbHlnb25Db250YWluc1BvaW50KHBvbHlnb25zW2ldLCB4LCB5KSkgcmV0dXJuIHRoaXMuYm91bmRpbmdCb3hlc1tpXTtcblx0XHRyZXR1cm4gbnVsbDtcblx0fSxcblx0LyoqIFJldHVybnMgdGhlIGZpcnN0IGJvdW5kaW5nIGJveCBhdHRhY2htZW50IHRoYXQgY29udGFpbnMgdGhlIGxpbmUgc2VnbWVudCwgb3IgbnVsbC4gV2hlbiBkb2luZyBtYW55IGNoZWNrcywgaXQgaXMgdXN1YWxseVxuXHQgKiBtb3JlIGVmZmljaWVudCB0byBvbmx5IGNhbGwgdGhpcyBtZXRob2QgaWYge0BsaW5rICNhYWJiSW50ZXJzZWN0c1NlZ21lbnQoZmxvYXQsIGZsb2F0LCBmbG9hdCwgZmxvYXQpfSByZXR1cm5zIHRydWUuICovXG5cdGludGVyc2VjdHNTZWdtZW50OiBmdW5jdGlvbiAoeDEsIHkxLCB4MiwgeTIpIHtcblx0XHR2YXIgcG9seWdvbnMgPSB0aGlzLnBvbHlnb25zO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gcG9seWdvbnMubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0aWYgKHBvbHlnb25zW2ldLmludGVyc2VjdHNTZWdtZW50KHgxLCB5MSwgeDIsIHkyKSkgcmV0dXJuIHRoaXMuYm91bmRpbmdCb3hlc1tpXTtcblx0XHRyZXR1cm4gbnVsbDtcblx0fSxcblx0LyoqIFJldHVybnMgdHJ1ZSBpZiB0aGUgcG9seWdvbiBjb250YWlucyB0aGUgcG9pbnQuICovXG5cdHBvbHlnb25Db250YWluc1BvaW50OiBmdW5jdGlvbiAocG9seWdvbiwgeCwgeSkge1xuXHRcdHZhciBubiA9IHBvbHlnb24ubGVuZ3RoO1xuXHRcdHZhciBwcmV2SW5kZXggPSBubiAtIDI7XG5cdFx0dmFyIGluc2lkZSA9IGZhbHNlO1xuXHRcdGZvciAodmFyIGlpID0gMDsgaWkgPCBubjsgaWkgKz0gMikge1xuXHRcdFx0dmFyIHZlcnRleFkgPSBwb2x5Z29uW2lpICsgMV07XG5cdFx0XHR2YXIgcHJldlkgPSBwb2x5Z29uW3ByZXZJbmRleCArIDFdO1xuXHRcdFx0aWYgKCh2ZXJ0ZXhZIDwgeSAmJiBwcmV2WSA+PSB5KSB8fCAocHJldlkgPCB5ICYmIHZlcnRleFkgPj0geSkpIHtcblx0XHRcdFx0dmFyIHZlcnRleFggPSBwb2x5Z29uW2lpXTtcblx0XHRcdFx0aWYgKHZlcnRleFggKyAoeSAtIHZlcnRleFkpIC8gKHByZXZZIC0gdmVydGV4WSkgKiAocG9seWdvbltwcmV2SW5kZXhdIC0gdmVydGV4WCkgPCB4KSBpbnNpZGUgPSAhaW5zaWRlO1xuXHRcdFx0fVxuXHRcdFx0cHJldkluZGV4ID0gaWk7XG5cdFx0fVxuXHRcdHJldHVybiBpbnNpZGU7XG5cdH0sXG5cdC8qKiBSZXR1cm5zIHRydWUgaWYgdGhlIHBvbHlnb24gY29udGFpbnMgdGhlIGxpbmUgc2VnbWVudC4gKi9cblx0cG9seWdvbkludGVyc2VjdHNTZWdtZW50OiBmdW5jdGlvbiAocG9seWdvbiwgeDEsIHkxLCB4MiwgeTIpIHtcblx0XHR2YXIgbm4gPSBwb2x5Z29uLmxlbmd0aDtcblx0XHR2YXIgd2lkdGgxMiA9IHgxIC0geDIsIGhlaWdodDEyID0geTEgLSB5Mjtcblx0XHR2YXIgZGV0MSA9IHgxICogeTIgLSB5MSAqIHgyO1xuXHRcdHZhciB4MyA9IHBvbHlnb25bbm4gLSAyXSwgeTMgPSBwb2x5Z29uW25uIC0gMV07XG5cdFx0Zm9yICh2YXIgaWkgPSAwOyBpaSA8IG5uOyBpaSArPSAyKSB7XG5cdFx0XHR2YXIgeDQgPSBwb2x5Z29uW2lpXSwgeTQgPSBwb2x5Z29uW2lpICsgMV07XG5cdFx0XHR2YXIgZGV0MiA9IHgzICogeTQgLSB5MyAqIHg0O1xuXHRcdFx0dmFyIHdpZHRoMzQgPSB4MyAtIHg0LCBoZWlnaHQzNCA9IHkzIC0geTQ7XG5cdFx0XHR2YXIgZGV0MyA9IHdpZHRoMTIgKiBoZWlnaHQzNCAtIGhlaWdodDEyICogd2lkdGgzNDtcblx0XHRcdHZhciB4ID0gKGRldDEgKiB3aWR0aDM0IC0gd2lkdGgxMiAqIGRldDIpIC8gZGV0Mztcblx0XHRcdGlmICgoKHggPj0geDMgJiYgeCA8PSB4NCkgfHwgKHggPj0geDQgJiYgeCA8PSB4MykpICYmICgoeCA+PSB4MSAmJiB4IDw9IHgyKSB8fCAoeCA+PSB4MiAmJiB4IDw9IHgxKSkpIHtcblx0XHRcdFx0dmFyIHkgPSAoZGV0MSAqIGhlaWdodDM0IC0gaGVpZ2h0MTIgKiBkZXQyKSAvIGRldDM7XG5cdFx0XHRcdGlmICgoKHkgPj0geTMgJiYgeSA8PSB5NCkgfHwgKHkgPj0geTQgJiYgeSA8PSB5MykpICYmICgoeSA+PSB5MSAmJiB5IDw9IHkyKSB8fCAoeSA+PSB5MiAmJiB5IDw9IHkxKSkpIHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0eDMgPSB4NDtcblx0XHRcdHkzID0geTQ7XG5cdFx0fVxuXHRcdHJldHVybiBmYWxzZTtcblx0fSxcblx0Z2V0UG9seWdvbjogZnVuY3Rpb24gKGF0dGFjaG1lbnQpIHtcblx0XHR2YXIgaW5kZXggPSB0aGlzLmJvdW5kaW5nQm94ZXMuaW5kZXhPZihhdHRhY2htZW50KTtcblx0XHRyZXR1cm4gaW5kZXggPT0gLTEgPyBudWxsIDogdGhpcy5wb2x5Z29uc1tpbmRleF07XG5cdH0sXG5cdGdldFdpZHRoOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMubWF4WCAtIHRoaXMubWluWDtcblx0fSxcblx0Z2V0SGVpZ2h0OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMubWF4WSAtIHRoaXMubWluWTtcblx0fVxufTtcbiIsIi8qKlxuICogQGZpbGUgICAgICAgIE1haW4gZXhwb3J0IG9mIHRoZSBQSVhJIHNwaW5lIGxpYnJhcnlcbiAqIEBhdXRob3IgICAgICBNYXQgR3JvdmVzIDxtYXRAZ29vZGJveWRpZ2l0YWwuY29tPlxuICogQGNvcHlyaWdodCAgIDIwMTMtMjAxNSBHb29kQm95RGlnaXRhbFxuICogQGxpY2Vuc2UgICAgIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vR29vZEJveURpZ2l0YWwvcGl4aS5qcy9ibG9iL21hc3Rlci9MSUNFTlNFfE1JVCBMaWNlbnNlfVxuICovXG5cbi8qKlxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIFNwaW5lOiAgICAgICAgICAgICAgcmVxdWlyZSgnLi9TcGluZScpXG59O1xuIiwidmFyIGNvcmUgPSByZXF1aXJlKCcuLi9jb3JlJyk7XG5cbi8qKlxuICogQSBCaXRtYXBUZXh0IG9iamVjdCB3aWxsIGNyZWF0ZSBhIGxpbmUgb3IgbXVsdGlwbGUgbGluZXMgb2YgdGV4dCB1c2luZyBiaXRtYXAgZm9udC4gVG9cbiAqIHNwbGl0IGEgbGluZSB5b3UgY2FuIHVzZSAnXFxuJywgJ1xccicgb3IgJ1xcclxcbicgaW4geW91ciBzdHJpbmcuIFlvdSBjYW4gZ2VuZXJhdGUgdGhlIGZudCBmaWxlcyB1c2luZzpcbiAqXG4gKiBodHRwOi8vd3d3LmFuZ2VsY29kZS5jb20vcHJvZHVjdHMvYm1mb250LyBmb3Igd2luZG93cyBvclxuICogaHR0cDovL3d3dy5ibWdseXBoLmNvbS8gZm9yIG1hYy5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIERpc3BsYXlPYmplY3RDb250YWluZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHRleHQge3N0cmluZ30gVGhlIGNvcHkgdGhhdCB5b3Ugd291bGQgbGlrZSB0aGUgdGV4dCB0byBkaXNwbGF5XG4gKiBAcGFyYW0gc3R5bGUge29iamVjdH0gVGhlIHN0eWxlIHBhcmFtZXRlcnNcbiAqIEBwYXJhbSBzdHlsZS5mb250IHtzdHJpbmd9IFRoZSBzaXplIChvcHRpb25hbCkgYW5kIGJpdG1hcCBmb250IGlkIChyZXF1aXJlZCkgZXEgJ0FyaWFsJyBvciAnMjBweCBBcmlhbCcgKG11c3QgaGF2ZSBsb2FkZWQgcHJldmlvdXNseSlcbiAqIEBwYXJhbSBbc3R5bGUuYWxpZ249J2xlZnQnXSB7c3RyaW5nfSBBbGlnbm1lbnQgZm9yIG11bHRpbGluZSB0ZXh0ICgnbGVmdCcsICdjZW50ZXInIG9yICdyaWdodCcpLCBkb2VzIG5vdCBhZmZlY3Qgc2luZ2xlIGxpbmUgdGV4dFxuICovXG5mdW5jdGlvbiBCaXRtYXBUZXh0KHRleHQsIHN0eWxlKSB7XG4gICAgY29yZS5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLmNhbGwodGhpcyk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgd2lkdGggb2YgdGhlIG92ZXJhbGwgdGV4dCwgZGlmZmVyZW50IGZyb20gZm9udFNpemUsXG4gICAgICogd2hpY2ggaXMgZGVmaW5lZCBpbiB0aGUgc3R5bGUgb2JqZWN0XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQHJlYWRPbmx5XG4gICAgICovXG4gICAgdGhpcy50ZXh0V2lkdGggPSAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGhlaWdodCBvZiB0aGUgb3ZlcmFsbCB0ZXh0LCBkaWZmZXJlbnQgZnJvbSBmb250U2l6ZSxcbiAgICAgKiB3aGljaCBpcyBkZWZpbmVkIGluIHRoZSBzdHlsZSBvYmplY3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAcmVhZE9ubHlcbiAgICAgKi9cbiAgICB0aGlzLnRleHRIZWlnaHQgPSAwO1xuXG4gICAgLyoqXG4gICAgICogUHJpdmF0ZSB0cmFja2VyIGZvciB0aGUgbGV0dGVyIHNwcml0ZSBwb29sLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7U3ByaXRlW119XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl9wb29sID0gW107XG5cbiAgICAvKipcbiAgICAgKiBQcml2YXRlIHRyYWNrZXIgZm9yIHRoZSBjdXJyZW50IHN0eWxlLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7b2JqZWN0fVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fc3R5bGUgPSB7XG4gICAgICAgIHRpbnQ6IHN0eWxlLnRpbnQsXG4gICAgICAgIGFsaWduOiBzdHlsZS5hbGlnbixcbiAgICAgICAgZm9udE5hbWU6IG51bGwsXG4gICAgICAgIGZvbnRTaXplOiAwXG4gICAgfTtcbiAgICB0aGlzLmZvbnQgPSBzdHlsZS5mb250OyAvLyBydW4gZm9udCBzZXR0ZXJcblxuICAgIC8qKlxuICAgICAqIFByaXZhdGUgdHJhY2tlciBmb3IgdGhlIGN1cnJlbnQgdGV4dC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge3N0cmluZ31cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuX3RleHQgPSB0ZXh0O1xuXG4gICAgLyoqXG4gICAgICogVGhlIGRpcnR5IHN0YXRlIG9mIHRoaXMgb2JqZWN0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLmRpcnR5ID0gZmFsc2U7XG5cbiAgICB0aGlzLnVwZGF0ZVRleHQoKTtcbn1cblxuLy8gY29uc3RydWN0b3JcbkJpdG1hcFRleHQucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShjb3JlLkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlKTtcbkJpdG1hcFRleHQucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQml0bWFwVGV4dDtcbm1vZHVsZS5leHBvcnRzID0gQml0bWFwVGV4dDtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQml0bWFwVGV4dC5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBUaGUgdGludCBvZiB0aGUgQml0bWFwVGV4dCBvYmplY3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgQml0bWFwVGV4dCNcbiAgICAgKi9cbiAgICB0aW50OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3N0eWxlLnRpbnQ7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLl9zdHlsZS50aW50ID0gKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgJiYgdmFsdWUgPj0gMCkgPyB2YWx1ZSA6IDB4RkZGRkZGO1xuXG4gICAgICAgICAgICB0aGlzLmRpcnR5ID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgdGludCBvZiB0aGUgQml0bWFwVGV4dCBvYmplY3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge3N0cmluZ31cbiAgICAgKiBAZGVmYXVsdCAnbGVmdCdcbiAgICAgKiBAbWVtYmVyb2YgQml0bWFwVGV4dCNcbiAgICAgKi9cbiAgICBhbGlnbjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9zdHlsZS5hbGlnbjtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuX3N0eWxlLmFsaWduID0gdmFsdWU7XG5cbiAgICAgICAgICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoZSB0aW50IG9mIHRoZSBCaXRtYXBUZXh0IG9iamVjdFxuICAgICAqXG4gICAgICogQG1lbWJlciB7Rm9udH1cbiAgICAgKiBAbWVtYmVyb2YgQml0bWFwVGV4dCNcbiAgICAgKi9cbiAgICBmb250OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3N0eWxlLmZvbnQ7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnNwbGl0KCcgJyk7XG5cbiAgICAgICAgICAgIC8vIFRPRE8gLSBUaGlzIHNob3VsZCBiZSBvYmplY3QtYmFzZWQgbm90IHN0cmluZyBiYXNlZCBsaWtlIGl0IGhhcyBiZWVuLlxuICAgICAgICAgICAgdGhpcy5fc3R5bGUuZm9udE5hbWUgPSB2YWx1ZVt2YWx1ZS5sZW5ndGggLSAxXTtcbiAgICAgICAgICAgIHRoaXMuX3N0eWxlLmZvbnRTaXplID0gdmFsdWUubGVuZ3RoID49IDIgPyBwYXJzZUludCh2YWx1ZVt2YWx1ZS5sZW5ndGggLSAyXSwgMTApIDogQml0bWFwVGV4dC5mb250c1t0aGlzLmZvbnROYW1lXS5zaXplO1xuXG4gICAgICAgICAgICB0aGlzLmRpcnR5ID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgdGV4dCBvZiB0aGUgQml0bWFwVGV4dCBvYmplY3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge3N0cmluZ31cbiAgICAgKiBAbWVtYmVyb2YgQml0bWFwVGV4dCNcbiAgICAgKi9cbiAgICB0ZXh0OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3RleHQ7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLl90ZXh0ID0gdmFsdWU7XG5cbiAgICAgICAgICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG5cbi8qKlxuICogUmVuZGVycyB0ZXh0IGFuZCB1cGRhdGVzIGl0IHdoZW4gbmVlZGVkXG4gKlxuICogQHByaXZhdGVcbiAqL1xuQml0bWFwVGV4dC5wcm90b3R5cGUudXBkYXRlVGV4dCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZGF0YSA9IEJpdG1hcFRleHQuZm9udHNbdGhpcy5mb250TmFtZV07XG4gICAgdmFyIHBvcyA9IG5ldyBjb3JlLm1hdGguUG9pbnQoKTtcbiAgICB2YXIgcHJldkNoYXJDb2RlID0gbnVsbDtcbiAgICB2YXIgY2hhcnMgPSBbXTtcbiAgICB2YXIgbWF4TGluZVdpZHRoID0gMDtcbiAgICB2YXIgbGluZVdpZHRocyA9IFtdO1xuICAgIHZhciBsaW5lID0gMDtcbiAgICB2YXIgc2NhbGUgPSB0aGlzLmZvbnRTaXplIC8gZGF0YS5zaXplO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnRleHQubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGNoYXJDb2RlID0gdGhpcy50ZXh0LmNoYXJDb2RlQXQoaSk7XG5cbiAgICAgICAgaWYgKC8oPzpcXHJcXG58XFxyfFxcbikvLnRlc3QodGhpcy50ZXh0LmNoYXJBdChpKSkpIHtcbiAgICAgICAgICAgIGxpbmVXaWR0aHMucHVzaChwb3MueCk7XG4gICAgICAgICAgICBtYXhMaW5lV2lkdGggPSBNYXRoLm1heChtYXhMaW5lV2lkdGgsIHBvcy54KTtcbiAgICAgICAgICAgIGxpbmUrKztcblxuICAgICAgICAgICAgcG9zLnggPSAwO1xuICAgICAgICAgICAgcG9zLnkgKz0gZGF0YS5saW5lSGVpZ2h0O1xuICAgICAgICAgICAgcHJldkNoYXJDb2RlID0gbnVsbDtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGNoYXJEYXRhID0gZGF0YS5jaGFyc1tjaGFyQ29kZV07XG5cbiAgICAgICAgaWYgKCFjaGFyRGF0YSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocHJldkNoYXJDb2RlICYmIGNoYXJEYXRhLmtlcm5pbmdbcHJldkNoYXJDb2RlXSkge1xuICAgICAgICAgICAgcG9zLnggKz0gY2hhckRhdGEua2VybmluZ1twcmV2Q2hhckNvZGVdO1xuICAgICAgICB9XG5cbiAgICAgICAgY2hhcnMucHVzaCh7dGV4dHVyZTpjaGFyRGF0YS50ZXh0dXJlLCBsaW5lOiBsaW5lLCBjaGFyQ29kZTogY2hhckNvZGUsIHBvc2l0aW9uOiBuZXcgY29yZS5tYXRoLlBvaW50KHBvcy54ICsgY2hhckRhdGEueE9mZnNldCwgcG9zLnkgKyBjaGFyRGF0YS55T2Zmc2V0KX0pO1xuICAgICAgICBwb3MueCArPSBjaGFyRGF0YS54QWR2YW5jZTtcblxuICAgICAgICBwcmV2Q2hhckNvZGUgPSBjaGFyQ29kZTtcbiAgICB9XG5cbiAgICBsaW5lV2lkdGhzLnB1c2gocG9zLngpO1xuICAgIG1heExpbmVXaWR0aCA9IE1hdGgubWF4KG1heExpbmVXaWR0aCwgcG9zLngpO1xuXG4gICAgdmFyIGxpbmVBbGlnbk9mZnNldHMgPSBbXTtcblxuICAgIGZvciAoaSA9IDA7IGkgPD0gbGluZTsgaSsrKSB7XG4gICAgICAgIHZhciBhbGlnbk9mZnNldCA9IDA7XG5cbiAgICAgICAgaWYgKHRoaXMuc3R5bGUuYWxpZ24gPT09ICdyaWdodCcpIHtcbiAgICAgICAgICAgIGFsaWduT2Zmc2V0ID0gbWF4TGluZVdpZHRoIC0gbGluZVdpZHRoc1tpXTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0aGlzLnN0eWxlLmFsaWduID09PSAnY2VudGVyJykge1xuICAgICAgICAgICAgYWxpZ25PZmZzZXQgPSAobWF4TGluZVdpZHRoIC0gbGluZVdpZHRoc1tpXSkgLyAyO1xuICAgICAgICB9XG5cbiAgICAgICAgbGluZUFsaWduT2Zmc2V0cy5wdXNoKGFsaWduT2Zmc2V0KTtcbiAgICB9XG5cbiAgICB2YXIgbGVuQ2hpbGRyZW4gPSB0aGlzLmNoaWxkcmVuLmxlbmd0aDtcbiAgICB2YXIgbGVuQ2hhcnMgPSBjaGFycy5sZW5ndGg7XG4gICAgdmFyIHRpbnQgPSB0aGlzLnRpbnQ7XG5cbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuQ2hhcnM7IGkrKykge1xuICAgICAgICB2YXIgYyA9IGkgPCBsZW5DaGlsZHJlbiA/IHRoaXMuY2hpbGRyZW5baV0gOiB0aGlzLl9wb29sLnBvcCgpOyAvLyBnZXQgb2xkIGNoaWxkIGlmIGhhdmUuIGlmIG5vdCAtIHRha2UgZnJvbSBwb29sLlxuXG4gICAgICAgIGlmIChjKSB7XG4gICAgICAgICAgICBjLnNldFRleHR1cmUoY2hhcnNbaV0udGV4dHVyZSk7IC8vIGNoZWNrIGlmIGdvdCBvbmUgYmVmb3JlLlxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgYyA9IG5ldyBjb3JlLlNwcml0ZShjaGFyc1tpXS50ZXh0dXJlKTsgLy8gaWYgbm8gY3JlYXRlIG5ldyBvbmUuXG4gICAgICAgIH1cblxuICAgICAgICBjLnBvc2l0aW9uLnggPSAoY2hhcnNbaV0ucG9zaXRpb24ueCArIGxpbmVBbGlnbk9mZnNldHNbY2hhcnNbaV0ubGluZV0pICogc2NhbGU7XG4gICAgICAgIGMucG9zaXRpb24ueSA9IGNoYXJzW2ldLnBvc2l0aW9uLnkgKiBzY2FsZTtcbiAgICAgICAgYy5zY2FsZS54ID0gYy5zY2FsZS55ID0gc2NhbGU7XG4gICAgICAgIGMudGludCA9IHRpbnQ7XG5cbiAgICAgICAgaWYgKCFjLnBhcmVudCkge1xuICAgICAgICAgICAgdGhpcy5hZGRDaGlsZChjKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIHJlbW92ZSB1bm5lY2Vzc2FyeSBjaGlsZHJlbi5cbiAgICAvLyBhbmQgcHV0IHRoZWlyIGludG8gdGhlIHBvb2wuXG4gICAgd2hpbGUodGhpcy5jaGlsZHJlbi5sZW5ndGggPiBsZW5DaGFycykge1xuICAgICAgICB2YXIgY2hpbGQgPSB0aGlzLmdldENoaWxkQXQodGhpcy5jaGlsZHJlbi5sZW5ndGggLSAxKTtcbiAgICAgICAgdGhpcy5fcG9vbC5wdXNoKGNoaWxkKTtcbiAgICAgICAgdGhpcy5yZW1vdmVDaGlsZChjaGlsZCk7XG4gICAgfVxuXG4gICAgdGhpcy50ZXh0V2lkdGggPSBtYXhMaW5lV2lkdGggKiBzY2FsZTtcbiAgICB0aGlzLnRleHRIZWlnaHQgPSAocG9zLnkgKyBkYXRhLmxpbmVIZWlnaHQpICogc2NhbGU7XG59O1xuXG4vKipcbiAqIFVwZGF0ZXMgdGhlIHRyYW5zZm9ybSBvZiB0aGlzIG9iamVjdFxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkJpdG1hcFRleHQucHJvdG90eXBlLnVwZGF0ZVRyYW5zZm9ybSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnVwZGF0ZVRleHQoKTtcbiAgICAgICAgdGhpcy5kaXJ0eSA9IGZhbHNlO1xuICAgIH1cblxuICAgIHRoaXMuZGlzcGxheU9iamVjdENvbnRhaW5lclVwZGF0ZVRyYW5zZm9ybSgpO1xufTtcblxuQml0bWFwVGV4dC5mb250cyA9IHt9O1xuIiwidmFyIGNvcmUgPSByZXF1aXJlKCcuLi9jb3JlJyk7XG5cbi8qKlxuICogQSBUZXh0IE9iamVjdCB3aWxsIGNyZWF0ZSBhIGxpbmUgb3IgbXVsdGlwbGUgbGluZXMgb2YgdGV4dC4gVG8gc3BsaXQgYSBsaW5lIHlvdSBjYW4gdXNlICdcXG4nIGluIHlvdXIgdGV4dCBzdHJpbmcsXG4gKiBvciBhZGQgYSB3b3JkV3JhcCBwcm9wZXJ0eSBzZXQgdG8gdHJ1ZSBhbmQgYW5kIHdvcmRXcmFwV2lkdGggcHJvcGVydHkgd2l0aCBhIHZhbHVlIGluIHRoZSBzdHlsZSBvYmplY3QuXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBTcHJpdGVcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHRleHQge3N0cmluZ30gVGhlIGNvcHkgdGhhdCB5b3Ugd291bGQgbGlrZSB0aGUgdGV4dCB0byBkaXNwbGF5XG4gKiBAcGFyYW0gW3N0eWxlXSB7b2JqZWN0fSBUaGUgc3R5bGUgcGFyYW1ldGVyc1xuICogQHBhcmFtIFtzdHlsZS5mb250XSB7c3RyaW5nfSBkZWZhdWx0ICdib2xkIDIwcHggQXJpYWwnIFRoZSBzdHlsZSBhbmQgc2l6ZSBvZiB0aGUgZm9udFxuICogQHBhcmFtIFtzdHlsZS5maWxsPSdibGFjayddIHtTdHJpbmd8TnVtYmVyfSBBIGNhbnZhcyBmaWxsc3R5bGUgdGhhdCB3aWxsIGJlIHVzZWQgb24gdGhlIHRleHQgZS5nICdyZWQnLCAnIzAwRkYwMCdcbiAqIEBwYXJhbSBbc3R5bGUuYWxpZ249J2xlZnQnXSB7c3RyaW5nfSBBbGlnbm1lbnQgZm9yIG11bHRpbGluZSB0ZXh0ICgnbGVmdCcsICdjZW50ZXInIG9yICdyaWdodCcpLCBkb2VzIG5vdCBhZmZlY3Qgc2luZ2xlIGxpbmUgdGV4dFxuICogQHBhcmFtIFtzdHlsZS5zdHJva2VdIHtTdHJpbmd8TnVtYmVyfSBBIGNhbnZhcyBmaWxsc3R5bGUgdGhhdCB3aWxsIGJlIHVzZWQgb24gdGhlIHRleHQgc3Ryb2tlIGUuZyAnYmx1ZScsICcjRkNGRjAwJ1xuICogQHBhcmFtIFtzdHlsZS5zdHJva2VUaGlja25lc3M9MF0ge251bWJlcn0gQSBudW1iZXIgdGhhdCByZXByZXNlbnRzIHRoZSB0aGlja25lc3Mgb2YgdGhlIHN0cm9rZS4gRGVmYXVsdCBpcyAwIChubyBzdHJva2UpXG4gKiBAcGFyYW0gW3N0eWxlLndvcmRXcmFwPWZhbHNlXSB7Ym9vbGVhbn0gSW5kaWNhdGVzIGlmIHdvcmQgd3JhcCBzaG91bGQgYmUgdXNlZFxuICogQHBhcmFtIFtzdHlsZS53b3JkV3JhcFdpZHRoPTEwMF0ge251bWJlcn0gVGhlIHdpZHRoIGF0IHdoaWNoIHRleHQgd2lsbCB3cmFwLCBpdCBuZWVkcyB3b3JkV3JhcCB0byBiZSBzZXQgdG8gdHJ1ZVxuICogQHBhcmFtIFtzdHlsZS5kcm9wU2hhZG93PWZhbHNlXSB7Ym9vbGVhbn0gU2V0IGEgZHJvcCBzaGFkb3cgZm9yIHRoZSB0ZXh0XG4gKiBAcGFyYW0gW3N0eWxlLmRyb3BTaGFkb3dDb2xvcj0nIzAwMDAwMCddIHtzdHJpbmd9IEEgZmlsbCBzdHlsZSB0byBiZSB1c2VkIG9uIHRoZSBkcm9wc2hhZG93IGUuZyAncmVkJywgJyMwMEZGMDAnXG4gKiBAcGFyYW0gW3N0eWxlLmRyb3BTaGFkb3dBbmdsZT1NYXRoLlBJLzRdIHtudW1iZXJ9IFNldCBhIGFuZ2xlIG9mIHRoZSBkcm9wIHNoYWRvd1xuICogQHBhcmFtIFtzdHlsZS5kcm9wU2hhZG93RGlzdGFuY2U9NV0ge251bWJlcn0gU2V0IGEgZGlzdGFuY2Ugb2YgdGhlIGRyb3Agc2hhZG93XG4gKi9cbmZ1bmN0aW9uIFRleHQodGV4dCwgc3R5bGUpIHtcbiAgICAvKipcbiAgICAgKiBUaGUgY2FudmFzIGVsZW1lbnQgdGhhdCBldmVyeXRoaW5nIGlzIGRyYXduIHRvXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtIVE1MQ2FudmFzRWxlbWVudH1cbiAgICAgKi9cbiAgICB0aGlzLmNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGNhbnZhcyAyZCBjb250ZXh0IHRoYXQgZXZlcnl0aGluZyBpcyBkcmF3biB3aXRoXG4gICAgICogQG1lbWJlciB7SFRNTENhbnZhc0VsZW1lbnR9XG4gICAgICovXG4gICAgdGhpcy5jb250ZXh0ID0gdGhpcy5jYW52YXMuZ2V0Q29udGV4dCgnMmQnKTtcblxuICAgIC8qKlxuICAgICAqIFRoZSByZXNvbHV0aW9uIG9mIHRoZSBjYW52YXMuXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMucmVzb2x1dGlvbiA9IDE7XG5cbiAgICBjb3JlLlNwcml0ZS5jYWxsKHRoaXMsIGNvcmUuVGV4dHVyZS5mcm9tQ2FudmFzKHRoaXMuY2FudmFzKSk7XG5cbiAgICB0aGlzLnNldFRleHQodGV4dCk7XG4gICAgdGhpcy5zZXRTdHlsZShzdHlsZSk7XG59XG5cbi8vIGNvbnN0cnVjdG9yXG5UZXh0LnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoY29yZS5TcHJpdGUucHJvdG90eXBlKTtcblRleHQucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gVGV4dDtcbm1vZHVsZS5leHBvcnRzID0gVGV4dDtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoVGV4dC5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBUaGUgd2lkdGggb2YgdGhlIFRleHQsIHNldHRpbmcgdGhpcyB3aWxsIGFjdHVhbGx5IG1vZGlmeSB0aGUgc2NhbGUgdG8gYWNoaWV2ZSB0aGUgdmFsdWUgc2V0XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIFRleHQjXG4gICAgICovXG4gICAgd2lkdGg6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlVGV4dCgpO1xuICAgICAgICAgICAgICAgIHRoaXMuZGlydHkgPSBmYWxzZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuc2NhbGUueCAqIHRoaXMudGV4dHVyZS5mcmFtZS53aWR0aDtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuc2NhbGUueCA9IHZhbHVlIC8gdGhpcy50ZXh0dXJlLmZyYW1lLndpZHRoO1xuICAgICAgICAgICAgdGhpcy5fd2lkdGggPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgaGVpZ2h0IG9mIHRoZSBUZXh0LCBzZXR0aW5nIHRoaXMgd2lsbCBhY3R1YWxseSBtb2RpZnkgdGhlIHNjYWxlIHRvIGFjaGlldmUgdGhlIHZhbHVlIHNldFxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUZXh0I1xuICAgICAqL1xuICAgIGhlaWdodDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLmRpcnR5KSB7XG4gICAgICAgICAgICAgICAgdGhpcy51cGRhdGVUZXh0KCk7XG4gICAgICAgICAgICAgICAgdGhpcy5kaXJ0eSA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gIHRoaXMuc2NhbGUueSAqIHRoaXMudGV4dHVyZS5mcmFtZS5oZWlnaHQ7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnNjYWxlLnkgPSB2YWx1ZSAvIHRoaXMudGV4dHVyZS5mcmFtZS5oZWlnaHQ7XG4gICAgICAgICAgICB0aGlzLl9oZWlnaHQgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG4vKipcbiAqIFNldCB0aGUgc3R5bGUgb2YgdGhlIHRleHRcbiAqXG4gKiBAcGFyYW0gW3N0eWxlXSB7b2JqZWN0fSBUaGUgc3R5bGUgcGFyYW1ldGVyc1xuICogQHBhcmFtIFtzdHlsZS5mb250PSdib2xkIDIwcHQgQXJpYWwnXSB7c3RyaW5nfSBUaGUgc3R5bGUgYW5kIHNpemUgb2YgdGhlIGZvbnRcbiAqIEBwYXJhbSBbc3R5bGUuZmlsbD0nYmxhY2snXSB7b2JqZWN0fSBBIGNhbnZhcyBmaWxsc3R5bGUgdGhhdCB3aWxsIGJlIHVzZWQgb24gdGhlIHRleHQgZWcgJ3JlZCcsICcjMDBGRjAwJ1xuICogQHBhcmFtIFtzdHlsZS5hbGlnbj0nbGVmdCddIHtzdHJpbmd9IEFsaWdubWVudCBmb3IgbXVsdGlsaW5lIHRleHQgKCdsZWZ0JywgJ2NlbnRlcicgb3IgJ3JpZ2h0JyksIGRvZXMgbm90IGFmZmVjdCBzaW5nbGUgbGluZSB0ZXh0XG4gKiBAcGFyYW0gW3N0eWxlLnN0cm9rZT0nYmxhY2snXSB7c3RyaW5nfSBBIGNhbnZhcyBmaWxsc3R5bGUgdGhhdCB3aWxsIGJlIHVzZWQgb24gdGhlIHRleHQgc3Ryb2tlIGVnICdibHVlJywgJyNGQ0ZGMDAnXG4gKiBAcGFyYW0gW3N0eWxlLnN0cm9rZVRoaWNrbmVzcz0wXSB7bnVtYmVyfSBBIG51bWJlciB0aGF0IHJlcHJlc2VudHMgdGhlIHRoaWNrbmVzcyBvZiB0aGUgc3Ryb2tlLiBEZWZhdWx0IGlzIDAgKG5vIHN0cm9rZSlcbiAqIEBwYXJhbSBbc3R5bGUud29yZFdyYXA9ZmFsc2VdIHtib29sZWFufSBJbmRpY2F0ZXMgaWYgd29yZCB3cmFwIHNob3VsZCBiZSB1c2VkXG4gKiBAcGFyYW0gW3N0eWxlLndvcmRXcmFwV2lkdGg9MTAwXSB7bnVtYmVyfSBUaGUgd2lkdGggYXQgd2hpY2ggdGV4dCB3aWxsIHdyYXBcbiAqIEBwYXJhbSBbc3R5bGUuZHJvcFNoYWRvdz1mYWxzZV0ge2Jvb2xlYW59IFNldCBhIGRyb3Agc2hhZG93IGZvciB0aGUgdGV4dFxuICogQHBhcmFtIFtzdHlsZS5kcm9wU2hhZG93Q29sb3I9JyMwMDAwMDAnXSB7c3RyaW5nfSBBIGZpbGwgc3R5bGUgdG8gYmUgdXNlZCBvbiB0aGUgZHJvcHNoYWRvdyBlLmcgJ3JlZCcsICcjMDBGRjAwJ1xuICogQHBhcmFtIFtzdHlsZS5kcm9wU2hhZG93QW5nbGU9TWF0aC5QSS80XSB7bnVtYmVyfSBTZXQgYSBhbmdsZSBvZiB0aGUgZHJvcCBzaGFkb3dcbiAqIEBwYXJhbSBbc3R5bGUuZHJvcFNoYWRvd0Rpc3RhbmNlPTVdIHtudW1iZXJ9IFNldCBhIGRpc3RhbmNlIG9mIHRoZSBkcm9wIHNoYWRvd1xuICovXG5UZXh0LnByb3RvdHlwZS5zZXRTdHlsZSA9IGZ1bmN0aW9uIChzdHlsZSkge1xuICAgIHN0eWxlID0gc3R5bGUgfHwge307XG4gICAgc3R5bGUuZm9udCA9IHN0eWxlLmZvbnQgfHwgJ2JvbGQgMjBwdCBBcmlhbCc7XG4gICAgc3R5bGUuZmlsbCA9IHN0eWxlLmZpbGwgfHwgJ2JsYWNrJztcbiAgICBzdHlsZS5hbGlnbiA9IHN0eWxlLmFsaWduIHx8ICdsZWZ0JztcbiAgICBzdHlsZS5zdHJva2UgPSBzdHlsZS5zdHJva2UgfHwgJ2JsYWNrJzsgLy9wcm92aWRlIGEgZGVmYXVsdCwgc2VlOiBodHRwczovL2dpdGh1Yi5jb20vR29vZEJveURpZ2l0YWwvcGl4aS5qcy9pc3N1ZXMvMTM2XG4gICAgc3R5bGUuc3Ryb2tlVGhpY2tuZXNzID0gc3R5bGUuc3Ryb2tlVGhpY2tuZXNzIHx8IDA7XG4gICAgc3R5bGUud29yZFdyYXAgPSBzdHlsZS53b3JkV3JhcCB8fCBmYWxzZTtcbiAgICBzdHlsZS53b3JkV3JhcFdpZHRoID0gc3R5bGUud29yZFdyYXBXaWR0aCB8fCAxMDA7XG5cbiAgICBzdHlsZS5kcm9wU2hhZG93ID0gc3R5bGUuZHJvcFNoYWRvdyB8fCBmYWxzZTtcbiAgICBzdHlsZS5kcm9wU2hhZG93QW5nbGUgPSBzdHlsZS5kcm9wU2hhZG93QW5nbGUgfHwgTWF0aC5QSSAvIDY7XG4gICAgc3R5bGUuZHJvcFNoYWRvd0Rpc3RhbmNlID0gc3R5bGUuZHJvcFNoYWRvd0Rpc3RhbmNlIHx8IDQ7XG4gICAgc3R5bGUuZHJvcFNoYWRvd0NvbG9yID0gc3R5bGUuZHJvcFNoYWRvd0NvbG9yIHx8ICdibGFjayc7XG5cbiAgICB0aGlzLnN0eWxlID0gc3R5bGU7XG4gICAgdGhpcy5kaXJ0eSA9IHRydWU7XG59O1xuXG4vKipcbiAqIFNldCB0aGUgY29weSBmb3IgdGhlIHRleHQgb2JqZWN0LiBUbyBzcGxpdCBhIGxpbmUgeW91IGNhbiB1c2UgJ1xcbicuXG4gKlxuICogQHBhcmFtIHRleHQge3N0cmluZ30gVGhlIGNvcHkgdGhhdCB5b3Ugd291bGQgbGlrZSB0aGUgdGV4dCB0byBkaXNwbGF5XG4gKi9cblRleHQucHJvdG90eXBlLnNldFRleHQgPSBmdW5jdGlvbiAodGV4dCkge1xuICAgIHRoaXMudGV4dCA9IHRleHQudG9TdHJpbmcoKSB8fCAnICc7XG4gICAgdGhpcy5kaXJ0eSA9IHRydWU7XG59O1xuXG4vKipcbiAqIFJlbmRlcnMgdGV4dCBhbmQgdXBkYXRlcyBpdCB3aGVuIG5lZWRlZFxuICpcbiAqIEBwcml2YXRlXG4gKi9cblRleHQucHJvdG90eXBlLnVwZGF0ZVRleHQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy50ZXh0dXJlLmJhc2VUZXh0dXJlLnJlc29sdXRpb24gPSB0aGlzLnJlc29sdXRpb247XG5cbiAgICB0aGlzLmNvbnRleHQuZm9udCA9IHRoaXMuc3R5bGUuZm9udDtcblxuICAgIHZhciBvdXRwdXRUZXh0ID0gdGhpcy50ZXh0O1xuXG4gICAgLy8gd29yZCB3cmFwXG4gICAgLy8gcHJlc2VydmUgb3JpZ2luYWwgdGV4dFxuICAgIGlmICh0aGlzLnN0eWxlLndvcmRXcmFwKSB7XG4gICAgICAgIG91dHB1dFRleHQgPSB0aGlzLndvcmRXcmFwKHRoaXMudGV4dCk7XG4gICAgfVxuXG4gICAgLy9zcGxpdCB0ZXh0IGludG8gbGluZXNcbiAgICB2YXIgbGluZXMgPSBvdXRwdXRUZXh0LnNwbGl0KC8oPzpcXHJcXG58XFxyfFxcbikvKTtcblxuICAgIC8vY2FsY3VsYXRlIHRleHQgd2lkdGhcbiAgICB2YXIgbGluZVdpZHRocyA9IFtdO1xuICAgIHZhciBtYXhMaW5lV2lkdGggPSAwO1xuICAgIHZhciBmb250UHJvcGVydGllcyA9IHRoaXMuZGV0ZXJtaW5lRm9udFByb3BlcnRpZXModGhpcy5zdHlsZS5mb250KTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBsaW5lV2lkdGggPSB0aGlzLmNvbnRleHQubWVhc3VyZVRleHQobGluZXNbaV0pLndpZHRoO1xuICAgICAgICBsaW5lV2lkdGhzW2ldID0gbGluZVdpZHRoO1xuICAgICAgICBtYXhMaW5lV2lkdGggPSBNYXRoLm1heChtYXhMaW5lV2lkdGgsIGxpbmVXaWR0aCk7XG4gICAgfVxuXG4gICAgdmFyIHdpZHRoID0gbWF4TGluZVdpZHRoICsgdGhpcy5zdHlsZS5zdHJva2VUaGlja25lc3M7XG4gICAgaWYgKHRoaXMuc3R5bGUuZHJvcFNoYWRvdykge1xuICAgICAgICB3aWR0aCArPSB0aGlzLnN0eWxlLmRyb3BTaGFkb3dEaXN0YW5jZTtcbiAgICB9XG5cbiAgICB0aGlzLmNhbnZhcy53aWR0aCA9ICggd2lkdGggKyB0aGlzLmNvbnRleHQubGluZVdpZHRoICkgKiB0aGlzLnJlc29sdXRpb247XG5cbiAgICAvL2NhbGN1bGF0ZSB0ZXh0IGhlaWdodFxuICAgIHZhciBsaW5lSGVpZ2h0ID0gZm9udFByb3BlcnRpZXMuZm9udFNpemUgKyB0aGlzLnN0eWxlLnN0cm9rZVRoaWNrbmVzcztcblxuICAgIHZhciBoZWlnaHQgPSBsaW5lSGVpZ2h0ICogbGluZXMubGVuZ3RoO1xuICAgIGlmICh0aGlzLnN0eWxlLmRyb3BTaGFkb3cpIHtcbiAgICAgICAgaGVpZ2h0ICs9IHRoaXMuc3R5bGUuZHJvcFNoYWRvd0Rpc3RhbmNlO1xuICAgIH1cblxuICAgIHRoaXMuY2FudmFzLmhlaWdodCA9IGhlaWdodCAqIHRoaXMucmVzb2x1dGlvbjtcblxuICAgIHRoaXMuY29udGV4dC5zY2FsZSggdGhpcy5yZXNvbHV0aW9uLCB0aGlzLnJlc29sdXRpb24pO1xuXG4gICAgaWYgKG5hdmlnYXRvci5pc0NvY29vbkpTKSB7XG4gICAgICAgIHRoaXMuY29udGV4dC5jbGVhclJlY3QoMCwgMCwgdGhpcy5jYW52YXMud2lkdGgsIHRoaXMuY2FudmFzLmhlaWdodCk7XG4gICAgfVxuXG4gICAgLy8gdXNlZCBmb3IgZGVidWdnaW5nLi5cbiAgICAvL3RoaXMuY29udGV4dC5maWxsU3R5bGUgPVwiI0ZGMDAwMFwiXG4gICAgLy90aGlzLmNvbnRleHQuZmlsbFJlY3QoMCwgMCwgdGhpcy5jYW52YXMud2lkdGgsdGhpcy5jYW52YXMuaGVpZ2h0KTtcblxuICAgIHRoaXMuY29udGV4dC5mb250ID0gdGhpcy5zdHlsZS5mb250O1xuICAgIHRoaXMuY29udGV4dC5zdHJva2VTdHlsZSA9IHRoaXMuc3R5bGUuc3Ryb2tlO1xuICAgIHRoaXMuY29udGV4dC5saW5lV2lkdGggPSB0aGlzLnN0eWxlLnN0cm9rZVRoaWNrbmVzcztcbiAgICB0aGlzLmNvbnRleHQudGV4dEJhc2VsaW5lID0gJ2FscGhhYmV0aWMnO1xuICAgIC8vdGhpcy5jb250ZXh0LmxpbmVKb2luID0gJ3JvdW5kJztcblxuICAgIHZhciBsaW5lUG9zaXRpb25YO1xuICAgIHZhciBsaW5lUG9zaXRpb25ZO1xuXG4gICAgaWYgKHRoaXMuc3R5bGUuZHJvcFNoYWRvdykge1xuICAgICAgICB0aGlzLmNvbnRleHQuZmlsbFN0eWxlID0gdGhpcy5zdHlsZS5kcm9wU2hhZG93Q29sb3I7XG5cbiAgICAgICAgdmFyIHhTaGFkb3dPZmZzZXQgPSBNYXRoLmNvcyh0aGlzLnN0eWxlLmRyb3BTaGFkb3dBbmdsZSkgKiB0aGlzLnN0eWxlLmRyb3BTaGFkb3dEaXN0YW5jZTtcbiAgICAgICAgdmFyIHlTaGFkb3dPZmZzZXQgPSBNYXRoLnNpbih0aGlzLnN0eWxlLmRyb3BTaGFkb3dBbmdsZSkgKiB0aGlzLnN0eWxlLmRyb3BTaGFkb3dEaXN0YW5jZTtcblxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGxpbmVQb3NpdGlvblggPSB0aGlzLnN0eWxlLnN0cm9rZVRoaWNrbmVzcyAvIDI7XG4gICAgICAgICAgICBsaW5lUG9zaXRpb25ZID0gKHRoaXMuc3R5bGUuc3Ryb2tlVGhpY2tuZXNzIC8gMiArIGkgKiBsaW5lSGVpZ2h0KSArIGZvbnRQcm9wZXJ0aWVzLmFzY2VudDtcblxuICAgICAgICAgICAgaWYgKHRoaXMuc3R5bGUuYWxpZ24gPT09ICdyaWdodCcpIHtcbiAgICAgICAgICAgICAgICBsaW5lUG9zaXRpb25YICs9IG1heExpbmVXaWR0aCAtIGxpbmVXaWR0aHNbaV07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICh0aGlzLnN0eWxlLmFsaWduID09PSAnY2VudGVyJykge1xuICAgICAgICAgICAgICAgIGxpbmVQb3NpdGlvblggKz0gKG1heExpbmVXaWR0aCAtIGxpbmVXaWR0aHNbaV0pIC8gMjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMuc3R5bGUuZmlsbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuY29udGV4dC5maWxsVGV4dChsaW5lc1tpXSwgbGluZVBvc2l0aW9uWCArIHhTaGFkb3dPZmZzZXQsIGxpbmVQb3NpdGlvblkgKyB5U2hhZG93T2Zmc2V0KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgIC8vICBpZiAoZHJvcFNoYWRvdylcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vc2V0IGNhbnZhcyB0ZXh0IHN0eWxlc1xuICAgIHRoaXMuY29udGV4dC5maWxsU3R5bGUgPSB0aGlzLnN0eWxlLmZpbGw7XG5cbiAgICAvL2RyYXcgbGluZXMgbGluZSBieSBsaW5lXG4gICAgZm9yIChpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGxpbmVQb3NpdGlvblggPSB0aGlzLnN0eWxlLnN0cm9rZVRoaWNrbmVzcyAvIDI7XG4gICAgICAgIGxpbmVQb3NpdGlvblkgPSAodGhpcy5zdHlsZS5zdHJva2VUaGlja25lc3MgLyAyICsgaSAqIGxpbmVIZWlnaHQpICsgZm9udFByb3BlcnRpZXMuYXNjZW50O1xuXG4gICAgICAgIGlmICh0aGlzLnN0eWxlLmFsaWduID09PSAncmlnaHQnKSB7XG4gICAgICAgICAgICBsaW5lUG9zaXRpb25YICs9IG1heExpbmVXaWR0aCAtIGxpbmVXaWR0aHNbaV07XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodGhpcy5zdHlsZS5hbGlnbiA9PT0gJ2NlbnRlcicpIHtcbiAgICAgICAgICAgIGxpbmVQb3NpdGlvblggKz0gKG1heExpbmVXaWR0aCAtIGxpbmVXaWR0aHNbaV0pIC8gMjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLnN0eWxlLnN0cm9rZSAmJiB0aGlzLnN0eWxlLnN0cm9rZVRoaWNrbmVzcykge1xuICAgICAgICAgICAgdGhpcy5jb250ZXh0LnN0cm9rZVRleHQobGluZXNbaV0sIGxpbmVQb3NpdGlvblgsIGxpbmVQb3NpdGlvblkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuc3R5bGUuZmlsbCkge1xuICAgICAgICAgICAgdGhpcy5jb250ZXh0LmZpbGxUZXh0KGxpbmVzW2ldLCBsaW5lUG9zaXRpb25YLCBsaW5lUG9zaXRpb25ZKTtcbiAgICAgICAgfVxuXG4gICAgICAvLyAgaWYgKGRyb3BTaGFkb3cpXG4gICAgfVxuXG4gICAgdGhpcy51cGRhdGVUZXh0dXJlKCk7XG59O1xuXG4vKipcbiAqIFVwZGF0ZXMgdGV4dHVyZSBzaXplIGJhc2VkIG9uIGNhbnZhcyBzaXplXG4gKlxuICogQHByaXZhdGVcbiAqL1xuVGV4dC5wcm90b3R5cGUudXBkYXRlVGV4dHVyZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnRleHR1cmUuYmFzZVRleHR1cmUud2lkdGggPSB0aGlzLmNhbnZhcy53aWR0aDtcbiAgICB0aGlzLnRleHR1cmUuYmFzZVRleHR1cmUuaGVpZ2h0ID0gdGhpcy5jYW52YXMuaGVpZ2h0O1xuICAgIHRoaXMudGV4dHVyZS5jcm9wLndpZHRoID0gdGhpcy50ZXh0dXJlLmZyYW1lLndpZHRoID0gdGhpcy5jYW52YXMud2lkdGg7XG4gICAgdGhpcy50ZXh0dXJlLmNyb3AuaGVpZ2h0ID0gdGhpcy50ZXh0dXJlLmZyYW1lLmhlaWdodCA9IHRoaXMuY2FudmFzLmhlaWdodDtcblxuICAgIHRoaXMuX3dpZHRoID0gdGhpcy5jYW52YXMud2lkdGg7XG4gICAgdGhpcy5faGVpZ2h0ID0gdGhpcy5jYW52YXMuaGVpZ2h0O1xuXG4gICAgLy8gdXBkYXRlIHRoZSBkaXJ0eSBiYXNlIHRleHR1cmVzXG4gICAgdGhpcy50ZXh0dXJlLmJhc2VUZXh0dXJlLmRpcnR5KCk7XG59O1xuXG4vKipcbiAqIFJlbmRlcnMgdGhlIG9iamVjdCB1c2luZyB0aGUgV2ViR0wgcmVuZGVyZXJcbipcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcn1cbiAqL1xuVGV4dC5wcm90b3R5cGUucmVuZGVyV2ViR0wgPSBmdW5jdGlvbiAocmVuZGVyZXIpIHtcbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnJlc29sdXRpb24gPSByZW5kZXJlci5yZXNvbHV0aW9uO1xuXG4gICAgICAgIHRoaXMudXBkYXRlVGV4dCgpO1xuICAgICAgICB0aGlzLmRpcnR5ID0gZmFsc2U7XG4gICAgfVxuXG4gICAgY29yZS5TcHJpdGUucHJvdG90eXBlLnJlbmRlcldlYkdMLmNhbGwodGhpcywgcmVuZGVyZXIpO1xufTtcblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBvYmplY3QgdXNpbmcgdGhlIENhbnZhcyByZW5kZXJlclxuKlxuICogQHBhcmFtIHJlbmRlcmVyIHtDYW52YXNSZW5kZXJlcn1cbiAqL1xuVGV4dC5wcm90b3R5cGUucmVuZGVyQ2FudmFzID0gZnVuY3Rpb24gKHJlbmRlcmVyKSB7XG4gICAgaWYgKHRoaXMuZGlydHkpIHtcbiAgICAgICAgdGhpcy5yZXNvbHV0aW9uID0gcmVuZGVyZXIucmVzb2x1dGlvbjtcblxuICAgICAgICB0aGlzLnVwZGF0ZVRleHQoKTtcbiAgICAgICAgdGhpcy5kaXJ0eSA9IGZhbHNlO1xuICAgIH1cblxuICAgIGNvcmUuU3ByaXRlLnByb3RvdHlwZS5yZW5kZXJDYW52YXMuY2FsbCh0aGlzLCByZW5kZXJlcik7XG59O1xuXG4vKipcbiAqIENhbGN1bGF0ZXMgdGhlIGFzY2VudCwgZGVzY2VudCBhbmQgZm9udFNpemUgb2YgYSBnaXZlbiBmb250U3R5bGVcbipcbiAqIEBwYXJhbSBmb250U3R5bGUge29iamVjdH1cbiAqIEBwcml2YXRlXG4gKi9cblRleHQucHJvdG90eXBlLmRldGVybWluZUZvbnRQcm9wZXJ0aWVzID0gZnVuY3Rpb24gKGZvbnRTdHlsZSkge1xuICAgIHZhciBwcm9wZXJ0aWVzID0gVGV4dC5mb250UHJvcGVydGllc0NhY2hlW2ZvbnRTdHlsZV07XG5cbiAgICBpZiAoIXByb3BlcnRpZXMpIHtcbiAgICAgICAgcHJvcGVydGllcyA9IHt9O1xuXG4gICAgICAgIHZhciBjYW52YXMgPSBUZXh0LmZvbnRQcm9wZXJ0aWVzQ2FudmFzO1xuICAgICAgICB2YXIgY29udGV4dCA9IFRleHQuZm9udFByb3BlcnRpZXNDb250ZXh0O1xuXG4gICAgICAgIGNvbnRleHQuZm9udCA9IGZvbnRTdHlsZTtcblxuICAgICAgICB2YXIgd2lkdGggPSBNYXRoLmNlaWwoY29udGV4dC5tZWFzdXJlVGV4dCgnfE1xJykud2lkdGgpO1xuICAgICAgICB2YXIgYmFzZWxpbmUgPSBNYXRoLmNlaWwoY29udGV4dC5tZWFzdXJlVGV4dCgnTScpLndpZHRoKTtcbiAgICAgICAgdmFyIGhlaWdodCA9IDIgKiBiYXNlbGluZTtcblxuICAgICAgICBiYXNlbGluZSA9IGJhc2VsaW5lICogMS40IHwgMDtcblxuICAgICAgICBjYW52YXMud2lkdGggPSB3aWR0aDtcbiAgICAgICAgY2FudmFzLmhlaWdodCA9IGhlaWdodDtcblxuICAgICAgICBjb250ZXh0LmZpbGxTdHlsZSA9ICcjZjAwJztcbiAgICAgICAgY29udGV4dC5maWxsUmVjdCgwLCAwLCB3aWR0aCwgaGVpZ2h0KTtcblxuICAgICAgICBjb250ZXh0LmZvbnQgPSBmb250U3R5bGU7XG5cbiAgICAgICAgY29udGV4dC50ZXh0QmFzZWxpbmUgPSAnYWxwaGFiZXRpYyc7XG4gICAgICAgIGNvbnRleHQuZmlsbFN0eWxlID0gJyMwMDAnO1xuICAgICAgICBjb250ZXh0LmZpbGxUZXh0KCd8TcOJcScsIDAsIGJhc2VsaW5lKTtcblxuICAgICAgICB2YXIgaW1hZ2VkYXRhID0gY29udGV4dC5nZXRJbWFnZURhdGEoMCwgMCwgd2lkdGgsIGhlaWdodCkuZGF0YTtcbiAgICAgICAgdmFyIHBpeGVscyA9IGltYWdlZGF0YS5sZW5ndGg7XG4gICAgICAgIHZhciBsaW5lID0gd2lkdGggKiA0O1xuXG4gICAgICAgIHZhciBpLCBqO1xuXG4gICAgICAgIHZhciBpZHggPSAwO1xuICAgICAgICB2YXIgc3RvcCA9IGZhbHNlO1xuXG4gICAgICAgIC8vIGFzY2VudC4gc2NhbiBmcm9tIHRvcCB0byBib3R0b20gdW50aWwgd2UgZmluZCBhIG5vbiByZWQgcGl4ZWxcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGJhc2VsaW5lOyBpKyspIHtcbiAgICAgICAgICAgIGZvciAoaiA9IDA7IGogPCBsaW5lOyBqICs9IDQpIHtcbiAgICAgICAgICAgICAgICBpZiAoaW1hZ2VkYXRhW2lkeCArIGpdICE9PSAyNTUpIHtcbiAgICAgICAgICAgICAgICAgICAgc3RvcCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghc3RvcCkge1xuICAgICAgICAgICAgICAgIGlkeCArPSBsaW5lO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBwcm9wZXJ0aWVzLmFzY2VudCA9IGJhc2VsaW5lIC0gaTtcblxuICAgICAgICBpZHggPSBwaXhlbHMgLSBsaW5lO1xuICAgICAgICBzdG9wID0gZmFsc2U7XG5cbiAgICAgICAgLy8gZGVzY2VudC4gc2NhbiBmcm9tIGJvdHRvbSB0byB0b3AgdW50aWwgd2UgZmluZCBhIG5vbiByZWQgcGl4ZWxcbiAgICAgICAgZm9yIChpID0gaGVpZ2h0OyBpID4gYmFzZWxpbmU7IGktLSkge1xuICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IGxpbmU7IGogKz0gNCkge1xuICAgICAgICAgICAgICAgIGlmIChpbWFnZWRhdGFbaWR4ICsgal0gIT09IDI1NSkge1xuICAgICAgICAgICAgICAgICAgICBzdG9wID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFzdG9wKSB7XG4gICAgICAgICAgICAgICAgaWR4IC09IGxpbmU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHByb3BlcnRpZXMuZGVzY2VudCA9IGkgLSBiYXNlbGluZTtcbiAgICAgICAgLy9UT0RPIG1pZ2h0IG5lZWQgYSB0d2Vhay4ga2luZCBvZiBhIHRlbXAgZml4IVxuICAgICAgICBwcm9wZXJ0aWVzLmRlc2NlbnQgKz0gNjtcbiAgICAgICAgcHJvcGVydGllcy5mb250U2l6ZSA9IHByb3BlcnRpZXMuYXNjZW50ICsgcHJvcGVydGllcy5kZXNjZW50O1xuXG4gICAgICAgIFRleHQuZm9udFByb3BlcnRpZXNDYWNoZVtmb250U3R5bGVdID0gcHJvcGVydGllcztcbiAgICB9XG5cbiAgICByZXR1cm4gcHJvcGVydGllcztcbn07XG5cbi8qKlxuICogQXBwbGllcyBuZXdsaW5lcyB0byBhIHN0cmluZyB0byBoYXZlIGl0IG9wdGltYWxseSBmaXQgaW50byB0aGUgaG9yaXpvbnRhbFxuICogYm91bmRzIHNldCBieSB0aGUgVGV4dCBvYmplY3QncyB3b3JkV3JhcFdpZHRoIHByb3BlcnR5LlxuICpcbiAqIEBwYXJhbSB0ZXh0IHtzdHJpbmd9XG4gKiBAcHJpdmF0ZVxuICovXG5UZXh0LnByb3RvdHlwZS53b3JkV3JhcCA9IGZ1bmN0aW9uICh0ZXh0KSB7XG4gICAgLy8gR3JlZWR5IHdyYXBwaW5nIGFsZ29yaXRobSB0aGF0IHdpbGwgd3JhcCB3b3JkcyBhcyB0aGUgbGluZSBncm93cyBsb25nZXJcbiAgICAvLyB0aGFuIGl0cyBob3Jpem9udGFsIGJvdW5kcy5cbiAgICB2YXIgcmVzdWx0ID0gJyc7XG4gICAgdmFyIGxpbmVzID0gdGV4dC5zcGxpdCgnXFxuJyk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgc3BhY2VMZWZ0ID0gdGhpcy5zdHlsZS53b3JkV3JhcFdpZHRoO1xuICAgICAgICB2YXIgd29yZHMgPSBsaW5lc1tpXS5zcGxpdCgnICcpO1xuICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHdvcmRzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICB2YXIgd29yZFdpZHRoID0gdGhpcy5jb250ZXh0Lm1lYXN1cmVUZXh0KHdvcmRzW2pdKS53aWR0aDtcbiAgICAgICAgICAgIHZhciB3b3JkV2lkdGhXaXRoU3BhY2UgPSB3b3JkV2lkdGggKyB0aGlzLmNvbnRleHQubWVhc3VyZVRleHQoJyAnKS53aWR0aDtcbiAgICAgICAgICAgIGlmIChqID09PSAwIHx8IHdvcmRXaWR0aFdpdGhTcGFjZSA+IHNwYWNlTGVmdCkge1xuICAgICAgICAgICAgICAgIC8vIFNraXAgcHJpbnRpbmcgdGhlIG5ld2xpbmUgaWYgaXQncyB0aGUgZmlyc3Qgd29yZCBvZiB0aGUgbGluZSB0aGF0IGlzXG4gICAgICAgICAgICAgICAgLy8gZ3JlYXRlciB0aGFuIHRoZSB3b3JkIHdyYXAgd2lkdGguXG4gICAgICAgICAgICAgICAgaWYgKGogPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdCArPSAnXFxuJztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmVzdWx0ICs9IHdvcmRzW2pdO1xuICAgICAgICAgICAgICAgIHNwYWNlTGVmdCA9IHRoaXMuc3R5bGUud29yZFdyYXBXaWR0aCAtIHdvcmRXaWR0aDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHNwYWNlTGVmdCAtPSB3b3JkV2lkdGhXaXRoU3BhY2U7XG4gICAgICAgICAgICAgICAgcmVzdWx0ICs9ICcgJyArIHdvcmRzW2pdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGkgPCBsaW5lcy5sZW5ndGgtMSkge1xuICAgICAgICAgICAgcmVzdWx0ICs9ICdcXG4nO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdGhlIGJvdW5kcyBvZiB0aGUgVGV4dCBhcyBhIHJlY3RhbmdsZS4gVGhlIGJvdW5kcyBjYWxjdWxhdGlvbiB0YWtlcyB0aGUgd29ybGRUcmFuc2Zvcm0gaW50byBhY2NvdW50LlxuICpcbiAqIEBwYXJhbSBtYXRyaXgge01hdHJpeH0gdGhlIHRyYW5zZm9ybWF0aW9uIG1hdHJpeCBvZiB0aGUgVGV4dFxuICogQHJldHVybiB7UmVjdGFuZ2xlfSB0aGUgZnJhbWluZyByZWN0YW5nbGVcbiAqL1xuVGV4dC5wcm90b3R5cGUuZ2V0Qm91bmRzID0gZnVuY3Rpb24gKG1hdHJpeCkge1xuICAgIGlmICh0aGlzLmRpcnR5KSB7XG4gICAgICAgIHRoaXMudXBkYXRlVGV4dCgpO1xuICAgICAgICB0aGlzLmRpcnR5ID0gZmFsc2U7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNvcmUuU3ByaXRlLnByb3RvdHlwZS5nZXRCb3VuZHMuY2FsbCh0aGlzLCBtYXRyaXgpO1xufTtcblxuLyoqXG4gKiBEZXN0cm95cyB0aGlzIHRleHQgb2JqZWN0LlxuICpcbiAqIEBwYXJhbSBkZXN0cm95QmFzZVRleHR1cmUge2Jvb2xlYW59IHdoZXRoZXIgdG8gZGVzdHJveSB0aGUgYmFzZSB0ZXh0dXJlIGFzIHdlbGxcbiAqL1xuVGV4dC5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uIChkZXN0cm95QmFzZVRleHR1cmUpIHtcbiAgICAvLyBtYWtlIHN1cmUgdG8gcmVzZXQgdGhlIHRoZSBjb250ZXh0IGFuZCBjYW52YXMuLiBkb250IHdhbnQgdGhpcyBoYW5naW5nIGFyb3VuZCBpbiBtZW1vcnkhXG4gICAgdGhpcy5jb250ZXh0ID0gbnVsbDtcbiAgICB0aGlzLmNhbnZhcyA9IG51bGw7XG5cbiAgICB0aGlzLnRleHR1cmUuZGVzdHJveShkZXN0cm95QmFzZVRleHR1cmUgPT09IHVuZGVmaW5lZCA/IHRydWUgOiBkZXN0cm95QmFzZVRleHR1cmUpO1xufTtcblxuVGV4dC5mb250UHJvcGVydGllc0NhY2hlID0ge307XG5UZXh0LmZvbnRQcm9wZXJ0aWVzQ2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG5UZXh0LmZvbnRQcm9wZXJ0aWVzQ29udGV4dCA9IFRleHQuZm9udFByb3BlcnRpZXNDYW52YXMuZ2V0Q29udGV4dCgnMmQnKTtcbiIsIi8qKlxuICogQGZpbGUgICAgICAgIE1haW4gZXhwb3J0IG9mIHRoZSBQSVhJIHRleHQgbGlicmFyeVxuICogQGF1dGhvciAgICAgIE1hdCBHcm92ZXMgPG1hdEBnb29kYm95ZGlnaXRhbC5jb20+XG4gKiBAY29weXJpZ2h0ICAgMjAxMy0yMDE1IEdvb2RCb3lEaWdpdGFsXG4gKiBAbGljZW5zZSAgICAge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9Hb29kQm95RGlnaXRhbC9waXhpLmpzL2Jsb2IvbWFzdGVyL0xJQ0VOU0V8TUlUIExpY2Vuc2V9XG4gKi9cblxuLyoqXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgVGV4dDogICAgICAgcmVxdWlyZSgnLi9UZXh0JyksXG4gICAgQml0bWFwVGV4dDogcmVxdWlyZSgnLi9CaXRtYXBUZXh0Jylcbn07XG4iXX0= diff --git a/dist/pixi.js b/dist/pixi.js deleted file mode 100644 index 2e6b3f4..0000000 --- a/dist/pixi.js +++ /dev/null @@ -1,19896 +0,0 @@ -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.PIXI=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o", - "Richard Davey " - ], - "main": "./src/index.js", - "homepage": "http://goodboydigital.com/", - "bugs": "https://github.com/GoodBoyDigital/pixi.js/issues", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/GoodBoyDigital/pixi.js.git" - }, - "scripts": { - "test": "gulp test", - "docs": "./node_modules/.bin/jsdoc -c ./gulp/util/jsdoc.conf.json" - }, - "devDependencies": { - "browserify": "^8.0.2", - "chai": "^1.10.0", - "del": "^1.1.0", - "gulp": "^3.8.10", - "gulp-jshint": "^1.9.0", - "gulp-plumber": "^0.6.6", - "gulp-rename": "^1.2.0", - "gulp-uglify": "^1.0.2", - "gulp-util": "^3.0.1", - "ink-docstrap": "^0.4.12", - "jsdoc": "^3.3.0-alpha13", - "jshint-summary": "^0.4.0", - "karma": "^0.12.28", - "karma-firefox-launcher": "^0.1.0", - "karma-mocha": "^0.1.10", - "karma-spec-reporter": "^0.0.16", - "mocha": "^2.1.0", - "require-dir": "^0.1.0", - "run-sequence": "^1.0.2", - "vinyl-buffer": "^1.0.0", - "vinyl-source-stream": "^1.0.0", - "watchify": "^2.2.1" - }, - "dependencies": { - "webgl-enabled": "^1.0.2" - } -} - -},{}],4:[function(require,module,exports){ -/** - * Constant values used in pixi - * - * @mixin const - */ -module.exports = { - /** - * Constant to identify the WEBGL Renderer Type - * - * @static - * @constant - * @property {number} WEBGL_RENDERER - */ - WEBGL_RENDERER: 1, - - /** - * Constant to identify the CANVAS Renderer Type - * - * @static - * @constant - * @property {number} CANVAS_RENDERER - */ - CANVAS_RENDERER: 2, - - /** - * String of the current PIXI version - * - * @static - * @constant - * @property {string} VERSION - */ - VERSION: require('../../package.json').version, - - /** - * Various blend modes supported by PIXI. IMPORTANT - The WebGL renderer only supports - * the NORMAL, ADD, MULTIPLY and SCREEN blend modes. Anything else will silently act like - * NORMAL. - * - * @static - * @constant - * @property {object} blendModes - * @property {number} blendModes.NORMAL - * @property {number} blendModes.ADD - * @property {number} blendModes.MULTIPLY - * @property {number} blendModes.SCREEN - * @property {number} blendModes.OVERLAY - * @property {number} blendModes.DARKEN - * @property {number} blendModes.LIGHTEN - * @property {number} blendModes.COLOR_DODGE - * @property {number} blendModes.COLOR_BURN - * @property {number} blendModes.HARD_LIGHT - * @property {number} blendModes.SOFT_LIGHT - * @property {number} blendModes.DIFFERENCE - * @property {number} blendModes.EXCLUSION - * @property {number} blendModes.HUE - * @property {number} blendModes.SATURATION - * @property {number} blendModes.COLOR - * @property {number} blendModes.LUMINOSITY - */ - blendModes: { - NORMAL: 0, - ADD: 1, - MULTIPLY: 2, - SCREEN: 3, - OVERLAY: 4, - DARKEN: 5, - LIGHTEN: 6, - COLOR_DODGE: 7, - COLOR_BURN: 8, - HARD_LIGHT: 9, - SOFT_LIGHT: 10, - DIFFERENCE: 11, - EXCLUSION: 12, - HUE: 13, - SATURATION: 14, - COLOR: 15, - LUMINOSITY: 16 - }, - - /** - * The scale modes that are supported by pixi. - * - * The DEFAULT scale mode affects the default scaling mode of future operations. - * It can be re-assigned to either LINEAR or NEAREST, depending upon suitability. - * - * @static - * @constant - * @property {object} scaleModes - * @property {number} scaleModes.DEFAULT=LINEAR - * @property {number} scaleModes.LINEAR Smooth scaling - * @property {number} scaleModes.NEAREST Pixelating scaling - */ - scaleModes: { - DEFAULT: 0, - LINEAR: 0, - NEAREST: 1 - }, - - /** - * The prefix that denotes a URL is for a retina asset - * - * @static - * @constant - * @property {string} RETINA_PREFIX - */ - RETINA_PREFIX: '@2x', - - /** - * The default render options if none are supplied to {@link PIXI.WebGLRenderer} - * or {@link PIXI.CanvasRenderer}. - * - * @static - * @constant - * @property {object} defaultRenderOptions - * @property {HTMLCanvasElement} defaultRenderOptions.view=null - * @property {boolean} defaultRenderOptions.transparent=false - * @property {boolean} defaultRenderOptions.antialias=false - * @property {boolean} defaultRenderOptions.preserveDrawingBuffer=false - * @property {number} defaultRenderOptions.resolution=1 - * @property {number} defaultRenderOptions.backgroundColor=0x000000 - * @property {boolean} defaultRenderOptions.clearBeforeRender=true - * @property {boolean} defaultRenderOptions.autoResize=false - */ - defaultRenderOptions: { - view: null, - resolution: 1, - antialias: false, - autoResize: false, - transparent: false, - backgroundColor: 0x000000, - clearBeforeRender: true, - preserveDrawingBuffer: false - }, - - /** - * Constants that identify shapes, mainly to prevent `instanceof` calls. - * - * @static - * @constant - * @property {object} SHAPES - * @property {object} SHAPES.POLY=0 - * @property {object} SHAPES.RECT=1 - * @property {object} SHAPES.CIRC=2 - * @property {object} SHAPES.ELIP=3 - * @property {object} SHAPES.RREC=4 - */ - SHAPES: { - POLY: 0, - RECT: 1, - CIRC: 2, - ELIP: 3, - RREC: 4 - } -}; - -},{"../../package.json":3}],5:[function(require,module,exports){ -var math = require('../math'); - -/** - * The base class for all objects that are rendered on the screen. - * This is an abstract class and should not be used on its own rather it should be extended. - * - * @class - * @namespace PIXI - */ -function DisplayObject() { - /** - * The coordinate of the object relative to the local coordinates of the parent. - * - * @member {Point} - */ - this.position = new math.Point(); - - /** - * The scale factor of the object. - * - * @member {Point} - */ - this.scale = new math.Point(1, 1); - - /** - * The pivot point of the displayObject that it rotates around - * - * @member {Point} - */ - this.pivot = new math.Point(0, 0); - - /** - * The rotation of the object in radians. - * - * @member {number} - */ - this.rotation = 0; - - /** - * The opacity of the object. - * - * @member {number} - */ - this.alpha = 1; - - /** - * The visibility of the object. If false the object will not be drawn, and - * the updateTransform function will not be called. - * - * @member {boolean} - */ - this.visible = true; - - /** - * Can this object be rendered, if false the object will not be drawn but the updateTransform - * methods will still be called. - * - * @member {boolean} - */ - this.renderable = false; - - /** - * The display object container that contains this display object. - * - * @member {DisplayObjectContainer} - * @readOnly - */ - this.parent = null; - - /** - * The multiplied alpha of the displayObject - * - * @member {number} - * @readOnly - */ - this.worldAlpha = 1; - - /** - * Current transform of the object based on world (parent) factors - * - * @member {Matrix} - * @readOnly - */ - this.worldTransform = new math.Matrix(); - - /** - * The area the filter is applied to. This is used as more of an optimisation - * rather than figuring out the dimensions of the displayObject each frame you can set this rectangle - * - * @member {Rectangle} - */ - this.filterArea = null; - - /** - * cached sin rotation - * - * @member {number} - * @private - */ - this._sr = 0; - - /** - * cached cos rotation - * - * @member {number} - * @private - */ - this._cr = 1; - - /** - * The original, cached bounds of the object - * - * @member {Rectangle} - * @private - */ - this._bounds = new math.Rectangle(0, 0, 1, 1); - - /** - * The most up-to-date bounds of the object - * - * @member {Rectangle} - * @private - */ - this._currentBounds = null; - - /** - * The original, cached mask of the object - * - * @member {Rectangle} - * @private - */ - this._mask = null; - - /** - * Cached internal flag. - * - * @member {boolean} - * @private - */ - this._cacheIsDirty = false; -} - -// constructor -DisplayObject.prototype.constructor = DisplayObject; -module.exports = DisplayObject; - -Object.defineProperties(DisplayObject.prototype, { - /** - * The position of the displayObject on the x axis relative to the local coordinates of the parent. - * - * @member {number} - * @memberof DisplayObject# - */ - x: { - get: function () { - return this.position.x; - }, - set: function (value) { - this.position.x = value; - } - }, - - /** - * The position of the displayObject on the y axis relative to the local coordinates of the parent. - * - * @member {number} - * @memberof DisplayObject# - */ - y: { - get: function () { - return this.position.y; - }, - set: function (value) { - this.position.y = value; - } - }, - - /** - * Indicates if the sprite is globally visible. - * - * @member {boolean} - * @memberof DisplayObject# - * @readonly - */ - worldVisible: { - get: function () { - var item = this; - - do { - if (!item.visible) { - return false; - } - - item = item.parent; - } while(item); - - return true; - } - }, - - /** - * Sets a mask for the displayObject. A mask is an object that limits the visibility of an object to the shape of the mask applied to it. - * In PIXI a regular mask must be a PIXI.Graphics object. This allows for much faster masking in canvas as it utilises shape clipping. - * To remove a mask, set this property to null. - * - * @member {Graphics} - * @memberof DisplayObject# - */ - mask: { - get: function () { - return this._mask; - }, - set: function (value) { - if (this._mask) { - this._mask.isMask = false; - } - - this._mask = value; - - if (this._mask) { - this._mask.isMask = true; - } - } - }, - - /** - * Sets the filters for the displayObject. - * * IMPORTANT: This is a webGL only feature and will be ignored by the canvas renderer. - * To remove filters simply set this property to 'null' - * - * @member {Filter[]} - * @memberof DisplayObject# - */ - filters: { - get: function () { - return this._filters; - }, - set: function (value) { - if (value) { - // now put all the passes in one place.. - var passes = []; - - for (var i = 0; i < value.length; i++) { - var filterPasses = value[i].passes; - - for (var j = 0; j < filterPasses.length; j++) { - passes.push(filterPasses[j]); - } - } - - // TODO change this as it is legacy - this._filterBlock = { target: this, filterPasses: passes }; - } - - this._filters = value; - } - } -}); - -/* - * Updates the object transform for rendering - * - * TODO - Optimization pass! - * - * @private - */ -DisplayObject.prototype.updateTransform = function () { - if (!this.parent) { - return; - } - - // create some matrix refs for easy access - var pt = this.parent.worldTransform; - var wt = this.worldTransform; - - // temporary matrix variables - var a, b, c, d, tx, ty; - - // so if rotation is between 0 then we can simplify the multiplication process.. - if (this.rotation % math.PI_2) { - // check to see if the rotation is the same as the previous render. This means we only need to use sin and cos when rotation actually changes - if (this.rotation !== this.rotationCache) { - this.rotationCache = this.rotation; - this._sr = Math.sin(this.rotation); - this._cr = Math.cos(this.rotation); - } - - // get the matrix values of the displayobject based on its transform properties.. - a = this._cr * this.scale.x; - b = this._sr * this.scale.x; - c = -this._sr * this.scale.y; - d = this._cr * this.scale.y; - tx = this.position.x; - ty = this.position.y; - - // check for pivot.. not often used so geared towards that fact! - if (this.pivot.x || this.pivot.y) { - tx -= this.pivot.x * a + this.pivot.y * c; - ty -= this.pivot.x * b + this.pivot.y * d; - } - - // concat the parent matrix with the objects transform. - wt.a = a * pt.a + b * pt.c; - wt.b = a * pt.b + b * pt.d; - wt.c = c * pt.a + d * pt.c; - wt.d = c * pt.b + d * pt.d; - wt.tx = tx * pt.a + ty * pt.c + pt.tx; - wt.ty = tx * pt.b + ty * pt.d + pt.ty; - } - else { - // lets do the fast version as we know there is no rotation.. - a = this.scale.x; - d = this.scale.y; - - tx = this.position.x - this.pivot.x * a; - ty = this.position.y - this.pivot.y * d; - - wt.a = a * pt.a; - wt.b = a * pt.b; - wt.c = d * pt.c; - wt.d = d * pt.d; - wt.tx = tx * pt.a + ty * pt.c + pt.tx; - wt.ty = tx * pt.b + ty * pt.d + pt.ty; - } - - // multiply the alphas.. - this.worldAlpha = this.alpha * this.parent.worldAlpha; -}; - -// performance increase to avoid using call.. (10x faster) -DisplayObject.prototype.displayObjectUpdateTransform = DisplayObject.prototype.updateTransform; - -/** - * Retrieves the bounds of the displayObject as a rectangle object - * - * @param matrix {Matrix} - * @return {Rectangle} the rectangular bounding area - */ -DisplayObject.prototype.getBounds = function (/* matrix */) { - return math.Rectangle.EMPTY; -}; - -/** - * Retrieves the local bounds of the displayObject as a rectangle object - * - * @return {Rectangle} the rectangular bounding area - */ -DisplayObject.prototype.getLocalBounds = function () { - return this.getBounds(math.Matrix.IDENTITY); -}; - -/** - * Calculates the global position of the display object - * - * @param position {Point} The world origin to calculate from - * @return {Point} A point object representing the position of this object - */ -DisplayObject.prototype.toGlobal = function (position) { - // don't need to u[date the lot - this.displayObjectUpdateTransform(); - return this.worldTransform.apply(position); -}; - -/** - * Calculates the local position of the display object relative to another point - * - * @param position {Point} The world origin to calculate from - * @param [from] {DisplayObject} The DisplayObject to calculate the global position from - * @return {Point} A point object representing the position of this object - */ -DisplayObject.prototype.toLocal = function (position, from) { - if (from) { - position = from.toGlobal(position); - } - - // don't need to update the lot - this.displayObjectUpdateTransform(); - return this.worldTransform.applyInverse(position); -}; - -/** - * Renders the object using the WebGL renderer - * - * @param renderer {WebGLRenderer} The renderer - * @private - */ -DisplayObject.prototype.renderWebGL = function (/* renderer */) { - // OVERWRITE; -}; - -/** - * Renders the object using the Canvas renderer - * - * @param renderer {CanvasRenderer} The renderer - * @private - */ -DisplayObject.prototype.renderCanvas = function (/* renderer */) { - // OVERWRITE; -}; - -},{"../math":12}],6:[function(require,module,exports){ -var math = require('../math'), - DisplayObject = require('./DisplayObject'), - RenderTexture = require('../textures/RenderTexture'), - // Sprite = require('./Sprite'), - _tempMatrix = new math.Matrix(); - -/** - * A DisplayObjectContainer represents a collection of display objects. - * It is the base class of all display objects that act as a container for other objects. - * - * @class - * @extends DisplayObject - * @namespace PIXI - */ -function DisplayObjectContainer() { - DisplayObject.call(this); - - /** - * The array of children of this container. - * - * @member {DisplayObject[]} - * @readonly - */ - this.children = []; - - /** - * Cached internal flag. - * - * @member {boolean} - * @private - */ - this._cacheAsBitmap = false; - - this._cachedSprite = null; -} - -// constructor -DisplayObjectContainer.prototype = Object.create(DisplayObject.prototype); -DisplayObjectContainer.prototype.constructor = DisplayObjectContainer; -module.exports = DisplayObjectContainer; - -Object.defineProperties(DisplayObjectContainer.prototype, { - /** - * The width of the displayObjectContainer, setting this will actually modify the scale to achieve the value set - * - * @member {number} - * @memberof DisplayObjectContainer# - */ - width: { - get: function () { - return this.scale.x * this.getLocalBounds().width; - }, - set: function (value) { - - var width = this.getLocalBounds().width; - - if(width !== 0) { - this.scale.x = value / width; - } - else { - this.scale.x = 1; - } - - - this._width = value; - } - }, - - /** - * The height of the displayObjectContainer, setting this will actually modify the scale to achieve the value set - * - * @member {number} - * @memberof DisplayObjectContainer# - */ - height: { - get: function () { - return this.scale.y * this.getLocalBounds().height; - }, - set: function (value) { - - var height = this.getLocalBounds().height; - - if (height !== 0) { - this.scale.y = value / height ; - } - else { - this.scale.y = 1; - } - - this._height = value; - } - }, - - /** - * Set if this display object is cached as a bitmap. - * This basically takes a snap shot of the display object as it is at that moment. It can provide a performance benefit for complex static displayObjects. - * To remove simply set this property to 'null' - * - * @member {boolean} - * @memberof DisplayObject# - */ - cacheAsBitmap: { - get: function () { - return this._cacheAsBitmap; - }, - set: function (value) { - if (this._cacheAsBitmap === value) { - return; - } - - if (value) { - this._generateCachedSprite(); - } - else { - this._destroyCachedSprite(); - } - - this._cacheAsBitmap = value; - } - } -}); - -/** - * Adds a child to the container. - * - * @param child {DisplayObject} The DisplayObject to add to the container - * @return {DisplayObject} The child that was added. - */ -DisplayObjectContainer.prototype.addChild = function (child) { - return this.addChildAt(child, this.children.length); -}; - -/** - * Adds a child to the container at a specified index. If the index is out of bounds an error will be thrown - * - * @param child {DisplayObject} The child to add - * @param index {Number} The index to place the child in - * @return {DisplayObject} The child that was added. - */ -DisplayObjectContainer.prototype.addChildAt = function (child, index) { - // prevent adding self as child - if (child === this) { - return; - } - - if (index >= 0 && index <= this.children.length) { - if (child.parent) { - child.parent.removeChild(child); - } - - child.parent = this; - - this.children.splice(index, 0, child); - - return child; - } - else { - throw new Error(child + 'addChildAt: The index '+ index +' supplied is out of bounds ' + this.children.length); - } -}; - -/** - * Swaps the position of 2 Display Objects within this container. - * - * @param child {DisplayObject} - * @param child2 {DisplayObject} - */ -DisplayObjectContainer.prototype.swapChildren = function (child, child2) { - if (child === child2) { - return; - } - - var index1 = this.getChildIndex(child); - var index2 = this.getChildIndex(child2); - - if (index1 < 0 || index2 < 0) { - throw new Error('swapChildren: Both the supplied DisplayObjects must be a child of the caller.'); - } - - this.children[index1] = child2; - this.children[index2] = child; -}; - -/** - * Returns the index position of a child DisplayObject instance - * - * @param child {DisplayObject} The DisplayObject instance to identify - * @return {Number} The index position of the child display object to identify - */ -DisplayObjectContainer.prototype.getChildIndex = function (child) { - var index = this.children.indexOf(child); - - if (index === -1) { - throw new Error('The supplied DisplayObject must be a child of the caller'); - } - - return index; -}; - -/** - * Changes the position of an existing child in the display object container - * - * @param child {DisplayObject} The child DisplayObject instance for which you want to change the index number - * @param index {Number} The resulting index number for the child display object - */ -DisplayObjectContainer.prototype.setChildIndex = function (child, index) { - if (index < 0 || index >= this.children.length) { - throw new Error('The supplied index is out of bounds'); - } - - var currentIndex = this.getChildIndex(child); - - this.children.splice(currentIndex, 1); //remove from old position - this.children.splice(index, 0, child); //add at new position -}; - -/** - * Returns the child at the specified index - * - * @param index {Number} The index to get the child from - * @return {DisplayObject} The child at the given index, if any. - */ -DisplayObjectContainer.prototype.getChildAt = function (index) { - if (index < 0 || index >= this.children.length) { - throw new Error('getChildAt: Supplied index ' + index + ' does not exist in the child list, or the supplied DisplayObject must be a child of the caller'); - } - - return this.children[index]; -}; - -/** - * Removes a child from the container. - * - * @param child {DisplayObject} The DisplayObject to remove - * @return {DisplayObject} The child that was removed. - */ -DisplayObjectContainer.prototype.removeChild = function (child) { - var index = this.children.indexOf(child); - - if (index === -1) { - return; - } - - return this.removeChildAt(index); -}; - -/** - * Removes a child from the specified index position. - * - * @param index {Number} The index to get the child from - * @return {DisplayObject} The child that was removed. - */ -DisplayObjectContainer.prototype.removeChildAt = function (index) { - var child = this.getChildAt(index); - - child.parent = null; - this.children.splice(index, 1); - - return child; -}; - -/** - * Removes all children from this container that are within the begin and end indexes. - * - * @param beginIndex {Number} The beginning position. Default value is 0. - * @param endIndex {Number} The ending position. Default value is size of the container. - */ -DisplayObjectContainer.prototype.removeChildren = function (beginIndex, endIndex) { - var begin = beginIndex || 0; - var end = typeof endIndex === 'number' ? endIndex : this.children.length; - var range = end - begin; - - if (range > 0 && range <= end) { - var removed = this.children.splice(begin, range); - - for (var i = 0; i < removed.length; ++i) { - removed[i].parent = null; - } - - return removed; - } - else if (range === 0 && this.children.length === 0) { - return []; - } - else { - throw new RangeError('removeChildren: numeric values are outside the acceptable range.'); - } -}; - -/** - * Generates and updates the cached sprite for this object. - * - */ -DisplayObjectContainer.prototype.updateCachedSprite = function () { - this._generateCachedSprite(); -}; - -/** - * Useful function that returns a texture of the displayObject object that can then be used to create sprites - * This can be quite useful if your displayObject is static / complicated and needs to be reused multiple times. - * - * @param resolution {Number} The resolution of the texture being generated - * @param scaleMode {Number} See {{#crossLink "PIXI/scaleModes:property"}}PIXI.scaleModes{{/crossLink}} for possible values - * @param renderer {CanvasRenderer|WebGLRenderer} The renderer used to generate the texture. - * @return {Texture} a texture of the graphics object - */ -DisplayObjectContainer.prototype.generateTexture = function (resolution, scaleMode, renderer) { - var bounds = this.getLocalBounds(); - - var renderTexture = new RenderTexture(renderer, bounds.width | 0, bounds.height | 0, renderer, scaleMode, resolution); - - _tempMatrix.tx = -bounds.x; - _tempMatrix.ty = -bounds.y; - - renderTexture.render(this, _tempMatrix); - - return renderTexture; -}; - -/* - * Updates the transform on all children of this container for rendering - * - * @private - */ -DisplayObjectContainer.prototype.updateTransform = function () { - if (!this.visible) { - return; - } - - this.displayObjectUpdateTransform(); - - if (this._cacheAsBitmap) { - return; - } - - for (var i = 0, j = this.children.length; i < j; ++i) { - this.children[i].updateTransform(); - } -}; - -// performance increase to avoid using call.. (10x faster) -DisplayObjectContainer.prototype.displayObjectContainerUpdateTransform = DisplayObjectContainer.prototype.updateTransform; - -/** - * Retrieves the bounds of the displayObjectContainer as a rectangle. The bounds calculation takes all visible children into consideration. - * - * @return {Rectangle} The rectangular bounding area - */ -DisplayObjectContainer.prototype.getBounds = function () { - if (this.children.length === 0) { - return math.Rectangle.EMPTY; - } - - // TODO the bounds have already been calculated this render session so return what we have - - var minX = Infinity; - var minY = Infinity; - - var maxX = -Infinity; - var maxY = -Infinity; - - var childBounds; - var childMaxX; - var childMaxY; - - var childVisible = false; - - for (var i = 0, j = this.children.length; i < j; ++i) { - var child = this.children[i]; - - if (!child.visible) { - continue; - } - - childVisible = true; - - childBounds = this.children[i].getBounds(); - - minX = minX < childBounds.x ? minX : childBounds.x; - minY = minY < childBounds.y ? minY : childBounds.y; - - childMaxX = childBounds.width + childBounds.x; - childMaxY = childBounds.height + childBounds.y; - - maxX = maxX > childMaxX ? maxX : childMaxX; - maxY = maxY > childMaxY ? maxY : childMaxY; - } - - if (!childVisible) { - return math.Rectangle.EMPTY; - } - - this._bounds.x = minX; - this._bounds.y = minY; - this._bounds.width = maxX - minX; - this._bounds.height = maxY - minY; - - // TODO: store a reference so that if this function gets called again in the render cycle we do not have to recalculate - //this._currentBounds = bounds; - - return this._bounds; -}; - -/** - * Retrieves the non-global local bounds of the displayObjectContainer as a rectangle. - * The calculation takes all visible children into consideration. - * - * @return {Rectangle} The rectangular bounding area - */ -DisplayObjectContainer.prototype.getLocalBounds = function () { - var matrixCache = this.worldTransform; - - this.worldTransform = math.Matrix.IDENTITY; - - for (var i = 0, j = this.children.length; i < j; ++i) { - this.children[i].updateTransform(); - } - - this.worldTransform = matrixCache; - - return this.getBounds(); -}; - -/** - * Renders the object using the WebGL renderer - * - * TODO - Optimization pass! - * - * @param renderer {WebGLRenderer} The renderer - */ -DisplayObjectContainer.prototype.renderWebGL = function (renderer) { - // if the object is not visible or the alpha is 0 then no need to render this element - if (!this.visible || this.alpha <= 0) { - return; - } - - if (this._cacheAsBitmap) { - this._renderCachedSprite(renderer); - return; - } - - var i, j; - - // do a quick check to see if this element has a mask or a filter. - if (this._mask || this._filters) { - // push filter first as we need to ensure the stencil buffer is correct for any masking - if (this._filters) { - renderer.spriteBatch.flush(); - renderer.filterManager.pushFilter(this._filterBlock); - } - - if (this._mask) { - renderer.spriteBatch.stop(); - renderer.maskManager.pushMask(this.mask, renderer); - renderer.spriteBatch.start(); - } - - // add this object to the batch, only rendered if it has a texture. - if (this.texture) { - renderer.spriteBatch.render(this); - } - - // now loop through the children and make sure they get rendered - for (i = 0, j = this.children.length; i < j; i++) { - this.children[i].renderWebGL(renderer); - } - - // time to stop the sprite batch as either a mask element or a filter draw will happen next - renderer.spriteBatch.stop(); - - if (this._mask) { - renderer.maskManager.popMask(this._mask, renderer); - } - - if (this._filters) { - renderer.filterManager.popFilter(); - } - - renderer.spriteBatch.start(); - } - else { - if (this.texture) { - renderer.spriteBatch.render(this); - } - - // simple render children! - for (i = 0, j = this.children.length; i < j; ++i) { - this.children[i].renderWebGL(renderer); - } - - } -}; - -/** - * Renders the object using the Canvas renderer - * - * @param renderer {CanvasRenderer} The renderer - */ -DisplayObjectContainer.prototype.renderCanvas = function (renderer) { - if (!this.visible || this.alpha <= 0) { - return; - } - - if (this._cacheAsBitmap) { - this._renderCachedSprite(renderer); - return; - } - - if (this._mask) { - renderer.maskManager.pushMask(this._mask, renderer); - } - - for (var i = 0, j = this.children.length; i < j; ++i) { - this.children[i].renderCanvas(renderer); - } - - if (this._mask) { - renderer.maskManager.popMask(renderer); - } -}; - -/** - * Internal method. - * - * @param renderer {WebGLRenderer|CanvasRenderer} The renderer - * @private - */ -DisplayObjectContainer.prototype._renderCachedSprite = function (renderer) { - this._cachedSprite.worldAlpha = this.worldAlpha; - - if (renderer.gl) { - this._cachedSprite.renderWebGL(renderer); - } - else { - this._cachedSprite.renderCanvas(renderer); - } -}; - -/** - * Internal method. - * - * @private - */ -DisplayObjectContainer.prototype._generateCachedSprite = function () { - var bounds = this.getLocalBounds(); - - if (!this._cachedSprite) { - // TODO - RenderTexture now *requires* a renderer instance, so this is like broken - // because `renderer` isn't actually in scope here :P - var renderTexture = new RenderTexture(renderer, bounds.width | 0, bounds.height | 0); - - this._cachedSprite = new Sprite(renderTexture); - this._cachedSprite.worldTransform = this.worldTransform; - } - else { - this._cachedSprite.texture.resize(bounds.width | 0, bounds.height | 0); - } - - var tempFilters = this._filters; - this._filters = null; - - this._cachedSprite.filters = tempFilters; - - _tempMatrix.tx = -bounds.x; - _tempMatrix.ty = -bounds.y; - - this._cachedSprite.texture.render(this, _tempMatrix, true); - - this._cachedSprite.anchor.x = -(bounds.x / bounds.width); - this._cachedSprite.anchor.y = -(bounds.y / bounds.height); - - this._filters = tempFilters; -}; - -/** - * Destroys the cached sprite. - * - * @private - */ -DisplayObjectContainer.prototype._destroyCachedSprite = function () { - if (!this._cachedSprite) { - return; - } - - // TODO: Pool this sprite - this._cachedSprite.destroy(true, true); - this._cachedSprite = null; -}; - -},{"../math":12,"../textures/RenderTexture":43,"./DisplayObject":5}],7:[function(require,module,exports){ -var math = require('../math'), - Texture = require('../textures/Texture'), - DisplayObjectContainer = require('./DisplayObjectContainer'), - CanvasTinter = require('../renderers/canvas/utils/CanvasTinter'), - utils = require('../utils'), - CONST = require('../const'); - -/** - * The Sprite object is the base for all textured objects that are rendered to the screen - * - * A sprite can be created directly from an image like this: - * - * ```js - * var sprite = new Sprite.fromImage('assets/image.png'); - * ``` - * - * @class Sprite - * @extends DisplayObjectContainer - * @namespace PIXI - * @param texture {Texture} The texture for this sprite - */ -function Sprite(texture) { - DisplayObjectContainer.call(this); - - /** - * The anchor sets the origin point of the texture. - * The default is 0,0 this means the texture's origin is the top left - * Setting than anchor to 0.5,0.5 means the textures origin is centered - * Setting the anchor to 1,1 would mean the textures origin points will be the bottom right corner - * - * @member {Point} - */ - this.anchor = new math.Point(); - - /** - * The texture that the sprite is using - * - * @member {Texture} - * @private - */ - this._texture = null; - - /** - * The width of the sprite (this is initially set by the texture) - * - * @member {number} - * @private - */ - this._width = 0; - - /** - * The height of the sprite (this is initially set by the texture) - * - * @member {number} - * @private - */ - this._height = 0; - - /** - * The tint applied to the sprite. This is a hex value. A value of 0xFFFFFF will remove any tint effect. - * - * @member {number} - * @default 0xFFFFFF - */ - this.tint = 0xFFFFFF; - - /** - * The blend mode to be applied to the sprite. Set to CONST.blendModes.NORMAL to remove any blend mode. - * - * @member {number} - * @default CONST.blendModes.NORMAL; - */ - this.blendMode = CONST.blendModes.NORMAL; - - /** - * The shader that will be used to render the sprite. Set to null to remove a current shader. - * - * @member {AbstractFilter} - */ - this.shader = null; - - this.renderable = true; - - // call texture setter - this.texture = texture || Texture.EMPTY; -} - -Sprite.prototype.destroy = function (destroyTexture, destroyBaseTexture) { - DisplayObjectContainer.prototype.destroy.call(this); - - this.anchor = null; - - if (destroyTexture) { - this._texture.destroy(destroyBaseTexture); - } - - this._texture = null; - this.shader = null; -}; - -// constructor -Sprite.prototype = Object.create(DisplayObjectContainer.prototype); -Sprite.prototype.constructor = Sprite; -module.exports = Sprite; - -Object.defineProperties(Sprite.prototype, { - /** - * The width of the sprite, setting this will actually modify the scale to achieve the value set - * - * @member - * @memberof Sprite# - */ - width: { - get: function () { - return this.scale.x * this.texture.frame.width; - }, - set: function (value) { - this.scale.x = value / this.texture.frame.width; - this._width = value; - } - }, - - /** - * The height of the sprite, setting this will actually modify the scale to achieve the value set - * - * @member - * @memberof Sprite# - */ - height: { - get: function () { - return this.scale.y * this.texture.frame.height; - }, - set: function (value) { - this.scale.y = value / this.texture.frame.height; - this._height = value; - } - }, - - /** - * The height of the sprite, setting this will actually modify the scale to achieve the value set - * - * @member - * @memberof Sprite# - */ - texture: { - get: function () { - return this._texture; - }, - set: function (value) { - if (this._texture === value) { - return; - } - - this._texture = value; - this.cachedTint = 0xFFFFFF; - - if (value) { - // wait for the texture to load - if (value.baseTexture.hasLoaded) { - this._onTextureUpdate(); - } - else { - value.once('update', this._onTextureUpdate.bind(this)); - } - } - } - }, -}); - -/** - * When the texture is updated, this event will fire to update the scale and frame - * - * @private - */ -Sprite.prototype._onTextureUpdate = function () { - // so if _width is 0 then width was not set.. - if (this._width) { - this.scale.x = this._width / this.texture.frame.width; - } - - if (this._height) { - this.scale.y = this._height / this.texture.frame.height; - } -}; - -/** - * Returns the bounds of the Sprite as a rectangle. The bounds calculation takes the worldTransform into account. - * - * @param matrix {Matrix} the transformation matrix of the sprite - * @return {Rectangle} the framing rectangle - */ -Sprite.prototype.getBounds = function (matrix) { - var width = this.texture.frame.width; - var height = this.texture.frame.height; - - var w0 = width * (1-this.anchor.x); - var w1 = width * -this.anchor.x; - - var h0 = height * (1-this.anchor.y); - var h1 = height * -this.anchor.y; - - var worldTransform = matrix || this.worldTransform ; - - var a = worldTransform.a; - var b = worldTransform.b; - var c = worldTransform.c; - var d = worldTransform.d; - var tx = worldTransform.tx; - var ty = worldTransform.ty; - - var minX, - maxX, - minY, - maxY; - - if(b === 0 && c === 0) - { - // scale may be negative! - if (a < 0) { - a *= -1; - } - - if (d < 0) { - d *= -1; - } - - // this means there is no rotation going on right? RIGHT? - // if thats the case then we can avoid checking the bound values! yay - minX = a * w1 + tx; - maxX = a * w0 + tx; - minY = d * h1 + ty; - maxY = d * h0 + ty; - } - else - { - var x1 = a * w1 + c * h1 + tx; - var y1 = d * h1 + b * w1 + ty; - - var x2 = a * w0 + c * h1 + tx; - var y2 = d * h1 + b * w0 + ty; - - var x3 = a * w0 + c * h0 + tx; - var y3 = d * h0 + b * w0 + ty; - - var x4 = a * w1 + c * h0 + tx; - var y4 = d * h0 + b * w1 + ty; - - minX = x1; - minX = x2 < minX ? x2 : minX; - minX = x3 < minX ? x3 : minX; - minX = x4 < minX ? x4 : minX; - - minY = y1; - minY = y2 < minY ? y2 : minY; - minY = y3 < minY ? y3 : minY; - minY = y4 < minY ? y4 : minY; - - maxX = x1; - maxX = x2 > maxX ? x2 : maxX; - maxX = x3 > maxX ? x3 : maxX; - maxX = x4 > maxX ? x4 : maxX; - - maxY = y1; - maxY = y2 > maxY ? y2 : maxY; - maxY = y3 > maxY ? y3 : maxY; - maxY = y4 > maxY ? y4 : maxY; - } - - var bounds = this._bounds; - - bounds.x = minX; - bounds.width = maxX - minX; - - bounds.y = minY; - bounds.height = maxY - minY; - - // store a reference so that if this function gets called again in the render cycle we do not have to recalculate - this._currentBounds = bounds; - - return bounds; -}; - -/** -* Renders the object using the Canvas renderer -* -* @param renderer {CanvasRenderer} The renderer -*/ -Sprite.prototype.renderCanvas = function (renderer) { - if (!this.visible || this.alpha <= 0 || this.texture.crop.width <= 0 || this.texture.crop.height <= 0) { - return; - } - - if (this.blendMode !== renderer.currentBlendMode) { - renderer.currentBlendMode = this.blendMode; - renderer.context.globalCompositeOperation = renderer.blendModes[renderer.currentBlendMode]; - } - - if (this._mask) { - renderer.maskManager.pushMask(this._mask, renderer); - } - - // Ignore null sources - if (this.texture.valid) { - var resolution = this.texture.baseTexture.resolution / renderer.resolution; - - renderer.context.globalAlpha = this.worldAlpha; - - // If smoothingEnabled is supported and we need to change the smoothing property for this texture - if (renderer.smoothProperty && renderer.scaleMode !== this.texture.baseTexture.scaleMode) { - renderer.scaleMode = this.texture.baseTexture.scaleMode; - renderer.context[renderer.smoothProperty] = (renderer.scaleMode === CONST.scaleModes.LINEAR); - } - - // If the texture is trimmed we offset by the trim x/y, otherwise we use the frame dimensions - var dx = (this.texture.trim ? this.texture.trim.x : 0) - (this.anchor.x * this.texture.trim.width); - var dy = (this.texture.trim ? this.texture.trim.y : 0) - (this.anchor.y * this.texture.trim.height); - - // Allow for pixel rounding - if (renderer.roundPixels) { - renderer.context.setTransform( - this.worldTransform.a, - this.worldTransform.b, - this.worldTransform.c, - this.worldTransform.d, - (this.worldTransform.tx * renderer.resolution) | 0, - (this.worldTransform.ty * renderer.resolution) | 0 - ); - - dx = dx | 0; - dy = dy | 0; - } - else { - renderer.context.setTransform( - this.worldTransform.a, - this.worldTransform.b, - this.worldTransform.c, - this.worldTransform.d, - this.worldTransform.tx * renderer.resolution, - this.worldTransform.ty * renderer.resolution - ); - } - - if (this.tint !== 0xFFFFFF) { - if (this.cachedTint !== this.tint) { - this.cachedTint = this.tint; - - // TODO clean up caching - how to clean up the caches? - this.tintedTexture = CanvasTinter.getTintedTexture(this, this.tint); - } - - renderer.context.drawImage( - this.tintedTexture, - 0, - 0, - this.texture.crop.width, - this.texture.crop.height, - dx / resolution, - dy / resolution, - this.texture.crop.width / resolution, - this.texture.crop.height / resolution - ); - } - else { - renderer.context.drawImage( - this.texture.baseTexture.source, - this.texture.crop.x, - this.texture.crop.y, - this.texture.crop.width, - this.texture.crop.height, - dx / resolution, - dy / resolution, - this.texture.crop.width / resolution, - this.texture.crop.height / resolution - ); - } - } - - for (var i = 0, j = this.children.length; i < j; i++) { - this.children[i].renderCanvas(renderer); - } - - if (this._mask) { - renderer.maskManager.popMask(renderer); - } -}; - -// some helper functions.. - -/** - * Helper function that creates a sprite that will contain a texture from the TextureCache based on the frameId - * The frame ids are created when a Texture packer file has been loaded - * - * @static - * @param frameId {String} The frame Id of the texture in the cache - * @return {Sprite} A new Sprite using a texture from the texture cache matching the frameId - */ -Sprite.fromFrame = function (frameId) { - var texture = utils.TextureCache[frameId]; - - if (!texture) { - throw new Error('The frameId "' + frameId + '" does not exist in the texture cache' + this); - } - - return new Sprite(texture); -}; - -/** - * Helper function that creates a sprite that will contain a texture based on an image url - * If the image is not in the texture cache it will be loaded - * - * @static - * @param imageId {String} The image url of the texture - * @return {Sprite} A new Sprite using a texture from the texture cache matching the image id - */ -Sprite.fromImage = function (imageId, crossorigin, scaleMode) { - return new Sprite(Texture.fromImage(imageId, crossorigin, scaleMode)); -}; - -},{"../const":4,"../math":12,"../renderers/canvas/utils/CanvasTinter":24,"../textures/Texture":44,"../utils":50,"./DisplayObjectContainer":6}],8:[function(require,module,exports){ -var DisplayObjectContainer = require('./DisplayObjectContainer'), - WebGLFastSpriteBatch = require('../renderers/webgl/utils/WebGLFastSpriteBatch'); - -/** - * The SpriteBatch class is a really fast version of the DisplayObjectContainer built solely for speed, - * so use when you need a lot of sprites or particles. The tradeoff of the SpriteBatch is that advanced - * functionality will not work. SpriteBatch implements only the basic object transform (position, scale, rotation). - * Any other functionality like tinting, masking, etc will not work on sprites in this batch. - * - * It's extremely easy to use : - * - * ```js - * var container = new SpriteBatch(); - * - * for(var i = 0; i < 100; ++i) { - * var sprite = new PIXI.Sprite.fromImage("myImage.png"); - * container.addChild(sprite); - * } - * ``` - * - * And here you have a hundred sprites that will be renderer at the speed of light. - * - * @class - * @namespace PIXI - */ - -//TODO RENAME to PARTICLE CONTAINER? -function SpriteBatch() { - DisplayObjectContainer.call(this); -} - -SpriteBatch.prototype = Object.create(DisplayObjectContainer.prototype); -SpriteBatch.prototype.constructor = SpriteBatch; -module.exports = SpriteBatch; - -/** - * Updates the object transform for rendering - * - * @private - */ -SpriteBatch.prototype.updateTransform = function () { - // TODO don't need to! - this.displayObjectUpdateTransform(); - // PIXI.DisplayObjectContainer.prototype.updateTransform.call( this ); -}; - -/** - * Renders the object using the WebGL renderer - * - * @param renderer {WebGLRenderer} The webgl renderer - * @private - */ -SpriteBatch.prototype.renderWebGL = function (renderer) { - if (!this.visible || this.alpha <= 0 || !this.children.length) { - return; - } - - renderer.spriteBatch.stop(); - - renderer.shaderManager.setShader(renderer.shaderManager.fastShader); - - renderer.fastSpriteBatch.begin(this); - renderer.fastSpriteBatch.render(this); - - renderer.spriteBatch.start(); -}; - -/** - * Renders the object using the Canvas renderer - * - * @param renderer {CanvasRenderer} The canvas renderer - * @private - */ -SpriteBatch.prototype.renderCanvas = function (renderer) { - if (!this.visible || this.alpha <= 0 || !this.children.length) { - return; - } - - var context = renderer.context; - var transform = this.worldTransform; - var isRotated = true; - - context.globalAlpha = this.worldAlpha; - - this.displayObjectUpdateTransform(); - - for (var i = 0; i < this.children.length; ++i) { - var child = this.children[i]; - - if (!child.visible) { - continue; - } - - var frame = child.texture.frame; - - context.globalAlpha = this.worldAlpha * child.alpha; - - if (child.rotation % (Math.PI * 2) === 0) { - // this is the fastest way to optimise! - if rotation is 0 then we can avoid any kind of setTransform call - if (isRotated) { - context.setTransform( - transform.a, - transform.b, - transform.c, - transform.d, - transform.tx, - transform.ty - ); - - isRotated = false; - } - - context.drawImage( - child.texture.baseTexture.source, - frame.x, - frame.y, - frame.width, - frame.height, - ((child.anchor.x) * (-frame.width * child.scale.x) + child.position.x + 0.5) | 0, - ((child.anchor.y) * (-frame.height * child.scale.y) + child.position.y + 0.5) | 0, - frame.width * child.scale.x, - frame.height * child.scale.y - ); - } - else { - if (!isRotated) { - isRotated = true; - } - - child.displayObjectUpdateTransform(); - - var childTransform = child.worldTransform; - - if (renderer.roundPixels) { - context.setTransform( - childTransform.a, - childTransform.b, - childTransform.c, - childTransform.d, - childTransform.tx | 0, - childTransform.ty | 0 - ); - } - else { - context.setTransform( - childTransform.a, - childTransform.b, - childTransform.c, - childTransform.d, - childTransform.tx, - childTransform.ty - ); - } - - context.drawImage( - child.texture.baseTexture.source, - frame.x, - frame.y, - frame.width, - frame.height, - ((child.anchor.x) * (-frame.width) + 0.5) | 0, - ((child.anchor.y) * (-frame.height) + 0.5) | 0, - frame.width, - frame.height - ); - } - } -}; - -},{"../renderers/webgl/utils/WebGLFastSpriteBatch":38,"./DisplayObjectContainer":6}],9:[function(require,module,exports){ -/** - * @file Main export of the PIXI core library - * @author Mat Groves - * @copyright 2013-2015 GoodBoyDigital - * @license {@link https://github.com/GoodBoyDigital/pixi.js/blob/master/LICENSE|MIT License} - */ - -/** - * @namespace PIXI - */ -var core = module.exports = { - CONST: require('./const'), - - // utils - utils: require('./utils'), - math: require('./math'), - - // display - DisplayObject: require('./display/DisplayObject'), - DisplayObjectContainer: require('./display/DisplayObjectContainer'), - Sprite: require('./display/Sprite'), - SpriteBatch: require('./display/SpriteBatch'), - - // primitives - Graphics: require('./primitives/Graphics'), - GraphicsData: require('./primitives/GraphicsData'), - - // textures - Texture: require('./textures/Texture'), - BaseTexture: require('./textures/BaseTexture'), - RenderTexture: require('./textures/RenderTexture'), - VideoBaseTexture: require('./textures/VideoBaseTexture'), - - // renderers - canvas - CanvasRenderer: require('./renderers/canvas/CanvasRenderer'), - CanvasGraphics: require('./renderers/canvas/utils/CanvasGraphics'), - CanvasBuffer: require('./renderers/canvas/utils/CanvasBuffer'), - - // renderers - webgl - WebGLRenderer: require('./renderers/webgl/WebGLRenderer'), - WebGLGraphics: require('./renderers/webgl/utils/WebGLGraphics'), - - /** - * This helper function will automatically detect which renderer you should be using. - * WebGL is the preferred renderer as it is a lot faster. If webGL is not supported by - * the browser then this function will return a canvas renderer - * - * @param width=800 {number} the width of the renderers view - * @param height=600 {number} the height of the renderers view - * @param [options] {object} The optional renderer parameters - * @param [options.view] {HTMLCanvasElement} the canvas to use as a view, optional - * @param [options.transparent=false] {boolean} If the render view is transparent, default false - * @param [options.antialias=false] {boolean} sets antialias (only applicable in chrome at the moment) - * @param [options.preserveDrawingBuffer=false] {boolean} enables drawing buffer preservation, enable this if you - * need to call toDataUrl on the webgl context - * @param [options.resolution=1] {number} the resolution of the renderer retina would be 2 - * @param [noWebGL=false] {Boolean} prevents selection of WebGL renderer, even if such is present - * - * @return {WebGLRenderer|CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer - */ - autoDetectRenderer: function (width, height, options, noWebGL) { - width = width || 800; - height = height || 600; - - if (!noWebGL && require('webgl-enabled')()) { - return new core.WebGLRenderer(width, height, options); - } - - return new core.CanvasRenderer(width, height, options); - }, - - /** - * This helper function will automatically detect which renderer you should be using. This function is very - * similar to the autoDetectRenderer function except that is will return a canvas renderer for android. - * Even thought both android chrome supports webGL the canvas implementation perform better at the time of writing. - * This function will likely change and update as webGL performance improves on these devices. - * - * @param width=800 {number} the width of the renderers view - * @param height=600 {number} the height of the renderers view - * @param [options] {object} The optional renderer parameters - * @param [options.view] {HTMLCanvasElement} the canvas to use as a view, optional - * @param [options.transparent=false] {boolean} If the render view is transparent, default false - * @param [options.antialias=false] {boolean} sets antialias (only applicable in chrome at the moment) - * @param [options.preserveDrawingBuffer=false] {boolean} enables drawing buffer preservation, enable this if you - * need to call toDataUrl on the webgl context - * @param [options.resolution=1] {number} the resolution of the renderer retina would be 2 - * - * @return {WebGLRenderer|CanvasRenderer} Returns WebGL renderer if available, otherwise CanvasRenderer - */ - autoDetectRecommendedRenderer: function (width, height, options) { - var isAndroid = /Android/i.test(navigator.userAgent); - - return core.autoDetectRenderer(width, height, options, isAndroid); - } -}; - -},{"./const":4,"./display/DisplayObject":5,"./display/DisplayObjectContainer":6,"./display/Sprite":7,"./display/SpriteBatch":8,"./math":12,"./primitives/Graphics":18,"./primitives/GraphicsData":19,"./renderers/canvas/CanvasRenderer":20,"./renderers/canvas/utils/CanvasBuffer":21,"./renderers/canvas/utils/CanvasGraphics":22,"./renderers/webgl/WebGLRenderer":25,"./renderers/webgl/utils/WebGLGraphics":39,"./textures/BaseTexture":42,"./textures/RenderTexture":43,"./textures/Texture":44,"./textures/VideoBaseTexture":46,"./utils":50,"webgl-enabled":2}],10:[function(require,module,exports){ -var Point = require('./Point'); - -/** - * The Matrix class is now an object, which makes it a lot faster, - * here is a representation of it : - * | a | b | tx| - * | c | d | ty| - * | 0 | 0 | 1 | - * - * @class - * @namespace PIXI - */ -function Matrix() { - /** - * @member {number} - * @default 1 - */ - this.a = 1; - - /** - * @member {number} - * @default 0 - */ - this.b = 0; - - /** - * @member {number} - * @default 0 - */ - this.c = 0; - - /** - * @member {number} - * @default 1 - */ - this.d = 1; - - /** - * @member {number} - * @default 0 - */ - this.tx = 0; - - /** - * @member {number} - * @default 0 - */ - this.ty = 0; -} - -Matrix.prototype.constructor = Matrix; -module.exports = Matrix; - -/** - * Creates a Matrix object based on the given array. The Element to Matrix mapping order is as follows: - * - * a = array[0] - * b = array[1] - * c = array[3] - * d = array[4] - * tx = array[2] - * ty = array[5] - * - * @param array {number[]} The array that the matrix will be populated from. - */ -Matrix.prototype.fromArray = function (array) { - this.a = array[0]; - this.b = array[1]; - this.c = array[3]; - this.d = array[4]; - this.tx = array[2]; - this.ty = array[5]; -}; - -/** - * Creates an array from the current Matrix object. - * - * @param transpose {boolean} Whether we need to transpose the matrix or not - * @return {number[]} the newly created array which contains the matrix - */ -Matrix.prototype.toArray = function (transpose) { - if (!this.array) { - this.array = new Float32Array(9); - } - - var array = this.array; - - if (transpose) { - array[0] = this.a; - array[1] = this.b; - array[2] = 0; - array[3] = this.c; - array[4] = this.d; - array[5] = 0; - array[6] = this.tx; - array[7] = this.ty; - array[8] = 1; - } - else { - array[0] = this.a; - array[1] = this.c; - array[2] = this.tx; - array[3] = this.b; - array[4] = this.d; - array[5] = this.ty; - array[6] = 0; - array[7] = 0; - array[8] = 1; - } - - return array; -}; - -/** - * Get a new position with the current transformation applied. - * Can be used to go from a child's coordinate space to the world coordinate space. (e.g. rendering) - * - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, transformed through this matrix - */ -Matrix.prototype.apply = function (pos, newPos) { - newPos = newPos || new Point(); - - newPos.x = this.a * pos.x + this.c * pos.y + this.tx; - newPos.y = this.b * pos.x + this.d * pos.y + this.ty; - - return newPos; -}; - -/** - * Get a new position with the inverse of the current transformation applied. - * Can be used to go from the world coordinate space to a child's coordinate space. (e.g. input) - * - * @param pos {Point} The origin - * @param [newPos] {Point} The point that the new position is assigned to (allowed to be same as input) - * @return {Point} The new point, inverse-transformed through this matrix - */ -Matrix.prototype.applyInverse = function (pos, newPos) { - newPos = newPos || new Point(); - - var id = 1 / (this.a * this.d + this.c * -this.b); - - newPos.x = this.d * id * pos.x + -this.c * id * pos.y + (this.ty * this.c - this.tx * this.d) * id; - newPos.y = this.a * id * pos.y + -this.b * id * pos.x + (-this.ty * this.a + this.tx * this.b) * id; - - return newPos; -}; - -/** - * Translates the matrix on the x and y. - * - * @param {number} x - * @param {number} y - * @return {Matrix} This matrix. Good for chaining method calls. - */ -Matrix.prototype.translate = function (x, y) { - this.tx += x; - this.ty += y; - - return this; -}; - -/** - * Applies a scale transformation to the matrix. - * - * @param {number} x The amount to scale horizontally - * @param {number} y The amount to scale vertically - * @return {Matrix} This matrix. Good for chaining method calls. - */ -Matrix.prototype.scale = function (x, y) { - this.a *= x; - this.d *= y; - this.c *= x; - this.b *= y; - this.tx *= x; - this.ty *= y; - - return this; -}; - - -/** - * Applies a rotation transformation to the matrix. - * - * @param {number} angle - The angle in radians. - * @return {Matrix} This matrix. Good for chaining method calls. - */ -Matrix.prototype.rotate = function (angle) { - var cos = Math.cos( angle ); - var sin = Math.sin( angle ); - - var a1 = this.a; - var c1 = this.c; - var tx1 = this.tx; - - this.a = a1 * cos-this.b * sin; - this.b = a1 * sin+this.b * cos; - this.c = c1 * cos-this.d * sin; - this.d = c1 * sin+this.d * cos; - this.tx = tx1 * cos - this.ty * sin; - this.ty = tx1 * sin + this.ty * cos; - - return this; -}; - -/** - * Appends the given Matrix to this Matrix. - * - * @param {Matrix} matrix - * @return {Matrix} This matrix. Good for chaining method calls. - */ -Matrix.prototype.append = function (matrix) { - var a1 = this.a; - var b1 = this.b; - var c1 = this.c; - var d1 = this.d; - - this.a = matrix.a * a1 + matrix.b * c1; - this.b = matrix.a * b1 + matrix.b * d1; - this.c = matrix.c * a1 + matrix.d * c1; - this.d = matrix.c * b1 + matrix.d * d1; - - this.tx = matrix.tx * a1 + matrix.ty * c1 + this.tx; - this.ty = matrix.tx * b1 + matrix.ty * d1 + this.ty; - - return this; -}; - -/** - * Resets this Matix to an identity (default) matrix. - * - * @return {Matrix} This matrix. Good for chaining method calls. - */ -Matrix.prototype.identity = function () { - this.a = 1; - this.b = 0; - this.c = 0; - this.d = 1; - this.tx = 0; - this.ty = 0; - - return this; -}; - -Matrix.IDENTITY = new Matrix(); - -},{"./Point":11}],11:[function(require,module,exports){ -/** - * The Point object represents a location in a two-dimensional coordinate system, where x represents - * the horizontal axis and y represents the vertical axis. - * - * @class - * @namespace PIXI - * @param [x=0] {number} position of the point on the x axis - * @param [y=0] {number} position of the point on the y axis - */ -function Point(x, y) { - /** - * @member {number} - * @default 0 - */ - this.x = x || 0; - - /** - * @member {number} - * @default 0 - */ - this.y = y || 0; -} - -Point.prototype.constructor = Point; -module.exports = Point; - -/** - * Creates a clone of this point - * - * @return {Point} a copy of the point - */ -Point.prototype.clone = function () { - return new Point(this.x, this.y); -}; - -/** - * Sets the point to a new x and y position. - * If y is omitted, both x and y will be set to x. - * - * @param [x=0] {number} position of the point on the x axis - * @param [y=0] {number} position of the point on the y axis - */ -Point.prototype.set = function (x, y) { - this.x = x || 0; - this.y = y || ( (y !== 0) ? this.x : 0 ) ; -}; - -},{}],12:[function(require,module,exports){ -/** - * @namespace PIXI.math - */ -module.exports = { - /** - * @property {number} PI_2 - Math.PI x 2 - * @constant - * @static - */ - PI_2: Math.PI * 2, - - /** - * @property {number} RAD_TO_DEG - Constant conversion factor for converting radians to degrees - * @constant - * @static - */ - RAD_TO_DEG: 180 / Math.PI, - - /** - * @property {Number} DEG_TO_RAD - Constant conversion factor for converting degrees to radians - * @constant - * @static - */ - DEG_TO_RAD: Math.PI / 180, - - Point: require('./Point'), - Matrix: require('./Matrix'), - - Circle: require('./shapes/Circle'), - Ellipse: require('./shapes/Ellipse'), - Polygon: require('./shapes/Polygon'), - Rectangle: require('./shapes/Rectangle'), - RoundedRectangle: require('./shapes/RoundedRectangle') -}; - -},{"./Matrix":10,"./Point":11,"./shapes/Circle":13,"./shapes/Ellipse":14,"./shapes/Polygon":15,"./shapes/Rectangle":16,"./shapes/RoundedRectangle":17}],13:[function(require,module,exports){ -var Rectangle = require('./Rectangle'), - CONST = require('../../const'); - -/** - * The Circle object can be used to specify a hit area for displayObjects - * - * @class - * @namespace PIXI - * @param x {number} The X coordinate of the center of this circle - * @param y {number} The Y coordinate of the center of this circle - * @param radius {number} The radius of the circle - */ -function Circle(x, y, radius) { - /** - * @member {number} - * @default 0 - */ - this.x = x || 0; - - /** - * @member {number} - * @default 0 - */ - this.y = y || 0; - - /** - * @member {number} - * @default 0 - */ - this.radius = radius || 0; - - /** - * The type of the object, mainly used to avoid `instanceof` checks - * - * @member {number} - */ - this.type = CONST.SHAPES.CIRC; -} - -Circle.prototype.constructor = Circle; -module.exports = Circle; - -/** - * Creates a clone of this Circle instance - * - * @method clone - * @return {Circle} a copy of the Circle - */ -Circle.prototype.clone = function () { - return new Circle(this.x, this.y, this.radius); -}; - -/** - * Checks whether the x and y coordinates given are contained within this circle - * - * @method contains - * @param x {number} The X coordinate of the point to test - * @param y {number} The Y coordinate of the point to test - * @return {boolean} Whether the x/y coordinates are within this Circle - */ -Circle.prototype.contains = function (x, y) { - if (this.radius <= 0) { - return false; - } - - var dx = (this.x - x), - dy = (this.y - y), - r2 = this.radius * this.radius; - - dx *= dx; - dy *= dy; - - return (dx + dy <= r2); -}; - -/** -* Returns the framing rectangle of the circle as a Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -Circle.prototype.getBounds = function () { - return new Rectangle(this.x - this.radius, this.y - this.radius, this.radius * 2, this.radius * 2); -}; - -},{"../../const":4,"./Rectangle":16}],14:[function(require,module,exports){ -var Rectangle = require('./Rectangle'), - CONST = require('../../const'); - -/** - * The Ellipse object can be used to specify a hit area for displayObjects - * - * @class - * @namespace PIXI - * @param x {number} The X coordinate of the center of the ellipse - * @param y {number} The Y coordinate of the center of the ellipse - * @param width {number} The half width of this ellipse - * @param height {number} The half height of this ellipse - */ -function Ellipse(x, y, width, height) { - /** - * @member {number} - * @default 0 - */ - this.x = x || 0; - - /** - * @member {number} - * @default 0 - */ - this.y = y || 0; - - /** - * @member {number} - * @default 0 - */ - this.width = width || 0; - - /** - * @member {number} - * @default 0 - */ - this.height = height || 0; - - /** - * The type of the object, mainly used to avoid `instanceof` checks - * - * @member {number} - */ - this.type = CONST.SHAPES.ELIP; -} - -Ellipse.prototype.constructor = Ellipse; -module.exports = Ellipse; - -/** - * Creates a clone of this Ellipse instance - * - * @method clone - * @return {Ellipse} a copy of the ellipse - */ -Ellipse.prototype.clone = function () { - return new Ellipse(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates given are contained within this ellipse - * - * @method contains - * @param x {number} The X coordinate of the point to test - * @param y {number} The Y coordinate of the point to test - * @return {boolean} Whether the x/y coords are within this ellipse - */ -Ellipse.prototype.contains = function (x, y) { - if (this.width <= 0 || this.height <= 0) { - return false; - } - - //normalize the coords to an ellipse with center 0,0 - var normx = ((x - this.x) / this.width), - normy = ((y - this.y) / this.height); - - normx *= normx; - normy *= normy; - - return (normx + normy <= 1); -}; - -/** -* Returns the framing rectangle of the ellipse as a Rectangle object -* -* @method getBounds -* @return {Rectangle} the framing rectangle -*/ -Ellipse.prototype.getBounds = function () { - return new Rectangle(this.x - this.width, this.y - this.height, this.width, this.height); -}; - -},{"../../const":4,"./Rectangle":16}],15:[function(require,module,exports){ -var Point = require('../Point'), - CONST = require('../../const'); - -/** - * @class - * @namespace PIXI - * @param points* {Point[]|number[]|Point...|number...} This can be an array of Points that form the polygon, - * a flat array of numbers that will be interpreted as [x,y, x,y, ...], or the arguments passed can be - * all the points of the polygon e.g. `new Polygon(new Point(), new Point(), ...)`, or the - * arguments passed can be flat x,y values e.g. `new Polygon(x,y, x,y, x,y, ...)` where `x` and `y` are - * Numbers. - */ -function Polygon(points) { - //if points isn't an array, use arguments as the array - if (!(points instanceof Array)) { - points = Array.prototype.slice.call(arguments); - } - - //if this is a flat array of numbers, convert it to points - if (points[0] instanceof Point) { - var p = []; - for (var i = 0, il = points.length; i < il; i++) { - p.push(points[i].x, points[i].y); - } - - points = p; - } - - this.closed = true; - - /** - * An array of the points of this polygon - * - * @member {Point[]} - */ - this.points = points; - - /** - * The type of the object, mainly used to avoid `instanceof` checks - * - * @member {number} - */ - this.type = CONST.SHAPES.POLY; -} - -Polygon.prototype.constructor = Polygon; -module.exports = Polygon; - -/** - * Creates a clone of this polygon - * - * @return {Polygon} a copy of the polygon - */ -Polygon.prototype.clone = function () { - return new Polygon(this.points.slice()); -}; - -/** - * Checks whether the x and y coordinates passed to this function are contained within this polygon - * - * @param x {number} The X coordinate of the point to test - * @param y {number} The Y coordinate of the point to test - * @return {boolean} Whether the x/y coordinates are within this polygon - */ -Polygon.prototype.contains = function (x, y) { - var inside = false; - - // use some raycasting to test hits - // https://github.com/substack/point-in-polygon/blob/master/index.js - var length = this.points.length / 2; - - for (var i = 0, j = length - 1; i < length; j = i++) { - var xi = this.points[i * 2], yi = this.points[i * 2 + 1], - xj = this.points[j * 2], yj = this.points[j * 2 + 1], - intersect = ((yi > y) !== (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - - if (intersect) { - inside = !inside; - } - } - - return inside; -}; - -},{"../../const":4,"../Point":11}],16:[function(require,module,exports){ -var CONST = require('../../const'); - -/** - * the Rectangle object is an area defined by its position, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class - * @namespace PIXI - * @param x {number} The X coordinate of the upper-left corner of the rectangle - * @param y {number} The Y coordinate of the upper-left corner of the rectangle - * @param width {number} The overall width of this rectangle - * @param height {number} The overall height of this rectangle - */ -function Rectangle(x, y, width, height) { - /** - * @member {number} - * @default 0 - */ - this.x = x || 0; - - /** - * @member {number} - * @default 0 - */ - this.y = y || 0; - - /** - * @member {number} - * @default 0 - */ - this.width = width || 0; - - /** - * @member {number} - * @default 0 - */ - this.height = height || 0; - - /** - * The type of the object, mainly used to avoid `instanceof` checks - * - * @member {number} - */ - this.type = CONST.SHAPES.RECT; -} - -Rectangle.prototype.constructor = Rectangle; -module.exports = Rectangle; - -/** - * A constant empty rectangle. - * - * @static - * @constant - */ -Rectangle.EMPTY = new Rectangle(0, 0, 0, 0); - - -/** - * Creates a clone of this Rectangle - * - * @return {Rectangle} a copy of the rectangle - */ -Rectangle.prototype.clone = function () { - return new Rectangle(this.x, this.y, this.width, this.height); -}; - -/** - * Checks whether the x and y coordinates given are contained within this Rectangle - * - * @param x {number} The X coordinate of the point to test - * @param y {number} The Y coordinate of the point to test - * @return {boolean} Whether the x/y coordinates are within this Rectangle - */ -Rectangle.prototype.contains = function (x, y) { - if (this.width <= 0 || this.height <= 0) { - return false; - } - - if (x >= this.x && x <= this.x + this.width) { - if (y >= this.y && y <= this.y + this.height) { - return true; - } - } - - return false; -}; - -},{"../../const":4}],17:[function(require,module,exports){ -var CONST = require('../../const'); - -/** - * The Rounded Rectangle object is an area defined by its position and has nice rounded corners, as indicated by its top-left corner point (x, y) and by its width and its height. - * - * @class - * @namespace PIXI - * @param x {number} The X coordinate of the upper-left corner of the rounded rectangle - * @param y {number} The Y coordinate of the upper-left corner of the rounded rectangle - * @param width {number} The overall width of this rounded rectangle - * @param height {number} The overall height of this rounded rectangle - * @param radius {number} Controls the radius of the rounded corners - */ -function RoundedRectangle(x, y, width, height, radius) { - /** - * @member {number} - * @default 0 - */ - this.x = x || 0; - - /** - * @member {number} - * @default 0 - */ - this.y = y || 0; - - /** - * @member {number} - * @default 0 - */ - this.width = width || 0; - - /** - * @member {number} - * @default 0 - */ - this.height = height || 0; - - /** - * @member {number} - * @default 20 - */ - this.radius = radius || 20; - - /** - * The type of the object, mainly used to avoid `instanceof` checks - * - * @member {number} - */ - this.type = CONST.SHAPES.RREC; -} - -RoundedRectangle.prototype.constructor = RoundedRectangle; -module.exports = RoundedRectangle; - -/** - * Creates a clone of this Rounded Rectangle - * - * @return {RoundedRectangle} a copy of the rounded rectangle - */ -RoundedRectangle.prototype.clone = function () { - return new RoundedRectangle(this.x, this.y, this.width, this.height, this.radius); -}; - -/** - * Checks whether the x and y coordinates given are contained within this Rounded Rectangle - * - * @param x {number} The X coordinate of the point to test - * @param y {number} The Y coordinate of the point to test - * @return {boolean} Whether the x/y coordinates are within this Rounded Rectangle - */ -RoundedRectangle.prototype.contains = function (x, y) { - if (this.width <= 0 || this.height <= 0) { - return false; - } - - if (x >= this.x && x <= this.x + this.width) { - if (y >= this.y && y <= this.y + this.height) { - return true; - } - } - - return false; -}; - -},{"../../const":4}],18:[function(require,module,exports){ -var DisplayObjectContainer = require('../display/DisplayObjectContainer'), - Sprite = require('../display/Sprite'), - Texture = require('../textures/Texture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), - CanvasGraphics = require('../renderers/canvas/utils/CanvasGraphics'), - WebGLGraphics = require('../renderers/webgl/utils/WebGLGraphics'), - GraphicsData = require('./GraphicsData'), - math = require('../math'), - CONST = require('../const'); - -/** - * The Graphics class contains methods used to draw primitive shapes such as lines, circles and - * rectangles to the display, and color and fill them. - * - * @class - * @extends DisplayObjectContainer - * @namespace PIXI - */ -function Graphics() { - DisplayObjectContainer.call(this); - - this.renderable = true; - - /** - * The alpha value used when filling the Graphics object. - * - * @member {number} - * @default 1 - */ - this.fillAlpha = 1; - - /** - * The width (thickness) of any lines drawn. - * - * @member {number} - * @default 0 - */ - this.lineWidth = 0; - - /** - * The color of any lines drawn. - * - * @member {string} - * @default 0 - */ - this.lineColor = 0; - - /** - * Graphics data - * - * @member {GraphicsData[]} - * @private - */ - this.graphicsData = []; - - /** - * The tint applied to the graphic shape. This is a hex value. Apply a value of 0xFFFFFF to reset the tint. - * - * @member {number} - * @default 0xFFFFFF - */ - this.tint = 0xFFFFFF; - - /** - * The blend mode to be applied to the graphic shape. Apply a value of blendModes.NORMAL to reset the blend mode. - * - * @member {number} - * @default CONST.blendModes.NORMAL; - */ - this.blendMode = CONST.blendModes.NORMAL; - - /** - * Current path - * - * @member {GraphicsData} - * @private - */ - this.currentPath = null; - - /** - * Array containing some WebGL-related properties used by the WebGL renderer. - * - * @member {object} - * @private - */ - // TODO - _webgl should use a prototype object, not a random undocumented object... - this._webGL = {}; - - /** - * Whether this shape is being used as a mask. - * - * @member {boolean} - */ - this.isMask = false; - - /** - * The bounds' padding used for bounds calculation. - * - * @member {number} - */ - this.boundsPadding = 0; - - /** - * A cache of the local bounds to prevent recalculation. - * - * @member {Rectangle} - * @private - */ - this._localBounds = new math.Rectangle(0,0,1,1); - - /** - * Used to detect if the graphics object has changed. If this is set to true then the graphics - * object will be recalculated. - * - * @member {boolean} - * @private - */ - this.dirty = true; - - /** - * Used to detect if the WebGL graphics object has changed. If this is set to true then the - * graphics object will be recalculated. - * - * @member {boolean} - * @private - */ - this.glDirty = false; - - /** - * Used to detect if the cached sprite object needs to be updated. - * - * @member {boolean} - * @private - */ - this.cachedSpriteDirty = false; -} - -// constructor -Graphics.prototype = Object.create(DisplayObjectContainer.prototype); -Graphics.prototype.constructor = Graphics; -module.exports = Graphics; - -Object.defineProperties(Graphics.prototype, { - /** - * When cacheAsBitmap is set to true the graphics object will be rendered as if it was a sprite. - * This is useful if your graphics element does not change often, as it will speed up the rendering - * of the object in exchange for taking up texture memory. It is also useful if you need the graphics - * object to be anti-aliased, because it will be rendered using canvas. This is not recommended if - * you are constantly redrawing the graphics element. - * - * @member {boolean} - * @memberof Graphics# - * @default false - * @private - */ - cacheAsBitmap: { - get: function () { - return this._cacheAsBitmap; - }, - set: function (value) { - this._cacheAsBitmap = value; - - if (this._cacheAsBitmap) { - this._generateCachedSprite(); - } - else { - this.destroyCachedSprite(); - this.dirty = true; - } - } - } -}); - -/** - * Creates a new Graphics object with the same values as this one. - * - * @return {Graphics} - */ -GraphicsData.prototype.clone = function () { - var clone = new Graphics(); - - clone.renderable = this.renderable; - clone.fillAlpha = this.fillAlpha; - clone.lineWidth = this.lineWidth; - clone.lineColor = this.lineColor; - clone.tint = this.tint; - clone.blendMode = this.blendMode; - clone.isMask = this.isMask; - clone.boundsPadding = this.boundsPadding; - clone.dirty = this.dirty; - clone.glDirty = this.glDirty; - clone.cachedSpriteDirty = this.cachedSpriteDirty; - - // copy graphics data - for (var i = 0; i < this.graphicsData.length; ++i) { - clone.graphicsData.push(this.graphicsData.clone()); - } - - clone.currentPath = clone.graphicsData[clone.graphicsData.length - 1]; - - clone.updateLocalBounds(); - - return clone; -}; - -/** - * Specifies the line style used for subsequent calls to Graphics methods such as the lineTo() method or the drawCircle() method. - * - * @param lineWidth {number} width of the line to draw, will update the objects stored style - * @param color {number} color of the line to draw, will update the objects stored style - * @param alpha {number} alpha of the line to draw, will update the objects stored style - * @return {Graphics} - */ -Graphics.prototype.lineStyle = function (lineWidth, color, alpha) { - this.lineWidth = lineWidth || 0; - this.lineColor = color || 0; - this.lineAlpha = (arguments.length < 3) ? 1 : alpha; - - if (this.currentPath) { - if (this.currentPath.shape.points.length) { - // halfway through a line? start a new one! - this.drawShape( new math.Polygon( this.currentPath.shape.points.slice(-2) )); - } - else { - // otherwise its empty so lets just set the line properties - this.currentPath.lineWidth = this.lineWidth; - this.currentPath.lineColor = this.lineColor; - this.currentPath.lineAlpha = this.lineAlpha; - } - } - - return this; -}; - -/** - * Moves the current drawing position to x, y. - * - * @param x {number} the X coordinate to move to - * @param y {number} the Y coordinate to move to - * @return {Graphics} - */ -Graphics.prototype.moveTo = function (x, y) { - this.drawShape(new math.Polygon([x,y])); - - return this; -}; - -/** - * Draws a line using the current line style from the current drawing position to (x, y); - * The current drawing position is then set to (x, y). - * - * @param x {number} the X coordinate to draw to - * @param y {number} the Y coordinate to draw to - * @return {Graphics} - */ -Graphics.prototype.lineTo = function (x, y) { - this.currentPath.shape.points.push(x, y); - this.dirty = true; - - return this; -}; - -/** - * Calculate the points for a quadratic bezier curve and then draws it. - * Based on: https://stackoverflow.com/questions/785097/how-do-i-implement-a-bezier-curve-in-c - * - * @param cpX {number} Control point x - * @param cpY {number} Control point y - * @param toX {number} Destination point x - * @param toY {number} Destination point y - * @return {Graphics} - */ -Graphics.prototype.quadraticCurveTo = function (cpX, cpY, toX, toY) { - if (this.currentPath) { - if (this.currentPath.shape.points.length === 0) { - this.currentPath.shape.points = [0, 0]; - } - } - else { - this.moveTo(0,0); - } - - var xa, - ya, - n = 20, - points = this.currentPath.shape.points; - - if (points.length === 0) { - this.moveTo(0, 0); - } - - var fromX = points[points.length-2]; - var fromY = points[points.length-1]; - - var j = 0; - for (var i = 1; i <= n; ++i) { - j = i / n; - - xa = fromX + ( (cpX - fromX) * j ); - ya = fromY + ( (cpY - fromY) * j ); - - points.push( xa + ( ((cpX + ( (toX - cpX) * j )) - xa) * j ), - ya + ( ((cpY + ( (toY - cpY) * j )) - ya) * j ) ); - } - - this.dirty = true; - - return this; -}; - -/** - * Calculate the points for a bezier curve and then draws it. - * - * @param cpX {number} Control point x - * @param cpY {number} Control point y - * @param cpX2 {number} Second Control point x - * @param cpY2 {number} Second Control point y - * @param toX {number} Destination point x - * @param toY {number} Destination point y - * @return {Graphics} - */ -Graphics.prototype.bezierCurveTo = function (cpX, cpY, cpX2, cpY2, toX, toY) { - if (this.currentPath) { - if (this.currentPath.shape.points.length === 0) { - this.currentPath.shape.points = [0, 0]; - } - } - else { - this.moveTo(0,0); - } - - var n = 20, - dt, - dt2, - dt3, - t2, - t3, - points = this.currentPath.shape.points; - - var fromX = points[points.length-2]; - var fromY = points[points.length-1]; - - var j = 0; - - for (var i = 1; i <= n; ++i) { - j = i / n; - - dt = (1 - j); - dt2 = dt * dt; - dt3 = dt2 * dt; - - t2 = j * j; - t3 = t2 * j; - - points.push( dt3 * fromX + 3 * dt2 * j * cpX + 3 * dt * t2 * cpX2 + t3 * toX, - dt3 * fromY + 3 * dt2 * j * cpY + 3 * dt * t2 * cpY2 + t3 * toY); - } - - this.dirty = true; - - return this; -}; - -/** - * The arcTo() method creates an arc/curve between two tangents on the canvas. - * - * "borrowed" from https://code.google.com/p/fxcanvas/ - thanks google! - * - * @param x1 {number} The x-coordinate of the beginning of the arc - * @param y1 {number} The y-coordinate of the beginning of the arc - * @param x2 {number} The x-coordinate of the end of the arc - * @param y2 {number} The y-coordinate of the end of the arc - * @param radius {number} The radius of the arc - * @return {Graphics} - */ -Graphics.prototype.arcTo = function (x1, y1, x2, y2, radius) { - if (this.currentPath) { - if (this.currentPath.shape.points.length === 0) { - this.currentPath.shape.points.push(x1, y1); - } - } - else { - this.moveTo(x1, y1); - } - - var points = this.currentPath.shape.points, - fromX = points[points.length-2], - fromY = points[points.length-1], - a1 = fromY - y1, - b1 = fromX - x1, - a2 = y2 - y1, - b2 = x2 - x1, - mm = Math.abs(a1 * b2 - b1 * a2); - - if (mm < 1.0e-8 || radius === 0) { - if (points[points.length-2] !== x1 || points[points.length-1] !== y1) { - points.push(x1, y1); - } - } - else { - var dd = a1 * a1 + b1 * b1, - cc = a2 * a2 + b2 * b2, - tt = a1 * a2 + b1 * b2, - k1 = radius * Math.sqrt(dd) / mm, - k2 = radius * Math.sqrt(cc) / mm, - j1 = k1 * tt / dd, - j2 = k2 * tt / cc, - cx = k1 * b2 + k2 * b1, - cy = k1 * a2 + k2 * a1, - px = b1 * (k2 + j1), - py = a1 * (k2 + j1), - qx = b2 * (k1 + j2), - qy = a2 * (k1 + j2), - startAngle = Math.atan2(py - cy, px - cx), - endAngle = Math.atan2(qy - cy, qx - cx); - - this.arc(cx + x1, cy + y1, radius, startAngle, endAngle, b1 * a2 > b2 * a1); - } - - this.dirty = true; - - return this; -}; - -/** - * The arc method creates an arc/curve (used to create circles, or parts of circles). - * - * @param cx {number} The x-coordinate of the center of the circle - * @param cy {number} The y-coordinate of the center of the circle - * @param radius {number} The radius of the circle - * @param startAngle {number} The starting angle, in radians (0 is at the 3 o'clock position of the arc's circle) - * @param endAngle {number} The ending angle, in radians - * @param anticlockwise {boolean} Optional. Specifies whether the drawing should be counterclockwise or clockwise. False is default, and indicates clockwise, while true indicates counter-clockwise. - * @return {Graphics} - */ -Graphics.prototype.arc = function (cx, cy, radius, startAngle, endAngle, anticlockwise) { - var startX = cx + Math.cos(startAngle) * radius; - var startY = cy + Math.sin(startAngle) * radius; - var points; - - // TODO - This if-else makes no sense. It uses currentPath in the else where it doesn't exist... - if (this.currentPath) { - points = this.currentPath.shape.points; - - if (points.length === 0) { - points.push(startX, startY); - } - else if (points[points.length-2] !== startX || points[points.length-1] !== startY) { - points.push(startX, startY); - } - } - else { - this.moveTo(startX, startY); - points = this.currentPath.shape.points; - } - - if (startAngle === endAngle) { - return this; - } - - if (!anticlockwise && endAngle <= startAngle) { - endAngle += Math.PI * 2; - } - else if (anticlockwise && startAngle <= endAngle) { - startAngle += Math.PI * 2; - } - - var sweep = anticlockwise ? (startAngle - endAngle) *-1 : (endAngle - startAngle); - var segs = (Math.abs(sweep)/ (Math.PI * 2)) * 40; - - if (sweep === 0) { - return this; - } - - var theta = sweep/(segs*2); - var theta2 = theta*2; - - var cTheta = Math.cos(theta); - var sTheta = Math.sin(theta); - - var segMinus = segs - 1; - - var remainder = ( segMinus % 1 ) / segMinus; - - for (var i = 0; i <= segMinus; ++i) { - var real = i + remainder * i; - var angle = ((theta) + startAngle + (theta2 * real)); - - var c = Math.cos(angle); - var s = -Math.sin(angle); - - points.push(( (cTheta * c) + (sTheta * s) ) * radius + cx, - ( (cTheta * -s) + (sTheta * c) ) * radius + cy); - } - - this.dirty = true; - - return this; -}; - -/** - * Specifies a simple one-color fill that subsequent calls to other Graphics methods - * (such as lineTo() or drawCircle()) use when drawing. - * - * @param color {number} the color of the fill - * @param alpha {number} the alpha of the fill - * @return {Graphics} - */ -Graphics.prototype.beginFill = function (color, alpha) { - this.filling = true; - this.fillColor = color || 0; - this.fillAlpha = (alpha === undefined) ? 1 : alpha; - - if (this.currentPath) { - if (this.currentPath.shape.points.length <= 2) { - this.currentPath.fill = this.filling; - this.currentPath.fillColor = this.fillColor; - this.currentPath.fillAlpha = this.fillAlpha; - } - } - return this; -}; - -/** - * Applies a fill to the lines and shapes that were added since the last call to the beginFill() method. - * - * @return {Graphics} - */ -Graphics.prototype.endFill = function () { - this.filling = false; - this.fillColor = null; - this.fillAlpha = 1; - - return this; -}; - -/** - * - * @param x {number} The X coord of the top-left of the rectangle - * @param y {number} The Y coord of the top-left of the rectangle - * @param width {number} The width of the rectangle - * @param height {number} The height of the rectangle - * @return {Graphics} - */ -Graphics.prototype.drawRect = function ( x, y, width, height ) { - this.drawShape(new math.Rectangle(x,y, width, height)); - - return this; -}; - -/** - * - * @param x {number} The X coord of the top-left of the rectangle - * @param y {number} The Y coord of the top-left of the rectangle - * @param width {number} The width of the rectangle - * @param height {number} The height of the rectangle - * @param radius {number} Radius of the rectangle corners - */ -Graphics.prototype.drawRoundedRect = function ( x, y, width, height, radius ) { - this.drawShape(new math.RoundedRectangle(x, y, width, height, radius)); - - return this; -}; - -/** - * Draws a circle. - * - * @param x {number} The X coordinate of the center of the circle - * @param y {number} The Y coordinate of the center of the circle - * @param radius {number} The radius of the circle - * @return {Graphics} - */ -Graphics.prototype.drawCircle = function (x, y, radius) { - this.drawShape(new math.Circle(x,y, radius)); - - return this; -}; - -/** - * Draws an ellipse. - * - * @param x {number} The X coordinate of the center of the ellipse - * @param y {number} The Y coordinate of the center of the ellipse - * @param width {number} The half width of the ellipse - * @param height {number} The half height of the ellipse - * @return {Graphics} - */ -Graphics.prototype.drawEllipse = function (x, y, width, height) { - this.drawShape(new math.Ellipse(x, y, width, height)); - - return this; -}; - -/** - * Draws a polygon using the given path. - * - * @param path {Array} The path data used to construct the polygon. - * @return {Graphics} - */ -Graphics.prototype.drawPolygon = function (path) { - if (!(path instanceof Array)) { - path = Array.prototype.slice.call(arguments); - } - - this.drawShape(new math.Polygon(path)); - - return this; -}; - -/** - * Clears the graphics that were drawn to this Graphics object, and resets fill and line style settings. - * - * @return {Graphics} - */ -Graphics.prototype.clear = function () { - this.lineWidth = 0; - this.filling = false; - - this.dirty = true; - this.clearDirty = true; - this.graphicsData = []; - - return this; -}; - -/** - * Useful function that returns a texture of the graphics object that can then be used to create sprites - * This can be quite useful if your geometry is complicated and needs to be reused multiple times. - * - * @param resolution {number} The resolution of the texture being generated - * @param scaleMode {number} Should be one of the scaleMode consts - * @return {Texture} a texture of the graphics object - */ -Graphics.prototype.generateTexture = function (resolution, scaleMode) { - resolution = resolution || 1; - - var bounds = this.getBounds(); - - var canvasBuffer = new CanvasBuffer(bounds.width * resolution, bounds.height * resolution); - - var texture = Texture.fromCanvas(canvasBuffer.canvas, scaleMode); - texture.baseTexture.resolution = resolution; - - canvasBuffer.context.scale(resolution, resolution); - - canvasBuffer.context.translate(-bounds.x,-bounds.y); - - CanvasGraphics.renderGraphics(this, canvasBuffer.context); - - return texture; -}; - -/** - * Renders the object using the WebGL renderer - * - * @param renderer {WebGLRenderer} - */ -Graphics.prototype.renderWebGL = function (renderer) { - // if the sprite is not visible or the alpha is 0 then no need to render this element - if (!this.visible || this.alpha <= 0 || this.isMask === true) { - return; - } - - if (this._cacheAsBitmap) { - if (this.dirty || this.cachedSpriteDirty) { - this._generateCachedSprite(); - - // we will also need to update the texture on the gpu too! - this.updateCachedSpriteTexture(); - - this.cachedSpriteDirty = false; - this.dirty = false; - } - - this._cachedSprite.worldAlpha = this.worldAlpha; - - Sprite.prototype.renderWebGL.call(this._cachedSprite, renderer); - - return; - } - else { - renderer.spriteBatch.stop(); - renderer.blendModeManager.setBlendMode(this.blendMode); - - if (this._mask) { - renderer.maskManager.pushMask(this._mask, renderer); - } - - if (this._filters) { - renderer.filterManager.pushFilter(this._filterBlock); - } - - // check blend mode - if (this.blendMode !== renderer.spriteBatch.currentBlendMode) { - renderer.spriteBatch.currentBlendMode = this.blendMode; - - var blendModeWebGL = renderer.blendModes[renderer.spriteBatch.currentBlendMode]; - - renderer.spriteBatch.gl.blendFunc(blendModeWebGL[0], blendModeWebGL[1]); - } - - // check if the webgl graphic needs to be updated - if (this.glDirty) { - this.dirty = true; - this.glDirty = false; - } - - WebGLGraphics.renderGraphics(this, renderer); - - // only render if it has children! - if (this.children.length) { - renderer.spriteBatch.start(); - - // simple render children! - for (var i = 0, j = this.children.length; i < j; ++i) { - this.children[i].renderWebGL(renderer); - } - - renderer.spriteBatch.stop(); - } - - if (this._filters) { - renderer.filterManager.popFilter(); - } - - if (this._mask) { - renderer.maskManager.popMask(this.mask, renderer); - } - - renderer.drawCount++; - - renderer.spriteBatch.start(); - } -}; - -/** - * Renders the object using the Canvas renderer - * - * @param renderer {CanvasRenderer} - * @private - */ -Graphics.prototype.renderCanvas = function (renderer) { - // if the sprite is not visible or the alpha is 0 then no need to render this element - if (!this.visible || this.alpha <= 0 || this.isMask === true) { - return; - } - - if (this._cacheAsBitmap) { - if (this.dirty || this.cachedSpriteDirty) { - this._generateCachedSprite(); - - // we will also need to update the texture - this.updateCachedSpriteTexture(); - - this.cachedSpriteDirty = false; - this.dirty = false; - } - - this._cachedSprite.alpha = this.alpha; - - Sprite.prototype.renderCanvas.call(this._cachedSprite, renderer); - - return; - } - else { - var context = renderer.context; - var transform = this.worldTransform; - - if (this.blendMode !== renderer.currentBlendMode) { - renderer.currentBlendMode = this.blendMode; - context.globalCompositeOperation = renderer.blendModes[renderer.currentBlendMode]; - } - - if (this._mask) { - renderer.maskManager.pushMask(this._mask, renderer); - } - - var resolution = renderer.resolution; - context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - - CanvasGraphics.renderGraphics(this, context); - - for (var i = 0, j = this.children.length; i < j; ++i) { - this.children[i].renderCanvas(renderer); - } - - if (this._mask) { - renderer.maskManager.popMask(renderer); - } - } -}; - -/** - * Retrieves the bounds of the graphic shape as a rectangle object - * - * @return {Rectangle} the rectangular bounding area - */ -Graphics.prototype.getBounds = function (matrix) { - // return an empty object if the item is a mask! - if (this.isMask) { - return math.Rectangle.EMPTY; - } - - if (this.dirty) { - this.updateLocalBounds(); - - this.glDirty = true; - this.cachedSpriteDirty = true; - this.dirty = false; - } - - var bounds = this._localBounds; - - var w0 = bounds.x; - var w1 = bounds.width + bounds.x; - - var h0 = bounds.y; - var h1 = bounds.height + bounds.y; - - var worldTransform = matrix || this.worldTransform; - - var a = worldTransform.a; - var b = worldTransform.b; - var c = worldTransform.c; - var d = worldTransform.d; - var tx = worldTransform.tx; - var ty = worldTransform.ty; - - var x1 = a * w1 + c * h1 + tx; - var y1 = d * h1 + b * w1 + ty; - - var x2 = a * w0 + c * h1 + tx; - var y2 = d * h1 + b * w0 + ty; - - var x3 = a * w0 + c * h0 + tx; - var y3 = d * h0 + b * w0 + ty; - - var x4 = a * w1 + c * h0 + tx; - var y4 = d * h0 + b * w1 + ty; - - var maxX = x1; - var maxY = y1; - - var minX = x1; - var minY = y1; - - minX = x2 < minX ? x2 : minX; - minX = x3 < minX ? x3 : minX; - minX = x4 < minX ? x4 : minX; - - minY = y2 < minY ? y2 : minY; - minY = y3 < minY ? y3 : minY; - minY = y4 < minY ? y4 : minY; - - maxX = x2 > maxX ? x2 : maxX; - maxX = x3 > maxX ? x3 : maxX; - maxX = x4 > maxX ? x4 : maxX; - - maxY = y2 > maxY ? y2 : maxY; - maxY = y3 > maxY ? y3 : maxY; - maxY = y4 > maxY ? y4 : maxY; - - this._bounds.x = minX; - this._bounds.width = maxX - minX; - - this._bounds.y = minY; - this._bounds.height = maxY - minY; - - return this._bounds; -}; - -/** - * Update the bounds of the object - * - */ -Graphics.prototype.updateLocalBounds = function () { - var minX = Infinity; - var maxX = -Infinity; - - var minY = Infinity; - var maxY = -Infinity; - - if (this.graphicsData.length) { - var shape, points, x, y, w, h; - - for (var i = 0; i < this.graphicsData.length; i++) { - var data = this.graphicsData[i]; - var type = data.type; - var lineWidth = data.lineWidth; - shape = data.shape; - - if (type === CONST.SHAPES.RECT || type === CONST.SHAPES.RREC) { - x = shape.x - lineWidth/2; - y = shape.y - lineWidth/2; - w = shape.width + lineWidth; - h = shape.height + lineWidth; - - minX = x < minX ? x : minX; - maxX = x + w > maxX ? x + w : maxX; - - minY = y < minY ? y : minY; - maxY = y + h > maxY ? y + h : maxY; - } - else if (type === CONST.SHAPES.CIRC) { - x = shape.x; - y = shape.y; - w = shape.radius + lineWidth/2; - h = shape.radius + lineWidth/2; - - minX = x - w < minX ? x - w : minX; - maxX = x + w > maxX ? x + w : maxX; - - minY = y - h < minY ? y - h : minY; - maxY = y + h > maxY ? y + h : maxY; - } - else if (type === CONST.SHAPES.ELIP) { - x = shape.x; - y = shape.y; - w = shape.width + lineWidth/2; - h = shape.height + lineWidth/2; - - minX = x - w < minX ? x - w : minX; - maxX = x + w > maxX ? x + w : maxX; - - minY = y - h < minY ? y - h : minY; - maxY = y + h > maxY ? y + h : maxY; - } - else { - // POLY - points = shape.points; - - for (var j = 0; j < points.length; j += 2) { - x = points[j]; - y = points[j+1]; - - minX = x-lineWidth < minX ? x-lineWidth : minX; - maxX = x+lineWidth > maxX ? x+lineWidth : maxX; - - minY = y-lineWidth < minY ? y-lineWidth : minY; - maxY = y+lineWidth > maxY ? y+lineWidth : maxY; - } - } - } - } - else { - minX = 0; - maxX = 0; - minY = 0; - maxY = 0; - } - - var padding = this.boundsPadding; - - this._localBounds.x = minX - padding; - this._localBounds.width = (maxX - minX) + padding * 2; - - this._localBounds.y = minY - padding; - this._localBounds.height = (maxY - minY) + padding * 2; -}; - -/** - * Generates the cached sprite when the sprite has cacheAsBitmap = true - * - * @private - */ -Graphics.prototype._generateCachedSprite = function () { - var bounds = this.getLocalBounds(); - - if (!this._cachedSprite) { - var canvasBuffer = new CanvasBuffer(bounds.width, bounds.height); - var texture = Texture.fromCanvas(canvasBuffer.canvas); - - this._cachedSprite = new Sprite(texture); - this._cachedSprite.buffer = canvasBuffer; - - this._cachedSprite.worldTransform = this.worldTransform; - } - else { - this._cachedSprite.buffer.resize(bounds.width, bounds.height); - } - - // leverage the anchor to account for the offset of the element - this._cachedSprite.anchor.x = -( bounds.x / bounds.width ); - this._cachedSprite.anchor.y = -( bounds.y / bounds.height ); - - // this._cachedSprite.buffer.context.save(); - this._cachedSprite.buffer.context.translate(-bounds.x,-bounds.y); - - // make sure we set the alpha of the graphics to 1 for the render.. - this.worldAlpha = 1; - - // now render the graphic.. - CanvasGraphics.renderGraphics(this, this._cachedSprite.buffer.context); - - this._cachedSprite.alpha = this.alpha; -}; - -/** - * Updates texture size based on canvas size - * - * @private - */ -Graphics.prototype.updateCachedSpriteTexture = function () { - var cachedSprite = this._cachedSprite; - var texture = cachedSprite.texture; - var canvas = cachedSprite.buffer.canvas; - - texture.baseTexture.width = canvas.width; - texture.baseTexture.height = canvas.height; - texture.crop.width = texture.frame.width = canvas.width; - texture.crop.height = texture.frame.height = canvas.height; - - cachedSprite._width = canvas.width; - cachedSprite._height = canvas.height; - - // update the dirty base textures - texture.baseTexture.dirty(); -}; - -/** - * Destroys a previous cached sprite. - * - */ -Graphics.prototype.destroyCachedSprite = function () { - this._cachedSprite.texture.destroy(true); - - // let the gc collect the unused sprite - // TODO could be object pooled! - this._cachedSprite = null; -}; - -/** - * Draws the given shape to this Graphics object. Can be any of Circle, Rectangle, Ellipse, Line or Polygon. - * - * @param {Circle|Rectangle|Ellipse|Line|Polygon} shape The Shape object to draw. - * @return {GraphicsData} The generated GraphicsData object. - */ -Graphics.prototype.drawShape = function (shape) { - if (this.currentPath) { - // check current path! - if (this.currentPath.shape.points.length <= 2) { - this.graphicsData.pop(); - } - } - - this.currentPath = null; - - var data = new GraphicsData(this.lineWidth, this.lineColor, this.lineAlpha, this.fillColor, this.fillAlpha, this.filling, shape); - - this.graphicsData.push(data); - - if (data.type === CONST.SHAPES.POLY) { - data.shape.closed = this.filling; - this.currentPath = data; - } - - this.dirty = true; - - return data; -}; - -},{"../const":4,"../display/DisplayObjectContainer":6,"../display/Sprite":7,"../math":12,"../renderers/canvas/utils/CanvasBuffer":21,"../renderers/canvas/utils/CanvasGraphics":22,"../renderers/webgl/utils/WebGLGraphics":39,"../textures/Texture":44,"./GraphicsData":19}],19:[function(require,module,exports){ -/** - * A GraphicsData object. - * - * @class - * @namespace PIXI - */ -function GraphicsData(lineWidth, lineColor, lineAlpha, fillColor, fillAlpha, fill, shape) { - this.lineWidth = lineWidth; - this.lineColor = lineColor; - this.lineAlpha = lineAlpha; - this._lineTint = lineColor; - - this.fillColor = fillColor; - this.fillAlpha = fillAlpha; - this._fillTint = fillColor; - this.fill = fill; - - this.shape = shape; - this.type = shape.type; -} - -GraphicsData.prototype.constructor = GraphicsData; -module.exports = GraphicsData; - -/** - * Creates a new GraphicsData object with the same values as this one. - * - * @return {GraphicsData} - */ -GraphicsData.prototype.clone = function () { - return new GraphicsData( - this.lineWidth, - this.lineColor, - this.lineAlpha, - this.fillColor, - this.fillAlpha, - this.fill, - this.shape - ); -}; - -},{}],20:[function(require,module,exports){ -var CanvasMaskManager = require('./utils/CanvasMaskManager'), - utils = require('../../utils'), - CONST = require('../../const'); - -/** - * The CanvasRenderer draws the scene and all its content onto a 2d canvas. This renderer should be used for browsers that do not support webGL. - * Don't forget to add the CanvasRenderer.view to your DOM or you will not see anything :) - * - * @class - * @namespace PIXI - * @param [width=800] {number} the width of the canvas view - * @param [height=600] {number} the height of the canvas view - * @param [options] {object} The optional renderer parameters - * @param [options.view] {HTMLCanvasElement} the canvas to use as a view, optional - * @param [options.transparent=false] {boolean} If the render view is transparent, default false - * @param [options.autoResize=false] {boolean} If the render view is automatically resized, default false - * @param [options.resolution=1] {number} the resolution of the renderer retina would be 2 - * @param [options.clearBeforeRender=true] {boolean} This sets if the CanvasRenderer will clear the canvas or not before the new render pass. - */ -function CanvasRenderer(width, height, options) { - utils.sayHello('Canvas'); - - if (options) { - for (var i in CONST.defaultRenderOptions) { - if (typeof options[i] === 'undefined') { - options[i] = CONST.defaultRenderOptions[i]; - } - } - } - else { - options = CONST.defaultRenderOptions; - } - - /** - * The renderer type. - * - * @member {number} - */ - this.type = CONST.CANVAS_RENDERER; - - /** - * The resolution of the canvas. - * - * @member {number} - */ - this.resolution = options.resolution; - - /** - * This sets if the CanvasRenderer will clear the canvas or not before the new render pass. - * If the scene is NOT transparent Pixi will use a canvas sized fillRect operation every frame to set the canvas background color. - * If the scene is transparent Pixi will use clearRect to clear the canvas every frame. - * Disable this by setting this to false. For example if your game has a canvas filling background image you often don't need this set. - * - * @member {boolean} - * @default - */ - this.clearBeforeRender = options.clearBeforeRender; - - /** - * The background color as a number. - * - * @member {number} - * @private - */ - this._backgroundColor = 0x000000; - - /** - * The background color as a string. - * - * @member {string} - * @private - */ - this._backgroundColorString = '#000000'; - - this.backgroundColor = options.backgroundColor || this._backgroundColor; // run bg color setter - - /** - * Whether the render view is transparent - * - * @member {boolean} - */ - this.transparent = options.transparent; - - /** - * Whether the render view should be resized automatically - * - * @member {boolean} - */ - this.autoResize = options.autoResize || false; - - - /** - * The width of the canvas view - * - * @member {number} - * @default 800 - */ - this.width = width || 800; - - /** - * The height of the canvas view - * - * @member {number} - * @default 600 - */ - this.height = height || 600; - - this.width *= this.resolution; - this.height *= this.resolution; - - /** - * The canvas element that everything is drawn to. - * - * @member {HTMLCanvasElement} - */ - this.view = options.view || document.createElement('canvas'); - - /** - * The canvas 2d context that everything is drawn with - * @member {CanvasRenderingContext2D} - */ - this.context = this.view.getContext('2d', { alpha: this.transparent }); - - /** - * Boolean flag controlling canvas refresh. - * - * @member {boolean} - */ - this.refresh = true; - - this.view.width = this.width * this.resolution; - this.view.height = this.height * this.resolution; - - /** - * Internal var. - * - * @member {number} - */ - this.count = 0; - - /** - * Instance of a CanvasMaskManager, handles masking when using the canvas renderer - * @member {CanvasMaskManager} - */ - this.maskManager = new CanvasMaskManager(); - - /** - * If true Pixi will Math.floor() x/y values when rendering, stopping pixel interpolation. - * Handy for crisp pixel art and speed on legacy devices. - * - * @member {boolean} - */ - this.roundPixels = false; - - this.scaleMode = null; - - this.smoothProperty = null; - - if (this.context.imageSmoothingEnabled) { - this.smoothProperty = 'imageSmoothingEnabled'; - } - else if (this.context.webkitImageSmoothingEnabled) { - this.smoothProperty = 'webkitImageSmoothingEnabled'; - } - else if (this.context.mozImageSmoothingEnabled) { - this.smoothProperty = 'mozImageSmoothingEnabled'; - } - else if (this.context.oImageSmoothingEnabled) { - this.smoothProperty = 'oImageSmoothingEnabled'; - } - else if (this.context.msImageSmoothingEnabled) { - this.smoothProperty = 'msImageSmoothingEnabled'; - } - - this.currentBlendMode = CONST.blendModes.NORMAL; - - this.blendModes = null; - - this._mapBlendModes(); - - this.resize(width, height); -} - -// constructor -CanvasRenderer.prototype.constructor = CanvasRenderer; -module.exports = CanvasRenderer; - -Object.defineProperties(CanvasRenderer.prototype, { - /** - * The background color to fill if not transparent - * - * @member {number} - * @memberof CanvasRenderer# - */ - backgroundColor: { - get: function () { - return this._backgroundColor; - }, - set: function (val) { - this._backgroundColor = val; - this._backgroundColorString = utils.hex2string(val); - } - } -}); - -/** - * Renders the object to this canvas view - * - * @param object {DisplayObject} the object to be rendered - */ -CanvasRenderer.prototype.render = function (object) { - object.updateTransform(); - - this.context.setTransform(1,0,0,1,0,0); - - this.context.globalAlpha = 1; - - this.currentBlendMode = CONST.blendModes.NORMAL; - this.context.globalCompositeOperation = this.blendModes[CONST.blendModes.NORMAL]; - - if (navigator.isCocoonJS && this.view.screencanvas) { - this.context.fillStyle = 'black'; - this.context.clear(); - } - - if (this.clearBeforeRender) { - if (this.transparent) { - this.context.clearRect(0, 0, this.width, this.height); - } - else { - this.context.fillStyle = this._backgroundColorString; - this.context.fillRect(0, 0, this.width , this.height); - } - } - - this.renderDisplayObject(object); -}; - -/** - * Removes everything from the renderer and optionally removes the Canvas DOM element. - * - * @param [removeView=false] {boolean} Removes the Canvas element from the DOM. - */ -CanvasRenderer.prototype.destroy = function (removeView) { - if (removeView && this.view.parent) { - this.view.parent.removeChild(this.view); - } - - this.view = null; - this.context = null; - this.maskManager = null; -}; - -/** - * Resizes the canvas view to the specified width and height - * - * @param width {number} the new width of the canvas view - * @param height {number} the new height of the canvas view - */ -CanvasRenderer.prototype.resize = function (width, height) { - this.width = width * this.resolution; - this.height = height * this.resolution; - - this.view.width = this.width; - this.view.height = this.height; - - if (this.autoResize) { - this.view.style.width = this.width / this.resolution + 'px'; - this.view.style.height = this.height / this.resolution + 'px'; - } -}; - -/** - * Renders a display object - * - * @param displayObject {DisplayObject} The displayObject to render - * @private - */ -CanvasRenderer.prototype.renderDisplayObject = function (displayObject) { - displayObject.renderCanvas(this); -}; - -/** - * Maps Pixi blend modes to canvas blend modes. - * - * @private - */ -CanvasRenderer.prototype._mapBlendModes = function () { - if (!this.blendModes) { - this.blendModes = {}; - - if (utils.canUseNewCanvasBlendModes()) { - this.blendModes[CONST.blendModes.NORMAL] = 'source-over'; - this.blendModes[CONST.blendModes.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.blendModes.MULTIPLY] = 'multiply'; - this.blendModes[CONST.blendModes.SCREEN] = 'screen'; - this.blendModes[CONST.blendModes.OVERLAY] = 'overlay'; - this.blendModes[CONST.blendModes.DARKEN] = 'darken'; - this.blendModes[CONST.blendModes.LIGHTEN] = 'lighten'; - this.blendModes[CONST.blendModes.COLOR_DODGE] = 'color-dodge'; - this.blendModes[CONST.blendModes.COLOR_BURN] = 'color-burn'; - this.blendModes[CONST.blendModes.HARD_LIGHT] = 'hard-light'; - this.blendModes[CONST.blendModes.SOFT_LIGHT] = 'soft-light'; - this.blendModes[CONST.blendModes.DIFFERENCE] = 'difference'; - this.blendModes[CONST.blendModes.EXCLUSION] = 'exclusion'; - this.blendModes[CONST.blendModes.HUE] = 'hue'; - this.blendModes[CONST.blendModes.SATURATION] = 'saturation'; - this.blendModes[CONST.blendModes.COLOR] = 'color'; - this.blendModes[CONST.blendModes.LUMINOSITY] = 'luminosity'; - } - else { - // this means that the browser does not support the cool new blend modes in canvas 'cough' ie 'cough' - this.blendModes[CONST.blendModes.NORMAL] = 'source-over'; - this.blendModes[CONST.blendModes.ADD] = 'lighter'; //IS THIS OK??? - this.blendModes[CONST.blendModes.MULTIPLY] = 'source-over'; - this.blendModes[CONST.blendModes.SCREEN] = 'source-over'; - this.blendModes[CONST.blendModes.OVERLAY] = 'source-over'; - this.blendModes[CONST.blendModes.DARKEN] = 'source-over'; - this.blendModes[CONST.blendModes.LIGHTEN] = 'source-over'; - this.blendModes[CONST.blendModes.COLOR_DODGE] = 'source-over'; - this.blendModes[CONST.blendModes.COLOR_BURN] = 'source-over'; - this.blendModes[CONST.blendModes.HARD_LIGHT] = 'source-over'; - this.blendModes[CONST.blendModes.SOFT_LIGHT] = 'source-over'; - this.blendModes[CONST.blendModes.DIFFERENCE] = 'source-over'; - this.blendModes[CONST.blendModes.EXCLUSION] = 'source-over'; - this.blendModes[CONST.blendModes.HUE] = 'source-over'; - this.blendModes[CONST.blendModes.SATURATION] = 'source-over'; - this.blendModes[CONST.blendModes.COLOR] = 'source-over'; - this.blendModes[CONST.blendModes.LUMINOSITY] = 'source-over'; - } - } -}; - -},{"../../const":4,"../../utils":50,"./utils/CanvasMaskManager":23}],21:[function(require,module,exports){ -/** - * Creates a Canvas element of the given size. - * - * @class - * @namespace PIXI - * @param width {number} the width for the newly created canvas - * @param height {number} the height for the newly created canvas - */ -function CanvasBuffer(width, height) { - /** - * The Canvas object that belongs to this CanvasBuffer. - * - * @member {HTMLCanvasElement} - */ - this.canvas = document.createElement('canvas'); - - /** - * A CanvasRenderingContext2D object representing a two-dimensional rendering context. - * - * @member {CanvasRenderingContext2D} - */ - this.context = this.canvas.getContext('2d'); - - this.canvas.width = width; - this.canvas.height = height; -} - -CanvasBuffer.prototype.constructor = CanvasBuffer; -module.exports = CanvasBuffer; - -Object.defineProperties(CanvasBuffer.prototype, { - /** - * The width of the canvas buffer in pixels. - * - * @member {number} - * @memberof CanvasBuffer# - */ - width: { - get: function () { - return this.canvas.width; - }, - set: function (val) { - this.canvas.width = val; - } - }, - /** - * The height of the canvas buffer in pixels. - * - * @member {number} - * @memberof CanvasBuffer# - */ - height: { - get: function () { - return this.canvas.height; - }, - set: function (val) { - this.canvas.height = val; - } - } -}); - -/** - * Clears the canvas that was created by the CanvasBuffer class. - * - * @private - */ -CanvasBuffer.prototype.clear = function () { - this.context.setTransform(1, 0, 0, 1, 0, 0); - this.context.clearRect(0,0, this.canvas.width, this.canvas.height); -}; - -/** - * Resizes the canvas to the specified width and height. - * - * @param width {number} the new width of the canvas - * @param height {number} the new height of the canvas - */ -CanvasBuffer.prototype.resize = function (width, height) { - this.canvas.width = width; - this.canvas.height = height; -}; - -},{}],22:[function(require,module,exports){ -var CONST = require('../../../const'); - -/** - * A set of functions used by the canvas renderer to draw the primitive graphics data. - * - * @namespace PIXI - */ -var CanvasGraphics = module.exports = {}; - -/* - * Renders a Graphics object to a canvas. - * - * @param graphics {Graphics} the actual graphics object to render - * @param context {CanvasRenderingContext2D} the 2d drawing method of the canvas - */ -CanvasGraphics.renderGraphics = function (graphics, context) { - var worldAlpha = graphics.worldAlpha; - - if (graphics.dirty) { - this.updateGraphicsTint(graphics); - graphics.dirty = false; - } - - for (var i = 0; i < graphics.graphicsData.length; i++) { - var data = graphics.graphicsData[i]; - var shape = data.shape; - - var fillColor = data._fillTint; - var lineColor = data._lineTint; - - context.lineWidth = data.lineWidth; - - if (data.type === CONST.SHAPES.POLY) { - context.beginPath(); - - var points = shape.points; - - context.moveTo(points[0], points[1]); - - for (var j=1; j < points.length/2; j++) { - context.lineTo(points[j * 2], points[j * 2 + 1]); - } - - if (shape.closed) { - context.lineTo(points[0], points[1]); - } - - // if the first and last point are the same close the path - much neater :) - if (points[0] === points[points.length-2] && points[1] === points[points.length-1]) { - context.closePath(); - } - - if (data.fill) { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = '#' + ('00000' + ( fillColor | 0).toString(16)).substr(-6); - context.fill(); - } - if (data.lineWidth) { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeStyle = '#' + ('00000' + ( lineColor | 0).toString(16)).substr(-6); - context.stroke(); - } - } - else if (data.type === CONST.SHAPES.RECT) { - - if (data.fillColor || data.fillColor === 0) { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = '#' + ('00000' + ( fillColor | 0).toString(16)).substr(-6); - context.fillRect(shape.x, shape.y, shape.width, shape.height); - - } - if (data.lineWidth) { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeStyle = '#' + ('00000' + ( lineColor | 0).toString(16)).substr(-6); - context.strokeRect(shape.x, shape.y, shape.width, shape.height); - } - } - else if (data.type === CONST.SHAPES.CIRC) { - // TODO - need to be Undefined! - context.beginPath(); - context.arc(shape.x, shape.y, shape.radius,0,2*Math.PI); - context.closePath(); - - if (data.fill) { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = '#' + ('00000' + ( fillColor | 0).toString(16)).substr(-6); - context.fill(); - } - if (data.lineWidth) { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeStyle = '#' + ('00000' + ( lineColor | 0).toString(16)).substr(-6); - context.stroke(); - } - } - else if (data.type === CONST.SHAPES.ELIP) { - // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - - var w = shape.width * 2; - var h = shape.height * 2; - - var x = shape.x - w/2; - var y = shape.y - h/2; - - context.beginPath(); - - var kappa = 0.5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - context.moveTo(x, ym); - context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - - context.closePath(); - - if (data.fill) { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = '#' + ('00000' + ( fillColor | 0).toString(16)).substr(-6); - context.fill(); - } - if (data.lineWidth) { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeStyle = '#' + ('00000' + ( lineColor | 0).toString(16)).substr(-6); - context.stroke(); - } - } - else if (data.type === CONST.SHAPES.RREC) { - var rx = shape.x; - var ry = shape.y; - var width = shape.width; - var height = shape.height; - var radius = shape.radius; - - var maxRadius = Math.min(width, height) / 2 | 0; - radius = radius > maxRadius ? maxRadius : radius; - - context.beginPath(); - context.moveTo(rx, ry + radius); - context.lineTo(rx, ry + height - radius); - context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height); - context.lineTo(rx + width - radius, ry + height); - context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius); - context.lineTo(rx + width, ry + radius); - context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry); - context.lineTo(rx + radius, ry); - context.quadraticCurveTo(rx, ry, rx, ry + radius); - context.closePath(); - - if (data.fillColor || data.fillColor === 0) { - context.globalAlpha = data.fillAlpha * worldAlpha; - context.fillStyle = '#' + ('00000' + ( fillColor | 0).toString(16)).substr(-6); - context.fill(); - - } - if (data.lineWidth) { - context.globalAlpha = data.lineAlpha * worldAlpha; - context.strokeStyle = '#' + ('00000' + ( lineColor | 0).toString(16)).substr(-6); - context.stroke(); - } - } - } -}; - -/* - * Renders a graphics mask - * - * @private - * @param graphics {Graphics} the graphics which will be used as a mask - * @param context {CanvasRenderingContext2D} the context 2d method of the canvas - */ -CanvasGraphics.renderGraphicsMask = function (graphics, context) { - var len = graphics.graphicsData.length; - - if (len === 0) { - return; - } - - context.beginPath(); - - for (var i = 0; i < len; i++) { - var data = graphics.graphicsData[i]; - var shape = data.shape; - - if (data.type === CONST.SHAPES.POLY) { - - var points = shape.points; - - context.moveTo(points[0], points[1]); - - for (var j=1; j < points.length/2; j++) { - context.lineTo(points[j * 2], points[j * 2 + 1]); - } - - // if the first and last point are the same close the path - much neater :) - if (points[0] === points[points.length-2] && points[1] === points[points.length-1]) { - context.closePath(); - } - - } - else if (data.type === CONST.SHAPES.RECT) { - context.rect(shape.x, shape.y, shape.width, shape.height); - context.closePath(); - } - else if (data.type === CONST.SHAPES.CIRC) { - // TODO - need to be Undefined! - context.arc(shape.x, shape.y, shape.radius, 0, 2 * Math.PI); - context.closePath(); - } - else if (data.type === CONST.SHAPES.ELIP) { - - // ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas - - var w = shape.width * 2; - var h = shape.height * 2; - - var x = shape.x - w/2; - var y = shape.y - h/2; - - var kappa = 0.5522848, - ox = (w / 2) * kappa, // control point offset horizontal - oy = (h / 2) * kappa, // control point offset vertical - xe = x + w, // x-end - ye = y + h, // y-end - xm = x + w / 2, // x-middle - ym = y + h / 2; // y-middle - - context.moveTo(x, ym); - context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y); - context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym); - context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye); - context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym); - context.closePath(); - } - else if (data.type === CONST.SHAPES.RREC) { - - var rx = shape.x; - var ry = shape.y; - var width = shape.width; - var height = shape.height; - var radius = shape.radius; - - var maxRadius = Math.min(width, height) / 2 | 0; - radius = radius > maxRadius ? maxRadius : radius; - - context.moveTo(rx, ry + radius); - context.lineTo(rx, ry + height - radius); - context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height); - context.lineTo(rx + width - radius, ry + height); - context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius); - context.lineTo(rx + width, ry + radius); - context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry); - context.lineTo(rx + radius, ry); - context.quadraticCurveTo(rx, ry, rx, ry + radius); - context.closePath(); - } - } -}; - -CanvasGraphics.updateGraphicsTint = function (graphics) { - if (graphics.tint === 0xFFFFFF) { - return; - } - - var tintR = (graphics.tint >> 16 & 0xFF) / 255; - var tintG = (graphics.tint >> 8 & 0xFF) / 255; - var tintB = (graphics.tint & 0xFF)/ 255; - - for (var i = 0; i < graphics.graphicsData.length; i++) { - var data = graphics.graphicsData[i]; - - var fillColor = data.fillColor | 0; - var lineColor = data.lineColor | 0; - - /* - var colorR = (fillColor >> 16 & 0xFF) / 255; - var colorG = (fillColor >> 8 & 0xFF) / 255; - var colorB = (fillColor & 0xFF) / 255; - - colorR *= tintR; - colorG *= tintG; - colorB *= tintB; - - fillColor = ((colorR*255 << 16) + (colorG*255 << 8) + colorB*255); - - colorR = (lineColor >> 16 & 0xFF) / 255; - colorG = (lineColor >> 8 & 0xFF) / 255; - colorB = (lineColor & 0xFF) / 255; - - colorR *= tintR; - colorG *= tintG; - colorB *= tintB; - - lineColor = ((colorR*255 << 16) + (colorG*255 << 8) + colorB*255); - */ - - // super inline cos im an optimization NAZI :) - data._fillTint = (((fillColor >> 16 & 0xFF) / 255 * tintR*255 << 16) + ((fillColor >> 8 & 0xFF) / 255 * tintG*255 << 8) + (fillColor & 0xFF) / 255 * tintB*255); - data._lineTint = (((lineColor >> 16 & 0xFF) / 255 * tintR*255 << 16) + ((lineColor >> 8 & 0xFF) / 255 * tintG*255 << 8) + (lineColor & 0xFF) / 255 * tintB*255); - - } -}; - - -},{"../../../const":4}],23:[function(require,module,exports){ -var CanvasGraphics = require('./CanvasGraphics'); - -/** - * A set of functions used to handle masking. - * - * @class - * @namespace PIXI - */ -function CanvasMaskManager() {} - -CanvasMaskManager.prototype.constructor = CanvasMaskManager; -module.exports = CanvasMaskManager; - -/** - * This method adds it to the current stack of masks. - * - * @param maskData {object} the maskData that will be pushed - * @param renderer {WebGLRenderer|CanvasRenderer} The renderer context to use. - */ -CanvasMaskManager.prototype.pushMask = function (maskData, renderer) { - renderer.context.save(); - - var cacheAlpha = maskData.alpha; - var transform = maskData.worldTransform; - var resolution = renderer.resolution; - - renderer.context.setTransform( - transform.a * resolution, - transform.b * resolution, - transform.c * resolution, - transform.d * resolution, - transform.tx * resolution, - transform.ty * resolution - ); - - CanvasGraphics.renderGraphicsMask(maskData, renderer.context); - - renderer.context.clip(); - - maskData.worldAlpha = cacheAlpha; -}; - -/** - * Restores the current drawing context to the state it was before the mask was applied. - * - * @param renderer {WebGLRenderer|CanvasRenderer} The renderer context to use. - */ -CanvasMaskManager.prototype.popMask = function (renderer) { - renderer.context.restore(); -}; - -},{"./CanvasGraphics":22}],24:[function(require,module,exports){ -var utils = require('../../../utils'); - -/** - * Utility methods for Sprite/Texture tinting. - * - * @namespace PIXI - */ -var CanvasTinter = module.exports = {}; - -/** - * Basically this method just needs a sprite and a color and tints the sprite with the given color. - * - * @param sprite {Sprite} the sprite to tint - * @param color {number} the color to use to tint the sprite with - * @return {HTMLCanvasElement} The tinted canvas - */ -CanvasTinter.getTintedTexture = function (sprite, color) { - var texture = sprite.texture; - - color = CanvasTinter.roundColor(color); - - var stringColor = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - texture.tintCache = texture.tintCache || {}; - - if (texture.tintCache[stringColor]) { - return texture.tintCache[stringColor]; - } - - // clone texture.. - var canvas = CanvasTinter.canvas || document.createElement('canvas'); - - //CanvasTinter.tintWithPerPixel(texture, stringColor, canvas); - CanvasTinter.tintMethod(texture, color, canvas); - - if (CanvasTinter.convertTintToImage) { - // is this better? - var tintImage = new Image(); - tintImage.src = canvas.toDataURL(); - - texture.tintCache[stringColor] = tintImage; - } - else { - texture.tintCache[stringColor] = canvas; - // if we are not converting the texture to an image then we need to lose the reference to the canvas - CanvasTinter.canvas = null; - } - - return canvas; -}; - -/** - * Tint a texture using the 'multiply' operation. - * - * @param texture {Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithMultiply = function (texture, color, canvas) { - var context = canvas.getContext( '2d' ); - - var crop = texture.crop; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'multiply'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - context.globalCompositeOperation = 'destination-atop'; - - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); -}; - -/** - * Tint a texture using the 'overlay' operation. - * - * @param texture {Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithOverlay = function (texture, color, canvas) { - var context = canvas.getContext( '2d' ); - - var crop = texture.crop; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.fillStyle = '#' + ('00000' + ( color | 0).toString(16)).substr(-6); - context.fillRect(0, 0, crop.width, crop.height); - - context.globalCompositeOperation = 'destination-atop'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - // context.globalCompositeOperation = 'copy'; -}; - -/** - * Tint a texture pixel per pixel. - * - * @param texture {Texture} the texture to tint - * @param color {number} the color to use to tint the sprite with - * @param canvas {HTMLCanvasElement} the current canvas - */ -CanvasTinter.tintWithPerPixel = function (texture, color, canvas) { - var context = canvas.getContext( '2d' ); - - var crop = texture.crop; - - canvas.width = crop.width; - canvas.height = crop.height; - - context.globalCompositeOperation = 'copy'; - context.drawImage( - texture.baseTexture.source, - crop.x, - crop.y, - crop.width, - crop.height, - 0, - 0, - crop.width, - crop.height - ); - - var rgbValues = utils.hex2rgb(color); - var r = rgbValues[0], g = rgbValues[1], b = rgbValues[2]; - - var pixelData = context.getImageData(0, 0, crop.width, crop.height); - - var pixels = pixelData.data; - - for (var i = 0; i < pixels.length; i += 4) { - pixels[i+0] *= r; - pixels[i+1] *= g; - pixels[i+2] *= b; - } - - context.putImageData(pixelData, 0, 0); -}; - -/** - * Rounds the specified color according to the CanvasTinter.cacheStepsPerColorChannel. - * - * @param color {number} the color to round, should be a hex color - */ -CanvasTinter.roundColor = function (color) { - var step = CanvasTinter.cacheStepsPerColorChannel; - - var rgbValues = utils.hex2rgb(color); - - rgbValues[0] = Math.min(255, (rgbValues[0] / step) * step); - rgbValues[1] = Math.min(255, (rgbValues[1] / step) * step); - rgbValues[2] = Math.min(255, (rgbValues[2] / step) * step); - - return utils.rgb2hex(rgbValues); -}; - -/** - * Number of steps which will be used as a cap when rounding colors. - * - * @member - */ -CanvasTinter.cacheStepsPerColorChannel = 8; - -/** - * Tint cache boolean flag. - * - * @member - */ -CanvasTinter.convertTintToImage = false; - -/** - * Whether or not the Canvas BlendModes are supported, consequently the ability to tint using the multiply method. - * - * @member - */ -CanvasTinter.canUseMultiply = utils.canUseNewCanvasBlendModes(); - -/** - * The tinting method that will be used. - * - */ -CanvasTinter.tintMethod = CanvasTinter.canUseMultiply ? CanvasTinter.tintWithMultiply : CanvasTinter.tintWithPerPixel; - -},{"../../../utils":50}],25:[function(require,module,exports){ -var WebGLSpriteBatch = require('./utils/WebGLSpriteBatch'), - WebGLFastSpriteBatch = require('./utils/WebGLFastSpriteBatch'), - WebGLShaderManager = require('./managers/WebGLShaderManager'), - WebGLMaskManager = require('./managers/WebGLMaskManager'), - WebGLFilterManager = require('./managers/WebGLFilterManager'), - WebGLStencilManager = require('./managers/WebGLStencilManager'), - WebGLBlendModeManager = require('./managers/WebGLBlendModeManager'), - math = require('../../math'), - utils = require('../../utils'), - CONST = require('../../const'); - -/** - * The WebGLRenderer draws the scene and all its content onto a webGL enabled canvas. This renderer - * should be used for browsers that support webGL. This Render works by automatically managing webGLBatchs. - * So no need for Sprite Batches or Sprite Clouds. - * Don't forget to add the view to your DOM or you will not see anything :) - * - * @class - * @namespace PIXI - * @param [width=0] {number} the width of the canvas view - * @param [height=0] {number} the height of the canvas view - * @param [options] {object} The optional renderer parameters - * @param [options.view] {HTMLCanvasElement} the canvas to use as a view, optional - * @param [options.transparent=false] {boolean} If the render view is transparent, default false - * @param [options.autoResize=false] {boolean} If the render view is automatically resized, default false - * @param [options.antialias=false] {boolean} sets antialias (only applicable in chrome at the moment) - * @param [options.preserveDrawingBuffer=false] {boolean} enables drawing buffer preservation, enable this if you need to call toDataUrl on the webgl context - * @param [options.resolution=1] {number} the resolution of the renderer retina would be 2 - */ -function WebGLRenderer(width, height, options) { - utils.sayHello('webGL'); - - if (options) { - for (var i in CONST.defaultRenderOptions) { - if (typeof options[i] === 'undefined') { - options[i] = CONST.defaultRenderOptions[i]; - } - } - } - else { - options = CONST.defaultRenderOptions; - } - - this.uuid = utils.uuid(); - - /** - * @member {number} - */ - this.type = CONST.WEBGL_RENDERER; - - /** - * The resolution of the renderer - * - * @member {number} - * @default 1 - */ - this.resolution = options.resolution; - - // do a catch.. only 1 webGL renderer.. - - /** - * Whether the render view is transparent - * - * @member {boolean} - */ - this.transparent = options.transparent; - - /** - * The background color as a number. - * - * @member {number} - * @private - */ - this._backgroundColor = 0x000000; - - /** - * The background color as an [R, G, B] array. - * - * @member {number[]} - * @private - */ - this._backgroundColorRgb = [0, 0, 0]; - - this.backgroundColor = options.backgroundColor || this._backgroundColor; // run bg color setter - - /** - * Whether the render view should be resized automatically - * - * @member {boolean} - */ - this.autoResize = options.autoResize || false; - - /** - * The value of the preserveDrawingBuffer flag affects whether or not the contents of the stencil buffer is retained after rendering. - * - * @member {boolean} - */ - this.preserveDrawingBuffer = options.preserveDrawingBuffer; - - /** - * This sets if the WebGLRenderer will clear the context texture or not before the new render pass. If true: - * If the renderer is NOT transparent, Pixi will clear to alpha (0, 0, 0, 0). - * If the renderer is transparent, Pixi will clear to the target Stage's background color. - * Disable this by setting this to false. For example: if your game has a canvas filling background image, you often don't need this set. - * - * @member {boolean} - * @default - */ - this.clearBeforeRender = options.clearBeforeRender; - - /** - * The width of the canvas view - * - * @member {number} - * @default 800 - */ - this.width = width || 800; - - /** - * The height of the canvas view - * - * @member {number} - * @default 600 - */ - this.height = height || 600; - - /** - * The canvas element that everything is drawn to - * - * @member {HTMLCanvasElement} - */ - this.view = options.view || document.createElement( 'canvas' ); - - // deal with losing context.. - - /** - * @member {Function} - */ - this.contextLostBound = this.handleContextLost.bind(this); - - /** - * @member {Function} - */ - this.contextRestoredBound = this.handleContextRestored.bind(this); - - this.view.addEventListener('webglcontextlost', this.contextLostBound, false); - this.view.addEventListener('webglcontextrestored', this.contextRestoredBound, false); - - /** - * @member {object} - * @private - */ - this._contextOptions = { - alpha: this.transparent, - antialias: options.antialias, // SPEED UP?? - premultipliedAlpha:this.transparent && this.transparent !== 'notMultiplied', - stencil:true, - preserveDrawingBuffer: options.preserveDrawingBuffer - }; - - /** - * @member {Point} - */ - this.projection = new math.Point(); - - /** - * @member {Point} - */ - this.offset = new math.Point(0, 0); - - /** - * Counter for the number of draws made each frame - * - * @member {number} - */ - this.drawCount = 0; - - // time to create the render managers! each one focuses on managing a state in webGL - - /** - * Deals with managing the shader programs and their attribs - * @member {WebGLShaderManager} - */ - this.shaderManager = new WebGLShaderManager(this); - - /** - * Manages the rendering of sprites - * @member {WebGLSpriteBatch} - */ - this.spriteBatch = new WebGLSpriteBatch(this); - - /** - * Manages the rendering of sprites - * @member {WebGLFastSpriteBatch} - */ - this.fastSpriteBatch = new WebGLFastSpriteBatch(this); - - /** - * Manages the masks using the stencil buffer - * @member {WebGLMaskManager} - */ - this.maskManager = new WebGLMaskManager(this); - - /** - * Manages the filters - * @member {WebGLFilterManager} - */ - this.filterManager = new WebGLFilterManager(this); - - /** - * Manages the stencil buffer - * @member {WebGLStencilManager} - */ - this.stencilManager = new WebGLStencilManager(this); - - /** - * Manages the blendModes - * @member {WebGLBlendModeManager} - */ - this.blendModeManager = new WebGLBlendModeManager(this); - - this.blendModes = null; - - this._boundUpdateTexture = this.updateTexture.bind(this); - this._boundDestroyTexture = this.destroyTexture.bind(this); - - // time init the context.. - this._initContext(); - - // map some webGL blend modes.. - this._mapBlendModes(); -} - -// constructor -WebGLRenderer.prototype.constructor = WebGLRenderer; -module.exports = WebGLRenderer; - -utils.eventTarget.mixin(WebGLRenderer.prototype); - -Object.defineProperties(WebGLRenderer.prototype, { - /** - * The background color to fill if not transparent - * - * @member {number} - * @memberof WebGLRenderer# - */ - backgroundColor: { - get: function () { - return this._backgroundColor; - }, - set: function (val) { - this._backgroundColor = val; - utils.hex2rgb(val, this._backgroundColorRgb); - } - } -}); - -/** - * - * @private - */ -WebGLRenderer.prototype._initContext = function () { - var gl = this.view.getContext('webgl', this._contextOptions) || this.view.getContext('experimental-webgl', this._contextOptions); - this.gl = gl; - - if (!gl) { - // fail, not able to get a context - throw new Error('This browser does not support webGL. Try using the canvas renderer'); - } - - this.glContextId = WebGLRenderer.glContextId++; - gl.id = this.glContextId; - gl.renderer = this; - - // set up the default pixi settings.. - gl.disable(gl.DEPTH_TEST); - gl.disable(gl.CULL_FACE); - gl.enable(gl.BLEND); - - this.emit('context', gl); - - // now resize and we are good to go! - this.resize(this.width, this.height); -}; - -/** - * Renders the object to its webGL view - * - * @param object {DisplayObject} the object to be rendered - */ -WebGLRenderer.prototype.render = function (object) { - // no point rendering if our context has been blown up! - if (this.gl.isContextLost()) { - return; - } - - // update the scene graph - object.updateTransform(); - - var gl = this.gl; - - // -- Does this need to be set every frame? -- // - gl.viewport(0, 0, this.width, this.height); - - // make sure we are bound to the main frame buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - if (this.clearBeforeRender) { - if (this.transparent) { - gl.clearColor(0, 0, 0, 0); - } - else { - gl.clearColor(this._backgroundColorRgb[0], this._backgroundColorRgb[1], this._backgroundColorRgb[2], 1); - } - - gl.clear(gl.COLOR_BUFFER_BIT); - } - - this.renderDisplayObject(object, this.projection); -}; - -/** - * Renders a Display Object. - * - * @param displayObject {DisplayObject} The DisplayObject to render - * @param projection {Point} The projection - * @param buffer {Array} a standard WebGL buffer - */ -WebGLRenderer.prototype.renderDisplayObject = function (displayObject, projection, buffer) { - this.blendModeManager.setBlendMode(CONST.blendModes.NORMAL); - - // reset the render session data.. - this.drawCount = 0; - - // make sure to flip the Y if using a render texture.. - this.flipY = buffer ? -1 : 1; - - // set the default projection - this.projection = projection; - - //set the default offset - this.offset = this.offset; - - // start the sprite batch - this.spriteBatch.begin(); - - // start the filter manager - this.filterManager.begin(buffer); - - // render the scene! - displayObject.renderWebGL(this); - - // finish the sprite batch - this.spriteBatch.end(); -}; - -/** - * Resizes the webGL view to the specified width and height. - * - * @param width {number} the new width of the webGL view - * @param height {number} the new height of the webGL view - */ -WebGLRenderer.prototype.resize = function (width, height) { - this.width = width * this.resolution; - this.height = height * this.resolution; - - this.view.width = this.width; - this.view.height = this.height; - - if (this.autoResize) { - this.view.style.width = this.width / this.resolution + 'px'; - this.view.style.height = this.height / this.resolution + 'px'; - } - - this.gl.viewport(0, 0, this.width, this.height); - - this.projection.x = this.width / 2 / this.resolution; - this.projection.y = -this.height / 2 / this.resolution; -}; - -/** - * Updates and/or Creates a WebGL texture for the renderer's context. - * - * @param texture {BaseTexture|Texture} the texture to update - */ -WebGLRenderer.prototype.updateTexture = function (texture) { - texture = texture.baseTexture || texture; - - if (!texture.hasLoaded) { - return; - } - - var gl = this.gl; - - if (!texture._glTextures[gl.id]) { - texture._glTextures[gl.id] = gl.createTexture(); - texture.on('update', this._boundUpdateTexture); - texture.on('dispose', this._boundDestroyTexture); - } - - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - - gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultipliedAlpha); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.source); - - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, texture.scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - - - if (texture.mipmap && utils.isPowerOfTwo(texture.width, texture.height)) { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR_MIPMAP_LINEAR : gl.NEAREST_MIPMAP_NEAREST); - gl.generateMipmap(gl.TEXTURE_2D); - } - else { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, texture.scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - } - - if (!texture._powerOf2) { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - } - else { - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); - } - - return texture._glTextures[gl.id]; -}; - -WebGLRenderer.prototype.destroyTexture = function (texture) { - texture = texture.baseTexture || texture; - - if (!texture.hasLoaded) { - return; - } - - if (texture._glTextures[this.gl.id]) { - this.gl.deleteTexture(texture._glTextures[this.gl.id]); - } -}; - -/** - * Handles a lost webgl context - * - * @param event {Event} - * @private - */ -WebGLRenderer.prototype.handleContextLost = function (event) { - event.preventDefault(); -}; - -/** - * Handles a restored webgl context - * - * @param event {Event} - * @private - */ -WebGLRenderer.prototype.handleContextRestored = function () { - this._initContext(); - - // empty all the ol gl textures as they are useless now - for (var key in utils.TextureCache) { - var texture = utils.TextureCache[key].baseTexture; - texture._glTextures = []; - } -}; - -/** - * Removes everything from the renderer (event listeners, spritebatch, etc...) - * - * @param [removeView=false] {boolean} Removes the Canvas element from the DOM. - */ -WebGLRenderer.prototype.destroy = function (removeView) { - if (removeView && this.view.parent) { - this.view.parent.removeChild(this.view); - } - - // remove listeners - this.view.removeEventListener('webglcontextlost', this.contextLostBound); - this.view.removeEventListener('webglcontextrestored', this.contextRestoredBound); - - // time to create the render managers! each one focuses on managine a state in webGL - this.shaderManager.destroy(); - this.spriteBatch.destroy(); - this.maskManager.destroy(); - this.filterManager.destroy(); - - - // this.uuid = utils.uuid(); - // this.type = CONST.WEBGL_RENDERER; - - // this.resolution = options.resolution; - // this.transparent = options.transparent; - - this._backgroundColor = 0x000000; - this._backgroundColorRgb = null; - - // this.backgroundColor = null; - // this.autoResize = options.autoResize || false; - // this.preserveDrawingBuffer = options.preserveDrawingBuffer; - // this.clearBeforeRender = options.clearBeforeRender; - // this.width = width || 800; - // this.height = height || 600; - - this.view = null; - - this.contextLostBound = null; - this.contextRestoredBound = null; - - this._contextOptions = null; - - this.projection = null; - this.offset = null; - this.drawCount = 0; - - this.shaderManager = null; - this.spriteBatch = null; - this.maskManager = null; - this.filterManager = null; - this.stencilManager = null; - this.blendModeManager = null; - - this.blendModes = null; - - this.gl = null; - this.blendModes = null; -}; - -/** - * Maps Pixi blend modes to WebGL blend modes. - * - * @private - */ -WebGLRenderer.prototype._mapBlendModes = function () { - var gl = this.gl; - - if (!this.blendModes) { - this.blendModes = {}; - - this.blendModes[CONST.blendModes.NORMAL] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.ADD] = [gl.SRC_ALPHA, gl.DST_ALPHA]; - this.blendModes[CONST.blendModes.MULTIPLY] = [gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.SCREEN] = [gl.SRC_ALPHA, gl.ONE]; - this.blendModes[CONST.blendModes.OVERLAY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.DARKEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.LIGHTEN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.COLOR_DODGE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.COLOR_BURN] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.HARD_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.SOFT_LIGHT] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.DIFFERENCE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.EXCLUSION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.HUE] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.SATURATION] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.COLOR] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - this.blendModes[CONST.blendModes.LUMINOSITY] = [gl.ONE, gl.ONE_MINUS_SRC_ALPHA]; - } -}; - -WebGLRenderer.glContextId = 0; - -},{"../../const":4,"../../math":12,"../../utils":50,"./managers/WebGLBlendModeManager":26,"./managers/WebGLFilterManager":27,"./managers/WebGLMaskManager":29,"./managers/WebGLShaderManager":30,"./managers/WebGLStencilManager":31,"./utils/WebGLFastSpriteBatch":38,"./utils/WebGLSpriteBatch":41}],26:[function(require,module,exports){ -var WebGLManager = require('./WebGLManager'); - -/** - * @class - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this manager works for. - */ -function WebGLBlendModeManager(renderer) { - WebGLManager.call(this, renderer); - - /** - * @member {number} - */ - this.currentBlendMode = 99999; -} - -WebGLBlendModeManager.prototype = Object.create(WebGLManager.prototype); -WebGLBlendModeManager.prototype.constructor = WebGLBlendModeManager; -module.exports = WebGLBlendModeManager; - -/** - * Sets-up the given blendMode from WebGL's point of view. - * - * @param blendMode {number} the blendMode, should be a Pixi const, such as BlendModes.ADD - */ -WebGLBlendModeManager.prototype.setBlendMode = function (blendMode) { - if (this.currentBlendMode === blendMode) { - return false; - } - - this.currentBlendMode = blendMode; - - var mode = this.renderer.blendModes[this.currentBlendMode]; - this.renderer.gl.blendFunc(mode[0], mode[1]); - - return true; -}; - -},{"./WebGLManager":28}],27:[function(require,module,exports){ -var WebGLManager = require('./WebGLManager'), - FilterTexture = require('../utils/FilterTexture'), - Shader = require('../shaders/Shader'); - -/** - * @class - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this manager works for. - */ -function WebGLFilterManager(renderer) { - WebGLManager.call(this, renderer); - - /** - * @member {any[]} - */ - this.filterStack = []; - - /** - * @member {any[]]} - */ - this.texturePool = []; - - /** - * @member {number} - */ - this.offsetX = 0; - - /** - * @member {number} - */ - this.offsetY = 0; - - // listen for context and update necessary buffers - var self = this; - this.renderer.on('context', function () { - self.texturePool.length = 0; - self.initShaderBuffers(); - }); -} - -WebGLFilterManager.prototype = Object.create(WebGLManager.prototype); -WebGLFilterManager.prototype.constructor = WebGLFilterManager; -module.exports = WebGLFilterManager; - -/** - * @param renderer {WebGLRenderer} - * @param buffer {ArrayBuffer} - */ -WebGLFilterManager.prototype.begin = function (buffer) { - this.defaultShader = this.renderer.shaderManager.defaultShader; - - this.width = this.renderer.projection.x * 2; - this.height = -this.renderer.projection.y * 2; - - this.buffer = buffer; -}; - -/** - * Applies the filter and adds it to the current filter stack. - * - * @param filterBlock {object} the filter that will be pushed to the current filter stack - */ -WebGLFilterManager.prototype.pushFilter = function (filterBlock) { - var gl = this.renderer.gl; - - var projection = this.renderer.projection; - var offset = this.renderer.offset; - - filterBlock._filterArea = filterBlock.target.filterArea || filterBlock.target.getBounds(); - - // filter program - // OPTIMISATION - the first filter is free if its a simple color change? - this.filterStack.push(filterBlock); - - var filter = filterBlock.filterPasses[0]; - - this.offsetX += filterBlock._filterArea.x; - this.offsetY += filterBlock._filterArea.y; - - var texture = this.texturePool.pop(); - if (!texture) { - texture = new FilterTexture(this.renderer.gl, this.width, this.height); - } - else { - texture.resize(this.width, this.height); - } - - gl.bindTexture(gl.TEXTURE_2D, texture.texture); - - var filterArea = filterBlock._filterArea;// filterBlock.target.getBounds();///filterBlock.target.filterArea; - - var padding = filter.padding; - filterArea.x -= padding; - filterArea.y -= padding; - filterArea.width += padding * 2; - filterArea.height += padding * 2; - - var localX = filterArea.x, - localY = filterArea.y; - - if (filterArea.x < 0) { - filterArea.width += filterArea.x; - filterArea.x = 0; - } - - if (filterArea.y < 0) { - filterArea.height += filterArea.y; - filterArea.y = 0; - } - - if (localX + filterArea.width > this.width) { - filterArea.width = this.width - localX; - } - - if (localY + filterArea.height > this.height) { - filterArea.height = this.height - localY; - } - - if (filterArea.width < 0) { - filterArea.width = 0; - } - - if (filterArea.height < 0) { - filterArea.height = 0; - } - - //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, filterArea.width, filterArea.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - gl.bindFramebuffer(gl.FRAMEBUFFER, texture.frameBuffer); - - // set view port - gl.viewport(0, 0, filterArea.width, filterArea.height); - - projection.x = filterArea.width/2; - projection.y = -filterArea.height/2; - - offset.x = -filterArea.x; - offset.y = -filterArea.y; - - // update projection - // now restore the regular shader.. - // this.renderer.shaderManager.setShader(this.defaultShader); - //gl.uniform2f(this.defaultShader.projectionVector, filterArea.width/2, -filterArea.height/2); - //gl.uniform2f(this.defaultShader.offsetVector, -filterArea.x, -filterArea.y); - - gl.colorMask(true, true, true, true); - gl.clearColor(0,0,0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); - - filterBlock._glFilterTexture = texture; - -}; - -/** - * Removes the last filter from the filter stack and doesn't return it. - * - */ -WebGLFilterManager.prototype.popFilter = function () { - var gl = this.renderer.gl; - - var filterBlock = this.filterStack.pop(); - var filterArea = filterBlock._filterArea; - var texture = filterBlock._glFilterTexture; - var projection = this.renderer.projection; - var offset = this.renderer.offset; - - if (filterBlock.filterPasses.length > 1) { - gl.viewport(0, 0, filterArea.width, filterArea.height); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - - this.vertexArray[0] = 0; - this.vertexArray[1] = filterArea.height; - - this.vertexArray[2] = filterArea.width; - this.vertexArray[3] = filterArea.height; - - this.vertexArray[4] = 0; - this.vertexArray[5] = 0; - - this.vertexArray[6] = filterArea.width; - this.vertexArray[7] = 0; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - // now set the uvs.. - this.uvArray[2] = filterArea.width/this.width; - this.uvArray[5] = filterArea.height/this.height; - this.uvArray[6] = filterArea.width/this.width; - this.uvArray[7] = filterArea.height/this.height; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); - - var inputTexture = texture; - var outputTexture = this.texturePool.pop(); - if (!outputTexture) { - outputTexture = new FilterTexture(this.renderer.gl, this.width, this.height); - } - outputTexture.resize(this.width, this.height); - - // need to clear this FBO as it may have some left over elements from a previous filter. - gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); - gl.clear(gl.COLOR_BUFFER_BIT); - - gl.disable(gl.BLEND); - - for (var i = 0; i < filterBlock.filterPasses.length-1; i++) { - var filterPass = filterBlock.filterPasses[i]; - - gl.bindFramebuffer(gl.FRAMEBUFFER, outputTexture.frameBuffer ); - - // set texture - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, inputTexture.texture); - - // draw texture.. - //filterPass.applyFilterPass(filterArea.width, filterArea.height); - this.applyFilterPass(filterPass, filterArea, filterArea.width, filterArea.height); - - // swap the textures.. - var temp = inputTexture; - inputTexture = outputTexture; - outputTexture = temp; - } - - gl.enable(gl.BLEND); - - texture = inputTexture; - this.texturePool.push(outputTexture); - } - - var filter = filterBlock.filterPasses[filterBlock.filterPasses.length-1]; - - this.offsetX -= filterArea.x; - this.offsetY -= filterArea.y; - - var sizeX = this.width; - var sizeY = this.height; - - var offsetX = 0; - var offsetY = 0; - - var buffer = this.buffer; - - // time to render the filters texture to the previous scene - if (this.filterStack.length === 0) { - gl.colorMask(true, true, true, true);//this.transparent); - } - else { - var currentFilter = this.filterStack[this.filterStack.length-1]; - filterArea = currentFilter._filterArea; - - sizeX = filterArea.width; - sizeY = filterArea.height; - - offsetX = filterArea.x; - offsetY = filterArea.y; - - buffer = currentFilter._glFilterTexture.frameBuffer; - } - - // TODO need to remove these global elements.. - projection.x = sizeX/2; - projection.y = -sizeY/2; - - offset.x = offsetX; - offset.y = offsetY; - - filterArea = filterBlock._filterArea; - - var x = filterArea.x-offsetX; - var y = filterArea.y-offsetY; - - // update the buffers.. - // make sure to flip the y! - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - - this.vertexArray[0] = x; - this.vertexArray[1] = y + filterArea.height; - - this.vertexArray[2] = x + filterArea.width; - this.vertexArray[3] = y + filterArea.height; - - this.vertexArray[4] = x; - this.vertexArray[5] = y; - - this.vertexArray[6] = x + filterArea.width; - this.vertexArray[7] = y; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertexArray); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - - this.uvArray[2] = filterArea.width/this.width; - this.uvArray[5] = filterArea.height/this.height; - this.uvArray[6] = filterArea.width/this.width; - this.uvArray[7] = filterArea.height/this.height; - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.uvArray); - - gl.viewport(0, 0, sizeX, sizeY); - - // bind the buffer - gl.bindFramebuffer(gl.FRAMEBUFFER, buffer ); - - // set the blend mode! - //gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) - - // set texture - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, texture.texture); - - // apply! - this.applyFilterPass(filter, filterArea, sizeX, sizeY); - - // now restore the regular shader.. should happen automatically now.. - // this.renderer.shaderManager.setShader(this.defaultShader); - // gl.uniform2f(this.defaultShader.projectionVector, sizeX/2, -sizeY/2); - // gl.uniform2f(this.defaultShader.offsetVector, -offsetX, -offsetY); - - // return the texture to the pool - this.texturePool.push(texture); - filterBlock._glFilterTexture = null; -}; - - -/** - * Applies the filter to the specified area. - * - * @param filter {AbstractFilter} the filter that needs to be applied - * @param filterArea {Texture} TODO - might need an update - * @param width {number} the horizontal range of the filter - * @param height {number} the vertical range of the filter - */ -WebGLFilterManager.prototype.applyFilterPass = function (filter, filterArea, width, height) { - // use program - var gl = this.renderer.gl; - - var shader = filter.shaders[gl.id]; - - if (!shader) { - shader = new Shader(gl); - - shader.fragmentSrc = filter.fragmentSrc; - shader.uniforms = filter.uniforms; - shader.init(); - - filter.shaders[gl.id] = shader; - } - - // set the shader - this.renderer.shaderManager.setShader(shader); - -// gl.useProgram(shader.program); - - gl.uniform2f(shader.projectionVector, width/2, -height/2); - gl.uniform2f(shader.offsetVector, 0,0); - - if (filter.uniforms.dimensions) { - filter.uniforms.dimensions.value[0] = this.width;//width; - filter.uniforms.dimensions.value[1] = this.height;//height; - filter.uniforms.dimensions.value[2] = this.vertexArray[0]; - filter.uniforms.dimensions.value[3] = this.vertexArray[5];//filterArea.height; - } - - shader.syncUniforms(); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); - gl.vertexAttribPointer(shader.aColor, 2, gl.FLOAT, false, 0, 0); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - // draw the filter... - gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 ); - - this.renderer.drawCount++; -}; - -/** - * Initialises the shader buffers. - * - */ -WebGLFilterManager.prototype.initShaderBuffers = function () { - var gl = this.renderer.gl; - - // create some buffers - this.vertexBuffer = gl.createBuffer(); - this.uvBuffer = gl.createBuffer(); - this.colorBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - - // bind and upload the vertexs.. - // keep a reference to the vertexFloatData.. - this.vertexArray = new Float32Array([0.0, 0.0, - 1.0, 0.0, - 0.0, 1.0, - 1.0, 1.0]); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.vertexArray, gl.STATIC_DRAW); - - // bind and upload the uv buffer - this.uvArray = new Float32Array([0.0, 0.0, - 1.0, 0.0, - 0.0, 1.0, - 1.0, 1.0]); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.uvArray, gl.STATIC_DRAW); - - this.colorArray = new Float32Array([1.0, 0xFFFFFF, - 1.0, 0xFFFFFF, - 1.0, 0xFFFFFF, - 1.0, 0xFFFFFF]); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.colorArray, gl.STATIC_DRAW); - - // bind and upload the index - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 1, 3, 2]), gl.STATIC_DRAW); - -}; - -/** - * Destroys the filter and removes it from the filter stack. - * - */ -WebGLFilterManager.prototype.destroy = function () { - var gl = this.renderer.gl; - - this.filterStack = null; - - this.offsetX = 0; - this.offsetY = 0; - - // destroy textures - for (var i = 0; i < this.texturePool.length; i++) { - this.texturePool[i].destroy(); - } - - this.texturePool = null; - - //destroy buffers.. - gl.deleteBuffer(this.vertexBuffer); - gl.deleteBuffer(this.uvBuffer); - gl.deleteBuffer(this.colorBuffer); - gl.deleteBuffer(this.indexBuffer); - - this.renderer = null; -}; - -},{"../shaders/Shader":35,"../utils/FilterTexture":37,"./WebGLManager":28}],28:[function(require,module,exports){ -/** - * @class - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this manager works for. - */ -function WebGLManager(renderer) { - /** - * The renderer this manager works for. - * - * @member {WebGLRenderer} - */ - this.renderer = renderer; -} - -WebGLManager.prototype.constructor = WebGLManager; -module.exports = WebGLManager; - -WebGLManager.prototype.destroy = function () { - this.renderer = null; -}; - -},{}],29:[function(require,module,exports){ -var WebGLManager = require('./WebGLManager'), - WebGLGraphics = require('../utils/WebGLGraphics'); - -/** - * @class - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this manager works for. - */ -function WebGLMaskManager(renderer) { - WebGLManager.call(this, renderer); -} - -WebGLMaskManager.prototype = Object.create(WebGLManager.prototype); -WebGLMaskManager.prototype.constructor = WebGLMaskManager; -module.exports = WebGLMaskManager; - -/** - * Applies the Mask and adds it to the current filter stack. - * - * @param maskData {any[]} - */ -WebGLMaskManager.prototype.pushMask = function (maskData) { - if (maskData.dirty) { - WebGLGraphics.updateGraphics(maskData, this.renderer.gl); - } - - if (!maskData._webGL[this.renderer.gl.id].data.length) { - return; - } - - this.renderer.stencilManager.pushStencil(maskData, maskData._webGL[this.renderer.gl.id].data[0], this.renderer); -}; - -/** - * Removes the last filter from the filter stack and doesn't return it. - * - * @param maskData {any[]} - */ -WebGLMaskManager.prototype.popMask = function (maskData) { - this.renderer.stencilManager.popStencil(maskData, maskData._webGL[this.renderer.gl.id].data[0], this.renderer); -}; - -},{"../utils/WebGLGraphics":39,"./WebGLManager":28}],30:[function(require,module,exports){ -var WebGLManager = require('./WebGLManager'), - PrimitiveShader = require('../shaders/PrimitiveShader'), - ComplexPrimitiveShader = require('../shaders/ComplexPrimitiveShader'), - Shader = require('../shaders/Shader'), - FastShader = require('../shaders/FastShader'), - StripShader = require('../shaders/StripShader'); - -/** - * @class - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this manager works for. - */ -function WebGLShaderManager(renderer) { - WebGLManager.call(this, renderer); - - /** - * @member {number} - */ - this.maxAttibs = 10; - - /** - * @member {any[]} - */ - this.attribState = []; - - /** - * @member {any[]} - */ - this.tempAttribState = []; - - for (var i = 0; i < this.maxAttibs; i++) { - this.attribState[i] = false; - } - - /** - * @member {any[]} - */ - this.stack = []; - - /** - * @member {number} - * @private - */ - this._currentId = -1; - - /** - * @member {Shader} - * @private - */ - this.currentShader = null; - - // this shader is used for rendering primitives - this.primitiveShader = null; - - // this shader is used for rendering triangle strips - this.complexPrimitiveShader = null; - - // this shader is used for the default sprite rendering - this.defaultShader = null; - - // this shader is used for the fast sprite rendering - this.fastShader = null; - - // the next one is used for rendering triangle strips - this.stripShader = null; - - // listen for context and update necessary shaders - var self = this; - this.renderer.on('context', function (event) { - var gl = event.data; - - // this shader is used for rendering primitives - self.primitiveShader = new PrimitiveShader(gl); - - // this shader is used for rendering triangle strips - self.complexPrimitiveShader = new ComplexPrimitiveShader(gl); - - // this shader is used for the default sprite rendering - self.defaultShader = new Shader(gl); - - // this shader is used for the fast sprite rendering - self.fastShader = new FastShader(gl); - - // the next one is used for rendering triangle strips - self.stripShader = new StripShader(gl); - - self.setShader(self.defaultShader); - }); -} - -WebGLShaderManager.prototype = Object.create(WebGLManager.prototype); -WebGLShaderManager.prototype.constructor = WebGLShaderManager; -module.exports = WebGLShaderManager; - -/** - * Takes the attributes given in parameters. - * - * @param attribs {Array} attribs - */ -WebGLShaderManager.prototype.setAttribs = function (attribs) { - // reset temp state - var i; - - for (i = 0; i < this.tempAttribState.length; i++) { - this.tempAttribState[i] = false; - } - - // set the new attribs - for (var a in attribs) { - this.tempAttribState[attribs[a]] = true; - } - - var gl = this.renderer.gl; - - for (i = 0; i < this.attribState.length; i++) { - if (this.attribState[i] !== this.tempAttribState[i]) { - this.attribState[i] = this.tempAttribState[i]; - - if (this.attribState[i]) { - gl.enableVertexAttribArray(i); - } - else { - gl.disableVertexAttribArray(i); - } - } - } -}; - -/** - * Sets the current shader. - * - * @param shader {Any} - */ -WebGLShaderManager.prototype.setShader = function (shader) { - if (this._currentId === shader.uuid) { - return false; - } - - this._currentId = shader.uuid; - - this.currentShader = shader; - - this.renderer.gl.useProgram(shader.program); - this.setAttribs(shader.attributes); - - return true; -}; - -/** - * Destroys this object. - * - */ -WebGLShaderManager.prototype.destroy = function () { - this.attribState = null; - - this.tempAttribState = null; - - this.primitiveShader.destroy(); - this.primitiveShader = null; - - this.complexPrimitiveShader.destroy(); - this.complexPrimitiveShader = null; - - this.defaultShader.destroy(); - this.defaultShader = null; - - this.fastShader.destroy(); - this.fastShader = null; - - this.stripShader.destroy(); - this.stripShader = null; - - this.renderer = null; -}; - -},{"../shaders/ComplexPrimitiveShader":32,"../shaders/FastShader":33,"../shaders/PrimitiveShader":34,"../shaders/Shader":35,"../shaders/StripShader":36,"./WebGLManager":28}],31:[function(require,module,exports){ -var WebGLManager = require('./WebGLManager'), - utils = require('../../../utils'); - -/** - * @class - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this manager works for. - */ -function WebGLStencilManager(renderer) { - WebGLManager.call(this, renderer); - - this.stencilStack = []; - this.reverse = true; - this.count = 0; -} - -WebGLStencilManager.prototype = Object.create(WebGLManager.prototype); -WebGLStencilManager.prototype.constructor = WebGLStencilManager; -module.exports = WebGLStencilManager; - -/** - * Applies the Mask and adds it to the current filter stack. - * - * @param graphics {Graphics} - * @param webGLData {any[]} - */ -WebGLStencilManager.prototype.pushStencil = function (graphics, webGLData) { - var gl = this.renderer.gl; - - this.bindGraphics(graphics, webGLData, this.renderer); - - if (this.stencilStack.length === 0) { - gl.enable(gl.STENCIL_TEST); - gl.clear(gl.STENCIL_BUFFER_BIT); - this.reverse = true; - this.count = 0; - } - - this.stencilStack.push(webGLData); - - var level = this.count; - - gl.colorMask(false, false, false, false); - - gl.stencilFunc(gl.ALWAYS,0,0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.INVERT); - - // draw the triangle strip! - - if (webGLData.mode === 1) { - gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 ); - - if (this.reverse) { - gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); - } - else { - gl.stencilFunc(gl.EQUAL,level, 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); - } - - // draw a quad to increment.. - gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_SHORT, ( webGLData.indices.length - 4 ) * 2 ); - - if (this.reverse) { - gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF); - } - else { - gl.stencilFunc(gl.EQUAL,level+1, 0xFF); - } - - this.reverse = !this.reverse; - } - else { - if (!this.reverse) { - gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); - } - else { - gl.stencilFunc(gl.EQUAL,level, 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); - } - - gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - - if (!this.reverse) { - gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF); - } - else { - gl.stencilFunc(gl.EQUAL,level+1, 0xFF); - } - } - - gl.colorMask(true, true, true, true); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - - this.count++; -}; - -/** - * TODO this does not belong here! - * - * @param graphics {Graphics} - * @param webGLData {Array} - */ -WebGLStencilManager.prototype.bindGraphics = function (graphics, webGLData) { - //if (this._currentGraphics === graphics)return; - this._currentGraphics = graphics; - - var gl = this.renderer.gl; - - // bind the graphics object.. - var projection = this.renderer.projection, - offset = this.renderer.offset, - shader;// = this.renderer.shaderManager.primitiveShader; - - if (webGLData.mode === 1) { - shader = this.renderer.shaderManager.complexPrimitiveShader; - - this.renderer.shaderManager.setShader(shader); - - gl.uniform1f(shader.flipY, this.renderer.flipY); - - gl.uniformMatrix3fv(shader.translationMatrix, false, graphics.worldTransform.toArray(true)); - - gl.uniform2f(shader.projectionVector, projection.x, -projection.y); - gl.uniform2f(shader.offsetVector, -offset.x, -offset.y); - - gl.uniform3fv(shader.tintColor, utils.hex2rgb(graphics.tint)); - gl.uniform3fv(shader.color, webGLData.color); - - gl.uniform1f(shader.alpha, graphics.worldAlpha * webGLData.alpha); - - gl.bindBuffer(gl.ARRAY_BUFFER, webGLData.buffer); - - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 4 * 2, 0); - - - // now do the rest.. - // set the index buffer! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webGLData.indexBuffer); - } - else { - //this.renderer.shaderManager.activatePrimitiveShader(); - shader = this.renderer.shaderManager.primitiveShader; - this.renderer.shaderManager.setShader( shader ); - - gl.uniformMatrix3fv(shader.translationMatrix, false, graphics.worldTransform.toArray(true)); - - gl.uniform1f(shader.flipY, this.renderer.flipY); - gl.uniform2f(shader.projectionVector, projection.x, -projection.y); - gl.uniform2f(shader.offsetVector, -offset.x, -offset.y); - - gl.uniform3fv(shader.tintColor, utils.hex2rgb(graphics.tint)); - - gl.uniform1f(shader.alpha, graphics.worldAlpha); - - gl.bindBuffer(gl.ARRAY_BUFFER, webGLData.buffer); - - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 4 * 6, 0); - gl.vertexAttribPointer(shader.aColor, 4, gl.FLOAT, false,4 * 6, 2 * 4); - - // set the index buffer! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webGLData.indexBuffer); - } -}; - -/** - * @param graphics {Graphics} - * @param webGLData {Array} - */ -WebGLStencilManager.prototype.popStencil = function (graphics, webGLData) { - var gl = this.renderer.gl; - - this.stencilStack.pop(); - - this.count--; - - if (this.stencilStack.length === 0) { - // the stack is empty! - gl.disable(gl.STENCIL_TEST); - - } - else { - - var level = this.count; - - this.bindGraphics(graphics, webGLData, this.renderer); - - gl.colorMask(false, false, false, false); - - if (webGLData.mode === 1) { - this.reverse = !this.reverse; - - if (this.reverse) { - gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); - } - else { - gl.stencilFunc(gl.EQUAL,level+1, 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); - } - - // draw a quad to increment.. - gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_SHORT, ( webGLData.indices.length - 4 ) * 2 ); - - gl.stencilFunc(gl.ALWAYS,0,0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.INVERT); - - // draw the triangle strip! - gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 ); - - if (!this.reverse) { - gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF); - } - else { - gl.stencilFunc(gl.EQUAL,level, 0xFF); - } - - } - else { - // console.log("<<>>") - if (!this.reverse) { - gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); - } - else { - gl.stencilFunc(gl.EQUAL,level+1, 0xFF); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); - } - - gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - - if (!this.reverse) { - gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF); - } - else { - gl.stencilFunc(gl.EQUAL,level, 0xFF); - } - } - - gl.colorMask(true, true, true, true); - gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - - - } -}; - -/** - * Destroys the mask stack. - * - */ -WebGLStencilManager.prototype.destroy = function () { - this.renderer = null; - this.stencilStack = null; -}; - -},{"../../../utils":50,"./WebGLManager":28}],32:[function(require,module,exports){ -var Shader = require('./Shader'); - -/** - * @class - * @namespace PIXI - * @param gl {WebGLContext} the current WebGL drawing context - */ -function ComplexPrimitiveShader(gl) { - Shader.call(this, - gl, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - // 'attribute vec2 aTextureCoord;', - // 'attribute vec4 aColor;', - - 'uniform mat3 translationMatrix;', - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - - 'uniform vec3 tint;', - 'uniform float alpha;', - 'uniform vec3 color;', - 'uniform float flipY;', - 'varying vec4 vColor;', - - 'void main(void) {', - ' vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);', - ' v -= offsetVector.xyx;', - ' gl_Position = vec4( v.x / projectionVector.x -1.0, (v.y / projectionVector.y * -flipY) + flipY , 0.0, 1.0);', - ' vColor = vec4(color * alpha * tint, alpha);',//" * vec4(tint * alpha, alpha);', - '}' - ].join('\n'), - // fragment shader - [ - 'precision mediump float;', - - 'varying vec4 vColor;', - - 'void main(void) {', - ' gl_FragColor = vColor;', - '}' - ].join('\n'), - // custom uniforms - { - tint: { type: '3f', value: [0, 0, 0] }, - flipY: { type: '1f', value: 0 }, - alpha: { type: '1f', value: 0 }, - translationMatrix: { type: 'mat3', value: new Float32Array(9) } - } - ); -} - -ComplexPrimitiveShader.prototype = Object.create(Shader.prototype); -ComplexPrimitiveShader.prototype.constructor = ComplexPrimitiveShader; -module.exports = ComplexPrimitiveShader; - -},{"./Shader":35}],33:[function(require,module,exports){ -var Shader = require('./Shader'); - -/** - * @class - * @extends Shader - * @namespace PIXI - * @param gl {WebGLContext} the current WebGL drawing context - */ -function FastShader(gl) { - Shader.call(this, - gl, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute vec4 aColor;', - - 'attribute vec2 aPositionCoord;', - 'attribute vec2 aScale;', - 'attribute float aRotation;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform mat3 uMatrix;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void) {', - ' vec2 v;', - ' vec2 sv = aVertexPosition * aScale;', - ' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);', - ' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);', - ' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;', - ' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - // ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;', - ' vColor = aColor;', - '}' - ].join('\n'), - // fragment shader, use default - null, - // custom uniforms - { - uMatrix: { type: 'mat3', value: new Float32Array(9) } - }, - // custom attributes - { - aPositionCoord: 0, - aRotation: 0, - aScale: 0 - } - ); -} - -FastShader.prototype = Object.create(Shader.prototype); -FastShader.prototype.constructor = FastShader; -module.exports = FastShader; - -},{"./Shader":35}],34:[function(require,module,exports){ -var Shader = require('./Shader'); - -/** - * @class - * @namespace PIXI - * @param gl {WebGLContext} the current WebGL drawing context - */ -function PrimitiveShader(gl) { - Shader.call(this, - gl, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - // 'attribute vec2 aTextureCoord;', - 'attribute vec4 aColor;', - - 'uniform mat3 translationMatrix;', - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - 'uniform float alpha;', - 'uniform float flipY;', - 'uniform vec3 tint;', - - 'varying vec4 vColor;', - - 'void main(void) {', - ' vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);', - ' v -= offsetVector.xyx;', - ' gl_Position = vec4( v.x / projectionVector.x -1.0, (v.y / projectionVector.y * -flipY) + flipY , 0.0, 1.0);', - ' vColor = aColor * vec4(tint * alpha, alpha);', - '}' - ].join('\n'), - // fragment shader - [ - 'precision mediump float;', - - 'varying vec4 vColor;', - - 'void main(void) {', - ' gl_FragColor = vColor;', - '}' - ].join('\n'), - // custom uniforms - { - tint: { type: '3f', value: [0, 0, 0] }, - flipY: { type: '1f', value: 0 }, - alpha: { type: '1f', value: 0 }, - translationMatrix: { type: 'mat3', value: new Float32Array(9) } - } - ); -} - -PrimitiveShader.prototype = Object.create(Shader.prototype); -PrimitiveShader.prototype.constructor = PrimitiveShader; -module.exports = PrimitiveShader; - -},{"./Shader":35}],35:[function(require,module,exports){ -var utils = require('../../../utils'); - -/** - * @class - * @namespace PIXI - * @param [fragmentSrc] {string} The source of the fragment shader. - * @param [vertexSrc] {string} The source of the vertex shader. - */ -function Shader(gl, vertexSrc, fragmentSrc, customUniforms, customAttributes) { - /** - * @member {number} - * @readonly - */ - this.uuid = utils.uuid(); - - /** - * @member {WebGLContext} - * @readonly - */ - this.gl = gl; - - /** - * The WebGL program. - * @member {WebGLProgram} - * @readonly - */ - this.program = null; - - this.uniforms = { - uSampler: { type: 'sampler2D', value: 0 }, - projectionVector: { type: '2f', value: { x: 0, y: 0 } }, - offsetVector: { type: '2f', value: { x: 0, y: 0 } }, - dimensions: { type: '4f', value: new Float32Array(4) } - }; - - for (var u in customUniforms) { - this.uniforms[u] = customUniforms[u]; - } - - this.attributes = { - aVertexPosition: 0, - aTextureCoord: 0, - aColor: 0 - }; - - for (var a in customAttributes) { - this.attributes[a] = customAttributes[a]; - } - - this.textureCount = 0; - - /** - * The vertex shader. - * @member {Array} - */ - this.vertexSrc = vertexSrc || [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - 'attribute vec4 aColor;', - - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'const vec2 center = vec2(-1.0, 1.0);', - - 'void main(void) {', - ' gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - ' vColor = vec4(aColor.rgb * aColor.a, aColor.a);', - '}' - ].join('\n'); - - /** - * The fragment shader. - * @member {Array} - */ - this.fragmentSrc = fragmentSrc || [ - 'precision lowp float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;', - '}' - ].join('\n'); - - this.init(); -} - -Shader.prototype.constructor = Shader; -module.exports = Shader; - -Shader.prototype.init = function () { - this.compile(); - - this.gl.useProgram(this.program); - - this.cacheUniformLocations(Object.keys(this.uniforms)); - this.cacheAttributeLocations(Object.keys(this.attributes)); -}; - -Shader.prototype.cacheUniformLocations = function (keys) { - for (var i = 0; i < keys.length; ++i) { - this.uniforms[keys[i]]._location = this.gl.getUniformLocation(this.program, keys[i]); - } -}; - -Shader.prototype.cacheAttributeLocations = function (keys) { - for (var i = 0; i < keys.length; ++i) { - this.attributes[keys[i]] = this.gl.getAttribLocation(this.program, keys[i]); - } - - // TODO: Check if this is needed anymore... - - // Begin worst hack eva // - - // WHY??? ONLY on my chrome pixel the line above returns -1 when using filters? - // maybe its something to do with the current state of the gl context. - // I'm convinced this is a bug in the chrome browser as there is NO reason why this should be returning -1 especially as it only manifests on my chrome pixel - // If theres any webGL people that know why could happen please help :) - // if (this.attributes.aColor === -1) { - // this.attributes.aColor = 2; - // } - - // End worst hack eva // -}; - -Shader.prototype.compile = function () { - var gl = this.gl; - - var glVertShader = this._glCompile(gl.VERTEX_SHADER, this.vertexSrc); - var glFragShader = this._glCompile(gl.FRAGMENT_SHADER, this.fragmentSrc); - - var program = gl.createProgram(); - - gl.attachShader(program, glVertShader); - gl.attachShader(program, glFragShader); - gl.linkProgram(program); - - // if linking fails, then log and cleanup - if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { - window.console.error('Pixi.js Error: Could not initialize shader.'); - window.console.error('gl.VALIDATE_STATUS', gl.getProgramParameter(program, gl.VALIDATE_STATUS)); - window.console.error('gl.getError()', gl.getError()); - - // if there is a program info log, log it - if (gl.getProgramInfoLog(program) !== '') { - window.console.warn('Pixi.js Warning: gl.getProgramInfoLog()', gl.getProgramInfoLog(program)); - } - - gl.deleteProgram(program); - program = null; - } - - // clean up some shaders - gl.deleteShader(glVertShader); - gl.deleteShader(glFragShader); - - return (this.program = program); -}; - -Shader.prototype.syncUniforms = function () { - var gl = this.gl; - - this.textureCount = 1; - - for (var key in this.uniforms) { - var uniform = this.uniforms[key], - location = uniform._location, - value = uniform.value, - i, il; - - switch (uniform.type) { - case 'i': - case '1i': - gl.uniform1i(location, value); - break; - - case 'f': - case '1f': - gl.uniform1f(location, value); - break; - - case '2f': - gl.uniform2f(location, value[0], value[1]); - break; - - case '3f': - gl.uniform3f(location, value[0], value[1], value[2]); - break; - - case '4f': - gl.uniform4f(location, value[0], value[1], value[2], value[3]); - break; - - // a 2D Point object - case 'v2': - gl.uniform2f(location, value.x, value.y); - break; - - // a 3D Point object - case 'v3': - gl.uniform3f(location, value.x, value.y, value.z); - break; - - // a 4D Point object - case 'v4': - gl.uniform4f(location, value.x, value.y, value.z, value.w); - break; - - case '1iv': - gl.uniform1iv(location, value); - break; - - case '3iv': - gl.uniform3iv(location, value); - break; - - case '1fv': - gl.uniform1fv(location, value); - break; - - case '2fv': - gl.uniform2fv(location, value); - break; - - case '3fv': - gl.uniform3fv(location, value); - break; - - case '4fv': - gl.uniform4fv(location, value); - break; - - case 'm2': - case 'mat2': - case 'Matrix2fv': - gl.uniformMatrix2fv(location, uniform.transpose, value); - break; - - case 'm3': - case 'mat3': - case 'Matrix3fv': - gl.uniformMatrix3fv(location, uniform.transpose, value); - break; - - case 'm4': - case 'mat4': - case 'Matrix4fv': - gl.uniformMatrix4fv(location, uniform.transpose, value); - break; - - // a Color Value - case 'c': - if (typeof value === 'number') { - value = utils.hex2rgb(value); - } - - gl.uniform3f(location, value[0], value[1], value[2]); - break; - - // flat array of integers (JS or typed array) - case 'iv1': - gl.uniform1iv(location, value); - break; - - // flat array of integers with 3 x N size (JS or typed array) - case 'iv': - gl.uniform3iv(location, value); - break; - - // flat array of floats (JS or typed array) - case 'fv1': - gl.uniform1fv(location, value); - break; - - // flat array of floats with 3 x N size (JS or typed array) - case 'fv': - gl.uniform3fv(location, value); - break; - - // array of 2D Point objects - case 'v2v': - if (!uniform._array) { - uniform._array = new Float32Array(2 * value.length); - } - - for (i = 0, il = value.length; i < il; ++i) { - uniform._array[i * 2] = value[i].x; - uniform._array[i * 2 + 1] = value[i].y; - } - - gl.uniform2fv(location, uniform._array); - break; - - // array of 3D Point objects - case 'v3v': - if (!uniform._array) { - uniform._array = new Float32Array(3 * value.length); - } - - for (i = 0, il = value.length; i < il; ++i) { - uniform._array[i * 3] = value[i].x; - uniform._array[i * 3 + 1] = value[i].y; - uniform._array[i * 3 + 2] = value[i].z; - - } - - gl.uniform3fv(location, uniform._array); - break; - - // array of 4D Point objects - case 'v4v': - if (!uniform._array) { - uniform._array = new Float32Array(4 * value.length); - } - - for (i = 0, il = value.length; i < il; ++i) { - uniform._array[i * 4] = value[i].x; - uniform._array[i * 4 + 1] = value[i].y; - uniform._array[i * 4 + 2] = value[i].z; - uniform._array[i * 4 + 3] = value[i].w; - - } - - gl.uniform4fv(location, uniform._array); - break; - - case 't': - case 'sampler2D': - if (!uniform.value || !uniform.value.baseTexture || !uniform.value.baseTexture.hasLoaded) { - break; - } - - // activate this texture - gl.activeTexture(gl['TEXTURE' + this.textureCount]); - - // bind the texture - gl.bindTexture(gl.TEXTURE_2D, uniform.value.baseTexture._glTextures[gl.id]); - - // set uniform to texture index - gl.uniform1i(uniform._location, this.textureCount); - - // increment next texture id - this.textureCount++; - - // initialize the texture if we haven't yet - if (!uniform._init) { - this.initSampler2D(uniform); - - uniform._init = true; - } - break; - - default: - window.console.warn('Pixi.js Shader Warning: Unknown uniform type: ' + uniform.type); - } - } -}; - - -/** - * Initialises a Sampler2D uniform (which may only be available later on after initUniforms once the texture has loaded) - * - */ -Shader.prototype.initSampler2D = function (uniform) { - var gl = this.gl; - - // Extended texture data - if (uniform.textureData) { - var data = uniform.textureData; - - // GLTexture = mag linear, min linear_mipmap_linear, wrap repeat + gl.generateMipmap(gl.TEXTURE_2D); - // GLTextureLinear = mag/min linear, wrap clamp - // GLTextureNearestRepeat = mag/min NEAREST, wrap repeat - // GLTextureNearest = mag/min nearest, wrap clamp - // AudioTexture = whatever + luminance + width 512, height 2, border 0 - // KeyTexture = whatever + luminance + width 256, height 2, border 0 - - // magFilter can be: gl.LINEAR, gl.LINEAR_MIPMAP_LINEAR or gl.NEAREST - // wrapS/T can be: gl.CLAMP_TO_EDGE or gl.REPEAT - - var magFilter = (data.magFilter) ? data.magFilter : gl.LINEAR; - var minFilter = (data.minFilter) ? data.minFilter : gl.LINEAR; - var wrapS = (data.wrapS) ? data.wrapS : gl.CLAMP_TO_EDGE; - var wrapT = (data.wrapT) ? data.wrapT : gl.CLAMP_TO_EDGE; - var format = (data.luminance) ? gl.LUMINANCE : gl.RGBA; - - if (data.repeat) { - wrapS = gl.REPEAT; - wrapT = gl.REPEAT; - } - - gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, !!data.flipY); - - if (data.width) { - var width = (data.width) ? data.width : 512; - var height = (data.height) ? data.height : 2; - var border = (data.border) ? data.border : 0; - - // void texImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, ArrayBufferView? pixels); - gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, border, format, gl.UNSIGNED_BYTE, null); - } - else { - // void texImage2D(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, ImageData? pixels); - gl.texImage2D(gl.TEXTURE_2D, 0, format, gl.RGBA, gl.UNSIGNED_BYTE, uniform.value.baseTexture.source); - } - - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT); - } -}; - -/** - * Destroys the shader. - * - */ -Shader.prototype.destroy = function () { - this.gl.deleteProgram(this.program); - - this.gl = null; - this.uniforms = null; - this.attributes = null; - - this.vertexSrc = null; - this.fragmentSrc = null; -}; - -Shader.prototype._glCompile = function (type, src) { - var shader = this.gl.createShader(type); - - if (Array.isArray(src)) { - debugger; - } - - this.gl.shaderSource(shader, src); - this.gl.compileShader(shader); - - if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) { - window.console.log(this.gl.getShaderInfoLog(shader)); - return null; - } - - return shader; -}; - -},{"../../../utils":50}],36:[function(require,module,exports){ -var Shader = require('./Shader'); - -/** - * @class - * @namespace PIXI - * @param gl {WebGLContext} the current WebGL drawing context - */ -function StripShader(gl) { - Shader.call(this, - gl, - // vertex shader - [ - 'attribute vec2 aVertexPosition;', - 'attribute vec2 aTextureCoord;', - // 'attribute vec4 aColor;', - - 'uniform mat3 translationMatrix;', - 'uniform vec2 projectionVector;', - 'uniform vec2 offsetVector;', - - 'varying vec2 vTextureCoord;', - - 'void main(void) {', - ' vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);', - ' v -= offsetVector.xyx;', - ' gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);', - ' vTextureCoord = aTextureCoord;', - '}' - ].join('\n'), - // fragment shader - [ - 'precision mediump float;', - - 'uniform float alpha;', - 'uniform sampler2D uSampler;', - - 'varying vec2 vTextureCoord;', - - 'void main(void) {', - ' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y)) * alpha;', - '}' - ].join('\n'), - // custom uniforms - { - alpha: { type: '1f', value: 0 }, - translationMatrix: { type: 'mat3', value: new Float32Array(9) } - } - ); -} - -StripShader.prototype = Object.create(Shader.prototype); -StripShader.prototype.constructor = StripShader; -module.exports = StripShader; - -},{"./Shader":35}],37:[function(require,module,exports){ -var CONST = require('../../../const'); - -/** - * @class - * @namespace PIXI - * @param gl {WebGLContext} the current WebGL drawing context - * @param width {number} the horizontal range of the filter - * @param height {number} the vertical range of the filter - * @param scaleMode {number} See {{#crossLink "PIXI/scaleModes:property"}}scaleModes{{/crossLink}} for possible values - */ -function FilterTexture(gl, width, height, scaleMode) { - /** - * @member {WebGLContext} - */ - this.gl = gl; - - // next time to create a frame buffer and texture - - /** - * @member {Any} - */ - this.frameBuffer = gl.createFramebuffer(); - - /** - * @member {Any} - */ - this.texture = gl.createTexture(); - - /** - * @member {number} - */ - scaleMode = scaleMode || CONST.scaleModes.DEFAULT; - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); - gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); - - // required for masking a mask?? - this.renderBuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.renderBuffer); - - // reset render buffer - gl.bindRenderbuffer(gl.RENDERBUFFER, null); - - this.resize(width, height); -} - -FilterTexture.prototype.constructor = FilterTexture; -module.exports = FilterTexture; - -/** - * Clears the filter texture. - * - */ -FilterTexture.prototype.clear = function () { - var gl = this.gl; - - gl.clearColor(0,0,0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); -}; - -/** - * Resizes the texture to the specified width and height - * - * @param width {number} the new width of the texture - * @param height {number} the new height of the texture - */ -FilterTexture.prototype.resize = function (width, height) { - if (this.width === width && this.height === height) { - return; - } - - this.width = width; - this.height = height; - - var gl = this.gl; - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width , height , 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - // update the stencil buffer width and height - gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width , height); - - // reset render buffer - gl.bindRenderbuffer(gl.RENDERBUFFER, null); -}; - -/** - * Destroys the filter texture. - * - */ -FilterTexture.prototype.destroy = function () { - var gl = this.gl; - gl.deleteFramebuffer( this.frameBuffer ); - gl.deleteTexture( this.texture ); - - this.frameBuffer = null; - this.texture = null; -}; - -},{"../../../const":4}],38:[function(require,module,exports){ -/** - * @author Mat Groves - * - * Big thanks to the very clever Matt DesLauriers https://github.com/mattdesl/ - * for creating the original pixi version! - * - * Heavily inspired by LibGDX's WebGLSpriteBatch: - * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java - */ - -/** - * @class - * @private - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this sprite batch works for. - */ -function WebGLFastSpriteBatch(renderer) { - /** - * The renderer instance this sprite batch operates on. - * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * - * @member {number} - */ - this.vertSize = 10; - - /** - * - * - * @member {number} - */ - this.maxSize = 6000;//Math.pow(2, 16) / this.vertSize; - - /** - * - * - * @member {number} - */ - this.size = this.maxSize; - - //the total number of floats in our batch - var numVerts = this.size * 4 * this.vertSize; - - //the total number of indices in our batch - var numIndices = this.maxSize * 6; - - /** - * Vertex data - * - * @member {Float32Array} - */ - this.vertices = new Float32Array(numVerts); - - /** - * Index data - * - * @member {Uint16Array} - */ - this.indices = new Uint16Array(numIndices); - - /** - * - * - * @member {object} - */ - this.vertexBuffer = null; - - /** - * - * - * @member {object} - */ - this.indexBuffer = null; - - /** - * - * - * @member {number} - */ - this.lastIndexCount = 0; - - for (var i=0, j=0; i < numIndices; i += 6, j += 4) { - this.indices[i + 0] = j + 0; - this.indices[i + 1] = j + 1; - this.indices[i + 2] = j + 2; - this.indices[i + 3] = j + 0; - this.indices[i + 4] = j + 2; - this.indices[i + 5] = j + 3; - } - - /** - * - * - * @member {boolean} - */ - this.drawing = false; - - /** - * - * - * @member {number} - */ - this.currentBatchSize = 0; - - /** - * - * - * @member {BaseTexture} - */ - this.currentBaseTexture = null; - - /** - * - * - * @member {number} - */ - this.currentBlendMode = 0; - - /** - * - * - * @member {object} - */ - this.shader = null; - - /** - * - * - * @member {Matrix} - */ - this.matrix = null; - - // listen for context and update necessary buffers - var self = this; - this.renderer.on('context', function () { - self.setupContext(); - }); -} - -WebGLFastSpriteBatch.prototype.constructor = WebGLFastSpriteBatch; -module.exports = WebGLFastSpriteBatch; - -/** - * Sets the WebGL Context. - * - * @param gl {WebGLContext} the current WebGL drawing context - */ -WebGLFastSpriteBatch.prototype.setupContext = function () { - var gl = this.renderer.gl; - - // create a couple of buffers - this.vertexBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - - // 65535 is max index, so 65535 / 6 = 10922. - - //upload the index data - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to prepare for. - */ -WebGLFastSpriteBatch.prototype.begin = function (spriteBatch) { - this.shader = this.renderer.shaderManager.fastShader; - - this.matrix = spriteBatch.worldTransform.toArray(true); - - this.start(); -}; - -/** - */ -WebGLFastSpriteBatch.prototype.end = function () { - this.flush(); -}; - -/** - * @param spriteBatch {SpriteBatch} The SpriteBatch container to render. - */ -WebGLFastSpriteBatch.prototype.render = function (spriteBatch) { - var children = spriteBatch.children; - var sprite = children[0]; - - // if the uvs have not updated then no point rendering just yet! - - // check texture. - if (!sprite.texture._uvs) { - return; - } - - this.currentBaseTexture = sprite.texture.baseTexture; - - // check blend mode - if (sprite.blendMode !== this.renderer.blendModeManager.currentBlendMode) { - this.flush(); - this.renderer.blendModeManager.setBlendMode(sprite.blendMode); - } - - for (var i=0,j= children.length; i= this.size) { - this.flush(); - } -}; - -/** - * - */ -WebGLFastSpriteBatch.prototype.flush = function () { - // If the batch is length 0 then return as there is nothing to draw - if (this.currentBatchSize === 0) { - return; - } - - var gl = this.renderer.gl; - - // bind the current texture - if (!this.currentBaseTexture._glTextures[gl.id]) { - this.renderer.updateTexture(this.currentBaseTexture, gl); - } - //TODO-SHOUD THIS BE ELSE??!?!?! - else { - gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTextures[gl.id]); - } - - // upload the verts to the buffer - - if (this.currentBatchSize > ( this.size * 0.5 ) ) { - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); - } - else { - var view = this.vertices.subarray(0, this.currentBatchSize * 4 * this.vertSize); - - gl.bufferSubData(gl.ARRAY_BUFFER, 0, view); - } - - // now draw those suckas! - gl.drawElements(gl.TRIANGLES, this.currentBatchSize * 6, gl.UNSIGNED_SHORT, 0); - - // then reset the batch! - this.currentBatchSize = 0; - - // increment the draw count - this.renderer.drawCount++; -}; - - -/** - * Ends the batch and flushes - * - */ -WebGLFastSpriteBatch.prototype.stop = function () { - this.flush(); -}; - -/** - * - */ -WebGLFastSpriteBatch.prototype.start = function () { - var gl = this.renderer.gl; - - // bind the main texture - gl.activeTexture(gl.TEXTURE0); - - // bind the buffers - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - // set the projection - var projection = this.renderer.projection; - gl.uniform2f(this.shader.projectionVector, projection.x, projection.y); - - // set the matrix - gl.uniformMatrix3fv(this.shader.uMatrix, false, this.matrix); - - // set the pointers - var stride = this.vertSize * 4; - - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aPositionCoord, 2, gl.FLOAT, false, stride, 2 * 4); - gl.vertexAttribPointer(this.shader.attributes.aScale, 2, gl.FLOAT, false, stride, 4 * 4); - gl.vertexAttribPointer(this.shader.attributes.aRotation, 1, gl.FLOAT, false, stride, 6 * 4); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 7 * 4); - gl.vertexAttribPointer(this.shader.attributes.aColor, 1, gl.FLOAT, false, stride, 9 * 4); -}; - -},{}],39:[function(require,module,exports){ -var utils = require('../../../utils'), - math = require('../../../math'), - CONST = require('../../../const'), - WebGLGraphicsData = require('./WebGLGraphicsData'); - -/** - * A set of functions used by the webGL renderer to draw the primitive graphics data - * - * @namespace PIXI - * @private - */ -var WebGLGraphics = module.exports = {}; - -/** - * Renders the graphics object - * - * @static - * @private - * @param graphics {Graphics} - * @param renderer {WebGLRenderer} - */ -WebGLGraphics.renderGraphics = function (graphics, renderer) {//projection, offset) { - var gl = renderer.gl; - - var projection = renderer.projection, - offset = renderer.offset, - shader = renderer.shaderManager.primitiveShader, - webGLData; - - if (graphics.dirty) { - WebGLGraphics.updateGraphics(graphics, gl); - } - - var webGL = graphics._webGL[gl.id]; - - // This could be speeded up for sure! - - for (var i = 0; i < webGL.data.length; i++) { - if (webGL.data[i].mode === 1) { - webGLData = webGL.data[i]; - - renderer.stencilManager.pushStencil(graphics, webGLData, renderer); - - // render quad.. - gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_SHORT, ( webGLData.indices.length - 4 ) * 2 ); - - renderer.stencilManager.popStencil(graphics, webGLData, renderer); - } - else { - webGLData = webGL.data[i]; - - - renderer.shaderManager.setShader( shader );//activatePrimitiveShader(); - shader = renderer.shaderManager.primitiveShader; - gl.uniformMatrix3fv(shader.translationMatrix, false, graphics.worldTransform.toArray(true)); - - gl.uniform1f(shader.flipY, 1); - - gl.uniform2f(shader.projectionVector, projection.x, -projection.y); - gl.uniform2f(shader.offsetVector, -offset.x, -offset.y); - - gl.uniform3fv(shader.tintColor, utils.hex2rgb(graphics.tint)); - - gl.uniform1f(shader.alpha, graphics.worldAlpha); - - - gl.bindBuffer(gl.ARRAY_BUFFER, webGLData.buffer); - - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 4 * 6, 0); - gl.vertexAttribPointer(shader.aColor, 4, gl.FLOAT, false,4 * 6, 2 * 4); - - // set the index buffer! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, webGLData.indexBuffer); - gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - } - } -}; - -/** - * Updates the graphics object - * - * @static - * @private - * @param graphicsData {Graphics} The graphics object to update - * @param gl {WebGLContext} the current WebGL drawing context - */ -WebGLGraphics.updateGraphics = function (graphics, gl) { - // get the contexts graphics object - var webGL = graphics._webGL[gl.id]; - - // if the graphics object does not exist in the webGL context time to create it! - if (!webGL) { - webGL = graphics._webGL[gl.id] = {lastIndex:0, data:[], gl:gl}; - } - - // flag the graphics as not dirty as we are about to update it... - graphics.dirty = false; - - var i; - - // if the user cleared the graphics object we will need to clear every object - if (graphics.clearDirty) { - graphics.clearDirty = false; - - // lop through and return all the webGLDatas to the object pool so than can be reused later on - for (i = 0; i < webGL.data.length; i++) { - var graphicsData = webGL.data[i]; - graphicsData.reset(); - WebGLGraphics.graphicsDataPool.push( graphicsData ); - } - - // clear the array and reset the index.. - webGL.data = []; - webGL.lastIndex = 0; - } - - var webGLData; - - // loop through the graphics datas and construct each one.. - // if the object is a complex fill then the new stencil buffer technique will be used - // other wise graphics objects will be pushed into a batch.. - for (i = webGL.lastIndex; i < graphics.graphicsData.length; i++) { - var data = graphics.graphicsData[i]; - - if (data.type === CONST.SHAPES.POLY) { - // need to add the points the the graphics object.. - data.points = data.shape.points.slice(); - if (data.shape.closed) { - // close the poly if the value is true! - if (data.points[0] !== data.points[data.points.length-2] || data.points[1] !== data.points[data.points.length-1]) { - data.points.push(data.points[0], data.points[1]); - } - } - - // MAKE SURE WE HAVE THE CORRECT TYPE.. - if (data.fill) { - if (data.points.length >= 6) { - if (data.points.length < 6 * 2) { - webGLData = WebGLGraphics.switchMode(webGL, 0); - - var canDrawUsingSimple = WebGLGraphics.buildPoly(data, webGLData); - // console.log(canDrawUsingSimple); - - if (!canDrawUsingSimple) { - // console.log("<>>>") - webGLData = WebGLGraphics.switchMode(webGL, 1); - WebGLGraphics.buildComplexPoly(data, webGLData); - } - - } - else { - webGLData = WebGLGraphics.switchMode(webGL, 1); - WebGLGraphics.buildComplexPoly(data, webGLData); - } - } - } - - if (data.lineWidth > 0) { - webGLData = WebGLGraphics.switchMode(webGL, 0); - WebGLGraphics.buildLine(data, webGLData); - - } - } - else { - webGLData = WebGLGraphics.switchMode(webGL, 0); - - if (data.type === CONST.SHAPES.RECT) { - WebGLGraphics.buildRectangle(data, webGLData); - } - else if (data.type === CONST.SHAPES.CIRC || data.type === CONST.SHAPES.ELIP) { - WebGLGraphics.buildCircle(data, webGLData); - } - else if (data.type === CONST.SHAPES.RREC) { - WebGLGraphics.buildRoundedRectangle(data, webGLData); - } - } - - webGL.lastIndex++; - } - - // upload all the dirty data... - for (i = 0; i < webGL.data.length; i++) { - webGLData = webGL.data[i]; - - if (webGLData.dirty) { - webGLData.upload(); - } - } -}; - -/** - * @static - * @private - * @param webGL {WebGLContext} - * @param type {number} - */ -WebGLGraphics.switchMode = function (webGL, type) { - var webGLData; - - if (!webGL.data.length) { - webGLData = WebGLGraphics.graphicsDataPool.pop() || new WebGLGraphicsData(webGL.gl); - webGLData.mode = type; - webGL.data.push(webGLData); - } - else { - webGLData = webGL.data[webGL.data.length-1]; - - if (webGLData.mode !== type || type === 1) { - webGLData = WebGLGraphics.graphicsDataPool.pop() || new WebGLGraphicsData(webGL.gl); - webGLData.mode = type; - webGL.data.push(webGLData); - } - } - - webGLData.dirty = true; - - return webGLData; -}; - -/** - * Builds a rectangle to draw - * - * @static - * @private - * @param graphicsData {Graphics} The graphics object containing all the necessary properties - * @param webGLData {object} - */ -WebGLGraphics.buildRectangle = function (graphicsData, webGLData) { - // --- // - // need to convert points to a nice regular data - // - var rectData = graphicsData.shape; - var x = rectData.x; - var y = rectData.y; - var width = rectData.width; - var height = rectData.height; - - if (graphicsData.fill) { - var color = utils.hex2rgb(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var verts = webGLData.points; - var indices = webGLData.indices; - - var vertPos = verts.length/6; - - // start - verts.push(x, y); - verts.push(r, g, b, alpha); - - verts.push(x + width, y); - verts.push(r, g, b, alpha); - - verts.push(x , y + height); - verts.push(r, g, b, alpha); - - verts.push(x + width, y + height); - verts.push(r, g, b, alpha); - - // insert 2 dead triangles.. - indices.push(vertPos, vertPos, vertPos+1, vertPos+2, vertPos+3, vertPos+3); - } - - if (graphicsData.lineWidth) { - var tempPoints = graphicsData.points; - - graphicsData.points = [x, y, - x + width, y, - x + width, y + height, - x, y + height, - x, y]; - - - WebGLGraphics.buildLine(graphicsData, webGLData); - - graphicsData.points = tempPoints; - } -}; - -/** - * Builds a rounded rectangle to draw - * - * @static - * @private - * @param graphicsData {Graphics} The graphics object containing all the necessary properties - * @param webGLData {object} - */ -WebGLGraphics.buildRoundedRectangle = function (graphicsData, webGLData) { - var rrectData = graphicsData.shape; - var x = rrectData.x; - var y = rrectData.y; - var width = rrectData.width; - var height = rrectData.height; - - var radius = rrectData.radius; - - var recPoints = []; - recPoints.push(x, y + radius); - recPoints = recPoints.concat(WebGLGraphics.quadraticBezierCurve(x, y + height - radius, x, y + height, x + radius, y + height)); - recPoints = recPoints.concat(WebGLGraphics.quadraticBezierCurve(x + width - radius, y + height, x + width, y + height, x + width, y + height - radius)); - recPoints = recPoints.concat(WebGLGraphics.quadraticBezierCurve(x + width, y + radius, x + width, y, x + width - radius, y)); - recPoints = recPoints.concat(WebGLGraphics.quadraticBezierCurve(x + radius, y, x, y, x, y + radius)); - - if (graphicsData.fill) { - var color = utils.hex2rgb(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var verts = webGLData.points; - var indices = webGLData.indices; - - var vecPos = verts.length/6; - - var triangles = utils.PolyK.Triangulate(recPoints); - - // - - var i = 0; - for (i = 0; i < triangles.length; i+=3) { - indices.push(triangles[i] + vecPos); - indices.push(triangles[i] + vecPos); - indices.push(triangles[i+1] + vecPos); - indices.push(triangles[i+2] + vecPos); - indices.push(triangles[i+2] + vecPos); - } - - - for (i = 0; i < recPoints.length; i++) { - verts.push(recPoints[i], recPoints[++i], r, g, b, alpha); - } - } - - if (graphicsData.lineWidth) { - var tempPoints = graphicsData.points; - - graphicsData.points = recPoints; - - WebGLGraphics.buildLine(graphicsData, webGLData); - - graphicsData.points = tempPoints; - } -}; - -/** - * Calculate the points for a quadratic bezier curve. (helper function..) - * Based on: https://stackoverflow.com/questions/785097/how-do-i-implement-a-bezier-curve-in-c - * - * @static - * @private - * @param fromX {number} Origin point x - * @param fromY {number} Origin point x - * @param cpX {number} Control point x - * @param cpY {number} Control point y - * @param toX {number} Destination point x - * @param toY {number} Destination point y - * @return {number[]} - */ -WebGLGraphics.quadraticBezierCurve = function (fromX, fromY, cpX, cpY, toX, toY) { - - var xa, - ya, - xb, - yb, - x, - y, - n = 20, - points = []; - - function getPt(n1 , n2, perc) { - var diff = n2 - n1; - - return n1 + ( diff * perc ); - } - - var j = 0; - for (var i = 0; i <= n; i++ ) { - j = i / n; - - // The Green Line - xa = getPt( fromX , cpX , j ); - ya = getPt( fromY , cpY , j ); - xb = getPt( cpX , toX , j ); - yb = getPt( cpY , toY , j ); - - // The Black Dot - x = getPt( xa , xb , j ); - y = getPt( ya , yb , j ); - - points.push(x, y); - } - return points; -}; - -/** - * Builds a circle to draw - * - * @static - * @private - * @param graphicsData {Graphics} The graphics object to draw - * @param webGLData {object} - */ -WebGLGraphics.buildCircle = function (graphicsData, webGLData) { - // need to convert points to a nice regular data - var circleData = graphicsData.shape; - var x = circleData.x; - var y = circleData.y; - var width; - var height; - - // TODO - bit hacky?? - if (graphicsData.type === CONST.SHAPES.CIRC) { - width = circleData.radius; - height = circleData.radius; - } - else { - width = circleData.width; - height = circleData.height; - } - - var totalSegs = 40; - var seg = (Math.PI * 2) / totalSegs ; - - var i = 0; - - if (graphicsData.fill) { - var color = utils.hex2rgb(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var verts = webGLData.points; - var indices = webGLData.indices; - - var vecPos = verts.length/6; - - indices.push(vecPos); - - for (i = 0; i < totalSegs + 1 ; i++) { - verts.push(x,y, r, g, b, alpha); - - verts.push(x + Math.sin(seg * i) * width, - y + Math.cos(seg * i) * height, - r, g, b, alpha); - - indices.push(vecPos++, vecPos++); - } - - indices.push(vecPos-1); - } - - if (graphicsData.lineWidth) { - var tempPoints = graphicsData.points; - - graphicsData.points = []; - - for (i = 0; i < totalSegs + 1; i++) { - graphicsData.points.push(x + Math.sin(seg * i) * width, - y + Math.cos(seg * i) * height); - } - - WebGLGraphics.buildLine(graphicsData, webGLData); - - graphicsData.points = tempPoints; - } -}; - -/** - * Builds a line to draw - * - * @static - * @private - * @param graphicsData {Graphics} The graphics object containing all the necessary properties - * @param webGLData {object} - */ -WebGLGraphics.buildLine = function (graphicsData, webGLData) { - // TODO OPTIMISE! - var i = 0; - var points = graphicsData.points; - - if (points.length === 0) { - return; - } - - // if the line width is an odd number add 0.5 to align to a whole pixel - if (graphicsData.lineWidth%2) { - for (i = 0; i < points.length; i++) { - points[i] += 0.5; - } - } - - // get first and last point.. figure out the middle! - var firstPoint = new math.Point(points[0], points[1]); - var lastPoint = new math.Point(points[points.length - 2], points[points.length - 1]); - - // if the first point is the last point - gonna have issues :) - if (firstPoint.x === lastPoint.x && firstPoint.y === lastPoint.y) { - // need to clone as we are going to slightly modify the shape.. - points = points.slice(); - - points.pop(); - points.pop(); - - lastPoint = new math.Point(points[points.length - 2], points[points.length - 1]); - - var midPointX = lastPoint.x + (firstPoint.x - lastPoint.x) *0.5; - var midPointY = lastPoint.y + (firstPoint.y - lastPoint.y) *0.5; - - points.unshift(midPointX, midPointY); - points.push(midPointX, midPointY); - } - - var verts = webGLData.points; - var indices = webGLData.indices; - var length = points.length / 2; - var indexCount = points.length; - var indexStart = verts.length/6; - - // DRAW the Line - var width = graphicsData.lineWidth / 2; - - // sort color - var color = utils.hex2rgb(graphicsData.lineColor); - var alpha = graphicsData.lineAlpha; - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var px, py, p1x, p1y, p2x, p2y, p3x, p3y; - var perpx, perpy, perp2x, perp2y, perp3x, perp3y; - var a1, b1, c1, a2, b2, c2; - var denom, pdist, dist; - - p1x = points[0]; - p1y = points[1]; - - p2x = points[2]; - p2y = points[3]; - - perpx = -(p1y - p2y); - perpy = p1x - p2x; - - dist = Math.sqrt(perpx*perpx + perpy*perpy); - - perpx /= dist; - perpy /= dist; - perpx *= width; - perpy *= width; - - // start - verts.push(p1x - perpx , p1y - perpy, - r, g, b, alpha); - - verts.push(p1x + perpx , p1y + perpy, - r, g, b, alpha); - - for (i = 1; i < length-1; i++) { - p1x = points[(i-1)*2]; - p1y = points[(i-1)*2 + 1]; - - p2x = points[(i)*2]; - p2y = points[(i)*2 + 1]; - - p3x = points[(i+1)*2]; - p3y = points[(i+1)*2 + 1]; - - perpx = -(p1y - p2y); - perpy = p1x - p2x; - - dist = Math.sqrt(perpx*perpx + perpy*perpy); - perpx /= dist; - perpy /= dist; - perpx *= width; - perpy *= width; - - perp2x = -(p2y - p3y); - perp2y = p2x - p3x; - - dist = Math.sqrt(perp2x*perp2x + perp2y*perp2y); - perp2x /= dist; - perp2y /= dist; - perp2x *= width; - perp2y *= width; - - a1 = (-perpy + p1y) - (-perpy + p2y); - b1 = (-perpx + p2x) - (-perpx + p1x); - c1 = (-perpx + p1x) * (-perpy + p2y) - (-perpx + p2x) * (-perpy + p1y); - a2 = (-perp2y + p3y) - (-perp2y + p2y); - b2 = (-perp2x + p2x) - (-perp2x + p3x); - c2 = (-perp2x + p3x) * (-perp2y + p2y) - (-perp2x + p2x) * (-perp2y + p3y); - - denom = a1*b2 - a2*b1; - - if (Math.abs(denom) < 0.1 ) { - - denom+=10.1; - verts.push(p2x - perpx , p2y - perpy, - r, g, b, alpha); - - verts.push(p2x + perpx , p2y + perpy, - r, g, b, alpha); - - continue; - } - - px = (b1*c2 - b2*c1)/denom; - py = (a2*c1 - a1*c2)/denom; - - - pdist = (px -p2x) * (px -p2x) + (py -p2y) + (py -p2y); - - - if (pdist > 140 * 140) { - perp3x = perpx - perp2x; - perp3y = perpy - perp2y; - - dist = Math.sqrt(perp3x*perp3x + perp3y*perp3y); - perp3x /= dist; - perp3y /= dist; - perp3x *= width; - perp3y *= width; - - verts.push(p2x - perp3x, p2y -perp3y); - verts.push(r, g, b, alpha); - - verts.push(p2x + perp3x, p2y +perp3y); - verts.push(r, g, b, alpha); - - verts.push(p2x - perp3x, p2y -perp3y); - verts.push(r, g, b, alpha); - - indexCount++; - } - else { - - verts.push(px , py); - verts.push(r, g, b, alpha); - - verts.push(p2x - (px-p2x), p2y - (py - p2y)); - verts.push(r, g, b, alpha); - } - } - - p1x = points[(length-2)*2]; - p1y = points[(length-2)*2 + 1]; - - p2x = points[(length-1)*2]; - p2y = points[(length-1)*2 + 1]; - - perpx = -(p1y - p2y); - perpy = p1x - p2x; - - dist = Math.sqrt(perpx*perpx + perpy*perpy); - perpx /= dist; - perpy /= dist; - perpx *= width; - perpy *= width; - - verts.push(p2x - perpx , p2y - perpy); - verts.push(r, g, b, alpha); - - verts.push(p2x + perpx , p2y + perpy); - verts.push(r, g, b, alpha); - - indices.push(indexStart); - - for (i = 0; i < indexCount; i++) { - indices.push(indexStart++); - } - - indices.push(indexStart-1); -}; - -/** - * Builds a complex polygon to draw - * - * @static - * @private - * @param graphicsData {Graphics} The graphics object containing all the necessary properties - * @param webGLData {object} - */ -WebGLGraphics.buildComplexPoly = function (graphicsData, webGLData) { - //TODO - no need to copy this as it gets turned into a FLoat32Array anyways.. - var points = graphicsData.points.slice(); - - if (points.length < 6) { - return; - } - - // get first and last point.. figure out the middle! - var indices = webGLData.indices; - webGLData.points = points; - webGLData.alpha = graphicsData.fillAlpha; - webGLData.color = utils.hex2rgb(graphicsData.fillColor); - - // calclate the bounds.. - var minX = Infinity; - var maxX = -Infinity; - - var minY = Infinity; - var maxY = -Infinity; - - var x,y; - - // get size.. - for (var i = 0; i < points.length; i+=2) { - x = points[i]; - y = points[i+1]; - - minX = x < minX ? x : minX; - maxX = x > maxX ? x : maxX; - - minY = y < minY ? y : minY; - maxY = y > maxY ? y : maxY; - } - - // add a quad to the end cos there is no point making another buffer! - points.push(minX, minY, - maxX, minY, - maxX, maxY, - minX, maxY); - - // push a quad onto the end.. - - //TODO - this aint needed! - var length = points.length / 2; - for (i = 0; i < length; i++) { - indices.push( i ); - } - -}; - -/** - * Builds a polygon to draw - * - * @static - * @private - * @param graphicsData {Graphics} The graphics object containing all the necessary properties - * @param webGLData {object} - */ -WebGLGraphics.buildPoly = function (graphicsData, webGLData) { - var points = graphicsData.points; - - if (points.length < 6) { - return; - } - // get first and last point.. figure out the middle! - var verts = webGLData.points; - var indices = webGLData.indices; - - var length = points.length / 2; - - // sort color - var color = utils.hex2rgb(graphicsData.fillColor); - var alpha = graphicsData.fillAlpha; - var r = color[0] * alpha; - var g = color[1] * alpha; - var b = color[2] * alpha; - - var triangles = utils.PolyK.Triangulate(points); - - if (!triangles) { - return false; - } - - var vertPos = verts.length / 6; - - var i = 0; - - for (i = 0; i < triangles.length; i+=3) { - indices.push(triangles[i] + vertPos); - indices.push(triangles[i] + vertPos); - indices.push(triangles[i+1] + vertPos); - indices.push(triangles[i+2] +vertPos); - indices.push(triangles[i+2] + vertPos); - } - - for (i = 0; i < length; i++) { - verts.push(points[i * 2], points[i * 2 + 1], - r, g, b, alpha); - } - - return true; -}; - -WebGLGraphics.graphicsDataPool = []; - -},{"../../../const":4,"../../../math":12,"../../../utils":50,"./WebGLGraphicsData":40}],40:[function(require,module,exports){ -/** - * @class - * @private - */ -function WebGLGraphicsData(gl) { - this.gl = gl; - - //TODO does this need to be split before uploding?? - this.color = [0, 0, 0]; // color split! - this.points = []; - this.indices = []; - this.buffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - this.mode = 1; - this.alpha = 1; - this.dirty = true; -} - -WebGLGraphicsData.prototype.constructor = WebGLGraphicsData; -module.exports = WebGLGraphicsData; - -/** - * - */ -WebGLGraphicsData.prototype.reset = function () { - this.points.length = 0; - this.indices.length = 0; -}; - -/** - * - */ -WebGLGraphicsData.prototype.upload = function () { - var gl = this.gl; - -// this.lastIndex = graphics.graphicsData.length; - this.glPoints = new Float32Array(this.points); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer); - gl.bufferData(gl.ARRAY_BUFFER, this.glPoints, gl.STATIC_DRAW); - - this.glIndicies = new Uint16Array(this.indices); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.glIndicies, gl.STATIC_DRAW); - - this.dirty = false; -}; - -},{}],41:[function(require,module,exports){ -var TextureUvs = require('../../../textures/TextureUvs'), - Shader = require('../shaders/Shader'); - -/** - * @author Mat Groves - * - * Big thanks to the very clever Matt DesLauriers https://github.com/mattdesl/ - * for creating the original pixi version! - * Also a thanks to https://github.com/bchevalier for tweaking the tint and alpha so that they now share 4 bytes on the vertex buffer - * - * Heavily inspired by LibGDX's WebGLSpriteBatch: - * https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java - */ - -/** - * - * @class - * @private - * @namespace PIXI - * @param renderer {WebGLRenderer} The renderer this sprite batch works for. - */ -function WebGLSpriteBatch(renderer) { - /** - * - * - * @member {WebGLRenderer} - */ - this.renderer = renderer; - - /** - * - * - * @member {number} - */ - this.vertSize = 5; - - /** - * The number of images in the SpriteBatch before it flushes. - * - * @member {number} - */ - this.size = 2000;//Math.pow(2, 16) / this.vertSize; - - // the total number of bytes in our batch - var numVerts = this.size * 4 * 4 * this.vertSize; - // the total number of indices in our batch - var numIndices = this.size * 6; - - /** - * Holds the vertices - * - * @member {ArrayBuffer} - */ - this.vertices = new ArrayBuffer(numVerts); - - /** - * View on the vertices as a Float32Array - * - * @member {Float32Array} - */ - this.positions = new Float32Array(this.vertices); - - /** - * View on the vertices as a Uint32Array - * - * @member {Uint32Array} - */ - this.colors = new Uint32Array(this.vertices); - - /** - * Holds the indices - * - * @member {Uint16Array} - */ - this.indices = new Uint16Array(numIndices); - - /** - * - * - * @member {number} - */ - this.lastIndexCount = 0; - - for (var i=0, j=0; i < numIndices; i += 6, j += 4) { - this.indices[i + 0] = j + 0; - this.indices[i + 1] = j + 1; - this.indices[i + 2] = j + 2; - this.indices[i + 3] = j + 0; - this.indices[i + 4] = j + 2; - this.indices[i + 5] = j + 3; - } - - /** - * - * - * @member {boolean} - */ - this.drawing = false; - - /** - * - * - * @member {number} - */ - this.currentBatchSize = 0; - - /** - * - * - * @member {BaseTexture} - */ - this.currentBaseTexture = null; - - /** - * - * - * @member {boolean} - */ - this.dirty = true; - - /** - * - * - * @member {Array} - */ - this.textures = []; - - /** - * - * - * @member {Array} - */ - this.blendModes = []; - - /** - * - * - * @member {Array} - */ - this.shaders = []; - - /** - * - * - * @member {Array} - */ - this.sprites = []; - - /** - * The default shader that is used if a sprite doesn't have a more specific one. - * - * @member {Shader} - */ - this.shader = null; - - // listen for context and update necessary buffers - var self = this; - this.renderer.on('context', function () { - self.setupContext(); - }); -} - -WebGLSpriteBatch.prototype.constructor = WebGLSpriteBatch; -module.exports = WebGLSpriteBatch; - -/** - * @param gl {WebGLContext} the current WebGL drawing context - */ -WebGLSpriteBatch.prototype.setupContext = function () { - var gl = this.renderer.gl; - - // setup default shader - this.shader = new Shader(gl); - - // create a couple of buffers - this.vertexBuffer = gl.createBuffer(); - this.indexBuffer = gl.createBuffer(); - - // 65535 is max index, so 65535 / 6 = 10922. - - //upload the index data - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW); - - this.currentBlendMode = 99999; -}; - -/** - * - */ -WebGLSpriteBatch.prototype.begin = function () { - // this.shader = this.renderer.shaderManager.defaultShader; - - this.start(); -}; - -/** - */ -WebGLSpriteBatch.prototype.end = function () { - this.flush(); -}; - -/** - * @param sprite {Sprite} the sprite to render when using this spritebatch - */ -WebGLSpriteBatch.prototype.render = function (sprite) { - var texture = sprite.texture; - - //TODO set blend modes.. - // check texture.. - if (this.currentBatchSize >= this.size) { - this.flush(); - this.currentBaseTexture = texture.baseTexture; - } - - // get the uvs for the texture - var uvs = texture._uvs; - - // if the uvs have not updated then no point rendering just yet! - if (!uvs) { - return; - } - - // TODO trim?? - var aX = sprite.anchor.x; - var aY = sprite.anchor.y; - - var w0, w1, h0, h1; - - if (texture.trim) { - // if the sprite is trimmed then we need to add the extra space before transforming the sprite coords.. - var trim = texture.trim; - - w1 = trim.x - aX * trim.width; - w0 = w1 + texture.crop.width; - - h1 = trim.y - aY * trim.height; - h0 = h1 + texture.crop.height; - - } - else { - w0 = (texture.frame.width ) * (1-aX); - w1 = (texture.frame.width ) * -aX; - - h0 = texture.frame.height * (1-aY); - h1 = texture.frame.height * -aY; - } - - var index = this.currentBatchSize * 4 * this.vertSize; - - var resolution = texture.baseTexture.resolution; - - var worldTransform = sprite.worldTransform; - - var a = worldTransform.a / resolution; - var b = worldTransform.b / resolution; - var c = worldTransform.c / resolution; - var d = worldTransform.d / resolution; - var tx = worldTransform.tx; - var ty = worldTransform.ty; - - var colors = this.colors; - var positions = this.positions; - - if (this.renderer.roundPixels) { - // xy - positions[index] = a * w1 + c * h1 + tx | 0; - positions[index+1] = d * h1 + b * w1 + ty | 0; - - // xy - positions[index+5] = a * w0 + c * h1 + tx | 0; - positions[index+6] = d * h1 + b * w0 + ty | 0; - - // xy - positions[index+10] = a * w0 + c * h0 + tx | 0; - positions[index+11] = d * h0 + b * w0 + ty | 0; - - // xy - positions[index+15] = a * w1 + c * h0 + tx | 0; - positions[index+16] = d * h0 + b * w1 + ty | 0; - } - else { - // xy - positions[index] = a * w1 + c * h1 + tx; - positions[index+1] = d * h1 + b * w1 + ty; - - // xy - positions[index+5] = a * w0 + c * h1 + tx; - positions[index+6] = d * h1 + b * w0 + ty; - - // xy - positions[index+10] = a * w0 + c * h0 + tx; - positions[index+11] = d * h0 + b * w0 + ty; - - // xy - positions[index+15] = a * w1 + c * h0 + tx; - positions[index+16] = d * h0 + b * w1 + ty; - } - - // uv - positions[index+2] = uvs.x0; - positions[index+3] = uvs.y0; - - // uv - positions[index+7] = uvs.x1; - positions[index+8] = uvs.y1; - - // uv - positions[index+12] = uvs.x2; - positions[index+13] = uvs.y2; - - // uv - positions[index+17] = uvs.x3; - positions[index+18] = uvs.y3; - - // color and alpha - var tint = sprite.tint; - colors[index+4] = colors[index+9] = colors[index+14] = colors[index+19] = (tint >> 16) + (tint & 0xff00) + ((tint & 0xff) << 16) + (sprite.worldAlpha * 255 << 24); - - // increment the batchsize - this.sprites[this.currentBatchSize++] = sprite; - - -}; - -/** - * Renders a TilingSprite using the spriteBatch. - * - * @param sprite {TilingSprite} the tilingSprite to render - */ -WebGLSpriteBatch.prototype.renderTilingSprite = function (tilingSprite) { - var texture = tilingSprite.tilingTexture; - - // check texture.. - if (this.currentBatchSize >= this.size) { - //return; - this.flush(); - this.currentBaseTexture = texture.baseTexture; - } - - // set the textures uvs temporarily - // TODO create a separate texture so that we can tile part of a texture - - if (!tilingSprite._uvs) { - tilingSprite._uvs = new TextureUvs(); - } - - var uvs = tilingSprite._uvs; - - tilingSprite.tilePosition.x %= texture.baseTexture.width * tilingSprite.tileScaleOffset.x; - tilingSprite.tilePosition.y %= texture.baseTexture.height * tilingSprite.tileScaleOffset.y; - - var offsetX = tilingSprite.tilePosition.x/(texture.baseTexture.width*tilingSprite.tileScaleOffset.x); - var offsetY = tilingSprite.tilePosition.y/(texture.baseTexture.height*tilingSprite.tileScaleOffset.y); - - var scaleX = (tilingSprite.width / texture.baseTexture.width) / (tilingSprite.tileScale.x * tilingSprite.tileScaleOffset.x); - var scaleY = (tilingSprite.height / texture.baseTexture.height) / (tilingSprite.tileScale.y * tilingSprite.tileScaleOffset.y); - - uvs.x0 = 0 - offsetX; - uvs.y0 = 0 - offsetY; - - uvs.x1 = (1 * scaleX) - offsetX; - uvs.y1 = 0 - offsetY; - - uvs.x2 = (1 * scaleX) - offsetX; - uvs.y2 = (1 * scaleY) - offsetY; - - uvs.x3 = 0 - offsetX; - uvs.y3 = (1 * scaleY) - offsetY; - - // get the tilingSprites current alpha and tint and combining them into a single color - var tint = tilingSprite.tint; - var color = (tint >> 16) + (tint & 0xff00) + ((tint & 0xff) << 16) + (tilingSprite.alpha * 255 << 24); - - var positions = this.positions; - var colors = this.colors; - - var width = tilingSprite.width; - var height = tilingSprite.height; - - // TODO trim?? - var aX = tilingSprite.anchor.x; - var aY = tilingSprite.anchor.y; - var w0 = width * (1-aX); - var w1 = width * -aX; - - var h0 = height * (1-aY); - var h1 = height * -aY; - - var index = this.currentBatchSize * 4 * this.vertSize; - - var resolution = texture.baseTexture.resolution; - - var worldTransform = tilingSprite.worldTransform; - - var a = worldTransform.a / resolution;//[0]; - var b = worldTransform.b / resolution;//[3]; - var c = worldTransform.c / resolution;//[1]; - var d = worldTransform.d / resolution;//[4]; - var tx = worldTransform.tx;//[2]; - var ty = worldTransform.ty;//[5]; - - // xy - positions[index++] = a * w1 + c * h1 + tx; - positions[index++] = d * h1 + b * w1 + ty; - // uv - positions[index++] = uvs.x0; - positions[index++] = uvs.y0; - // color - colors[index++] = color; - - // xy - positions[index++] = (a * w0 + c * h1 + tx); - positions[index++] = d * h1 + b * w0 + ty; - // uv - positions[index++] = uvs.x1; - positions[index++] = uvs.y1; - // color - colors[index++] = color; - - // xy - positions[index++] = a * w0 + c * h0 + tx; - positions[index++] = d * h0 + b * w0 + ty; - // uv - positions[index++] = uvs.x2; - positions[index++] = uvs.y2; - // color - colors[index++] = color; - - // xy - positions[index++] = a * w1 + c * h0 + tx; - positions[index++] = d * h0 + b * w1 + ty; - // uv - positions[index++] = uvs.x3; - positions[index++] = uvs.y3; - // color - colors[index++] = color; - - // increment the batchsize - this.sprites[this.currentBatchSize++] = tilingSprite; -}; - -/** - * Renders the content and empties the current batch. - * - */ -WebGLSpriteBatch.prototype.flush = function () { - // If the batch is length 0 then return as there is nothing to draw - if (this.currentBatchSize === 0) { - return; - } - - var gl = this.renderer.gl; - var shader; - - if (this.dirty) { - this.dirty = false; - // bind the main texture - gl.activeTexture(gl.TEXTURE0); - - // bind the buffers - gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - // this is the same for each shader? - var stride = this.vertSize * 4; - gl.vertexAttribPointer(this.shader.attributes.aVertexPosition, 2, gl.FLOAT, false, stride, 0); - gl.vertexAttribPointer(this.shader.attributes.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4); - - // color attributes will be interpreted as unsigned bytes and normalized - gl.vertexAttribPointer(this.shader.attributes.aColor, 4, gl.UNSIGNED_BYTE, true, stride, 4 * 4); - } - - // upload the verts to the buffer - if (this.currentBatchSize > ( this.size * 0.5 ) ) { - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); - } - else { - var view = this.positions.subarray(0, this.currentBatchSize * 4 * this.vertSize); - gl.bufferSubData(gl.ARRAY_BUFFER, 0, view); - } - - var nextTexture, nextBlendMode, nextShader; - var batchSize = 0; - var start = 0; - - var currentBaseTexture = null; - var currentBlendMode = this.renderer.blendModeManager.currentBlendMode; - var currentShader = null; - - var blendSwap = false; - var shaderSwap = false; - var sprite; - - for (var i = 0, j = this.currentBatchSize; i < j; i++) { - - sprite = this.sprites[i]; - - nextTexture = sprite.texture.baseTexture; - nextBlendMode = sprite.blendMode; - nextShader = sprite.shader || this.shader; - - blendSwap = currentBlendMode !== nextBlendMode; - shaderSwap = currentShader !== nextShader; // should I use uuidS??? - - if (currentBaseTexture !== nextTexture || blendSwap || shaderSwap) { - this.renderBatch(currentBaseTexture, batchSize, start); - - start = i; - batchSize = 0; - currentBaseTexture = nextTexture; - - if (blendSwap) { - currentBlendMode = nextBlendMode; - this.renderer.blendModeManager.setBlendMode( currentBlendMode ); - } - - if (shaderSwap) { - currentShader = nextShader; - - shader = currentShader.shaders ? currentShader.shaders[gl.id] : currentShader; - - if (!shader) { - shader = new Shader(gl, null, currentShader.fragmentSrc, currentShader.uniforms); - currentShader.shaders[gl.id] = shader; - } - - // set shader function??? - this.renderer.shaderManager.setShader(shader); - - if (shader.dirty) { - shader.syncUniforms(); - } - - // both thease only need to be set if they are changing.. - // set the projection - var projection = this.renderer.projection; - gl.uniform2f(shader.uniforms.projectionVector._location, projection.x, projection.y); - - // TODO - this is temprorary! - var offsetVector = this.renderer.offset; - gl.uniform2f(shader.uniforms.offsetVector._location, offsetVector.x, offsetVector.y); - - // set the pointers - } - } - - batchSize++; - } - - this.renderBatch(currentBaseTexture, batchSize, start); - - // then reset the batch! - this.currentBatchSize = 0; -}; - -/** - * @param texture {Texture} - * @param size {number} - * @param startIndex {number} - */ -WebGLSpriteBatch.prototype.renderBatch = function (texture, size, startIndex) { - if (size === 0) { - return; - } - - var gl = this.renderer.gl; - - if (!texture._glTextures[gl.id]) { - this.renderer.updateTexture(texture); - } - else { - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, texture._glTextures[gl.id]); - } - - // now draw those suckas! - gl.drawElements(gl.TRIANGLES, size * 6, gl.UNSIGNED_SHORT, startIndex * 6 * 2); - - // increment the draw count - this.renderer.drawCount++; -}; - -/** - * - */ -WebGLSpriteBatch.prototype.stop = function () { - this.flush(); - this.dirty = true; -}; - -/** - * - */ -WebGLSpriteBatch.prototype.start = function () { - this.dirty = true; -}; - -/** - * Destroys the SpriteBatch. - * - */ -WebGLSpriteBatch.prototype.destroy = function () { - this.renderer.gl.deleteBuffer(this.vertexBuffer); - this.renderer.gl.deleteBuffer(this.indexBuffer); - - this.vertices = null; - this.indices = null; - - this.vertexBuffer = null; - this.indexBuffer = null; - - this.currentBaseTexture = null; - - this.renderer = null; -}; - -},{"../../../textures/TextureUvs":45,"../shaders/Shader":35}],42:[function(require,module,exports){ -var utils = require('../utils'), - CONST = require('../const'); - -/** - * A texture stores the information that represents an image. All textures have a base texture. - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param source {Image|Canvas} the source object of the texture. - * @param [scaleMode=scaleModes.DEFAULT] {number} See {@link scaleModes} for possible values - */ -function BaseTexture(source, scaleMode) { - this.uuid = utils.uuid(); - - /** - * The Resolution of the texture. - * - * @member {number} - */ - this.resolution = 1; - - /** - * The width of the base texture set when the image has loaded - * - * @member {number} - * @readOnly - */ - this.width = 100; - - /** - * The height of the base texture set when the image has loaded - * - * @member {number} - * @readOnly - */ - this.height = 100; - - /** - * The scale mode to apply when scaling this texture - * - * @member {{number}} - * @default scaleModes.LINEAR - */ - this.scaleMode = scaleMode || CONST.scaleModes.DEFAULT; - - /** - * Set to true once the base texture has successfully loaded. - * - * This is never true if the underlying source fails to load or has no texture data. - * - * @member {boolean} - * @readOnly - */ - this.hasLoaded = false; - - /** - * Set to true if the source is currently loading. - * - * If an Image source is loading the 'loaded' or 'error' event will be - * dispatched when the operation ends. An underyling source that is - * immediately-available bypasses loading entirely. - * - * @member {boolean} - * @readonly - */ - this.isLoading = false; - - /** - * The image source that is used to create the texture. - * - * TODO: Make this a setter that calls loadSource(); - * - * @member {Image|Canvas} - * @readonly - */ - this.source = null; // set in loadSource, if at all - - /** - * Controls if RGB channels should be pre-multiplied by Alpha (WebGL only) - * - * @member {boolean} - * @default true - */ - this.premultipliedAlpha = true; - - /** - * @member {string} - */ - this.imageUrl = null; - - /** - * @member {boolean} - * @private - */ - this._powerOf2 = false; - - // used for webGL - - /** - * - * Set this to true if a mipmap of this texture needs to be generated. This value needs to be set before the texture is used - * Also the texture must be a power of two size to work - * - * @member {boolean} - */ - this.mipmap = false; - - /** - * A map of renderer IDs to webgl textures - * - * @member {object} - * @private - */ - this._glTextures = {}; - - /** - * Does the texture on the GPU need to be updated? - * - * @member {boolean} - * @private - */ - this._needsUpdate = false; - - // if no source passed don't try to load - if (source) { - this.loadSource(source); - } - - /** - * Fired when a not-immediately-available source finishes loading. - * - * @event loaded - * @protected - */ - - /** - * Fired when a not-immediately-available source fails to load. - * - * @event error - * @protected - */ -} - -BaseTexture.prototype.constructor = BaseTexture; -module.exports = BaseTexture; - -utils.eventTarget.mixin(BaseTexture.prototype); - -Object.defineProperties(BaseTexture.prototype, { - needsUpdate: { - get: function () { - return this._needsUpdate; - }, - set: function (val) { - this._needsUpdate = val; - - if (val) { - this.emit('update', this); - } - } - } -}); - -/** - * Load a source. - * - * If the source is not-immediately-available, such as an image that needs to be - * downloaded, then the 'loaded' or 'error' event will be dispatched in the future - * and `hasLoaded` will remain false after this call. - * - * The logic state after calling `loadSource` directly or indirectly (eg. `fromImage`, `new BaseTexture`) is: - * - * if (texture.hasLoaded) { - * // texture ready for use - * } else if (texture.isLoading) { - * // listen to 'loaded' and/or 'error' events on texture - * } else { - * // not loading, not going to load UNLESS the source is reloaded - * // (it may still make sense to listen to the events) - * } - * - * @protected - * @param source {Image|Canvas} the source object of the texture. - */ -BaseTexture.prototype.loadSource = function (source) { - var wasLoading = this.isLoading; - this.hasLoaded = false; - this.isLoading = false; - - if (wasLoading && this.source) { - this.source.onload = null; - this.source.onerror = null; - } - - this.source = source; - - // Apply source if loaded. Otherwise setup appropriate loading monitors. - if ((this.source.complete || this.source.getContext) && this.source.width && this.source.height) { - this._sourceLoaded(); - } - else if(!source.getContext) { - // Image fail / not ready - this.isLoading = true; - - var scope = this; - - source.onload = function () { - source.onload = null; - source.onerror = null; - - if(!scope.isLoading) { - return; - } - - scope.isLoading = false; - scope._sourceLoaded(); - - scope.emit('loaded', scope); - }; - - source.onerror = function () { - source.onload = null; - source.onerror = null; - - if(!scope.isLoading) { - return; - } - - scope.isLoading = false; - scope.emit('error', scope); - }; - - // Per http://www.w3.org/TR/html5/embedded-content-0.html#the-img-element - // "The value of `complete` can thus change while a script is executing." - // So complete needs to be re-checked after the callbacks have been added.. - if (source.complete) { - this.isLoading = false; - - // ..and if we're complete now, no need for callbacks - source.onload = null; - source.onerror = null; - - if (source.width && source.height) { - this._sourceLoaded(); - - // If any previous subscribers possible - if (wasLoading) { - this.emit('loaded', this); - } - } - else { - // If any previous subscribers possible - if (wasLoading) { - this.emit('error', this); - } - } - } - } -}; - -/** - * Used internally to update the width, height, and some other tracking vars once - * a source has successfully loaded. - * - * @private - */ -BaseTexture.prototype._sourceLoaded = function () { - this.hasLoaded = true; - - this.width = this.source.naturalWidth || this.source.width; - this.height = this.source.naturalHeight || this.source.height; - - this.needsUpdate = true; -}; - -/** - * Destroys this base texture - * - */ -BaseTexture.prototype.destroy = function () { - if (this.imageUrl) { - delete utils.BaseTextureCache[this.imageUrl]; - delete utils.TextureCache[this.imageUrl]; - this.imageUrl = null; - if (!navigator.isCocoonJS) { - this.source.src = ''; - } - } - else if (this.source && this.source._pixiId) { - delete utils.BaseTextureCache[this.source._pixiId]; - } - this.source = null; - - this.dispose(); -}; - -/** - * Frees the texture from WebGL memory without destroying this texture object. - * This means you can still use the texture later which will upload it to GPU - * memory again. - * - */ -BaseTexture.prototype.dispose = function () { - this.emit('dispose', this); -}; - -/** - * Changes the source image of the texture. - * The original source must be an Image element. - * - * @param newSrc {string} the path of the image - */ -BaseTexture.prototype.updateSourceImage = function (newSrc) { - this.source.src = newSrc; - this.loadSource(this.source); -}; - -/** - * Helper function that creates a base texture from the given image url. - * If the image is not in the base texture cache it will be created and loaded. - * - * @static - * @param imageUrl {string} The image url of the texture - * @param [crossorigin=(auto)] {boolean} Should use anonymouse CORS? Defaults to true if the URL is not a data-URI. - * @param [scaleMode=scaleModes.DEFAULT] {number} See {@link scaleModes} for possible values - * @return BaseTexture - */ -BaseTexture.fromImage = function (imageUrl, crossorigin, scaleMode) { - var baseTexture = utils.BaseTextureCache[imageUrl]; - - if (crossorigin === undefined && imageUrl.indexOf('data:') !== 0) { - crossorigin = true; - } - - if (!baseTexture) { - // new Image() breaks tex loading in some versions of Chrome. - // See https://code.google.com/p/chromium/issues/detail?id=238071 - var image = new Image();//document.createElement('img'); - if (crossorigin) { - image.crossOrigin = ''; - } - - image.src = imageUrl; - baseTexture = new BaseTexture(image, scaleMode); - baseTexture.imageUrl = imageUrl; - utils.BaseTextureCache[imageUrl] = baseTexture; - - // if there is an @2x at the end of the url we are going to assume its a highres image - if ( imageUrl.indexOf(CONST.RETINA_PREFIX + '.') !== -1) { - baseTexture.resolution = 2; - } - } - - return baseTexture; -}; - -/** - * Helper function that creates a base texture from the given canvas element. - * - * @static - * @param canvas {Canvas} The canvas element source of the texture - * @param scaleMode {number} See {{#crossLink "PIXI/scaleModes:property"}}scaleModes{{/crossLink}} for possible values - * @return BaseTexture - */ -BaseTexture.fromCanvas = function (canvas, scaleMode) { - if (!canvas._pixiId) { - canvas._pixiId = 'canvas_' + utils.uuid(); - } - - var baseTexture = utils.BaseTextureCache[canvas._pixiId]; - - if (!baseTexture) { - baseTexture = new BaseTexture(canvas, scaleMode); - utils.BaseTextureCache[canvas._pixiId] = baseTexture; - } - - return baseTexture; -}; - -},{"../const":4,"../utils":50}],43:[function(require,module,exports){ -var BaseTexture = require('./BaseTexture'), - Texture = require('./Texture'), - FilterTexture = require('../renderers/webgl/utils/FilterTexture'), - CanvasBuffer = require('../renderers/canvas/utils/CanvasBuffer'), - math = require('../math'), - CONST = require('../const'); - -/** - * A RenderTexture is a special texture that allows any Pixi display object to be rendered to it. - * - * __Hint__: All DisplayObjects (i.e. Sprites) that render to a RenderTexture should be preloaded - * otherwise black rectangles will be drawn instead. - * - * A RenderTexture takes a snapshot of any Display Object given to its render method. The position - * and rotation of the given Display Objects is ignored. For example: - * - * ```js - * var renderTexture = new PIXI.RenderTexture(800, 600); - * var sprite = PIXI.Sprite.fromImage("spinObj_01.png"); - * - * sprite.position.x = 800/2; - * sprite.position.y = 600/2; - * sprite.anchor.x = 0.5; - * sprite.anchor.y = 0.5; - * - * renderTexture.render(sprite); - * ``` - * - * The Sprite in this case will be rendered to a position of 0,0. To render this sprite at its actual - * position a DisplayObjectContainer should be used: - * - * ```js - * var doc = new DisplayObjectContainer(); - * - * doc.addChild(sprite); - * - * renderTexture.render(doc); // Renders to center of renderTexture - * ``` - * - * @class - * @extends Texture - * @namespace PIXI - * @param renderer {CanvasRenderer|WebGLRenderer} The renderer used for this RenderTexture - * @param [width=100] {number} The width of the render texture - * @param [height=100] {number} The height of the render texture - * @param [scaleMode] {number} See {@link scaleModes} for possible values - * @param [resolution=1] {number} The resolution of the texture being generated - */ -function RenderTexture(renderer, width, height, scaleMode, resolution) { - if (!renderer) { - throw new Error('Unable to create RenderTexture, you must pass a renderer into the constructor.'); - } - - /** - * The with of the render texture - * - * @member {number} - */ - this.width = width || 100; - - /** - * The height of the render texture - * - * @member {number} - */ - this.height = height || 100; - - /** - * The Resolution of the texture. - * - * @member {number} - */ - this.resolution = resolution || 1; - - /** - * The framing rectangle of the render texture - * - * @member {Rectangle} - */ - this.frame = new math.Rectangle(0, 0, this.width * this.resolution, this.height * this.resolution); - - /** - * This is the area of the BaseTexture image to actually copy to the Canvas / WebGL when rendering, - * irrespective of the actual frame size or placement (which can be influenced by trimmed texture atlases) - * - * @member {Rectangle} - */ - this.crop = new math.Rectangle(0, 0, this.width * this.resolution, this.height * this.resolution); - - /** - * Draw/render the given DisplayObject onto the texture. - * - * The displayObject and descendents are transformed during this operation. - * If `restoreWorldTransform` is true then the transformations will be restored before the - * method returns. Otherwise it is up to the calling code to correctly use or reset - * the transformed display objects. - * - * The display object is always rendered with a worldAlpha value of 1. - * - * @method - * @param displayObject {DisplayObject} The display object to render this texture on - * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering. - * @param [clear=false] {boolean} If true the texture will be cleared before the displayObject is drawn - * @param [restoreWorldTransform=true] {boolean} If true the displayObject's worldTransform/worldAlpha and all children - * transformations will be restored. Not restoring this information will be a little faster. - */ - this.render = null; - - /** - * The base texture object that this texture uses - * - * @member {BaseTexture} - */ - this.baseTexture = new BaseTexture(); - this.baseTexture.width = this.width * this.resolution; - this.baseTexture.height = this.height * this.resolution; - this.baseTexture._glTextures = []; - this.baseTexture.resolution = this.resolution; - - this.baseTexture.scaleMode = scaleMode || CONST.scaleModes.DEFAULT; - - this.baseTexture.hasLoaded = true; - - Texture.call(this, - this.baseTexture, - new math.Rectangle(0, 0, this.width, this.height) - ); - - /** - * The renderer this RenderTexture uses. A RenderTexture can only belong to one renderer at the moment if its webGL. - * - * @member {CanvasRenderer|WebGLRenderer} - */ - this.renderer = renderer; - - if (this.renderer.type === CONST.WEBGL_RENDERER) { - var gl = this.renderer.gl; - - this.textureBuffer = new FilterTexture(gl, this.width * this.resolution, this.height * this.resolution, this.baseTexture.scaleMode); - this.baseTexture._glTextures[gl.id] = this.textureBuffer.texture; - - this.render = this.renderWebGL; - this.projection = new math.Point(this.width*0.5, -this.height*0.5); - } - else { - this.render = this.renderCanvas; - this.textureBuffer = new CanvasBuffer(this.width* this.resolution, this.height* this.resolution); - this.baseTexture.source = this.textureBuffer.canvas; - } - - /** - * @member {boolean} - */ - this.valid = true; - - this._updateUvs(); -} - -RenderTexture.prototype = Object.create(Texture.prototype); -RenderTexture.prototype.constructor = RenderTexture; -module.exports = RenderTexture; - -/** - * Resizes the RenderTexture. - * - * @param width {number} The width to resize to. - * @param height {number} The height to resize to. - * @param updateBase {boolean} Should the baseTexture.width and height values be resized as well? - */ -RenderTexture.prototype.resize = function (width, height, updateBase) { - if (width === this.width && height === this.height) { - return; - } - - this.valid = (width > 0 && height > 0); - - this.width = this.frame.width = this.crop.width = width; - this.height = this.frame.height = this.crop.height = height; - - if (updateBase) { - this.baseTexture.width = this.width; - this.baseTexture.height = this.height; - } - - if (this.renderer.type === CONST.WEBGL_RENDERER) { - this.projection.x = this.width / 2; - this.projection.y = -this.height / 2; - } - - if (!this.valid) { - return; - } - - this.textureBuffer.resize(this.width * this.resolution, this.height * this.resolution); -}; - -/** - * Clears the RenderTexture. - * - */ -RenderTexture.prototype.clear = function () { - if (!this.valid) { - return; - } - - if (this.renderer.type === CONST.WEBGL_RENDERER) { - this.renderer.gl.bindFramebuffer(this.renderer.gl.FRAMEBUFFER, this.textureBuffer.frameBuffer); - } - - this.textureBuffer.clear(); -}; - -/** - * Internal method assigned to the `render` property if using a CanvasRenderer. - * - * @private - * @param displayObject {DisplayObject} The display object to render this texture on - * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering. - * @param [clear=false] {boolean} If true the texture will be cleared before the displayObject is drawn - * @param [restoreWorldTransform=true] {boolean} If true the displayObject's worldTransform/worldAlpha and all children - * transformations will be restored. Not restoring this information will be a little faster. - */ -RenderTexture.prototype.renderWebGL = function (displayObject, matrix, clear, restoreWorldTransform) { - if (!this.valid) { - return; - } - - if (typeof restoreWorldTransform === 'undefined') { - restoreWorldTransform = true; - } - - var tempAlpha, - tempTransform; - - if (restoreWorldTransform) { - tempAlpha = displayObject.worldAlpha; - tempTransform = displayObject.worldTransform.toArray(); - } - - //TOOD replace position with matrix.. - - //Lets create a nice matrix to apply to our display object. Frame buffers come in upside down so we need to flip the matrix - var wt = displayObject.worldTransform; - - wt.identity(); - wt.translate(0, this.projection.y * 2); - - if (matrix) { - wt.append(matrix); - } - - wt.scale(1,-1); - - // setWorld Alpha to ensure that the object is renderer at full opacity - displayObject.worldAlpha = 1; - - // Time to update all the children of the displayObject with the new matrix.. - var children = displayObject.children; - var i, j; - - for (i = 0, j = children.length; i < j; ++i) { - children[i].updateTransform(); - } - - // time for the webGL fun stuff! - var gl = this.renderer.gl; - - gl.viewport(0, 0, this.width * this.resolution, this.height * this.resolution); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.textureBuffer.frameBuffer ); - - if (clear) { - this.textureBuffer.clear(); - } - - this.renderer.spriteBatch.dirty = true; - - this.renderer.renderDisplayObject(displayObject, this.projection, this.textureBuffer.frameBuffer); - - this.renderer.spriteBatch.dirty = true; - - if (restoreWorldTransform) { - displayObject.worldAlpha = tempAlpha; - displayObject.worldTransform.fromArray(tempTransform); - - for (i = 0, j = children.length; i < j; ++i) { - children[i].updateTransform(); - } - } -}; - - -/** - * Internal method assigned to the `render` property if using a CanvasRenderer. - * - * @private - * @param displayObject {DisplayObject} The display object to render this texture on - * @param [matrix] {Matrix} Optional matrix to apply to the display object before rendering. - * @param [clear] {boolean} If true the texture will be cleared before the displayObject is drawn - * @param [restoreWorldTransform=true] {boolean} If true the displayObject's worldTransform/worldAlpha and all children - * transformations will be restored. Not restoring this information will be a little faster. - */ -RenderTexture.prototype.renderCanvas = function (displayObject, matrix, clear, restoreWorldTransform) { - if (!this.valid) { - return; - } - - if (typeof restoreWorldTransform === 'undefined') { - restoreWorldTransform = true; - } - - var tempAlpha, - tempTransform; - - if (restoreWorldTransform) { - tempAlpha = displayObject.worldAlpha; - tempTransform = displayObject.worldTransform.toArray(); - } - - var wt = displayObject.worldTransform; - wt.identity(); - if (matrix) { - wt.append(matrix); - } - - // setWorld Alpha to ensure that the object is renderer at full opacity - displayObject.worldAlpha = 1; - - // Time to update all the children of the displayObject with the new matrix.. - var children = displayObject.children; - var i, j; - - for (i = 0, j = children.length; i < j; ++i) { - children[i].updateTransform(); - } - - if (clear) { - this.textureBuffer.clear(); - } - - var context = this.textureBuffer.context; - - var realResolution = this.renderer.resolution; - - this.renderer.resolution = this.resolution; - - this.renderer.renderDisplayObject(displayObject, context); - - this.renderer.resolution = realResolution; - - if (restoreWorldTransform) { - displayObject.worldAlpha = tempAlpha; - displayObject.worldTransform.fromArray(tempTransform); - - for (i = 0, j = children.length; i < j; ++i) { - children[i].updateTransform(); - } - } -}; - -/** - * Will return a HTML Image of the texture - * - * @return {Image} - */ -RenderTexture.prototype.getImage = function () { - var image = new Image(); - image.src = this.getBase64(); - return image; -}; - -/** - * Will return a a base64 encoded string of this texture. It works by calling RenderTexture.getCanvas and then running toDataURL on that. - * - * @return {string} A base64 encoded string of the texture. - */ -RenderTexture.prototype.getBase64 = function () { - return this.getCanvas().toDataURL(); -}; - -/** - * Creates a Canvas element, renders this RenderTexture to it and then returns it. - * - * @return {HTMLCanvasElement} A Canvas element with the texture rendered on. - */ -RenderTexture.prototype.getCanvas = function () { - if (this.renderer.type === CONST.WEBGL_RENDERER) { - var gl = this.renderer.gl; - var width = this.textureBuffer.width; - var height = this.textureBuffer.height; - - var webGLPixels = new Uint8Array(4 * width * height); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.textureBuffer.frameBuffer); - gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, webGLPixels); - gl.bindFramebuffer(gl.FRAMEBUFFER, null); - - var tempCanvas = new CanvasBuffer(width, height); - var canvasData = tempCanvas.context.getImageData(0, 0, width, height); - canvasData.data.set(webGLPixels); - - tempCanvas.context.putImageData(canvasData, 0, 0); - - return tempCanvas.canvas; - } - else { - return this.textureBuffer.canvas; - } -}; - -},{"../const":4,"../math":12,"../renderers/canvas/utils/CanvasBuffer":21,"../renderers/webgl/utils/FilterTexture":37,"./BaseTexture":42,"./Texture":44}],44:[function(require,module,exports){ -var BaseTexture = require('./BaseTexture'), - VideoBaseTexture = require('./VideoBaseTexture'), - TextureUvs = require('./TextureUvs'), - eventTarget = require('../utils/eventTarget'), - math = require('../math'), - utils = require('../utils'); - -/** - * A texture stores the information that represents an image or part of an image. It cannot be added - * to the display list directly. Instead use it as the texture for a Sprite. If no frame is provided then the whole image is used. - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param baseTexture {BaseTexture} The base texture source to create the texture from - * @param [frame] {Rectangle} The rectangle frame of the texture to show - * @param [crop] {Rectangle} The area of original texture - * @param [trim] {Rectangle} Trimmed texture rectangle - */ -function Texture(baseTexture, frame, crop, trim) { - /** - * Does this Texture have any frame data assigned to it? - * - * @member {boolean} - */ - this.noFrame = false; - - if (!frame) { - this.noFrame = true; - frame = new math.Rectangle(0, 0, 1, 1); - } - - if (baseTexture instanceof Texture) { - baseTexture = baseTexture.baseTexture; - } - - /** - * The base texture that this texture uses. - * - * @member {BaseTexture} - */ - this.baseTexture = baseTexture; - - /** - * The frame specifies the region of the base texture that this texture uses - * - * @member {Rectangle} - * @private - */ - this._frame = frame; - - /** - * The texture trim data. - * - * @member {Rectangle} - */ - this.trim = trim; - - /** - * This will let the renderer know if the texture is valid. If it's not then it cannot be rendered. - * - * @member {boolean} - */ - this.valid = false; - - /** - * This will let a renderer know that a texture has been updated (used mainly for webGL uv updates) - * - * @member {boolean} - */ - this.requiresUpdate = false; - - /** - * The WebGL UV data cache. - * - * @member {object} - * @private - */ - this._uvs = null; - - /** - * The width of the Texture in pixels. - * - * @member {number} - */ - this.width = 0; - - /** - * The height of the Texture in pixels. - * - * @member {number} - */ - this.height = 0; - - /** - * This is the area of the BaseTexture image to actually copy to the Canvas / WebGL when rendering, - * irrespective of the actual frame size or placement (which can be influenced by trimmed texture atlases) - * - * @member {Rectangle} - */ - this.crop = crop || new math.Rectangle(0, 0, 1, 1); - - if (baseTexture.hasLoaded) { - if (this.noFrame) { - frame = new math.Rectangle(0, 0, baseTexture.width, baseTexture.height); - } - this.frame = frame; - } - else { - baseTexture.addEventListener('loaded', this.onBaseTextureLoaded.bind(this)); - } -} - -Texture.prototype.constructor = Texture; -module.exports = Texture; - -eventTarget.mixin(Texture.prototype); - -Object.defineProperties(Texture.prototype, { - needsUpdate: { - get: function () { - return this.baseTexture.needsUpdate; - }, - set: function (val) { - this.baseTexture.needsUpdate = val; - } - }, - - frame: { - get: function () { - return this._frame; - }, - set: function (frame) { - this._frame = frame; - - this.noFrame = false; - - this.width = frame.width; - this.height = frame.height; - - this.crop.x = frame.x; - this.crop.y = frame.y; - this.crop.width = frame.width; - this.crop.height = frame.height; - - if (!this.trim && (frame.x + frame.width > this.baseTexture.width || frame.y + frame.height > this.baseTexture.height)) { - throw new Error('Texture Error: frame does not fit inside the base Texture dimensions ' + this); - } - - this.valid = frame && frame.width && frame.height && this.baseTexture.source && this.baseTexture.hasLoaded; - - if (this.trim) { - this.width = this.trim.width; - this.height = this.trim.height; - this._frame.width = this.trim.width; - this._frame.height = this.trim.height; - } - - if (this.valid) { - this._updateUvs(); - } - } - } -}); - -/** - * Called when the base texture is loaded - * - * @private - */ -Texture.prototype.onBaseTextureLoaded = function () { - var baseTexture = this.baseTexture; - baseTexture.removeEventListener('loaded', this.onLoaded); - - if (this.noFrame) { - this.frame = new math.Rectangle(0, 0, baseTexture.width, baseTexture.height); - } - - this.dispatchEvent( { type: 'update', content: this } ); -}; - -/** - * Destroys this texture - * - * @param destroyBase {boolean} Whether to destroy the base texture as well - */ -Texture.prototype.destroy = function (destroyBase) { - if (destroyBase) { - this.baseTexture.destroy(); - } - - this.valid = false; -}; - -/** - * Updates the internal WebGL UV cache. - * - * @private - */ -Texture.prototype._updateUvs = function () { - if (!this._uvs) { - this._uvs = new TextureUvs(); - } - - var frame = this.crop; - var tw = this.baseTexture.width; - var th = this.baseTexture.height; - - this._uvs.x0 = frame.x / tw; - this._uvs.y0 = frame.y / th; - - this._uvs.x1 = (frame.x + frame.width) / tw; - this._uvs.y1 = frame.y / th; - - this._uvs.x2 = (frame.x + frame.width) / tw; - this._uvs.y2 = (frame.y + frame.height) / th; - - this._uvs.x3 = frame.x / tw; - this._uvs.y3 = (frame.y + frame.height) / th; -}; - -/** - * Helper function that creates a Texture object from the given image url. - * If the image is not in the texture cache it will be created and loaded. - * - * @static - * @param imageUrl {string} The image url of the texture - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - * @param scaleMode {number} See {{#crossLink "PIXI/scaleModes:property"}}scaleModes{{/crossLink}} for possible values - * @return Texture - */ -Texture.fromImage = function (imageUrl, crossorigin, scaleMode) { - var texture = utils.TextureCache[imageUrl]; - - if (!texture) { - texture = new Texture(BaseTexture.fromImage(imageUrl, crossorigin, scaleMode)); - utils.TextureCache[imageUrl] = texture; - } - - return texture; -}; - -/** - * Helper function that returns a Texture objected based on the given frame id. - * If the frame id is not in the texture cache an error will be thrown. - * - * @static - * @param frameId {string} The frame id of the texture - * @return Texture - */ -Texture.fromFrame = function (frameId) { - var texture = utils.TextureCache[frameId]; - if (!texture) { - throw new Error('The frameId "' + frameId + '" does not exist in the texture cache '); - } - return texture; -}; - -/** - * Helper function that creates a new Texture based on the given canvas element. - * - * @static - * @param canvas {Canvas} The canvas element source of the texture - * @param scaleMode {number} See {{#crossLink "PIXI/scaleModes:property"}}scaleModes{{/crossLink}} for possible values - * @return {Texture} - */ -Texture.fromCanvas = function (canvas, scaleMode) { - return new Texture(BaseTexture.fromCanvas(canvas, scaleMode)); -}; - -/** - * Helper function that creates a new Texture based on the given video element. - * - * @static - * @param video {HTMLVideoElement} - * @param scaleMode {number} See {{#crossLink "PIXI/scaleModes:property"}}scaleModes{{/crossLink}} for possible values - * @return {Texture} A Texture - */ -Texture.fromVideo = function (video, scaleMode) { - return new Texture(VideoBaseTexture.baseTextureFromVideo(video, scaleMode)); -}; - -/** - * Adds a texture to the global utils.TextureCache. This cache is shared across the whole PIXI object. - * - * @static - * @param texture {Texture} The Texture to add to the cache. - * @param id {string} The id that the texture will be stored against. - */ -Texture.addTextureToCache = function (texture, id) { - utils.TextureCache[id] = texture; -}; - -/** - * Remove a texture from the global utils.TextureCache. - * - * @static - * @param id {string} The id of the texture to be removed - * @return {Texture} The texture that was removed - */ -Texture.removeTextureFromCache = function (id) { - var texture = utils.TextureCache[id]; - - delete utils.TextureCache[id]; - delete utils.BaseTextureCache[id]; - - return texture; -}; - -Texture.emptyTexture = new Texture(new BaseTexture()); - -},{"../math":12,"../utils":50,"../utils/eventTarget":49,"./BaseTexture":42,"./TextureUvs":45,"./VideoBaseTexture":46}],45:[function(require,module,exports){ -function TextureUvs() { - this.x0 = 0; - this.y0 = 0; - - this.x1 = 0; - this.y1 = 0; - - this.x2 = 0; - this.y2 = 0; - - this.x3 = 0; - this.y3 = 0; -} - -module.exports = TextureUvs; - -},{}],46:[function(require,module,exports){ -var BaseTexture = require('./BaseTexture'), - utils = require('../utils'); - -/** - * A texture of a [playing] Video. - * - * See the ["deus" demo](http://www.goodboydigital.com/pixijs/examples/deus/). - * - * @class - * @extends BaseTexture - * @namespace PIXI - * @param source {HTMLVideoElement} - * @param [scaleMode] {number} See {@link scaleModes} for possible values - */ -function VideoBaseTexture(source, scaleMode) { - if (!source){ - throw new Error('No video source element specified.'); - } - - // hook in here to check if video is already available. - // BaseTexture looks for a source.complete boolean, plus width & height. - - if ((source.readyState === source.HAVE_ENOUGH_DATA || source.readyState === source.HAVE_FUTURE_DATA) && source.width && source.height) { - source.complete = true; - } - - BaseTexture.call(this, source, scaleMode); - - this.autoUpdate = false; - - this._boundOnUpdate = this._onUpdate.bind(this); - this._boundOnCanPlay = this._onCanPlay.bind(this); - - if (!source.complete) { - source.addEventListener('canplay', this._boundOnCanPlay); - source.addEventListener('canplaythrough', this._boundOnCanPlay); - - // started playing.. - source.addEventListener('play', this._onPlayStart.bind(this)); - source.addEventListener('pause', this._onPlayStop.bind(this)); - } - - this.__loaded = false; -} - -VideoBaseTexture.prototype = Object.create(BaseTexture.prototype); -VideoBaseTexture.prototype.constructor = VideoBaseTexture; -module.exports = VideoBaseTexture; - -VideoBaseTexture.prototype._onUpdate = function () { - if (this.autoUpdate) { - window.requestAnimationFrame(this._boundOnUpdate); - this.needsUpdate = true; - } -}; - -VideoBaseTexture.prototype._onPlayStart = function () { - if (!this.autoUpdate) { - window.requestAnimationFrame(this._boundOnUpdate); - this.autoUpdate = true; - } -}; - -VideoBaseTexture.prototype._onPlayStop = function () { - this.autoUpdate = false; -}; - -VideoBaseTexture.prototype._onCanPlay = function () { - this.hasLoaded = true; - - if (this.source) { - this.source.removeEventListener('canplay', this._boundOnCanPlay); - this.source.removeEventListener('canplaythrough', this._boundOnCanPlay); - - this.width = this.source.videoWidth; - this.height = this.source.videoHeight; - - this.source.play(); - - // prevent multiple loaded dispatches.. - if(!this.__loaded){ - this.__loaded = true; - this.emit('loaded', this); - } - } -}; - -VideoBaseTexture.prototype.destroy = function () { - if (this.source && this.source._pixiId) { - utils.BaseTextureCache[ this.source._pixiId ] = null; - delete utils.BaseTextureCache[ this.source._pixiId ]; - - this.source._pixiId = null; - delete this.source._pixiId; - } - - BaseTexture.prototype.destroy.call(this); -}; - -/** - * Mimic Pixi BaseTexture.from.... method. - * - * @static - * @param video {HTMLVideoElement} - * @param scaleMode {number} See {@link scaleModes} for possible values - * @return {VideoBaseTexture} - */ -VideoBaseTexture.fromVideo = function (video, scaleMode) { - if (!video._pixiId) { - video._pixiId = 'video_' + utils.uuid(); - } - - var baseTexture = utils.BaseTextureCache[video._pixiId]; - - if (!baseTexture) { - baseTexture = new VideoBaseTexture(video, scaleMode); - utils.BaseTextureCache[ video._pixiId ] = baseTexture; - } - - return baseTexture; -}; - -/** - * Mimic Pixi BaseTexture.from.... method. - * - * This can be used in a couple ways, such as: - * - * ```js - * var texture = PIXI.VideoBaseTexture.fromUrl('http://mydomain.com/video.mp4'); - * - * var texture = PIXI.VideoBaseTexture.fromUrl({ src: 'http://mydomain.com/video.mp4', mime: 'video/mp4' }); - * - * var texture = PIXI.VideoBaseTexture.fromUrls(['/video.webm', '/video.mp4']); - * - * var texture = PIXI.VideoBaseTexture.fromUrls([ - * { src: '/video.webm', mime: 'video/webm' }, - * { src: '/video.mp4', mime: 'video/mp4' } - * ]); - * ``` - * - * @alias fromUrls - * @static - * @param videoSrc {string|object|string[]|object[]} The URL(s) for the video. - * @param [videoSrc.src] {string} One of the source urls for the video - * @param [videoSrc.mime] {string} The mimetype of the video (e.g. 'video/mp4'). If not specified - * the url's extension will be used as the second part of the mime type. - * @param scaleMode {number} See {@link scaleModes} for possible values - * @return {VideoBaseTexture} - */ -VideoBaseTexture.fromUrl = function (videoSrc, scaleMode) { - var video = document.createElement('video'); - - // array of objects or strings - if (Array.isArray(videoSrc)) { - for (var i = 0; i < videoSrc.length; ++i) { - video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime)); - } - } - // single object or string - else { - video.appendChild(createSource(videoSrc.src || videoSrc, videoSrc.mime)); - } - - video.load(); - video.play(); - - return VideoBaseTexture.textureFromVideo(video, scaleMode); -}; - -VideoBaseTexture.fromUrls = VideoBaseTexture.fromUrl; - -function createSource(path, type) { - if (!type) { - type = 'video/' + path.substr(path.lastIndexOf('.') + 1); - } - - var source = document.createElement('source'); - - source.src = path; - source.type = type; - - return source; -} - -},{"../utils":50,"./BaseTexture":42}],47:[function(require,module,exports){ -/** - * Creates an homogenous object for tracking events so users can know what to expect. - * - * @class - * @namespace PIXI - * @param target {object} The target object that the event is called on - * @param name {string} The string name of the event that was triggered - * @param data {object} Arbitrary event data to pass along - */ -function EventData(target, name, data) { - // for duck typing in the ".on()" function - this.__isEventObject = true; - - /** - * Tracks the state of bubbling propagation. Do not - * set this directly, instead use `event.stopPropagation()` - * - * @member {boolean} - * @private - * @readonly - */ - this.stopped = false; - - /** - * Tracks the state of sibling listener propagation. Do not - * set this directly, instead use `event.stopImmediatePropagation()` - * - * @member {boolean} - * @private - * @readonly - */ - this.stoppedImmediate = false; - - /** - * The original target the event triggered on. - * - * @member {object} - * @readonly - */ - this.target = target; - - /** - * The string name of the event that this represents. - * - * @member {string} - * @readonly - */ - this.type = name; - - /** - * The data that was passed in with this event. - * - * @member {object} - * @readonly - */ - this.data = data; - - /** - * The timestamp when the event occurred. - * - * @member {number} - * @readonly - */ - this.timeStamp = Date.now(); -} - -EventData.prototype.constructor = EventData; -module.exports = EventData; - -/** - * Stops the propagation of events up the scene graph (prevents bubbling). - * - */ -EventData.prototype.stopPropagation = function stopPropagation() { - this.stopped = true; -}; - -/** - * Stops the propagation of events to sibling listeners (no longer calls any listeners). - * - */ -EventData.prototype.stopImmediatePropagation = function stopImmediatePropagation() { - this.stoppedImmediate = true; -}; - -},{}],48:[function(require,module,exports){ -//TODO: Have Graphics use https://github.com/mattdesl/shape2d -// and https://github.com/mattdesl/shape2d-triangulate instead of custom code. - -/* - PolyK library - url: http://polyk.ivank.net - Released under MIT licence. - - Copyright (c) 2012 Ivan Kuckir - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - This is an amazing lib! - - Slightly modified by Mat Groves (matgroves.com); -*/ - -/** - * Based on the Polyk library http://polyk.ivank.net released under MIT licence. - * This is an amazing lib! - * Slightly modified by Mat Groves (matgroves.com); - * - * @namespace PIXI - */ -var PolyK = module.exports = {}; - -/** - * Triangulates shapes for webGL graphic fills. - * - */ -PolyK.Triangulate = function (p) { - var sign = true; - - var n = p.length >> 1; - if (n < 3) return []; - - var tgs = []; - var avl = []; - for (var i = 0; i < n; i++) avl.push(i); - - i = 0; - var al = n; - while(al > 3) { - var i0 = avl[(i+0)%al]; - var i1 = avl[(i+1)%al]; - var i2 = avl[(i+2)%al]; - - var ax = p[2*i0], ay = p[2*i0+1]; - var bx = p[2*i1], by = p[2*i1+1]; - var cx = p[2*i2], cy = p[2*i2+1]; - - var earFound = false; - if (PolyK._convex(ax, ay, bx, by, cx, cy, sign)) { - earFound = true; - for (var j = 0; j < al; j++) { - var vi = avl[j]; - if (vi === i0 || vi === i1 || vi === i2) continue; - - if (PolyK._PointInTriangle(p[2*vi], p[2*vi+1], ax, ay, bx, by, cx, cy)) { - earFound = false; - break; - } - } - } - - if (earFound) { - tgs.push(i0, i1, i2); - avl.splice((i+1)%al, 1); - al--; - i = 0; - } - else if (i++ > 3*al) { - // need to flip flip reverse it! - // reset! - if (sign) { - tgs = []; - avl = []; - for (i = 0; i < n; i++) avl.push(i); - - i = 0; - al = n; - - sign = false; - } - else { - // window.console.log("PIXI Warning: shape too complex to fill"); - return null; - } - } - } - - tgs.push(avl[0], avl[1], avl[2]); - return tgs; -}; - -/** - * Checks whether a point is within a triangle - * - * @param px {number} x coordinate of the point to test - * @param py {number} y coordinate of the point to test - * @param ax {number} x coordinate of the a point of the triangle - * @param ay {number} y coordinate of the a point of the triangle - * @param bx {number} x coordinate of the b point of the triangle - * @param by {number} y coordinate of the b point of the triangle - * @param cx {number} x coordinate of the c point of the triangle - * @param cy {number} y coordinate of the c point of the triangle - * @private - * @return {boolean} - */ -PolyK._PointInTriangle = function (px, py, ax, ay, bx, by, cx, cy) { - var v0x = cx-ax; - var v0y = cy-ay; - var v1x = bx-ax; - var v1y = by-ay; - var v2x = px-ax; - var v2y = py-ay; - - var dot00 = v0x*v0x+v0y*v0y; - var dot01 = v0x*v1x+v0y*v1y; - var dot02 = v0x*v2x+v0y*v2y; - var dot11 = v1x*v1x+v1y*v1y; - var dot12 = v1x*v2x+v1y*v2y; - - var invDenom = 1 / (dot00 * dot11 - dot01 * dot01); - var u = (dot11 * dot02 - dot01 * dot12) * invDenom; - var v = (dot00 * dot12 - dot01 * dot02) * invDenom; - - // Check if point is in triangle - return (u >= 0) && (v >= 0) && (u + v < 1); -}; - -/** - * Checks whether a shape is convex - * - * @private - * @return {boolean} - */ -PolyK._convex = function (ax, ay, bx, by, cx, cy, sign) { - return ((ay-by)*(cx-bx) + (bx-ax)*(cy-by) >= 0) === sign; -}; - -},{}],49:[function(require,module,exports){ -var EventData = require('./EventData'); - -/** - * Mixins event emitter functionality to an object. - * - * @mixin - * @namespace PIXI - * @example - * function MyEmitter() {} - * - * eventTarget.mixin(MyEmitter.prototype); - * - * var em = new MyEmitter(); - * em.emit('eventName', 'some data', 'some more data', {}, null, ...); - */ -function eventTarget(obj) { - /** - * Return a list of assigned event listeners. - * - * @param eventName {string} The events that should be listed. - * @return {Array} An array of listener functions - */ - obj.listeners = function listeners(eventName) { - this._listeners = this._listeners || {}; - - return this._listeners[eventName] ? this._listeners[eventName].slice() : []; - }; - - /** - * Emit an event to all registered event listeners. - * - * @alias dispatchEvent - * @param eventName {string} The name of the event. - * @return {boolean} Indication if we've emitted an event. - */ - obj.emit = obj.dispatchEvent = function emit(eventName, data) { - this._listeners = this._listeners || {}; - - // fast return when there are no listeners - if (!this._listeners[eventName]) { - return; - } - - //backwards compat with old method ".emit({ type: 'something' })" - if (typeof eventName === 'object') { - data = eventName; - eventName = eventName.type; - } - - //ensure we are using a real pixi event - if (!data || data.__isEventObject !== true) { - data = new EventData(this, eventName, data); - } - - //iterate the listeners - var listeners = this._listeners[eventName].slice(0), - length = listeners.length, - fn = listeners[0], - i; - - for (i = 0; i < length; fn = listeners[++i]) { - //call the event listener - fn.call(this, data); - - //if "stopImmediatePropagation" is called, stop calling sibling events - if (data.stoppedImmediate) { - return this; - } - } - - //if "stopPropagation" is called then don't bubble the event - if (data.stopped) { - return this; - } - - //bubble this event up the scene graph - if (this.parent && this.parent.emit) { - this.parent.emit.call(this.parent, eventName, data); - } - - return this; - }; - - /** - * Register a new EventListener for the given event. - * - * @alias addEventListener - * @param eventName {string} Name of the event. - * @param callback {Functon} fn Callback function. - */ - obj.on = obj.addEventListener = function on(eventName, fn) { - this._listeners = this._listeners || {}; - - (this._listeners[eventName] = this._listeners[eventName] || []) - .push(fn); - - return this; - }; - - /** - * Add an EventListener that's only called once. - * - * @param eventName {string} Name of the event. - * @param callback {Function} Callback function. - */ - obj.once = function once(eventName, fn) { - this._listeners = this._listeners || {}; - - var self = this; - function onceHandlerWrapper() { - fn.apply(self.off(eventName, onceHandlerWrapper), arguments); - } - onceHandlerWrapper._originalHandler = fn; - - return this.on(eventName, onceHandlerWrapper); - }; - - /** - * Remove event listeners. - * - * @alias removeEventListener - * @param eventName {string} The event we want to remove. - * @param callback {Function} The listener that we need to find. - */ - obj.off = obj.removeEventListener = function off(eventName, fn) { - this._listeners = this._listeners || {}; - - if (!this._listeners[eventName]) { - return this; - } - - var list = this._listeners[eventName], - i = fn ? list.length : 0; - - while(i-- > 0) { - if (list[i] === fn || list[i]._originalHandler === fn) { - list.splice(i, 1); - } - } - - if (list.length === 0) { - delete this._listeners[eventName]; - } - - return this; - }; - - /** - * Remove all listeners or only the listeners for the specified event. - * - * @param eventName {string} The event you want to remove all listeners for. - */ - obj.removeAllListeners = function removeAllListeners(eventName) { - this._listeners = this._listeners || {}; - - if (!this._listeners[eventName]) { - return this; - } - - delete this._listeners[eventName]; - - return this; - }; -} - -module.exports = { - /** - * Mixes in the properties of the eventTarget prototype onto another object - * - * @param object {object} The obj to mix into - */ - mixin: function mixin(obj) { - eventTarget(obj); - } -}; - -},{"./EventData":47}],50:[function(require,module,exports){ -var CONST = require('../const'); - -/** - * @namespace PIXI - */ -var utils = module.exports = { - _uid: 0, - _saidHello: false, - - PolyK: require('./PolyK'), - EventData: require('./EventData'), - eventTarget: require('./eventTarget'), - - /** - * Gets the next uuid - * - * @return {number} The next uuid to use. - */ - uuid: function () { - return ++utils._uid; - }, - - /** - * Converts a hex color number to an [R, G, B] array - * - * @param hex {number} - * @return {number[]} An array representing the [R, G, B] of the color. - */ - hex2rgb: function (hex, out) { - out = out || []; - - out[0] = (hex >> 16 & 0xFF) / 255; - out[1] = (hex >> 8 & 0xFF) / 255; - out[2] = (hex & 0xFF) / 255; - - return out; - }, - - /** - * Converts a hex color number to a string. - * - * @param hex {number} - * @return {string} The string color. - */ - hex2string: function (hex) { - hex = hex.toString(16); - hex = '000000'.substr(0, 6 - hex.length) + hex; - - return '#' + hex; - }, - - /** - * Converts a color as an [R, G, B] array to a hex number - * - * @param rgb {number[]} - * @return {number} The color number - */ - rgb2hex: function (rgb) { - return ((rgb[0]*255 << 16) + (rgb[1]*255 << 8) + rgb[2]*255); - }, - - /** - * Checks whether the Canvas BlendModes are supported by the current browser - * - * @return {boolean} whether they are supported - */ - canUseNewCanvasBlendModes: function () { - if (typeof document === 'undefined') { - return false; - } - - var canvas = document.createElement('canvas'), - context = canvas.getContext('2d'); - - canvas.width = 1; - canvas.height = 1; - - context.fillStyle = '#000'; - context.fillRect(0, 0, 1, 1); - - context.globalCompositeOperation = 'multiply'; - - context.fillStyle = '#fff'; - context.fillRect(0, 0, 1, 1); - - return context.getImageData(0,0,1,1).data[0] === 0; - }, - - /** - * Given a number, this function returns the closest number that is a power of two - * this function is taken from Starling Framework as its pretty neat ;) - * - * @param number {number} - * @return {number} the closest number that is a power of two - */ - getNextPowerOfTwo: function (number) { - // see: http://en.wikipedia.org/wiki/Power_of_two#Fast_algorithm_to_check_if_a_positive_number_is_a_power_of_two - if (number > 0 && (number & (number - 1)) === 0) { - return number; - } - else { - var result = 1; - - while (result < number) { - result <<= 1; - } - - return result; - } - }, - - /** - * checks if the given width and height make a power of two rectangle - * - * @param width {number} - * @param height {number} - * @return {boolean} - */ - isPowerOfTwo: function (width, height) { - return (width > 0 && (width & (width - 1)) === 0 && height > 0 && (height & (height - 1)) === 0); - }, - - /** - * Logs out the version and renderer information for this running instance of PIXI. - * If you don't want to see this message you can set `PIXI.utils._saidHello = true;` - * so the library thinks it already said it. Keep in mind that doing that will forever - * makes you a jerk face. - * - * @param {string} type - The string renderer type to log. - * @constant - * @static - */ - sayHello: function (type) { - if (utils._saidHello) { - return; - } - - if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) { - var args = [ - '%c %c %c Pixi.js ' + CONST.VERSION + ' - ' + type + ' %c ' + ' %c ' + ' http://www.pixijs.com/ %c %c ♥%c♥%c♥ ', - 'background: #ff66a5', - 'background: #ff66a5', - 'color: #ff66a5; background: #030307;', - 'background: #ff66a5', - 'background: #ffc3dc', - 'background: #ff66a5', - 'color: #ff2424; background: #fff', - 'color: #ff2424; background: #fff', - 'color: #ff2424; background: #fff' - ]; - - console.log.apply(console, args); //jshint ignore:line - } - else if (window.console) { - console.log('Pixi.js ' + CONST.VERSION + ' - ' + type + ' - http://www.pixijs.com/'); //jshint ignore:line - } - - utils._saidHello = true; - }, - - /** - * A wrapper for ajax requests to be handled cross browser - * - * TODO: Replace this wil superagent - * - * @class - * @namespace PIXI - */ - AjaxRequest: function () { - var activexmodes = ['Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.3.0', 'Microsoft.XMLHTTP']; //activeX versions to check for in IE - - if (window.ActiveXObject) { //Test for support for ActiveXObject in IE first (as XMLHttpRequest in IE7 is broken) - for (var i=0; i= this.textures.length) { - this.gotoAndStop(this.textures.length - 1); - - if (this.onComplete) { - this.onComplete(); - } - } -}; - -/** - * A short hand way of creating a movieclip from an array of frame ids - * - * @static - * @param frames {string[]} the array of frames ids the movieclip will use as its texture frames - */ -MovieClip.fromFrames = function (frames) { - var textures = []; - - for (var i = 0; i < frames.length; ++i) { - textures.push(new core.Texture.fromFrame(frames[i])); - } - - return new MovieClip(textures); -}; - -/** - * A short hand way of creating a movieclip from an array of image ids - * - * @static - * @param images {string[]} the array of image urls the movieclip will use as its texture frames - */ -MovieClip.fromImages = function (images) { - var textures = []; - - for (var i = 0; i < images.length; ++i) { - textures.push(new core.Texture.fromImage(images[i])); - } - - return new MovieClip(textures); -}; - -},{"../core":9}],52:[function(require,module,exports){ -var Strip = require('./Strip'); - -/** - * - * @class - * @namespace PIXI - * @extends Strip - * @param {Texture} texture - The texture to use on the rope. - * @param {Array} points - An array of {Point}. - * - */ -function Rope(texture, points) { - Strip.call(this, texture); - this.points = points; - - this.vertices = new Float32Array(points.length * 4); - this.uvs = new Float32Array(points.length * 4); - this.colors = new Float32Array(points.length * 2); - this.indices = new Uint16Array(points.length * 2); - - this.refresh(); -} - - -// constructor -Rope.prototype = Object.create(Strip.prototype); -Rope.prototype.constructor = Rope; -module.exports = Rope; - -/** - * Refreshes - * - */ -Rope.prototype.refresh = function () { - var points = this.points; - - if (points.length < 1) { - return; - } - - var uvs = this.uvs; - - var indices = this.indices; - var colors = this.colors; - - // this.count -= 0.2; - - uvs[0] = 0; - uvs[1] = 0; - uvs[2] = 0; - uvs[3] = 1; - - colors[0] = 1; - colors[1] = 1; - - indices[0] = 0; - indices[1] = 1; - - var total = points.length, - point, index, amount; - - for (var i = 1; i < total; i++) { - point = points[i]; - index = i * 4; - // time to do some smart drawing! - amount = i / (total-1); - - if (i%2) { - uvs[index] = amount; - uvs[index+1] = 0; - - uvs[index+2] = amount; - uvs[index+3] = 1; - } - else { - uvs[index] = amount; - uvs[index+1] = 0; - - uvs[index+2] = amount; - uvs[index+3] = 1; - } - - index = i * 2; - colors[index] = 1; - colors[index+1] = 1; - - index = i * 2; - indices[index] = index; - indices[index + 1] = index + 1; - } -}; - -/* - * Updates the object transform for rendering - * - * @private - */ -Rope.prototype.updateTransform = function () { - var points = this.points; - - if (points.length < 1) { - return; - } - - var lastPoint = points[0]; - var nextPoint; - var perpX = 0; - var perpY = 0; - - // this.count -= 0.2; - - var vertices = this.vertices; - var total = points.length, - point, index, ratio, perpLength, num; - - for (var i = 0; i < total; i++) { - point = points[i]; - index = i * 4; - - if (i < points.length-1) { - nextPoint = points[i+1]; - } - else { - nextPoint = point; - } - - perpY = -(nextPoint.x - lastPoint.x); - perpX = nextPoint.y - lastPoint.y; - - ratio = (1 - (i / (total-1))) * 10; - - if (ratio > 1) { - ratio = 1; - } - - perpLength = Math.sqrt(perpX * perpX + perpY * perpY); - num = this.texture.height / 2; //(20 + Math.abs(Math.sin((i + this.count) * 0.3) * 50) )* ratio; - perpX /= perpLength; - perpY /= perpLength; - - perpX *= num; - perpY *= num; - - vertices[index] = point.x + perpX; - vertices[index+1] = point.y + perpY; - vertices[index+2] = point.x - perpX; - vertices[index+3] = point.y - perpY; - - lastPoint = point; - } - - this.displayObjectContainerUpdateTransform(); -}; - -/** - * Sets the texture that the Rope will use - * - * @param texture {Texture} the texture that will be used - */ -Rope.prototype.setTexture = function (texture) { - // stop current texture - this.texture = texture; - //this.updateFrame = true; -}; - -},{"./Strip":53}],53:[function(require,module,exports){ -var core = require('../core'); - -/** - * - * @class - * @extends DisplayObjectContainer - * @namespace PIXI - * @param texture {Texture} The texture to use - * @param width {number} the width - * @param height {number} the height - * - */ -function Strip(texture) { - core.DisplayObjectContainer.call(this); - - /** - * The texture of the strip - * - * @member {Texture} - */ - this.texture = texture; - - // set up the main bits.. - this.uvs = new Float32Array([0, 1, - 1, 1, - 1, 0, - 0, 1]); - - this.vertices = new Float32Array([0, 0, - 100, 0, - 100, 100, - 0, 100]); - - this.colors = new Float32Array([1, 1, 1, 1]); - - this.indices = new Uint16Array([0, 1, 2, 3]); - - /** - * Whether the strip is dirty or not - * - * @member {boolean} - */ - this.dirty = true; - - /** - * The blend mode to be applied to the sprite. Set to blendModes.NORMAL to remove any blend mode. - * - * @member {number} - * @default CONST.blendModes.NORMAL; - */ - this.blendMode = core.CONST.blendModes.NORMAL; - - /** - * Triangles in canvas mode are automatically antialiased, use this value to force triangles to overlap a bit with each other. - * - * @member {number} - */ - this.canvasPadding = 0; - - this.drawMode = Strip.DrawModes.TRIANGLE_STRIP; -} - -// constructor -Strip.prototype = Object.create(core.DisplayObjectContainer.prototype); -Strip.prototype.constructor = Strip; -module.exports = Strip; - -/** - * Renders the object using the WebGL renderer - * - * @param renderer {WebGLRenderer} - */ -Strip.prototype.renderWebGL = function (renderer) { - // if the sprite is not visible or the alpha is 0 then no need to render this element - if (!this.visible || this.alpha <= 0) { - return; - } - - // render triangle strip.. - - renderer.spriteBatch.stop(); - - // init! init! - if (!this._vertexBuffer) { - this._initWebGL(renderer); - } - - renderer.shaderManager.setShader(renderer.shaderManager.stripShader); - - this._renderStrip(renderer); - - ///renderer.shaderManager.activateDefaultShader(); - - renderer.spriteBatch.start(); - - //TODO check culling -}; - -Strip.prototype._initWebGL = function (renderer) { - // build the strip! - var gl = renderer.gl; - - this._vertexBuffer = gl.createBuffer(); - this._indexBuffer = gl.createBuffer(); - this._uvBuffer = gl.createBuffer(); - this._colorBuffer = gl.createBuffer(); - - gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, this._uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.uvs, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ARRAY_BUFFER, this._colorBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.colors, gl.STATIC_DRAW); - - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); -}; - -Strip.prototype._renderStrip = function (renderer) { - var gl = renderer.gl; - var projection = renderer.projection, - offset = renderer.offset, - shader = renderer.shaderManager.stripShader; - - var drawMode = this.drawMode === Strip.DrawModes.TRIANGLE_STRIP ? gl.TRIANGLE_STRIP : gl.TRIANGLES; - - // gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mat4Real); - - renderer.blendModeManager.setBlendMode(this.blendMode); - - - // set uniforms - gl.uniformMatrix3fv(shader.translationMatrix, false, this.worldTransform.toArray(true)); - gl.uniform2f(shader.projectionVector, projection.x, -projection.y); - gl.uniform2f(shader.offsetVector, -offset.x, -offset.y); - gl.uniform1f(shader.alpha, this.worldAlpha); - - if (!this.dirty) { - - gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer); - gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.vertices); - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - - // update the uvs - gl.bindBuffer(gl.ARRAY_BUFFER, this._uvBuffer); - gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.activeTexture(gl.TEXTURE0); - - // check if a texture is dirty.. - if (this.texture.baseTexture._dirty[gl.id]) { - renderer.updateTexture(this.texture.baseTexture); - } - else { - // bind the current texture - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); - } - - // dont need to upload! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); - - - } - else { - - this.dirty = false; - gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.STATIC_DRAW); - gl.vertexAttribPointer(shader.aVertexPosition, 2, gl.FLOAT, false, 0, 0); - - // update the uvs - gl.bindBuffer(gl.ARRAY_BUFFER, this._uvBuffer); - gl.bufferData(gl.ARRAY_BUFFER, this.uvs, gl.STATIC_DRAW); - gl.vertexAttribPointer(shader.aTextureCoord, 2, gl.FLOAT, false, 0, 0); - - gl.activeTexture(gl.TEXTURE0); - - // check if a texture is dirty.. - if (this.texture.baseTexture._dirty[gl.id]) { - renderer.updateTexture(this.texture.baseTexture); - } - else { - gl.bindTexture(gl.TEXTURE_2D, this.texture.baseTexture._glTextures[gl.id]); - } - - // dont need to upload! - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer); - gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW); - - } - //console.log(gl.TRIANGLE_STRIP) - // - // - gl.drawElements(drawMode, this.indices.length, gl.UNSIGNED_SHORT, 0); - - -}; - -/** - * Renders the object using the Canvas renderer - * - * @param renderer {CanvasRenderer} - */ -Strip.prototype.renderCanvas = function (renderer) { - var context = renderer.context; - - var transform = this.worldTransform; - - if (renderer.roundPixels) { - context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx | 0, transform.ty | 0); - } - else { - context.setTransform(transform.a, transform.b, transform.c, transform.d, transform.tx, transform.ty); - } - - if (this.drawMode === Strip.DrawModes.TRIANGLE_STRIP) { - this._renderCanvasTriangleStrip(context); - } - else { - this._renderCanvasTriangles(context); - } -}; - -Strip.prototype._renderCanvasTriangleStrip = function (context) { - // draw triangles!! - var vertices = this.vertices; - var uvs = this.uvs; - - var length = vertices.length / 2; - // this.count++; - - for (var i = 0; i < length - 2; i++) { - // draw some triangles! - var index = i * 2; - this._renderCanvasDrawTriangle(context, vertices, uvs, index, (index + 2), (index + 4)); - } -}; - -Strip.prototype._renderCanvasTriangles = function (context) { - // draw triangles!! - var vertices = this.vertices; - var uvs = this.uvs; - var indices = this.indices; - - var length = indices.length; - // this.count++; - - for (var i = 0; i < length; i += 3) { - // draw some triangles! - var index0 = indices[i] * 2, index1 = indices[i + 1] * 2, index2 = indices[i + 2] * 2; - this._renderCanvasDrawTriangle(context, vertices, uvs, index0, index1, index2); - } -}; - -Strip.prototype._renderCanvasDrawTriangle = function (context, vertices, uvs, index0, index1, index2) { - var textureSource = this.texture.baseTexture.source; - var textureWidth = this.texture.width; - var textureHeight = this.texture.height; - - var x0 = vertices[index0], x1 = vertices[index1], x2 = vertices[index2]; - var y0 = vertices[index0 + 1], y1 = vertices[index1 + 1], y2 = vertices[index2 + 1]; - - var u0 = uvs[index0] * textureWidth, u1 = uvs[index1] * textureWidth, u2 = uvs[index2] * textureWidth; - var v0 = uvs[index0 + 1] * textureHeight, v1 = uvs[index1 + 1] * textureHeight, v2 = uvs[index2 + 1] * textureHeight; - - if (this.canvasPadding > 0) { - var paddingX = this.canvasPadding / this.worldTransform.a; - var paddingY = this.canvasPadding / this.worldTransform.d; - var centerX = (x0 + x1 + x2) / 3; - var centerY = (y0 + y1 + y2) / 3; - - var normX = x0 - centerX; - var normY = y0 - centerY; - - var dist = Math.sqrt(normX * normX + normY * normY); - x0 = centerX + (normX / dist) * (dist + paddingX); - y0 = centerY + (normY / dist) * (dist + paddingY); - - // - - normX = x1 - centerX; - normY = y1 - centerY; - - dist = Math.sqrt(normX * normX + normY * normY); - x1 = centerX + (normX / dist) * (dist + paddingX); - y1 = centerY + (normY / dist) * (dist + paddingY); - - normX = x2 - centerX; - normY = y2 - centerY; - - dist = Math.sqrt(normX * normX + normY * normY); - x2 = centerX + (normX / dist) * (dist + paddingX); - y2 = centerY + (normY / dist) * (dist + paddingY); - } - - context.save(); - context.beginPath(); - - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - - context.closePath(); - - context.clip(); - - // Compute matrix transform - var delta = (u0 * v1) + (v0 * u2) + (u1 * v2) - (v1 * u2) - (v0 * u1) - (u0 * v2); - var deltaA = (x0 * v1) + (v0 * x2) + (x1 * v2) - (v1 * x2) - (v0 * x1) - (x0 * v2); - var deltaB = (u0 * x1) + (x0 * u2) + (u1 * x2) - (x1 * u2) - (x0 * u1) - (u0 * x2); - var deltaC = (u0 * v1 * x2) + (v0 * x1 * u2) + (x0 * u1 * v2) - (x0 * v1 * u2) - (v0 * u1 * x2) - (u0 * x1 * v2); - var deltaD = (y0 * v1) + (v0 * y2) + (y1 * v2) - (v1 * y2) - (v0 * y1) - (y0 * v2); - var deltaE = (u0 * y1) + (y0 * u2) + (u1 * y2) - (y1 * u2) - (y0 * u1) - (u0 * y2); - var deltaF = (u0 * v1 * y2) + (v0 * y1 * u2) + (y0 * u1 * v2) - (y0 * v1 * u2) - (v0 * u1 * y2) - (u0 * y1 * v2); - - context.transform(deltaA / delta, deltaD / delta, - deltaB / delta, deltaE / delta, - deltaC / delta, deltaF / delta); - - context.drawImage(textureSource, 0, 0); - context.restore(); -}; - - - -/** - * Renders a flat strip - * - * @param strip {Strip} The Strip to render - * @private - */ -Strip.prototype.renderStripFlat = function (strip) { - var context = this.context; - var vertices = strip.vertices; - - var length = vertices.length/2; - // this.count++; - - context.beginPath(); - for (var i=1; i < length-2; i++) { - // draw some triangles! - var index = i*2; - - var x0 = vertices[index], x1 = vertices[index+2], x2 = vertices[index+4]; - var y0 = vertices[index+1], y1 = vertices[index+3], y2 = vertices[index+5]; - - context.moveTo(x0, y0); - context.lineTo(x1, y1); - context.lineTo(x2, y2); - } - - context.fillStyle = '#FF0000'; - context.fill(); - context.closePath(); -}; - -/* -Strip.prototype.setTexture = function (texture) { - //TODO SET THE TEXTURES - //TODO VISIBILITY - - // stop current texture - this.texture = texture; - this.width = texture.frame.width; - this.height = texture.frame.height; - this.updateFrame = true; -}; - */ - -/** - * When the texture is updated, this event will fire to update the scale and frame - * - * @param event - * @private - */ - -Strip.prototype.onTextureUpdate = function () { - this.updateFrame = true; -}; - -/** - * Returns the bounds of the mesh as a rectangle. The bounds calculation takes the worldTransform into account. - * - * @param matrix {Matrix} the transformation matrix of the sprite - * @return {Rectangle} the framing rectangle - */ -Strip.prototype.getBounds = function (matrix) { - var worldTransform = matrix || this.worldTransform; - - var a = worldTransform.a; - var b = worldTransform.b; - var c = worldTransform.c; - var d = worldTransform.d; - var tx = worldTransform.tx; - var ty = worldTransform.ty; - - var maxX = -Infinity; - var maxY = -Infinity; - - var minX = Infinity; - var minY = Infinity; - - var vertices = this.vertices; - for (var i = 0, n = vertices.length; i < n; i += 2) { - var rawX = vertices[i], rawY = vertices[i + 1]; - var x = (a * rawX) + (c * rawY) + tx; - var y = (d * rawY) + (b * rawX) + ty; - - minX = x < minX ? x : minX; - minY = y < minY ? y : minY; - - maxX = x > maxX ? x : maxX; - maxY = y > maxY ? y : maxY; - } - - if (minX === -Infinity || maxY === Infinity) { - return core.math.Rectangle.EMPTY; - } - - var bounds = this._bounds; - - bounds.x = minX; - bounds.width = maxX - minX; - - bounds.y = minY; - bounds.height = maxY - minY; - - // store a reference so that if this function gets called again in the render cycle we do not have to recalculate - this._currentBounds = bounds; - - return bounds; -}; - -/** - * Different drawing buffer modes supported - * - * @static - * @constant - * @property {object} DrawModes - * @property {number} DrawModes.TRIANGLE_STRIP - * @property {number} DrawModes.TRIANGLES - */ -Strip.DrawModes = { - TRIANGLE_STRIP: 0, - TRIANGLES: 1 -}; - -},{"../core":9}],54:[function(require,module,exports){ -var core = require('../core'); - -/** - * A tiling sprite is a fast way of rendering a tiling image - * - * @class - * @extends Sprite - * @namespace PIXI - * @param texture {Texture} the texture of the tiling sprite - * @param width {number} the width of the tiling sprite - * @param height {number} the height of the tiling sprite - */ -function TilingSprite(texture, width, height) { - core.Sprite.call( this, texture); - - /** - * The with of the tiling sprite - * - * @member {number} - */ - this._width = width || 100; - - /** - * The height of the tiling sprite - * - * @member {number} - */ - this._height = height || 100; - - /** - * The scaling of the image that is being tiled - * - * @member {Point} - */ - this.tileScale = new core.math.Point(1,1); - - /** - * A point that represents the scale of the texture object - * - * @member {Point} - */ - this.tileScaleOffset = new core.math.Point(1,1); - - /** - * The offset position of the image that is being tiled - * - * @member {Point} - */ - this.tilePosition = new core.math.Point(0,0); - - /** - * Whether this sprite is renderable or not - * - * @member {boolean} - * @default true - */ - this.renderable = true; - - /** - * The tint applied to the sprite. This is a hex value - * - * @member {number} - * @default 0xFFFFFF - */ - this.tint = 0xFFFFFF; - - /** - * The blend mode to be applied to the sprite - * - * @member {number} - * @default blendModes.NORMAL; - */ - this.blendMode = core.CONST.blendModes.NORMAL; -} - -TilingSprite.prototype = Object.create(core.Sprite.prototype); -TilingSprite.prototype.constructor = TilingSprite; -module.exports = TilingSprite; - - -Object.defineProperties(TilingSprite.prototype, { - /** - * The width of the sprite, setting this will actually modify the scale to achieve the value set - * - * @member {number} - * @memberof TilingSprite# - */ - width: { - get: function () { - return this._width; - }, - set: function (value) { - this._width = value; - } - }, - - /** - * The height of the TilingSprite, setting this will actually modify the scale to achieve the value set - * - * @member {number} - * @memberof TilingSprite# - */ - height: { - get: function () { - return this._height; - }, - set: function (value) { - this._height = value; - } - }, - - texture: { - get: function () { - return this._texture; - }, - set: function (value) { - if (this._texture === value) { - return; - } - - this._texture = value; - this.refreshTexture = true; - this.cachedTint = 0xFFFFFF; - } - } -}); - -/** - * Renders the object using the WebGL renderer - * - * @param renderer {WebGLRenderer} - */ -TilingSprite.prototype.renderWebGL = function (renderer) { - if (!this.visible || this.alpha <= 0) { - return; - } - - var i, j; - - if (this._mask) { - renderer.spriteBatch.stop(); - renderer.maskManager.pushMask(this.mask, renderer); - renderer.spriteBatch.start(); - } - - if (this._filters) { - renderer.spriteBatch.flush(); - renderer.filterManager.pushFilter(this._filterBlock); - } - - - - if (!this.tilingTexture || this.refreshTexture) { - this.generateTilingTexture(true); - - if (this.tilingTexture && this.tilingTexture.needsUpdate) { - //TODO - tweaking - renderer.updateTexture(this.tilingTexture.baseTexture); - this.tilingTexture.needsUpdate = false; - // this.tilingTexture._uvs = null; - } - } - else { - renderer.spriteBatch.renderTilingSprite(this); - } - // simple render children! - for (i=0,j=this.children.length; i maxX ? x2 : maxX; - maxX = x3 > maxX ? x3 : maxX; - maxX = x4 > maxX ? x4 : maxX; - - maxY = y1; - maxY = y2 > maxY ? y2 : maxY; - maxY = y3 > maxY ? y3 : maxY; - maxY = y4 > maxY ? y4 : maxY; - - var bounds = this._bounds; - - bounds.x = minX; - bounds.width = maxX - minX; - - bounds.y = minY; - bounds.height = maxY - minY; - - // store a reference so that if this function gets called again in the render cycle we do not have to recalculate - this._currentBounds = bounds; - - return bounds; -}; - -/** - * When the texture is updated, this event will fire to update the scale and frame - * - * @param event - * @private - */ -TilingSprite.prototype.onTextureUpdate = function () { - // overriding the sprite version of this! -}; - -/** - * - * @param forcePowerOfTwo {boolean} Whether we want to force the texture to be a power of two - */ -TilingSprite.prototype.generateTilingTexture = function (forcePowerOfTwo) { - if (!this.texture.baseTexture.hasLoaded) { - return; - } - - var texture = this.originalTexture || this.texture; - var frame = texture.frame; - var targetWidth, targetHeight; - - // Check that the frame is the same size as the base texture. - var isFrame = frame.width !== texture.baseTexture.width || frame.height !== texture.baseTexture.height; - - var newTextureRequired = false; - - if (!forcePowerOfTwo) { - if (isFrame) { - targetWidth = frame.width; - targetHeight = frame.height; - - newTextureRequired = true; - } - } - else { - targetWidth = core.utils.getNextPowerOfTwo(frame.width); - targetHeight = core.utils.getNextPowerOfTwo(frame.height); - - // If the BaseTexture dimensions don't match the texture frame then we need a new texture anyway because it's part of a texture atlas - if (frame.width !== targetWidth || frame.height !== targetHeight || texture.baseTexture.width !== targetWidth || texture.baseTexture.height || targetHeight) { - newTextureRequired = true; - } - } - - if (newTextureRequired) { - var canvasBuffer; - - if (this.tilingTexture && this.tilingTexture.isTiling) { - canvasBuffer = this.tilingTexture.canvasBuffer; - canvasBuffer.resize(targetWidth, targetHeight); - this.tilingTexture.baseTexture.width = targetWidth; - this.tilingTexture.baseTexture.height = targetHeight; - this.tilingTexture.needsUpdate = true; - } - else { - canvasBuffer = new core.CanvasBuffer(targetWidth, targetHeight); - - this.tilingTexture = core.Texture.fromCanvas(canvasBuffer.canvas); - this.tilingTexture.canvasBuffer = canvasBuffer; - this.tilingTexture.isTiling = true; - } - - canvasBuffer.context.drawImage(texture.baseTexture.source, - texture.crop.x, - texture.crop.y, - texture.crop.width, - texture.crop.height, - 0, - 0, - targetWidth, - targetHeight); - - this.tileScaleOffset.x = frame.width / targetWidth; - this.tileScaleOffset.y = frame.height / targetHeight; - } - else { - // TODO - switching? - if (this.tilingTexture && this.tilingTexture.isTiling) { - // destroy the tiling texture! - // TODO could store this somewhere? - this.tilingTexture.destroy(true); - } - - this.tileScaleOffset.x = 1; - this.tileScaleOffset.y = 1; - this.tilingTexture = texture; - } - - this.refreshTexture = false; - - this.originalTexture = this.texture; - this.texture = this.tilingTexture; - - this.tilingTexture.baseTexture._powerOf2 = true; -}; - -},{"../core":9}],55:[function(require,module,exports){ -/** - * @file Main export of the PIXI extras library - * @author Mat Groves - * @copyright 2013-2015 GoodBoyDigital - * @license {@link https://github.com/GoodBoyDigital/pixi.js/blob/master/LICENSE|MIT License} - */ - -/** - * @namespace PIXI - */ -module.exports = { - MovieClip: require('./MovieClip'), - Rope: require('./Rope'), - Strip: require('./Strip'), - TilingSprite: require('./TilingSprite') -}; - -},{"./MovieClip":51,"./Rope":52,"./Strip":53,"./TilingSprite":54}],56:[function(require,module,exports){ -/** - * This is the base class for creating a PIXI filter. Currently only WebGL supports filters. - * If you want to make a custom filter this should be your base class. - * - * @class - * @namespace PIXI - * @param fragmentSrc {string|string[]} The fragment source in an array of strings. - * @param uniforms {object} An object containing the uniforms for this filter. - */ -function AbstractFilter(fragmentSrc, uniforms) { - /** - * An array of passes - some filters contain a few steps this array simply stores the steps in a liniear fashion. - * For example the blur filter has two passes blurX and blurY. - * - * @member {AbstractFilter[]} - * @private - */ - this.passes = [this]; - - /** - * @member {Shader[]} - * @private - */ - this.shaders = []; - - /** - * @member {number} - */ - this.padding = 0; - - /** - * @member {object} - * @private - */ - this.uniforms = uniforms || {}; - - /** - * @member {string[]} - * @private - */ - this.fragmentSrc = typeof fragmentSrc === 'string' ? fragmentSrc.split('') : (fragmentSrc || []); -} - -AbstractFilter.prototype.constructor = AbstractFilter; -module.exports = AbstractFilter; - -/** - * Syncs the uniforms between the class object and the shaders. - * - */ -AbstractFilter.prototype.syncUniforms = function () { - for (var i = 0, j = this.shaders.length; i < j; ++i) { - this.shaders[i].dirty = true; - } -}; - -/* -AbstractFilter.prototype.apply = function (frameBuffer) { - // TODO :) -}; -*/ - -},{}],57:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * The AlphaMaskFilter class uses the pixel values from the specified texture (called the displacement map) to perform a displacement of an object. - * You can use this filter to apply all manor of crazy warping effects - * Currently the r property of the texture is used to offset the x and the g property of the texture is used to offset the y. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - * @param texture {Texture} The texture used for the displacement map * must be power of 2 texture at the moment - */ -function AlphaMaskFilter(texture) { - AbstractFilter.call(this); - - texture.baseTexture._powerOf2 = true; - - // set the uniforms - this.uniforms = { - mask: { type: 'sampler2D', value: texture }, - mapDimensions: { type: '2f', value: { x: 1, y: 5112 } }, - dimensions: { type: '4fv', value: [0, 0, 0, 0] }, - offset: { type: '2f', value: { x: 0, y: 0 } } - }; - - if (texture.baseTexture.hasLoaded) { - this.uniforms.mask.value.x = texture.width; - this.uniforms.mask.value.y = texture.height; - } - else { - this.boundLoadedFunction = this.onTextureLoaded.bind(this); - - texture.baseTexture.on('loaded', this.boundLoadedFunction); - } - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform sampler2D uSampler;', - 'uniform sampler2D mask;', - 'uniform vec2 mapDimensions;', - 'uniform vec4 dimensions;', - 'uniform vec2 offset;', - - 'void main() {', - ' vec2 mapCords = vTextureCoord.xy;', - ' mapCords += (dimensions.zw + offset)/ dimensions.xy ;', - ' mapCords.y *= -1.0;', - ' mapCords.y += 1.0;', - ' mapCords *= dimensions.xy / mapDimensions;', - - ' vec4 original = texture2D(uSampler, vTextureCoord);', - ' float maskAlpha = texture2D(mask, mapCords).r;', - ' original *= maskAlpha;', - //' original.rgb *= maskAlpha;', - ' gl_FragColor = original;', - //' gl_FragColor = gl_FragColor;', - '}' - ]; -} - -AlphaMaskFilter.prototype = Object.create(AbstractFilter.prototype); -AlphaMaskFilter.prototype.constructor = AlphaMaskFilter; -module.exports = AlphaMaskFilter; - -/** - * Sets the map dimensions uniforms when the texture becomes available. - * - */ -AlphaMaskFilter.prototype.onTextureLoaded = function () { - this.uniforms.mapDimensions.value.x = this.uniforms.mask.value.width; - this.uniforms.mapDimensions.value.y = this.uniforms.mask.value.height; - - this.uniforms.mask.value.baseTexture.off('loaded', this.boundLoadedFunction); -}; - -Object.defineProperties(AlphaMaskFilter.prototype, { - /** - * The texture used for the displacement map. Must be power of 2 sized texture. - * - * @member {Texture} - * @memberof AlphaMaskFilter# - */ - map: { - get: function () { - return this.uniforms.mask.value; - }, - set: function (value) { - this.uniforms.mask.value = value; - } - }, - - /** - * The offset used to move the displacement map. - * - * @member {Point} - * @memberof AlphaMaskFilter# - */ - offset: { - get: function() { - return this.uniforms.offset.value; - }, - set: function(value) { - this.uniforms.offset.value = value; - } - } -}); - -},{"./AbstractFilter":56}],58:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * @author Vico @vicocotea - * original shader : https://www.shadertoy.com/view/lssGDj by @movAX13h - */ - -/** - * An ASCII filter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function AsciiFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - dimensions: { type: '4fv', value: new Float32Array([10000, 100, 10, 10]) }, - pixelSize: { type: '1f', value: 8} - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'uniform vec4 dimensions;', - 'uniform float pixelSize;', - 'uniform sampler2D uSampler;', - - 'float character(float n, vec2 p)', - '{', - ' p = floor(p*vec2(4.0, -4.0) + 2.5);', - ' if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y)', - ' {', - ' if (int(mod(n/exp2(p.x + 5.0*p.y), 2.0)) == 1) return 1.0;', - ' }', - ' return 0.0;', - '}', - - 'void main()', - '{', - ' vec2 uv = gl_FragCoord.xy;', - ' vec3 col = texture2D(uSampler, floor( uv / pixelSize ) * pixelSize / dimensions.xy).rgb;', - - ' #ifdef HAS_GREENSCREEN', - ' float gray = (col.r + col.b)/2.0;', - ' #else', - ' float gray = (col.r + col.g + col.b)/3.0;', - ' #endif', - - ' float n = 65536.0; // .', - ' if (gray > 0.2) n = 65600.0; // :', - ' if (gray > 0.3) n = 332772.0; // *', - ' if (gray > 0.4) n = 15255086.0; // o', - ' if (gray > 0.5) n = 23385164.0; // &', - ' if (gray > 0.6) n = 15252014.0; // 8', - ' if (gray > 0.7) n = 13199452.0; // @', - ' if (gray > 0.8) n = 11512810.0; // #', - - ' vec2 p = mod( uv / ( pixelSize * 0.5 ), 2.0) - vec2(1.0);', - ' col = col * character(n, p);', - - ' gl_FragColor = vec4(col, 1.0);', - '}' - ]; -} - -AsciiFilter.prototype = Object.create(AbstractFilter.prototype); -AsciiFilter.prototype.constructor = AsciiFilter; -module.exports = AsciiFilter; - -Object.defineProperties(AsciiFilter.prototype, { - /** - * The pixel size used by the filter. - * - * @member {number} - * @memberof AsciiFilter# - */ - size: { - get: function () { - return this.uniforms.pixelSize.value; - }, - set: function (value) { - this.uniforms.pixelSize.value = value; - } - } -}); - -},{"./AbstractFilter":56}],59:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'), - BlurXFilter = require('./BlurXFilter'), - BlurYFilter = require('./BlurYFilter'); - -/** - * The BlurFilter applies a Gaussian blur to an object. - * The strength of the blur can be set for x- and y-axis separately. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function BlurFilter() { - AbstractFilter.call(this); - - this.blurXFilter = new BlurXFilter(); - this.blurYFilter = new BlurYFilter(); - - this.passes = [this.blurXFilter, this.blurYFilter]; -} - -BlurFilter.prototype = Object.create(AbstractFilter.prototype); -BlurFilter.prototype.constructor = BlurFilter; -module.exports = BlurFilter; - -Object.defineProperties(BlurFilter.prototype, { - /** - * Sets the strength of both the blurX and blurY properties simultaneously - * - * @member {number} - * @memberOf BlurFilter# - * @default 2 - */ - blur: { - get: function () { - return this.blurXFilter.blur; - }, - set: function (value) { - this.blurXFilter.blur = this.blurYFilter.blur = value; - } - }, - - /** - * Sets the strength of the blurX property - * - * @member {number} - * @memberOf BlurFilter# - * @default 2 - */ - blurX: { - get: function () { - return this.blurXFilter.blur; - }, - set: function (value) { - this.blurXFilter.blur = value; - } - }, - - /** - * Sets the strength of the blurY property - * - * @member {number} - * @memberOf BlurFilter# - * @default 2 - */ - blurY: { - get: function () { - return this.blurYFilter.blur; - }, - set: function (value) { - this.blurYFilter.blur = value; - } - } -}); - -},{"./AbstractFilter":56,"./BlurXFilter":60,"./BlurYFilter":61}],60:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'), - blurFactor = 1 / 7000; - -/** - * The BlurXFilter applies a horizontal Gaussian blur to an object. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function BlurXFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - blur: { type: '1f', value: 1 / 512 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float blur;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' vec4 sum = vec4(0.0);', - - ' sum += texture2D(uSampler, vec2(vTextureCoord.x - 4.0*blur, vTextureCoord.y)) * 0.05;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x - 3.0*blur, vTextureCoord.y)) * 0.09;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x - 2.0*blur, vTextureCoord.y)) * 0.12;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x - blur, vTextureCoord.y)) * 0.15;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y)) * 0.16;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x + blur, vTextureCoord.y)) * 0.15;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x + 2.0*blur, vTextureCoord.y)) * 0.12;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x + 3.0*blur, vTextureCoord.y)) * 0.09;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x + 4.0*blur, vTextureCoord.y)) * 0.05;', - - ' gl_FragColor = sum;', - '}' - ]; -} - -BlurXFilter.prototype = Object.create(AbstractFilter.prototype); -BlurXFilter.prototype.constructor = BlurXFilter; -module.exports = BlurXFilter; - -Object.defineProperties(BlurXFilter.prototype, { - /** - * Sets the strength of both the blur. - * - * @member {number} - * @memberof BlurXFilter# - * @default 2 - */ - blur: { - get: function () { - return this.uniforms.blur.value / blurFactor; - }, - set: function (value) { - this.uniforms.blur.value = blurFactor * value; - } - } -}); - -},{"./AbstractFilter":56}],61:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'), - blurFactor = 1 / 7000; - -/** - * The BlurYFilter applies a vertical Gaussian blur to an object. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function BlurYFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - blur: { type: '1f', value: 1 / 512 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float blur;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' vec4 sum = vec4(0.0);', - - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - 4.0*blur)) * 0.05;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - 3.0*blur)) * 0.09;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - 2.0*blur)) * 0.12;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - blur)) * 0.15;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y)) * 0.16;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + blur)) * 0.15;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + 2.0*blur)) * 0.12;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + 3.0*blur)) * 0.09;', - ' sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + 4.0*blur)) * 0.05;', - - ' gl_FragColor = sum;', - '}' - ]; -} - -BlurYFilter.prototype = Object.create(AbstractFilter.prototype); -BlurYFilter.prototype.constructor = BlurYFilter; -module.exports = BlurYFilter; - -Object.defineProperties(BlurYFilter.prototype, { - /** - * Sets the strength of both the blur. - * - * @member {number} - * @memberof BlurYFilter - * @default 2 - */ - blur: { - get: function () { - return this.uniforms.blur.value / blurFactor; - }, - set: function (value) { - //this.padding = value; - this.uniforms.blur.value = blurFactor * value; - } - } -}); - -},{"./AbstractFilter":56}],62:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * The ColorMatrixFilter class lets you apply a 4x4 matrix transformation on the RGBA - * color and alpha values of every pixel on your displayObject to produce a result - * with a new set of RGBA color and alpha values. It's pretty powerful! - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function ColorMatrixFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - matrix: { type: 'mat4', value: [1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1] } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float invert;', - 'uniform mat4 matrix;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;', - '}' - ]; -} - -ColorMatrixFilter.prototype = Object.create(AbstractFilter.prototype); -ColorMatrixFilter.prototype.constructor = ColorMatrixFilter; -module.exports = ColorMatrixFilter; - -Object.defineProperties(ColorMatrixFilter.prototype, { - /** - * Sets the matrix of the color matrix filter - * - * @member {number[]} - * @memberof ColorMatrixFilter# - * @default [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1] - */ - matrix: { - get: function () { - return this.uniforms.matrix.value; - }, - set: function (value) { - this.uniforms.matrix.value = value; - } - } -}); - -},{"./AbstractFilter":56}],63:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * This lowers the color depth of your image by the given amount, producing an image with a smaller palette. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function ColorStepFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - step: { type: '1f', value: 5 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - 'uniform sampler2D uSampler;', - 'uniform float step;', - - 'void main(void) {', - ' vec4 color = texture2D(uSampler, vTextureCoord);', - ' color = floor(color * step) / step;', - ' gl_FragColor = color;', - '}' - ]; -} - -ColorStepFilter.prototype = Object.create(AbstractFilter.prototype); -ColorStepFilter.prototype.constructor = ColorStepFilter; -module.exports = ColorStepFilter; - -Object.defineProperties(ColorStepFilter.prototype, { - /** - * The number of steps to reduce the palette by. - * - * @member {number} - * @memberof ColorStepFilter# - */ - step: { - get: function () { - return this.uniforms.step.value; - }, - set: function (value) { - this.uniforms.step.value = value; - } - } -}); - -},{"./AbstractFilter":56}],64:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * The ConvolutionFilter class applies a matrix convolution filter effect. - * A convolution combines pixels in the input image with neighboring pixels to produce a new image. - * A wide variety of image effects can be achieved through convolutions, including blurring, edge - * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. - * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. - * @param width {number} Width of the object you are transforming - * @param height {number} Height of the object you are transforming - */ -function ConvolutionFilter(matrix, width, height) { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - matrix: { type: '1fv', value: new Float32Array(matrix) }, - texelSizeX: { type: '1f', value: 1 / width }, - texelSizeY: { type: '1f', value: 1 / height } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying mediump vec2 vTextureCoord;', - - 'uniform sampler2D texture;', - 'uniform float texelSizeX;', - 'uniform float texelSizeY;', - 'uniform float matrix[9];', - - 'vec2 px = vec2(texelSizeX, texelSizeY);', - - 'void main(void) {', - ' vec4 c11 = texture2D(texture, vTextureCoord - px);', // top left - ' vec4 c12 = texture2D(texture, vec2(vTextureCoord.x, vTextureCoord.y - px.y));', // top center - ' vec4 c13 = texture2D(texture, vec2(vTextureCoord.x + px.x, vTextureCoord.y - px.y));', // top right - - ' vec4 c21 = texture2D(texture, vec2(vTextureCoord.x - px.x, vTextureCoord.y) );', // mid left - ' vec4 c22 = texture2D(texture, vTextureCoord);', // mid center - ' vec4 c23 = texture2D(texture, vec2(vTextureCoord.x + px.x, vTextureCoord.y) );', // mid right - - ' vec4 c31 = texture2D(texture, vec2(vTextureCoord.x - px.x, vTextureCoord.y + px.y) );', // bottom left - ' vec4 c32 = texture2D(texture, vec2(vTextureCoord.x, vTextureCoord.y + px.y) );', // bottom center - ' vec4 c33 = texture2D(texture, vTextureCoord + px );', // bottom right - - ' gl_FragColor = ', - ' c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] +', - ' c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] +', - ' c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8];', - ' gl_FragColor.a = c22.a;', - '}' - ]; -} - -ConvolutionFilter.prototype = Object.create(AbstractFilter.prototype); -ConvolutionFilter.prototype.constructor = ConvolutionFilter; -module.exports = ConvolutionFilter; - -Object.defineProperties(ConvolutionFilter.prototype, { - /** - * An array of values used for matrix transformation. Specified as a 9 point Array. - * - * @member {number[]} - * @memberof ConvolutionFilter# - */ - matrix: { - get: function () { - return this.uniforms.matrix.value; - }, - set: function (value) { - this.uniforms.matrix.value = new Float32Array(value); - } - }, - - /** - * Width of the object you are transforming - * - * @member {number} - * @memberof ConvolutionFilter# - */ - width: { - get: function () { - return this.uniforms.texelSizeX.value; - }, - set: function (value) { - this.uniforms.texelSizeX.value = 1/value; - } - }, - - /** - * Height of the object you are transforming - * - * @member {number} - * @memberof ConvolutionFilter# - */ - height: { - get: function () { - return this.uniforms.texelSizeY.value; - }, - set: function (value) { - this.uniforms.texelSizeY.value = 1/value; - } - } -}); - -},{"./AbstractFilter":56}],65:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * A Cross Hatch effect filter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function CrossHatchFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - blur: { type: '1f', value: 1 / 512 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float blur;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' float lum = length(texture2D(uSampler, vTextureCoord.xy).rgb);', - - ' gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);', - - ' if (lum < 1.00) {', - ' if (mod(gl_FragCoord.x + gl_FragCoord.y, 10.0) == 0.0) {', - ' gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);', - ' }', - ' }', - - ' if (lum < 0.75) {', - ' if (mod(gl_FragCoord.x - gl_FragCoord.y, 10.0) == 0.0) {', - ' gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);', - ' }', - ' }', - - ' if (lum < 0.50) {', - ' if (mod(gl_FragCoord.x + gl_FragCoord.y - 5.0, 10.0) == 0.0) {', - ' gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);', - ' }', - ' }', - - ' if (lum < 0.3) {', - ' if (mod(gl_FragCoord.x - gl_FragCoord.y - 5.0, 10.0) == 0.0) {', - ' gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);', - ' }', - ' }', - '}' - ]; -} - -CrossHatchFilter.prototype = Object.create(AbstractFilter.prototype); -CrossHatchFilter.prototype.constructor = CrossHatchFilter; -module.exports = CrossHatchFilter; - -Object.defineProperties(CrossHatchFilter.prototype, { - /** - * Sets the strength of both the blur. - * - * @member {number} - * @memberof CrossHatchFilter# - * @default 2 - */ - blur: { - get: function () { - return this.uniforms.blur.value / (1/7000); - }, - set: function (value) { - //this.padding = value; - this.uniforms.blur.value = (1/7000) * value; - } - } -}); - -},{"./AbstractFilter":56}],66:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * The DisplacementFilter class uses the pixel values from the specified texture (called the displacement map) to perform a displacement of an object. - * You can use this filter to apply all manor of crazy warping effects - * Currently the r property of the texture is used offset the x and the g property of the texture is used to offset the y. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - * @param texture {Texture} The texture used for the displacement map * must be power of 2 texture at the moment - */ -function DisplacementFilter(texture) { - AbstractFilter.call(this); - - texture.baseTexture._powerOf2 = true; - - // set the uniforms - this.uniforms = { - displacementMap: { type: 'sampler2D', value: texture }, - scale: { type: '2f', value: { x: 30, y: 30 } }, - offset: { type: '2f', value: { x: 0, y: 0 } }, - mapDimensions: { type: '2f', value: { x: 1, y: 5112 } }, - dimensions: { type: '4fv', value: [0, 0, 0, 0] } - }; - - if (texture.baseTexture.hasLoaded) { - this.onTextureLoaded(); - } - else { - this.boundLoadedFunction = this.onTextureLoaded.bind(this); - - texture.baseTexture.on('loaded', this.boundLoadedFunction); - } - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform sampler2D displacementMap;', - 'uniform sampler2D uSampler;', - 'uniform vec2 scale;', - 'uniform vec2 offset;', - 'uniform vec4 dimensions;', - 'uniform vec2 mapDimensions;',// = vec2(256.0, 256.0);', - // 'const vec2 textureDimensions = vec2(750.0, 750.0);', - - 'void main(void) {', - ' vec2 mapCords = vTextureCoord.xy;', - ' mapCords += (dimensions.zw + offset)/ dimensions.xy ;', - ' mapCords.y *= -1.0;', - ' mapCords.y += 1.0;', - - ' vec2 matSample = texture2D(displacementMap, mapCords).xy;', - ' matSample -= 0.5;', - ' matSample *= scale;', - ' matSample /= mapDimensions;', - - ' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x + matSample.x, vTextureCoord.y + matSample.y));', - - //TODO: Is this needed? - ' gl_FragColor.rgb = mix( gl_FragColor.rgb, gl_FragColor.rgb, 1.0);', - '}' - ]; -} - -DisplacementFilter.prototype = Object.create(AbstractFilter.prototype); -DisplacementFilter.prototype.constructor = DisplacementFilter; -module.exports = DisplacementFilter; - -/** - * Sets the map dimensions uniforms when the texture becomes available. - * - * @private - */ -DisplacementFilter.prototype.onTextureLoaded = function () { - this.uniforms.mapDimensions.value.x = this.uniforms.displacementMap.value.width; - this.uniforms.mapDimensions.value.y = this.uniforms.displacementMap.value.height; - - this.uniforms.displacementMap.value.baseTexture.off('loaded', this.boundLoadedFunction); -}; - -Object.defineProperties(DisplacementFilter.prototype, { - /** - * The texture used for the displacement map. Must be power of 2 texture. - * - * @member {Texture} - * @memberof DisplacementFilter# - */ - map: { - get: function () { - return this.uniforms.displacementMap.value; - }, - set: function (value) { - this.uniforms.displacementMap.value = value; - } - }, - - /** - * The multiplier used to scale the displacement result from the map calculation. - * - * @member {Point} - * @memberof DisplacementFilter# - */ - scale: { - get: function () { - return this.uniforms.scale.value; - }, - set: function (value) { - this.uniforms.scale.value = value; - } - }, - - /** - * The offset used to move the displacement map. - * - * @member {Point} - * @memberof DisplacementFilter# - */ - offset: { - get: function () { - return this.uniforms.offset.value; - }, - set: function (value) { - this.uniforms.offset.value = value; - } - } -}); - -},{"./AbstractFilter":56}],67:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js - */ - -/** - * This filter applies a dotscreen effect making display objects appear to be made out of - * black and white halftone dots like an old printer. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function DotScreenFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - scale: { type: '1f', value: 1 }, - angle: { type: '1f', value: 5 }, - dimensions: { type: '4fv', value: [0, 0, 0, 0] } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform vec4 dimensions;', - 'uniform sampler2D uSampler;', - - 'uniform float angle;', - 'uniform float scale;', - - 'float pattern() {', - ' float s = sin(angle), c = cos(angle);', - ' vec2 tex = vTextureCoord * dimensions.xy;', - ' vec2 point = vec2(', - ' c * tex.x - s * tex.y,', - ' s * tex.x + c * tex.y', - ' ) * scale;', - ' return (sin(point.x) * sin(point.y)) * 4.0;', - '}', - - 'void main() {', - ' vec4 color = texture2D(uSampler, vTextureCoord);', - ' float average = (color.r + color.g + color.b) / 3.0;', - ' gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a);', - '}' - ]; -} - -DotScreenFilter.prototype = Object.create(AbstractFilter.prototype); -DotScreenFilter.prototype.constructor = DotScreenFilter; -module.exports = DotScreenFilter; - -Object.defineProperties(DotScreenFilter.prototype, { - /** - * The scale of the effect. - * @member {number} - * @memberof DotScreenFilter# - */ - scale: { - get: function () { - return this.uniforms.scale.value; - }, - set: function (value) { - this.uniforms.scale.value = value; - } - }, - - /** - * The radius of the effect. - * @member {number} - * @memberof DotScreenFilter# - */ - angle: { - get: function () { - return this.uniforms.angle.value; - }, - set: function (value) { - this.uniforms.angle.value = value; - } - } -}); - -},{"./AbstractFilter":56}],68:[function(require,module,exports){ -/** - * A target and pass info object for filters. - * - * @class - * @namespace PIXI - */ -function FilterBlock() { - /** - * The visible state of this FilterBlock. - * - * @member {boolean} - */ - this.visible = true; - - /** - * The renderable state of this FilterBlock. - * - * @member {boolean} - */ - this.renderable = true; -} - -FilterBlock.prototype.constructor = FilterBlock; -module.exports = FilterBlock; - -},{}],69:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * This greyscales the palette of your Display Objects. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function GrayFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - gray: { type: '1f', value: 1 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform sampler2D uSampler;', - 'uniform float gray;', - - 'void main(void) {', - ' gl_FragColor = texture2D(uSampler, vTextureCoord);', - ' gl_FragColor.rgb = mix(gl_FragColor.rgb, vec3(0.2126*gl_FragColor.r + 0.7152*gl_FragColor.g + 0.0722*gl_FragColor.b), gray);', - // ' gl_FragColor = gl_FragColor;', - '}' - ]; -} - -GrayFilter.prototype = Object.create(AbstractFilter.prototype); -GrayFilter.prototype.constructor = GrayFilter; -module.exports = GrayFilter; - -Object.defineProperties(GrayFilter.prototype, { - /** - * The strength of the gray. 1 will make the object black and white, 0 will make the object its normal color. - * - * @member {number} - * @memberof GrayFilter# - */ - gray: { - get: function () { - return this.uniforms.gray.value; - }, - set: function (value) { - this.uniforms.gray.value = value; - } - } -}); - -},{"./AbstractFilter":56}],70:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * This inverts your Display Objects colors. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function InvertFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - invert: { type: '1f', value: 1 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float invert;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' gl_FragColor = texture2D(uSampler, vTextureCoord);', - ' gl_FragColor.rgb = mix( (vec3(1)-gl_FragColor.rgb) * gl_FragColor.a, gl_FragColor.rgb, 1.0 - invert);', - //' gl_FragColor.rgb = gl_FragColor.rgb * gl_FragColor.a;', - // ' gl_FragColor = gl_FragColor * vColor;', - '}' - ]; -} - -InvertFilter.prototype = Object.create(AbstractFilter.prototype); -InvertFilter.prototype.constructor = InvertFilter; -module.exports = InvertFilter; - -Object.defineProperties(InvertFilter.prototype, { - /** - * The strength of the invert. 1 will fully invert the colors, 0 will make the object its normal color - * - * @member {number} - * @memberof InvertFilter# - */ - invert: { - get: function () { - return this.uniforms.invert.value; - }, - set: function (value) { - this.uniforms.invert.value = value; - } - } -}); - -},{"./AbstractFilter":56}],71:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * @author Vico @vicocotea - * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/noise.js - */ - -/** - * A Noise effect filter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function NoiseFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - noise: { type: '1f', value: 0.5 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float noise;', - 'uniform sampler2D uSampler;', - - 'float rand(vec2 co) {', - ' return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);', - '}', - - 'void main() {', - ' vec4 color = texture2D(uSampler, vTextureCoord);', - - ' float diff = (rand(vTextureCoord) - 0.5) * noise;', - ' color.r += diff;', - ' color.g += diff;', - ' color.b += diff;', - - ' gl_FragColor = color;', - '}' - ]; -} - -NoiseFilter.prototype = Object.create(AbstractFilter.prototype); -NoiseFilter.prototype.constructor = NoiseFilter; -module.exports = NoiseFilter; - -Object.defineProperties(NoiseFilter.prototype, { - /** - * The amount of noise to apply. - * - * @member {number} - * @memberof NoiseFilter# - * @default 0.5 - */ - noise: { - get: function () { - return this.uniforms.noise.value; - }, - set: function (value) { - this.dirty = true; - this.uniforms.noise.value = value; - } - } -}); - -},{"./AbstractFilter":56}],72:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * The NormalMapFilter class uses the pixel values from the specified texture (called the displacement map) to perform a displacement of an object. - * You can use this filter to apply all manor of crazy warping effects - * Currently the r property of the texture is used offset the x and the g property of the texture is used to offset the y. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - * @param texture {Texture} The texture used for the normal map, must be power of 2 texture at the moment - */ -function NormalMapFilter(texture) { - AbstractFilter.call(this); - - texture.baseTexture._powerOf2 = true; - - // set the uniforms - this.uniforms = { - displacementMap: { type: 'sampler2D', value: texture }, - scale: { type: '2f', value: { x: 15, y: 15 } }, - offset: { type: '2f', value: { x: 0, y: 0 } }, - mapDimensions: { type: '2f', value: { x: 1, y: 1 } }, - dimensions: { type: '4f', value: [0, 0, 0, 0] }, - // LightDir: { type: 'f3', value: [0, 1, 0] }, - LightPos: { type: '3f', value: [0, 1, 0] } - }; - - if (texture.baseTexture.hasLoaded) { - this.onTextureLoaded(); - } - else { - this.boundLoadedFunction = this.onTextureLoaded.bind(this); - - texture.baseTexture.on('loaded', this.boundLoadedFunction); - } - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying float vColor;', - - 'uniform sampler2D displacementMap;', - 'uniform sampler2D uSampler;', - - 'uniform vec4 dimensions;', - - 'const vec2 Resolution = vec2(1.0,1.0);', //resolution of screen - 'uniform vec3 LightPos;', //light position, normalized - 'const vec4 LightColor = vec4(1.0, 1.0, 1.0, 1.0);', //light RGBA -- alpha is intensity - 'const vec4 AmbientColor = vec4(1.0, 1.0, 1.0, 0.5);', //ambient RGBA -- alpha is intensity - 'const vec3 Falloff = vec3(0.0, 1.0, 0.2);', //attenuation coefficients - - 'uniform vec3 LightDir;',//' = vec3(1.0, 0.0, 1.0);', - - - 'uniform vec2 mapDimensions;',// = vec2(256.0, 256.0);', - - - 'void main(void) {', - ' vec2 mapCords = vTextureCoord.xy;', - - ' vec4 color = texture2D(uSampler, vTextureCoord.st);', - ' vec3 nColor = texture2D(displacementMap, vTextureCoord.st).rgb;', - - - ' mapCords *= vec2(dimensions.x/512.0, dimensions.y/512.0);', - - ' mapCords.y *= -1.0;', - ' mapCords.y += 1.0;', - - //RGBA of our diffuse color - ' vec4 DiffuseColor = texture2D(uSampler, vTextureCoord);', - - //RGB of our normal map - ' vec3 NormalMap = texture2D(displacementMap, mapCords).rgb;', - - //The delta position of light - //'vec3 LightDir = vec3(LightPos.xy - (gl_FragCoord.xy / Resolution.xy), LightPos.z);', - ' vec3 LightDir = vec3(LightPos.xy - (mapCords.xy), LightPos.z);', - //Correct for aspect ratio - // ' LightDir.x *= Resolution.x / Resolution.y;', - - //Determine distance (used for attenuation) BEFORE we normalize our LightDir - ' float D = length(LightDir);', - - //normalize our vectors - ' vec3 N = normalize(NormalMap * 2.0 - 1.0);', - ' vec3 L = normalize(LightDir);', - - //Pre-multiply light color with intensity - //Then perform 'N dot L' to determine our diffuse term - ' vec3 Diffuse = (LightColor.rgb * LightColor.a) * max(dot(N, L), 0.0);', - - //pre-multiply ambient color with intensity - ' vec3 Ambient = AmbientColor.rgb * AmbientColor.a;', - - //calculate attenuation - ' float Attenuation = 1.0 / ( Falloff.x + (Falloff.y*D) + (Falloff.z*D*D) );', - - //the calculation which brings it all together - ' vec3 Intensity = Ambient + Diffuse * Attenuation;', - ' vec3 FinalColor = DiffuseColor.rgb * Intensity;', - ' gl_FragColor = vColor * vec4(FinalColor, DiffuseColor.a);', - // ' gl_FragColor = vec4(1.0, 0.0, 0.0, Attenuation);',//vColor * vec4(FinalColor, DiffuseColor.a);', - - /*// normalise color - ' vec3 normal = normalize(nColor * 2.0 - 1.0);', - - ' vec3 deltaPos = vec3( (light.xy - gl_FragCoord.xy) / resolution.xy, light.z );', - - ' float lambert = clamp(dot(normal, lightDir), 0.0, 1.0);', - - ' float d = sqrt(dot(deltaPos, deltaPos));', - ' float att = 1.0 / ( attenuation.x + (attenuation.y*d) + (attenuation.z*d*d) );', - - ' vec3 result = (ambientColor * ambientIntensity) + (lightColor.rgb * lambert) * att;', - ' result *= color.rgb;', - - ' gl_FragColor = vec4(result, 1.0);',*/ - '}' - ]; -} - -NormalMapFilter.prototype = Object.create(AbstractFilter.prototype); -NormalMapFilter.prototype.constructor = NormalMapFilter; -module.exports = NormalMapFilter; - -/** - * Sets the map dimensions uniforms when the texture becomes available. - * - */ -NormalMapFilter.prototype.onTextureLoaded = function () { - this.uniforms.mapDimensions.value.x = this.uniforms.displacementMap.value.width; - this.uniforms.mapDimensions.value.y = this.uniforms.displacementMap.value.height; - - this.uniforms.displacementMap.value.baseTexture.off('loaded', this.boundLoadedFunction); -}; - -Object.defineProperties(NormalMapFilter.prototype, { - /** - * The texture used for the displacement map. Must be power of 2 texture. - * - * @member {Texture} - * @memberof NormalMapFilter# - */ - map: { - get: function () { - return this.uniforms.displacementMap.value; - }, - set: function (value) { - this.uniforms.displacementMap.value = value; - } - }, - - /** - * The multiplier used to scale the displacement result from the map calculation. - * - * @member {Point} - * @memberof NormalMapFilter# - */ - scale: { - get: function () { - return this.uniforms.scale.value; - }, - set: function (value) { - this.uniforms.scale.value = value; - } - }, - - /** - * The offset used to move the displacement map. - * - * @member {Point} - * @memberof NormalMapFilter# - */ - offset: { - get: function () { - return this.uniforms.offset.value; - }, - set: function (value) { - this.uniforms.offset.value = value; - } - } -}); - -},{"./AbstractFilter":56}],73:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * This filter applies a pixelate effect making display objects appear 'blocky'. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function PixelateFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - invert: { type: '1f', value: 0 }, - dimensions: { type: '4fv', value: new Float32Array([10000, 100, 10, 10]) }, - pixelSize: { type: '2f', value: { x: 10, y: 10 } } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform vec2 testDim;', - 'uniform vec4 dimensions;', - 'uniform vec2 pixelSize;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' vec2 coord = vTextureCoord;', - - ' vec2 size = dimensions.xy/pixelSize;', - - ' vec2 color = floor( ( vTextureCoord * size ) ) / size + pixelSize/dimensions.xy * 0.5;', - ' gl_FragColor = texture2D(uSampler, color);', - '}' - ]; -} - -PixelateFilter.prototype = Object.create(AbstractFilter.prototype); -PixelateFilter.prototype.constructor = PixelateFilter; -module.exports = PixelateFilter; - -Object.defineProperties(PixelateFilter.prototype, { - /** - * This a point that describes the size of the blocks. x is the width of the block and y is the height. - * - * @member {Point} - * @memberof PixelateFilter# - */ - size: { - get: function () { - return this.uniforms.pixelSize.value; - }, - set: function (value) { - this.uniforms.pixelSize.value = value; - } - } -}); - -},{"./AbstractFilter":56}],74:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * An RGB Split Filter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function RGBSplitFilter() { - AbstractFilter.call(this); - - this.passes = [this]; - - // set the uniforms - this.uniforms = { - red: { type: '2f', value: { x: 20, y: 20 } }, - green: { type: '2f', value: { x: -20, y: 20 } }, - blue: { type: '2f', value: { x: 20, y: -20 } }, - dimensions: { type: '4fv', value: [0, 0, 0, 0] } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform vec2 red;', - 'uniform vec2 green;', - 'uniform vec2 blue;', - 'uniform vec4 dimensions;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' gl_FragColor.r = texture2D(uSampler, vTextureCoord + red/dimensions.xy).r;', - ' gl_FragColor.g = texture2D(uSampler, vTextureCoord + green/dimensions.xy).g;', - ' gl_FragColor.b = texture2D(uSampler, vTextureCoord + blue/dimensions.xy).b;', - ' gl_FragColor.a = texture2D(uSampler, vTextureCoord).a;', - '}' - ]; -} - -RGBSplitFilter.prototype = Object.create(AbstractFilter.prototype); -RGBSplitFilter.prototype.constructor = RGBSplitFilter; -module.exports = RGBSplitFilter; - -Object.defineProperties(RGBSplitFilter.prototype, { - /** - * Red channel offset. - * - * @member {Point} - * @memberof RGBSplitFilter# - */ - red: { - get: function () { - return this.uniforms.red.value; - }, - set: function (value) { - this.uniforms.red.value = value; - } - }, - - /** - * Green channel offset. - * - * @member {Point} - * @memberof RGBSplitFilter# - */ - green: { - get: function () { - return this.uniforms.green.value; - }, - set: function (value) { - this.uniforms.green.value = value; - } - }, - - /** - * Blue offset. - * - * @member {Point} - * @memberof RGBSplitFilter# - */ - blue: { - get: function () { - return this.uniforms.blue.value; - }, - set: function (value) { - this.uniforms.blue.value = value; - } - } -}); - -},{"./AbstractFilter":56}],75:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * This applies a sepia effect to your Display Objects. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function SepiaFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - sepia: { type: '1f', value: 1 } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float sepia;', - 'uniform sampler2D uSampler;', - - 'const mat3 sepiaMatrix = mat3(0.3588, 0.7044, 0.1368, 0.2990, 0.5870, 0.1140, 0.2392, 0.4696, 0.0912);', - - 'void main(void) {', - ' gl_FragColor = texture2D(uSampler, vTextureCoord);', - ' gl_FragColor.rgb = mix( gl_FragColor.rgb, gl_FragColor.rgb * sepiaMatrix, sepia);', - '}' - ]; -} - -SepiaFilter.prototype = Object.create(AbstractFilter.prototype); -SepiaFilter.prototype.constructor = SepiaFilter; -module.exports = SepiaFilter; - -Object.defineProperties(SepiaFilter.prototype, { - /** - * The strength of the sepia. 1 will apply the full sepia effect, 0 will make the object its normal color. - * - * @member {number} - * @memberof SepiaFilter# - */ - sepia: { - get: function () { - return this.uniforms.sepia.value; - }, - set: function (value) { - this.uniforms.sepia.value = value; - } - } -}); - -},{"./AbstractFilter":56}],76:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * A Smart Blur Filter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function SmartBlurFilter() { - AbstractFilter.call(this); - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - - 'uniform sampler2D uSampler;', - 'const vec2 delta = vec2(1.0/10.0, 0.0);', - - 'float random(vec3 scale, float seed) {', - ' return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);', - '}', - - - 'void main(void) {', - ' vec4 color = vec4(0.0);', - ' float total = 0.0;', - - ' float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);', - - ' for (float t = -30.0; t <= 30.0; t++) {', - ' float percent = (t + offset - 0.5) / 30.0;', - ' float weight = 1.0 - abs(percent);', - ' vec4 sample = texture2D(uSampler, vTextureCoord + delta * percent);', - ' sample.rgb *= sample.a;', - ' color += sample * weight;', - ' total += weight;', - ' }', - - ' gl_FragColor = color / total;', - ' gl_FragColor.rgb /= gl_FragColor.a + 0.00001;', - '}' - ]; -} - -SmartBlurFilter.prototype = Object.create(AbstractFilter.prototype); -SmartBlurFilter.prototype.constructor = SmartBlurFilter; -module.exports = SmartBlurFilter; - -},{"./AbstractFilter":56}],77:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'), - TiltShiftXFilter = require('./TiltShiftXFilter'), - TiltShiftYFilter = require('./TiltShiftYFilter'); - -/** - * @author Vico @vicocotea - * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ - */ - -/** - * A TiltShift Filter. Manages the pass of both a TiltShiftXFilter and TiltShiftYFilter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function TiltShiftFilter() { - AbstractFilter.call(this); - - this.tiltShiftXFilter = new TiltShiftXFilter(); - this.tiltShiftYFilter = new TiltShiftYFilter(); - - this.tiltShiftXFilter.updateDelta(); - this.tiltShiftXFilter.updateDelta(); - - this.passes = [this.tiltShiftXFilter, this.tiltShiftYFilter]; -} - -TiltShiftFilter.prototype = Object.create(AbstractFilter.prototype); -TiltShiftFilter.prototype.constructor = TiltShiftFilter; -module.exports = TiltShiftFilter; - -Object.defineProperties(TiltShiftFilter.prototype, { - /** - * The strength of the blur. - * - * @member {number} - * @memberof TiltShiftFilter# - */ - blur: { - get: function () { - return this.tiltShiftXFilter.blur; - }, - set: function (value) { - this.tiltShiftXFilter.blur = this.tiltShiftYFilter.blur = value; - } - }, - - /** - * The strength of the gradient blur. - * - * @member {number} - * @memberof TiltShiftFilter# - */ - gradientBlur: { - get: function () { - return this.tiltShiftXFilter.gradientBlur; - }, - set: function (value) { - this.tiltShiftXFilter.gradientBlur = this.tiltShiftYFilter.gradientBlur = value; - } - }, - - /** - * The Y value to start the effect at. - * - * @member {number} - * @memberof TiltShiftFilter# - */ - start: { - get: function () { - return this.tiltShiftXFilter.start; - }, - set: function (value) { - this.tiltShiftXFilter.start = this.tiltShiftYFilter.start = value; - } - }, - - /** - * The Y value to end the effect at. - * - * @member {number} - * @memberof TiltShiftFilter# - */ - end: { - get: function () { - return this.tiltShiftXFilter.end; - }, - set: function (value) { - this.tiltShiftXFilter.end = this.tiltShiftYFilter.end = value; - } - }, -}); - -},{"./AbstractFilter":56,"./TiltShiftXFilter":78,"./TiltShiftYFilter":79}],78:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * @author Vico @vicocotea - * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ - */ - -/** - * A TiltShiftXFilter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function TiltShiftXFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - blur: { type: '1f', value: 100 }, - gradientBlur: { type: '1f', value: 600 }, - start: { type: '2f', value: { x: 0, y: window.screenHeight / 2 } }, - end: { type: '2f', value: { x: 600, y: window.screenHeight / 2 } }, - delta: { type: '2f', value: { x: 30, y: 30 } }, - texSize: { type: '2f', value: { x: window.screenWidth, y: window.screenHeight } } - }; - - this.updateDelta(); - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - - 'uniform sampler2D uSampler;', - 'uniform float blur;', - 'uniform float gradientBlur;', - 'uniform vec2 start;', - 'uniform vec2 end;', - 'uniform vec2 delta;', - 'uniform vec2 texSize;', - - 'float random(vec3 scale, float seed) {', - ' return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);', - '}', - - 'void main(void) {', - ' vec4 color = vec4(0.0);', - ' float total = 0.0;', - - ' float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);', - ' vec2 normal = normalize(vec2(start.y - end.y, end.x - start.x));', - ' float radius = smoothstep(0.0, 1.0, abs(dot(vTextureCoord * texSize - start, normal)) / gradientBlur) * blur;', - - ' for (float t = -30.0; t <= 30.0; t++) {', - ' float percent = (t + offset - 0.5) / 30.0;', - ' float weight = 1.0 - abs(percent);', - ' vec4 sample = texture2D(uSampler, vTextureCoord + delta / texSize * percent * radius);', - ' sample.rgb *= sample.a;', - ' color += sample * weight;', - ' total += weight;', - ' }', - - ' gl_FragColor = color / total;', - ' gl_FragColor.rgb /= gl_FragColor.a + 0.00001;', - '}' - ]; -} - -TiltShiftXFilter.prototype = Object.create(AbstractFilter.prototype); -TiltShiftXFilter.prototype.constructor = TiltShiftXFilter; -module.exports = TiltShiftXFilter; - -/** - * Updates the filter delta values. - * - */ -TiltShiftXFilter.prototype.updateDelta = function () { - var dx = this.uniforms.end.value.x - this.uniforms.start.value.x; - var dy = this.uniforms.end.value.y - this.uniforms.start.value.y; - var d = Math.sqrt(dx * dx + dy * dy); - - this.uniforms.delta.value.x = dx / d; - this.uniforms.delta.value.y = dy / d; -}; - - -Object.defineProperties(TiltShiftXFilter.prototype, { - /** - * The strength of the blur. - * - * @member {number} - * @memberof TilttShiftXFilter# - */ - blur: { - get: function () { - return this.uniforms.blur.value; - }, - set: function (value) { - this.uniforms.blur.value = value; - } - }, - - /** - * The strength of the gradient blur. - * - * @member {number} - * @memberof TilttShiftXFilter# - */ - gradientBlur: { - get: function () { - return this.uniforms.gradientBlur.value; - }, - set: function (value) { - this.uniforms.gradientBlur.value = value; - } - }, - - /** - * The X value to start the effect at. - * - * @member {number} - * @memberof TilttShiftXFilter# - */ - start: { - get: function () { - return this.uniforms.start.value; - }, - set: function (value) { - this.uniforms.start.value = value; - this.updateDelta(); - } - }, - - /** - * The X value to end the effect at. - * - * @member {number} - * @memberof TilttShiftXFilter# - */ - end: { - get: function () { - return this.uniforms.end.value; - }, - set: function (value) { - this.uniforms.end.value = value; - this.updateDelta(); - } - } -}); - -},{"./AbstractFilter":56}],79:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * @author Vico @vicocotea - * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ - */ - -/** - * A TiltShiftYFilter. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function TiltShiftYFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - blur: { type: '1f', value: 100 }, - gradientBlur: { type: '1f', value: 600 }, - start: { type: '2f', value: { x: 0, y: window.screenHeight / 2 } }, - end: { type: '2f', value: { x: 600, y: window.screenHeight / 2 } }, - delta: { type: '2f', value: { x: 30, y: 30 } }, - texSize: { type: '2f', value: { x: window.screenWidth, y: window.screenHeight } } - }; - - this.updateDelta(); - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - - 'uniform sampler2D uSampler;', - 'uniform float blur;', - 'uniform float gradientBlur;', - 'uniform vec2 start;', - 'uniform vec2 end;', - 'uniform vec2 delta;', - 'uniform vec2 texSize;', - - 'float random(vec3 scale, float seed) {', - ' return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);', - '}', - - 'void main(void) {', - ' vec4 color = vec4(0.0);', - ' float total = 0.0;', - - ' float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);', - ' vec2 normal = normalize(vec2(start.y - end.y, end.x - start.x));', - ' float radius = smoothstep(0.0, 1.0, abs(dot(vTextureCoord * texSize - start, normal)) / gradientBlur) * blur;', - - ' for (float t = -30.0; t <= 30.0; t++) {', - ' float percent = (t + offset - 0.5) / 30.0;', - ' float weight = 1.0 - abs(percent);', - ' vec4 sample = texture2D(uSampler, vTextureCoord + delta / texSize * percent * radius);', - ' sample.rgb *= sample.a;', - ' color += sample * weight;', - ' total += weight;', - ' }', - - ' gl_FragColor = color / total;', - ' gl_FragColor.rgb /= gl_FragColor.a + 0.00001;', - '}' - ]; -} - -TiltShiftYFilter.prototype = Object.create(AbstractFilter.prototype); -TiltShiftYFilter.prototype.constructor = TiltShiftYFilter; -module.exports = TiltShiftYFilter; - -/** - * Updates the filter delta values. - * - */ -TiltShiftYFilter.prototype.updateDelta = function (){ - var dx = this.uniforms.end.value.x - this.uniforms.start.value.x; - var dy = this.uniforms.end.value.y - this.uniforms.start.value.y; - var d = Math.sqrt(dx * dx + dy * dy); - this.uniforms.delta.value.x = -dy / d; - this.uniforms.delta.value.y = dx / d; -}; - -Object.defineProperties(TiltShiftYFilter.prototype, { - /** - * The strength of the blur. - * - * @member {number} - * @memberof TiltShiftYFilter# - */ - blur: { - get: function () { - return this.uniforms.blur.value; - }, - set: function (value) { - this.uniforms.blur.value = value; - } - }, - - /** - * The strength of the gradient blur. - * - * @member {number} - * @memberof TiltShiftYFilter# - */ - gradientBlur: { - get: function () { - return this.uniforms.gradientBlur.value; - }, - set: function (value) { - this.uniforms.gradientBlur.value = value; - } - }, - - /** - * The Y value to start the effect at. - * - * @member {number} - * @memberof TiltShiftYFilter# - */ - start: { - get: function () { - return this.uniforms.start.value; - }, - set: function (value) { - this.uniforms.start.value = value; - this.updateDelta(); - } - }, - - /** - * The Y value to end the effect at. - * - * @member {number} - * @memberof TiltShiftYFilter# - */ - end: { - get: function () { - return this.uniforms.end.value; - }, - set: function (value) { - this.uniforms.end.value = value; - this.updateDelta(); - } - } -}); - -},{"./AbstractFilter":56}],80:[function(require,module,exports){ -var AbstractFilter = require('./AbstractFilter'); - -/** - * This filter applies a twist effect making display objects appear twisted in the given direction. - * - * @class - * @extends AbstractFilter - * @namespace PIXI - */ -function TwistFilter() { - AbstractFilter.call(this); - - // set the uniforms - this.uniforms = { - radius: { type: '1f', value: 0.5}, - angle: { type: '1f', value: 5}, - offset: { type: '2f', value: { x: 0.5, y: 0.5 } } - }; - - this.fragmentSrc = [ - 'precision mediump float;', - - 'varying vec2 vTextureCoord;', - 'varying vec4 vColor;', - - 'uniform float radius;', - 'uniform float angle;', - 'uniform vec2 offset;', - 'uniform sampler2D uSampler;', - - 'void main(void) {', - ' vec2 coord = vTextureCoord - offset;', - ' float distance = length(coord);', - - ' if (distance < radius) {', - ' float ratio = (radius - distance) / radius;', - ' float angleMod = ratio * ratio * angle;', - ' float s = sin(angleMod);', - ' float c = cos(angleMod);', - ' coord = vec2(coord.x * c - coord.y * s, coord.x * s + coord.y * c);', - ' }', - - ' gl_FragColor = texture2D(uSampler, coord+offset);', - '}' - ]; -} - -TwistFilter.prototype = Object.create(AbstractFilter.prototype); -TwistFilter.prototype.constructor = TwistFilter; -module.exports = TwistFilter; - -Object.defineProperties(TwistFilter.prototype, { - /** - * This point describes the the offset of the twist. - * - * @member {Point} - * @memberof TwistFilter# - */ - offset: { - get: function () { - return this.uniforms.offset.value; - }, - set: function (value) { - this.uniforms.offset.value = value; - } - }, - - /** - * This radius of the twist. - * - * @member {number} - * @memberof TwistFilter# - */ - radius: { - get: function () { - return this.uniforms.radius.value; - }, - set: function (value) { - this.uniforms.radius.value = value; - } - }, - - /** - * This angle of the twist. - * - * @member {number} - * @memberof TwistFilter# - */ - angle: { - get: function () { - return this.uniforms.angle.value; - }, - set: function (value) { - this.uniforms.angle.value = value; - } - } -}); - -},{"./AbstractFilter":56}],81:[function(require,module,exports){ -/** - * @file Main export of the PIXI filters library - * @author Mat Groves - * @copyright 2013-2015 GoodBoyDigital - * @license {@link https://github.com/GoodBoyDigital/pixi.js/blob/master/LICENSE|MIT License} - */ - -/** - * @namespace PIXI - */ -module.exports = { - AbstractFilter: require('./AbstractFilter'), - AlphaMaskFilter: require('./AlphaMaskFilter'), - AsciiFilter: require('./AsciiFilter'), - BlurFilter: require('./BlurFilter'), - BlurXFilter: require('./BlurXFilter'), - BlurYFilter: require('./BlurYFilter'), - ColorMatrixFilter: require('./ColorMatrixFilter'), - ColorStepFilter: require('./ColorStepFilter'), - ConvolutionFilter: require('./ConvolutionFilter'), - CrossHatchFilter: require('./CrossHatchFilter'), - DisplacementFilter: require('./DisplacementFilter'), - DotScreenFilter: require('./DotScreenFilter'), - FilterBlock: require('./FilterBlock'), - GrayFilter: require('./GrayFilter'), - InvertFilter: require('./InvertFilter'), - NoiseFilter: require('./NoiseFilter'), - NormalMapFilter: require('./NormalMapFilter'), - PixelateFilter: require('./PixelateFilter'), - RGBSplitFilter: require('./RGBSplitFilter'), - SepiaFilter: require('./SepiaFilter'), - SmartBlurFilter: require('./SmartBlurFilter'), - TiltShiftFilter: require('./TiltShiftFilter'), - TiltShiftXFilter: require('./TiltShiftXFilter'), - TiltShiftYFilter: require('./TiltShiftYFilter'), - TwistFilter: require('./TwistFilter') -}; - -},{"./AbstractFilter":56,"./AlphaMaskFilter":57,"./AsciiFilter":58,"./BlurFilter":59,"./BlurXFilter":60,"./BlurYFilter":61,"./ColorMatrixFilter":62,"./ColorStepFilter":63,"./ConvolutionFilter":64,"./CrossHatchFilter":65,"./DisplacementFilter":66,"./DotScreenFilter":67,"./FilterBlock":68,"./GrayFilter":69,"./InvertFilter":70,"./NoiseFilter":71,"./NormalMapFilter":72,"./PixelateFilter":73,"./RGBSplitFilter":74,"./SepiaFilter":75,"./SmartBlurFilter":76,"./TiltShiftFilter":77,"./TiltShiftXFilter":78,"./TiltShiftYFilter":79,"./TwistFilter":80}],82:[function(require,module,exports){ -var core = require('../core'); - -/** - * Holds all information related to an Interaction event - * - * @class - * @namespace PIXI - */ -function InteractionData() { - /** - * This point stores the global coords of where the touch/mouse event happened - * - * @member {Point} - */ - this.global = new core.math.Point(); - - /** - * The target Sprite that was interacted with - * - * @member {Sprite} - */ - this.target = null; - - /** - * When passed to an event handler, this will be the original DOM Event that was captured - * - * @member {Event} - */ - this.originalEvent = null; -} - -InteractionData.prototype.constructor = InteractionData; -module.exports = InteractionData; - -/** - * This will return the local coordinates of the specified displayObject for this InteractionData - * - * @param displayObject {DisplayObject} The DisplayObject that you would like the local coords off - * @param [point] {Point} A Point object in which to store the value, optional (otherwise will create a new point) - * @return {Point} A point containing the coordinates of the InteractionData position relative to the DisplayObject - */ -InteractionData.prototype.getLocalPosition = function (displayObject, point) { - var worldTransform = displayObject.worldTransform; - var global = this.global; - - // do a cheeky transform to get the mouse coords; - var a00 = worldTransform.a, a01 = worldTransform.c, a02 = worldTransform.tx, - a10 = worldTransform.b, a11 = worldTransform.d, a12 = worldTransform.ty, - id = 1 / (a00 * a11 + a01 * -a10); - - point = point || new core.math.Point(); - - point.x = a11 * id * global.x + -a01 * id * global.y + (a12 * a01 - a02 * a11) * id; - point.y = a00 * id * global.y + -a10 * id * global.x + (-a12 * a00 + a02 * a10) * id; - - // set the mouse coords... - return point; -}; - -},{"../core":9}],83:[function(require,module,exports){ -var core = require('../core'), - InteractionData = require('./InteractionData'); - -// TODO: Obviously rewrite this... -var INTERACTION_FREQUENCY = 30; -var AUTO_PREVENT_DEFAULT = true; - -/** - * The interaction manager deals with mouse and touch events. Any DisplayObject can be interactive - * if its interactive parameter is set to true - * This manager also supports multitouch. - * - * @class - * @namespace PIXI - * @param stage {Stage} The stage to handle interactions - */ -function InteractionManager(stage) { - /** - * A reference to the stage - * - * @member {Stage} - */ - this.stage = stage; - - /** - * The mouse data - * - * @member {InteractionData} - */ - this.mouse = new InteractionData(); - - /** - * An object that stores current touches (InteractionData) by id reference - * - * @member {object} - */ - this.touches = {}; - - /** - * @member {Point} - * @private - */ - this.tempPoint = new core.math.Point(); - - /** - * @member {boolean} - * @default - */ - this.mouseoverEnabled = true; - - /** - * Tiny little interactiveData pool ! - * - * @member {Array} - */ - this.pool = []; - - /** - * An array containing all the iterative items from the our interactive tree - * - * @member {Array} - * @private - */ - this.interactiveItems = []; - - /** - * The DOM element to bind to. - * - * @member {HTMLElement} - * @private - */ - this.interactionDOMElement = null; - - /** - * Have events been attached to the dom element? - * - * @member {boolean} - * @private - */ - this.eventsAdded = false; - - //this will make it so that you don't have to call bind all the time - - /** - * @member {Function} - */ - this.onMouseMove = this.onMouseMove.bind( this ); - - /** - * @member {Function} - */ - this.onMouseDown = this.onMouseDown.bind(this); - - /** - * @member {Function} - */ - this.onMouseOut = this.onMouseOut.bind(this); - - /** - * @member {Function} - */ - this.onMouseUp = this.onMouseUp.bind(this); - - /** - * @member {Function} - */ - this.onTouchStart = this.onTouchStart.bind(this); - - /** - * @member {Function} - */ - this.onTouchEnd = this.onTouchEnd.bind(this); - - /** - * @member {Function} - */ - this.onTouchMove = this.onTouchMove.bind(this); - - /** - * @member {number} - */ - this.last = 0; - - /** - * The css style of the cursor that is being used - * @member {string} - */ - this.currentCursorStyle = 'inherit'; - - /** - * Is set to true when the mouse is moved out of the canvas - * @member {boolean} - */ - this.mouseOut = false; - - /** - * @member {number} - */ - this.resolution = 1; - - // used for hit testing - this._tempPoint = new core.math.Point(); -} - -InteractionManager.prototype.constructor = InteractionManager; -module.exports = InteractionManager; - -/** - * Collects an interactive sprite recursively to have their interactions managed - * - * @param displayObject {DisplayObject} the displayObject to collect - * @param iParent {DisplayObject} the display object's parent - * @private - */ -InteractionManager.prototype.collectInteractiveSprite = function (displayObject, iParent) { - var children = displayObject.children; - var length = children.length; - - // make an interaction tree... {item.__interactiveParent} - for (var i = length - 1; i >= 0; i--) { - var child = children[i]; - - // push all interactive bits - if (child._interactive) { - iParent.interactiveChildren = true; - //child.__iParent = iParent; - this.interactiveItems.push(child); - - if (child.children.length > 0) { - this.collectInteractiveSprite(child, child); - } - } - else { - child.__iParent = null; - if (child.children.length > 0) { - this.collectInteractiveSprite(child, iParent); - } - } - - } -}; - -/** - * Sets the DOM element which will receive mouse/touch events. This is useful for when you have - * other DOM elements on top of the renderers Canvas element. With this you'll be bale to deletegate - * another DOM element to receive those events. - * - * @param element {HTMLElement} the DOM element which will receive mouse and touch events. - * @param [resolution=1] {number} THe resolution of the new element (relative to the canvas). - * @private - */ -InteractionManager.prototype.setTargetElement = function (element, resolution) { - this.removeEvents(); - - this.interactionDOMElement = element; - - this.resolution = resolution || 1; - - this.addEvents(); -}; - -/** - * - * @private - */ -InteractionManager.prototype.addEvents = function () { - if (!this.interactionDOMElement) { - return; - } - - if (window.navigator.msPointerEnabled) { - this.interactionDOMElement.style['-ms-content-zooming'] = 'none'; - this.interactionDOMElement.style['-ms-touch-action'] = 'none'; - } - - this.interactionDOMElement.addEventListener('mousemove', this.onMouseMove, true); - this.interactionDOMElement.addEventListener('mousedown', this.onMouseDown, true); - this.interactionDOMElement.addEventListener('mouseout', this.onMouseOut, true); - - this.interactionDOMElement.addEventListener('touchstart', this.onTouchStart, true); - this.interactionDOMElement.addEventListener('touchend', this.onTouchEnd, true); - this.interactionDOMElement.addEventListener('touchmove', this.onTouchMove, true); - - window.addEventListener('mouseup', this.onMouseUp, true); - - this.eventsAdded = true; -}; - -/** - * - * @private - */ -InteractionManager.prototype.removeEvents = function () { - if (!this.interactionDOMElement) { - return; - } - - if (window.navigator.msPointerEnabled) { - this.interactionDOMElement.style['-ms-content-zooming'] = ''; - this.interactionDOMElement.style['-ms-touch-action'] = ''; - } - - this.interactionDOMElement.removeEventListener('mousemove', this.onMouseMove, true); - this.interactionDOMElement.removeEventListener('mousedown', this.onMouseDown, true); - this.interactionDOMElement.removeEventListener('mouseout', this.onMouseOut, true); - - this.interactionDOMElement.removeEventListener('touchstart', this.onTouchStart, true); - this.interactionDOMElement.removeEventListener('touchend', this.onTouchEnd, true); - this.interactionDOMElement.removeEventListener('touchmove', this.onTouchMove, true); - - this.interactionDOMElement = null; - - window.removeEventListener('mouseup', this.onMouseUp, true); - - this.eventsAdded = false; -}; - -/** - * updates the state of interactive objects - * - * @private - */ -InteractionManager.prototype.update = function () { - if (!this.interactionDOMElement) { - return; - } - - // frequency of 30fps?? - var now = Date.now(); - var diff = now - this.last; - diff = (diff * INTERACTION_FREQUENCY ) / 1000; - if (diff < 1) { - return; - } - - this.last = now; - - var i = 0; - - // ok.. so mouse events?? - // yes for now :) - // OPTIMISE - how often to check?? - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - // loop through interactive objects! - var length = this.interactiveItems.length; - var cursor = 'inherit'; - var over = false; - - for (i = 0; i < length; i++) { - var item = this.interactiveItems[i]; - - // OPTIMISATION - only calculate every time if the mousemove function exists.. - // OK so.. does the object have any other interactive functions? - // hit-test the clip! - // if (item.mouseover || item.mouseout || item.buttonMode) - // { - // ok so there are some functions so lets hit test it.. - item.__hit = this.hitTest(item, this.mouse); - this.mouse.target = item; - // ok so deal with interactions.. - // looks like there was a hit! - if (item.__hit && !over) { - if (item.buttonMode) { - cursor = item.defaultCursor; - } - - if (!item.interactiveChildren) { - over = true; - } - - if (!item.__isOver) { - if (item.mouseover) { - item.mouseover (this.mouse); - } - item.__isOver = true; - } - } - else { - if (item.__isOver) { - // roll out! - if (item.mouseout) { - item.mouseout (this.mouse); - } - item.__isOver = false; - } - } - } - - if (this.currentCursorStyle !== cursor) { - this.currentCursorStyle = cursor; - this.interactionDOMElement.style.cursor = cursor; - } -}; - -/** - * @private - */ -InteractionManager.prototype.rebuildInteractiveGraph = function () { - this.dirty = false; - - var len = this.interactiveItems.length; - - for (var i = 0; i < len; i++) { - this.interactiveItems[i].interactiveChildren = false; - } - - this.interactiveItems.length = 0; - - if (this.stage.interactive) { - this.interactiveItems.push(this.stage); - } - - // Go through and collect all the objects that are interactive.. - this.collectInteractiveSprite(this.stage, this.stage); -}; - -/** - * Is called when the mouse moves across the renderer element - * - * @param event {Event} The DOM event of the mouse moving - * @private - */ -InteractionManager.prototype.onMouseMove = function (event) { - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - this.mouse.originalEvent = event; - - // TODO optimize by not check EVERY TIME! maybe half as often? // - var rect = this.interactionDOMElement.getBoundingClientRect(); - - this.mouse.global.x = (event.clientX - rect.left) * (this.interactionDOMElement.width / rect.width) / this.resolution; - this.mouse.global.y = (event.clientY - rect.top) * ( this.interactionDOMElement.height / rect.height) / this.resolution; - - var length = this.interactiveItems.length; - - for (var i = 0; i < length; i++) { - var item = this.interactiveItems[i]; - - // Call the function! - if (item.mousemove) { - item.mousemove(this.mouse); - } - } -}; - -/** - * Is called when the mouse button is pressed down on the renderer element - * - * @param event {Event} The DOM event of a mouse button being pressed down - * @private - */ -InteractionManager.prototype.onMouseDown = function (event) { - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - this.mouse.originalEvent = event; - - if (AUTO_PREVENT_DEFAULT) { - this.mouse.originalEvent.preventDefault(); - } - - // loop through interaction tree... - // hit test each item! -> - // get interactive items under point?? - //stage.__i - var length = this.interactiveItems.length; - - var e = this.mouse.originalEvent; - var isRightButton = e.button === 2 || e.which === 3; - var downFunction = isRightButton ? 'rightdown' : 'mousedown'; - var clickFunction = isRightButton ? 'rightclick' : 'click'; - var buttonIsDown = isRightButton ? '__rightIsDown' : '__mouseIsDown'; - var isDown = isRightButton ? '__isRightDown' : '__isDown'; - - // while - // hit test - for (var i = 0; i < length; i++) { - var item = this.interactiveItems[i]; - - if (item[downFunction] || item[clickFunction]) { - item[buttonIsDown] = true; - item.__hit = this.hitTest(item, this.mouse); - - if (item.__hit) { - //call the function! - if (item[downFunction]) { - item[downFunction](this.mouse); - } - item[isDown] = true; - - // just the one! - if (!item.interactiveChildren) { - break; - } - } - } - } -}; - -/** - * Is called when the mouse is moved out of the renderer element - * - * @param event {Event} The DOM event of a mouse being moved out - * @private - */ -InteractionManager.prototype.onMouseOut = function (event) { - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - this.mouse.originalEvent = event; - - var length = this.interactiveItems.length; - - this.interactionDOMElement.style.cursor = 'inherit'; - - for (var i = 0; i < length; i++) { - var item = this.interactiveItems[i]; - if (item.__isOver) { - this.mouse.target = item; - if (item.mouseout) { - item.mouseout(this.mouse); - } - item.__isOver = false; - } - } - - this.mouseOut = true; - - // move the mouse to an impossible position - this.mouse.global.x = -10000; - this.mouse.global.y = -10000; -}; - -/** - * Is called when the mouse button is released on the renderer element - * - * @param event {Event} The DOM event of a mouse button being released - * @private - */ -InteractionManager.prototype.onMouseUp = function (event) { - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - this.mouse.originalEvent = event; - - var length = this.interactiveItems.length; - var up = false; - - var e = this.mouse.originalEvent; - var isRightButton = e.button === 2 || e.which === 3; - - var upFunction = isRightButton ? 'rightup' : 'mouseup'; - var clickFunction = isRightButton ? 'rightclick' : 'click'; - var upOutsideFunction = isRightButton ? 'rightupoutside' : 'mouseupoutside'; - var isDown = isRightButton ? '__isRightDown' : '__isDown'; - - for (var i = 0; i < length; i++) { - var item = this.interactiveItems[i]; - - if (item[clickFunction] || item[upFunction] || item[upOutsideFunction]) { - item.__hit = this.hitTest(item, this.mouse); - - if (item.__hit && !up) { - //call the function! - if (item[upFunction]) { - item[upFunction](this.mouse); - } - if (item[isDown]) { - if (item[clickFunction]) { - item[clickFunction](this.mouse); - } - } - - if (!item.interactiveChildren) { - up = true; - } - } - else { - if (item[isDown]) { - if (item[upOutsideFunction]) { - item[upOutsideFunction](this.mouse); - } - } - } - - item[isDown] = false; - } - } -}; - -/** - * Tests if the current mouse coordinates hit a sprite - * - * @param item {DisplayObject} The displayObject to test for a hit - * @param interactionData {InteractionData} The interactionData object to update in the case there is a hit - * @private - */ -InteractionManager.prototype.hitTest = function (item, interactionData) { - var global = interactionData.global; - - if (!item.worldVisible) { - return false; - } - - // map the global point to local space. - item.worldTransform.applyInverse(global, this._tempPoint); - - var x = this._tempPoint.x, - y = this._tempPoint.y, - i; - - interactionData.target = item; - - //a sprite or display object with a hit area defined - if (item.hitArea && item.hitArea.contains) { - return item.hitArea.contains(x, y); - } - // a sprite with no hitarea defined - else if (item instanceof core.Sprite) { - var width = item.texture.frame.width; - var height = item.texture.frame.height; - var x1 = -width * item.anchor.x; - var y1; - - if (x > x1 && x < x1 + width) { - y1 = -height * item.anchor.y; - - if (y > y1 && y < y1 + height) { - // set the target property if a hit is true! - return true; - } - } - } - else if (item instanceof core.Graphics) { - var graphicsData = item.graphicsData; - for (i = 0; i < graphicsData.length; i++) { - var data = graphicsData[i]; - - if (!data.fill) { - continue; - } - - // only deal with fills.. - if (data.shape) { - if (data.shape.contains(x, y)) { - //interactionData.target = item; - return true; - } - } - } - } - - var length = item.children.length; - - for (i = 0; i < length; i++) { - var tempItem = item.children[i]; - var hit = this.hitTest(tempItem, interactionData); - if (hit) { - // hmm.. TODO SET CORRECT TARGET? - interactionData.target = item; - return true; - } - } - return false; -}; - -/** - * Is called when a touch is moved across the renderer element - * - * @param event {Event} The DOM event of a touch moving across the renderer view - * @private - */ -InteractionManager.prototype.onTouchMove = function (event) { - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - var rect = this.interactionDOMElement.getBoundingClientRect(); - var changedTouches = event.changedTouches; - var touchData; - var i = 0; - - for (i = 0; i < changedTouches.length; i++) { - var touchEvent = changedTouches[i]; - touchData = this.touches[touchEvent.identifier]; - touchData.originalEvent = event; - - // update the touch position - touchData.global.x = ( (touchEvent.clientX - rect.left) * (this.interactionDOMElement.width / rect.width) ) / this.resolution; - touchData.global.y = ( (touchEvent.clientY - rect.top) * (this.interactionDOMElement.height / rect.height) ) / this.resolution; - if (navigator.isCocoonJS && !rect.left && !rect.top && !event.target.style.width && !event.target.style.height) { - //Support for CocoonJS fullscreen scale modes - touchData.global.x = touchEvent.clientX; - touchData.global.y = touchEvent.clientY; - } - - for (var j = 0; j < this.interactiveItems.length; j++) { - var item = this.interactiveItems[j]; - if (item.touchmove && item.__touchData && item.__touchData[touchEvent.identifier]) { - item.touchmove(touchData); - } - } - } -}; - -/** - * Is called when a touch is started on the renderer element - * - * @param event {Event} The DOM event of a touch starting on the renderer view - * @private - */ -InteractionManager.prototype.onTouchStart = function (event) { - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - var rect = this.interactionDOMElement.getBoundingClientRect(); - - if (AUTO_PREVENT_DEFAULT) { - event.preventDefault(); - } - - var changedTouches = event.changedTouches; - for (var i=0; i < changedTouches.length; i++) { - var touchEvent = changedTouches[i]; - - var touchData = this.pool.pop(); - if (!touchData) { - touchData = new InteractionData(); - } - - touchData.originalEvent = event; - - this.touches[touchEvent.identifier] = touchData; - touchData.global.x = ( (touchEvent.clientX - rect.left) * (this.interactionDOMElement.width / rect.width) ) / this.resolution; - touchData.global.y = ( (touchEvent.clientY - rect.top) * (this.interactionDOMElement.height / rect.height) ) / this.resolution; - if (navigator.isCocoonJS && !rect.left && !rect.top && !event.target.style.width && !event.target.style.height) { - //Support for CocoonJS fullscreen scale modes - touchData.global.x = touchEvent.clientX; - touchData.global.y = touchEvent.clientY; - } - - var length = this.interactiveItems.length; - - for (var j = 0; j < length; j++) { - var item = this.interactiveItems[j]; - - if (item.touchstart || item.tap) { - item.__hit = this.hitTest(item, touchData); - - if (item.__hit) { - //call the function! - if (item.touchstart) { - item.touchstart(touchData); - } - - item.__isDown = true; - item.__touchData = item.__touchData || {}; - item.__touchData[touchEvent.identifier] = touchData; - - if (!item.interactiveChildren) { - break; - } - } - } - } - } -}; - -/** - * Is called when a touch is ended on the renderer element - * - * @param event {Event} The DOM event of a touch ending on the renderer view - * @private - */ -InteractionManager.prototype.onTouchEnd = function (event) { - if (this.dirty) { - this.rebuildInteractiveGraph(); - } - - var rect = this.interactionDOMElement.getBoundingClientRect(); - var changedTouches = event.changedTouches; - - for (var i=0; i < changedTouches.length; i++) { - var touchEvent = changedTouches[i]; - var touchData = this.touches[touchEvent.identifier]; - var up = false; - touchData.global.x = ( (touchEvent.clientX - rect.left) * (this.interactionDOMElement.width / rect.width) ) / this.resolution; - touchData.global.y = ( (touchEvent.clientY - rect.top) * (this.interactionDOMElement.height / rect.height) ) / this.resolution; - if (navigator.isCocoonJS && !rect.left && !rect.top && !event.target.style.width && !event.target.style.height) { - //Support for CocoonJS fullscreen scale modes - touchData.global.x = touchEvent.clientX; - touchData.global.y = touchEvent.clientY; - } - - var length = this.interactiveItems.length; - for (var j = 0; j < length; j++) { - var item = this.interactiveItems[j]; - - if (item.__touchData && item.__touchData[touchEvent.identifier]) { - - item.__hit = this.hitTest(item, item.__touchData[touchEvent.identifier]); - - // so this one WAS down... - touchData.originalEvent = event; - // hitTest?? - - if (item.touchend || item.tap) { - if (item.__hit && !up) { - if (item.touchend) { - item.touchend(touchData); - } - if (item.__isDown && item.tap) { - item.tap(touchData); - } - if (!item.interactiveChildren) { - up = true; - } - } - else { - if (item.__isDown && item.touchendoutside) { - item.touchendoutside(touchData); - } - } - - item.__isDown = false; - } - - item.__touchData[touchEvent.identifier] = null; - } - } - // remove the touch.. - this.pool.push(touchData); - this.touches[touchEvent.identifier] = null; - } -}; - -},{"../core":9,"./InteractionData":82}],84:[function(require,module,exports){ -/** - * @file Main export of the PIXI interactions library - * @author Mat Groves - * @copyright 2013-2015 GoodBoyDigital - * @license {@link https://github.com/GoodBoyDigital/pixi.js/blob/master/LICENSE|MIT License} - */ - -/** - * @namespace PIXI - */ -module.exports = { - InteractionData: require('./InteractionData'), - InteractionManager: require('./InteractionManager') -}; - -},{"./InteractionData":82,"./InteractionManager":83}],85:[function(require,module,exports){ -var core = require('../core'), - ImageLoader = require('./ImageLoader'); - -/** - * The atlas file loader is used to load in Texture Atlas data and parse it. When loaded this class will dispatch a 'loaded' event. If loading fails this class will dispatch an 'error' event. - * - * To generate the data you can use http://www.codeandweb.com/texturepacker and publish in the 'JSON' format. - * - * It is highly recommended to use texture atlases (also know as 'sprite sheets') as it allowed sprites to be batched and drawn together for highly increased rendering speed. - * Once the data has been loaded the frames are stored in the PIXI texture cache and can be accessed though Texture.fromFrameId() and Sprite.fromFrameId() - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param url {String} The url of the JSON file - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - */ -function AtlasLoader(url, crossorigin) { - this.url = url; - this.baseUrl = url.replace(/[^\/]*$/, ''); - this.crossorigin = crossorigin; - this.loaded = false; -} - -AtlasLoader.prototype.constructor = AtlasLoader; -module.exports = AtlasLoader; - -core.utils.eventTarget.mixin(AtlasLoader.prototype); - - /** - * Starts loading the JSON file - * - */ -AtlasLoader.prototype.load = function () { - this.ajaxRequest = new core.utils.AjaxRequest(); - this.ajaxRequest.onreadystatechange = this.onAtlasLoaded.bind(this); - - this.ajaxRequest.open('GET', this.url, true); - - if (this.ajaxRequest.overrideMimeType) { - this.ajaxRequest.overrideMimeType('application/json'); - } - - this.ajaxRequest.send(null); -}; - -/** - * Invoked when the Atlas has fully loaded. Parses the JSON and builds the texture frames. - * - * @private - */ -AtlasLoader.prototype.onAtlasLoaded = function () { - if (this.ajaxRequest.readyState === 4) { - if (this.ajaxRequest.status === 200 || window.location.href.indexOf('http') === -1) { - this.atlas = { - meta : { - image : [] - }, - frames : [] - }; - var result = this.ajaxRequest.responseText.split(/\r?\n/); - var lineCount = -3; - - var currentImageId = 0; - var currentFrame = null; - var nameInNextLine = false; - - var i = 0, - j = 0, - selfOnLoaded = this.onLoaded.bind(this); - - // parser without rotation support yet! - for (i = 0; i < result.length; i++) { - result[i] = result[i].replace(/^\s+|\s+$/g, ''); - - if (result[i] === '') { - nameInNextLine = i+1; - } - - if (result[i].length > 0) { - if (nameInNextLine === i) { - this.atlas.meta.image.push(result[i]); - currentImageId = this.atlas.meta.image.length - 1; - this.atlas.frames.push({}); - lineCount = -3; - } else if (lineCount > 0) { - if (lineCount % 7 === 1) { // frame name - if (currentFrame != null) { //jshint ignore:line - this.atlas.frames[currentImageId][currentFrame.name] = currentFrame; - } - currentFrame = { name: result[i], frame : {} }; - } else { - var text = result[i].split(' '); - if (lineCount % 7 === 3) { // position - currentFrame.frame.x = Number(text[1].replace(',', '')); - currentFrame.frame.y = Number(text[2]); - } else if (lineCount % 7 === 4) { // size - currentFrame.frame.w = Number(text[1].replace(',', '')); - currentFrame.frame.h = Number(text[2]); - } else if (lineCount % 7 === 5) { // real size - var realSize = { - x : 0, - y : 0, - w : Number(text[1].replace(',', '')), - h : Number(text[2]) - }; - - if (realSize.w > currentFrame.frame.w || realSize.h > currentFrame.frame.h) { - currentFrame.trimmed = true; - currentFrame.realSize = realSize; - } else { - currentFrame.trimmed = false; - } - } - } - } - lineCount++; - } - } - - if (currentFrame != null) { //jshint ignore:line - this.atlas.frames[currentImageId][currentFrame.name] = currentFrame; - } - - if (this.atlas.meta.image.length > 0) { - this.images = []; - for (j = 0; j < this.atlas.meta.image.length; j++) { - // sprite sheet - var textureUrl = this.baseUrl + this.atlas.meta.image[j]; - var frameData = this.atlas.frames[j]; - this.images.push(new ImageLoader(textureUrl, this.crossorigin)); - - for (i in frameData) { - var rect = frameData[i].frame; - if (rect) { - core.utils.TextureCache[i] = new core.Texture(this.images[j].texture.baseTexture, { - x: rect.x, - y: rect.y, - width: rect.w, - height: rect.h - }); - if (frameData[i].trimmed) { - core.utils.TextureCache[i].realSize = frameData[i].realSize; - // trim in pixi not supported yet, todo update trim properties if it is done ... - core.utils.TextureCache[i].trim.x = 0; - core.utils.TextureCache[i].trim.y = 0; - } - } - } - } - - this.currentImageId = 0; - for (j = 0; j < this.images.length; j++) { - this.images[j].on('loaded', selfOnLoaded); - } - this.images[this.currentImageId].load(); - - } else { - this.onLoaded(); - } - - } else { - this.onError(); - } - } -}; - -/** - * Invoked when json file has loaded. - * - * @private - */ -AtlasLoader.prototype.onLoaded = function () { - if (this.images.length - 1 > this.currentImageId) { - this.currentImageId++; - this.images[this.currentImageId].load(); - } else { - this.loaded = true; - this.emit('loaded', { content: this }); - } -}; - -/** - * Invoked when an error occurs. - * - * @private - */ -AtlasLoader.prototype.onError = function () { - this.emit('error', { content: this }); -}; - -},{"../core":9,"./ImageLoader":87}],86:[function(require,module,exports){ -var core = require('../core'), - ImageLoader = require('./ImageLoader'); - -/** - * The xml loader is used to load in XML bitmap font data ('xml' or 'fnt') - * To generate the data you can use http://www.angelcode.com/products/bmfont/ - * This loader will also load the image file as the data. - * When loaded this class will dispatch a 'loaded' event - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param url {String} The url of the sprite sheet JSON file - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - */ -function BitmapFontLoader(url, crossorigin) { - /** - * The url of the bitmap font data - * - * @member {String} - */ - this.url = url; - - /** - * Whether the requests should be treated as cross origin - * - * @member {boolean} - */ - this.crossorigin = crossorigin; - - /** - * The base url of the bitmap font data - * - * @member {String} - * @readOnly - */ - this.baseUrl = url.replace(/[^\/]*$/, ''); - - /** - * The texture of the bitmap font - * - * @member {Texture} - */ - this.texture = null; -} - -// constructor -BitmapFontLoader.prototype.constructor = BitmapFontLoader; -module.exports = BitmapFontLoader; - -core.utils.eventTarget.mixin(BitmapFontLoader.prototype); - -/** - * Loads the XML font data - * - */ -BitmapFontLoader.prototype.load = function () { - this.ajaxRequest = new core.utils.AjaxRequest(); - this.ajaxRequest.onreadystatechange = this.onXMLLoaded.bind(this); - - this.ajaxRequest.open('GET', this.url, true); - - if (this.ajaxRequest.overrideMimeType) { - this.ajaxRequest.overrideMimeType('application/xml'); - } - - this.ajaxRequest.send(null); -}; - -/** - * Invoked when the XML file is loaded, parses the data. - * - * @private - */ -BitmapFontLoader.prototype.onXMLLoaded = function () { - if (this.ajaxRequest.readyState === 4) { - if (this.ajaxRequest.status === 200 || window.location.protocol.indexOf('http') === -1) { - var responseXML = this.ajaxRequest.responseXML; - if (!responseXML || /MSIE 9/i.test(navigator.userAgent) || navigator.isCocoonJS) { - if (typeof(window.DOMParser) === 'function') { - var domparser = new DOMParser(); - responseXML = domparser.parseFromString(this.ajaxRequest.responseText, 'text/xml'); - } else { - var div = document.createElement('div'); - div.innerHTML = this.ajaxRequest.responseText; - responseXML = div; - } - } - - var textureUrl = this.baseUrl + responseXML.getElementsByTagName('page')[0].getAttribute('file'); - var image = new ImageLoader(textureUrl, this.crossorigin); - this.texture = image.texture.baseTexture; - - var data = {}; - var info = responseXML.getElementsByTagName('info')[0]; - var common = responseXML.getElementsByTagName('common')[0]; - data.font = info.getAttribute('face'); - data.size = parseInt(info.getAttribute('size'), 10); - data.lineHeight = parseInt(common.getAttribute('lineHeight'), 10); - data.chars = {}; - - //parse letters - var letters = responseXML.getElementsByTagName('char'); - - for (var i = 0; i < letters.length; i++) { - var charCode = parseInt(letters[i].getAttribute('id'), 10); - - var textureRect = new core.math.Rectangle( - parseInt(letters[i].getAttribute('x'), 10), - parseInt(letters[i].getAttribute('y'), 10), - parseInt(letters[i].getAttribute('width'), 10), - parseInt(letters[i].getAttribute('height'), 10) - ); - - data.chars[charCode] = { - xOffset: parseInt(letters[i].getAttribute('xoffset'), 10), - yOffset: parseInt(letters[i].getAttribute('yoffset'), 10), - xAdvance: parseInt(letters[i].getAttribute('xadvance'), 10), - kerning: {}, - texture: core.utils.TextureCache[charCode] = new core.Texture(this.texture, textureRect) - - }; - } - - //parse kernings - var kernings = responseXML.getElementsByTagName('kerning'); - for (i = 0; i < kernings.length; i++) { - var first = parseInt(kernings[i].getAttribute('first'), 10); - var second = parseInt(kernings[i].getAttribute('second'), 10); - var amount = parseInt(kernings[i].getAttribute('amount'), 10); - - data.chars[second].kerning[first] = amount; - - } - - core.BitmapText.fonts[data.font] = data; - - image.addEventListener('loaded', this.onLoaded.bind(this)); - image.load(); - } - } -}; - -/** - * Invoked when all files are loaded (xml/fnt and texture) - * - * @private - */ -BitmapFontLoader.prototype.onLoaded = function () { - this.emit('loaded', { content: this }); -}; - -},{"../core":9,"./ImageLoader":87}],87:[function(require,module,exports){ -var core = require('../core'); - -/** - * The image loader class is responsible for loading images file formats ('jpeg', 'jpg', 'png' and 'gif') - * Once the image has been loaded it is stored in the PIXI texture cache and can be accessed though Texture.fromFrame() and Sprite.fromFrame() - * When loaded this class will dispatch a 'loaded' event - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param url {String} The url of the image - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - */ -function ImageLoader(url, crossorigin) { - /** - * The texture being loaded - * - * @member {Texture} - */ - this.texture = core.Texture.fromImage(url, crossorigin); - - /** - * if the image is loaded with loadFramedSpriteSheet - * frames will contain the sprite sheet frames - * - * @member {Array} - * @readOnly - */ - this.frames = []; -} - -// constructor -ImageLoader.prototype.constructor = ImageLoader; -module.exports = ImageLoader; - -core.utils.eventTarget.mixin(ImageLoader.prototype); - -/** - * Loads image or takes it from cache - * - */ -ImageLoader.prototype.load = function () { - if (!this.texture.baseTexture.hasLoaded) { - this.texture.baseTexture.on('loaded', this.onLoaded.bind(this)); - this.texture.baseTexture.on('error', this.onError.bind(this)); - } - else { - this.onLoaded(); - } -}; - -/** - * Invoked when image file is loaded or it is already cached and ready to use - * - * @private - */ -ImageLoader.prototype.onLoaded = function () { - this.emit('loaded', { content: this }); -}; - -/** - * Invoked when image file failed loading - * - * @method onError - * @private - */ -ImageLoader.prototype.onError = function () { - this.emit('error', { content: this }); -}; - -/** - * Loads image and split it to uniform sized frames - * - * @param frameWidth {number} width of each frame - * @param frameHeight {number} height of each frame - * @param textureName {String} if given, the frames will be cached in - format - */ -ImageLoader.prototype.loadFramedSpriteSheet = function (frameWidth, frameHeight, textureName) { - this.frames = []; - - var cols = Math.floor(this.texture.width / frameWidth); - var rows = Math.floor(this.texture.height / frameHeight); - - var i=0; - for (var y = 0; y < rows; ++y) { - for (var x = 0; x < cols; ++x, ++i) { - var texture = new core.Texture( - this.texture.baseTexture, - new core.math.Rectangle( - x * frameWidth, - y * frameHeight, - frameWidth, - frameHeight - ) - ); - - this.frames.push(texture); - - if (textureName) { - core.utils.TextureCache[textureName + '-' + i] = texture; - } - } - } - - this.load(); -}; - -},{"../core":9}],88:[function(require,module,exports){ -var core = require('../core'), - spine = require('../spine/SpineRuntime'), - ImageLoader = require('./ImageLoader'), - SpineTextureLoader = require('./SpineTextureLoader'); - -/** - * The json file loader is used to load in JSON data and parse it - * When loaded this class will dispatch a 'loaded' event - * If loading fails this class will dispatch an 'error' event - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param url {String} The url of the JSON file - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - */ -function JsonLoader(url, crossorigin) { - /** - * The url of the bitmap font data - * - * @member {String} - */ - this.url = url; - - /** - * Whether the requests should be treated as cross origin - * - * @member {boolean} - */ - this.crossorigin = crossorigin; - - /** - * The base url of the bitmap font data - * - * @member {String} - * @readOnly - */ - this.baseUrl = url.replace(/[^\/]*$/, ''); - - /** - * Whether the data has loaded yet - * - * @member {boolean} - * @readOnly - */ - this.loaded = false; -} - -// constructor -JsonLoader.prototype.constructor = JsonLoader; -module.exports = JsonLoader; - -core.utils.eventTarget.mixin(JsonLoader.prototype); - -/** - * Loads the JSON data - * - */ -JsonLoader.prototype.load = function () { - if (window.XDomainRequest && this.crossorigin) { - this.ajaxRequest = new window.XDomainRequest(); - - // XDomainRequest has a few quirks. Occasionally it will abort requests - // A way to avoid this is to make sure ALL callbacks are set even if not used - // More info here: http://stackoverflow.com/questions/15786966/xdomainrequest-aborts-post-on-ie-9 - this.ajaxRequest.timeout = 3000; - - this.ajaxRequest.onerror = this.onError.bind(this); - this.ajaxRequest.ontimeout = this.onError.bind(this); - - this.ajaxRequest.onprogress = function () {}; - - this.ajaxRequest.onload = this.onJSONLoaded.bind(this); - } - else { - if (window.XMLHttpRequest) { - this.ajaxRequest = new window.XMLHttpRequest(); - } - else { - this.ajaxRequest = new window.ActiveXObject('Microsoft.XMLHTTP'); - } - - this.ajaxRequest.onreadystatechange = this.onReadyStateChanged.bind(this); - } - - this.ajaxRequest.open('GET',this.url,true); - - this.ajaxRequest.send(); -}; - -/** - * Bridge function to be able to use the more reliable onreadystatechange in XMLHttpRequest. - * - * @private - */ -JsonLoader.prototype.onReadyStateChanged = function () { - if (this.ajaxRequest.readyState === 4 && (this.ajaxRequest.status === 200 || window.location.href.indexOf('http') === -1)) { - this.onJSONLoaded(); - } -}; - -/** - * Invoke when JSON file is loaded - * - * @private - */ -JsonLoader.prototype.onJSONLoaded = function () { - if (!this.ajaxRequest.responseText) { - this.onError(); - return; - } - - this.json = JSON.parse(this.ajaxRequest.responseText); - - if (this.json.frames) { - // sprite sheet - var textureUrl = this.baseUrl + this.json.meta.image; - var image = new ImageLoader(textureUrl, this.crossorigin); - var frameData = this.json.frames; - - this.texture = image.texture.baseTexture; - image.addEventListener('loaded', this.onLoaded.bind(this)); - image.addEventListener('error', this.onError.bind(this)); - - for (var i in frameData) { - var rect = frameData[i].frame; - - if (rect) { - var textureSize = new core.math.Rectangle(rect.x, rect.y, rect.w, rect.h); - var crop = textureSize.clone(); - var trim = null; - - // Check to see if the sprite is trimmed - if (frameData[i].trimmed) { - var actualSize = frameData[i].sourceSize; - var realSize = frameData[i].spriteSourceSize; - trim = new core.math.Rectangle(realSize.x, realSize.y, actualSize.w, actualSize.h); - } - core.utils.TextureCache[i] = new core.Texture(this.texture, textureSize, crop, trim); - } - } - - image.load(); - - } - else if (this.json.bones) { - // check if the json was loaded before - if (core.utils.AnimCache[this.url]) { - this.onLoaded(); - } - else { - /** - * use a bit of hackery to load the atlas file, here we assume that the .json, .atlas and .png files - * that correspond to the spine file are in the same base URL and that the .json and .atlas files - * have the same name - */ - var atlasPath = this.url.substr(0, this.url.lastIndexOf('.')) + '.atlas'; - var atlasLoader = new JsonLoader(atlasPath, this.crossorigin); - // save a copy of the current object for future reference // - var originalLoader = this; - // before loading the file, replace the "onJSONLoaded" function for our own // - atlasLoader.onJSONLoaded = function () { - // at this point "this" points at the atlasLoader (JsonLoader) instance // - if (!this.ajaxRequest.responseText) { - this.onError(); // FIXME: hmm, this is funny because we are not responding to errors yet - return; - } - // create a new instance of a spine texture loader for this spine object // - var textureLoader = new SpineTextureLoader(this.url.substring(0, this.url.lastIndexOf('/'))); - // create a spine atlas using the loaded text and a spine texture loader instance // - var spineAtlas = new spine.Atlas(this.ajaxRequest.responseText, textureLoader); - // now we use an atlas attachment loader // - var attachmentLoader = new spine.AtlasAttachmentLoader(spineAtlas); - // spine animation - var spineJsonParser = new spine.SkeletonJson(attachmentLoader); - var skeletonData = spineJsonParser.readSkeletonData(originalLoader.json); - core.utils.AnimCache[originalLoader.url] = skeletonData; - originalLoader.spine = skeletonData; - originalLoader.spineAtlas = spineAtlas; - originalLoader.spineAtlasLoader = atlasLoader; - // wait for textures to finish loading if needed - if (textureLoader.loadingCount > 0) { - textureLoader.addEventListener('loadedBaseTexture', function (evt){ - if (evt.content.content.loadingCount <= 0) { - originalLoader.onLoaded(); - } - }); - } - else { - originalLoader.onLoaded(); - } - }; - // start the loading // - atlasLoader.load(); - } - } - else { - this.onLoaded(); - } -}; - -/** - * Invoke when json file loaded - * - * @private - */ -JsonLoader.prototype.onLoaded = function () { - this.loaded = true; - this.dispatchEvent({ - type: 'loaded', - content: this - }); -}; - -/** - * Invoke when error occured - * - * @private - */ -JsonLoader.prototype.onError = function () { - - this.dispatchEvent({ - type: 'error', - content: this - }); -}; - -},{"../core":9,"../spine/SpineRuntime":94,"./ImageLoader":87,"./SpineTextureLoader":90}],89:[function(require,module,exports){ -var core = require('../core'), - JsonLoader = require('./JsonLoader'); - -/** - * @author Mat Groves http://matgroves.com/ @Doormat23 - * based on pixi impact spine implementation made by Eemeli Kelokorpi (@ekelokorpi) https://github.com/ekelokorpi - * - * Awesome JS run time provided by EsotericSoftware - * https://github.com/EsotericSoftware/spine-runtimes - * - */ - -/** - * The Spine loader is used to load in JSON spine data - * To generate the data you need to use http://esotericsoftware.com/ and export in the "JSON" format - * Due to a clash of names You will need to change the extension of the spine file from *.json to *.anim for it to load - * See example 12 (http://www.goodboydigital.com/pixijs/examples/12/) to see a working example and check out the source - * You will need to generate a sprite sheet to accompany the spine data - * When loaded this class will dispatch a "loaded" event - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param url {String} The url of the JSON file - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - */ -function SpineLoader(url, crossorigin) { - /** - * The url of the bitmap font data - * - * @member {String} - */ - this.url = url; - - /** - * Whether the requests should be treated as cross origin - * - * @member {boolean} - */ - this.crossorigin = crossorigin; - - /** - * Whether the data has loaded yet - * - * @member {boolean} - * @readOnly - */ - this.loaded = false; -} - -SpineLoader.prototype.constructor = SpineLoader; -module.exports = SpineLoader; - -core.utils.eventTarget.mixin(SpineLoader.prototype); - -/** - * Loads the JSON data - * - */ -SpineLoader.prototype.load = function () { - var scope = this; - var jsonLoader = new JsonLoader(this.url, this.crossorigin); - - jsonLoader.on('loaded', function (event) { - scope.json = event.data.content.json; - scope.onLoaded(); - }); - - jsonLoader.load(); -}; - -/** - * Invoked when JSON file is loaded. - * - * @private - */ -SpineLoader.prototype.onLoaded = function () { - this.loaded = true; - this.emit('loaded', { content: this }); -}; - -},{"../core":9,"./JsonLoader":88}],90:[function(require,module,exports){ -var core = require('../core'); - -/** - * Supporting class to load images from spine atlases as per spine spec. - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param basePath {string} Tha base path where to look for the images to be loaded - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - */ -function SpineTextureLoader(basePath, crossorigin) { - this.basePath = basePath; - this.crossorigin = crossorigin; - this.loadingCount = 0; -} - -SpineTextureLoader.prototype.constructor = SpineTextureLoader; -module.exports = SpineTextureLoader; - -core.utils.eventTarget.mixin(SpineTextureLoader.prototype); - -/** - * Starts loading a base texture as per spine specification - * - * @param page {spine.AtlasPage} Atlas page to which texture belongs - * @param file {string} The file to load, this is just the file path relative to the base path configured in the constructor - */ -SpineTextureLoader.prototype.load = function (page, file) { - page.rendererObject = core.BaseTexture.fromImage(this.basePath + '/' + file, this.crossorigin); - if (!page.rendererObject.hasLoaded) { - var scope = this; - ++scope.loadingCount; - page.rendererObject.addEventListener('loaded', function (){ - --scope.loadingCount; - scope.dispatchEvent({ - type: 'loadedBaseTexture', - content: scope - }); - }); - } -}; - -/** - * Unloads a previously loaded texture as per spine specification - * - * @param texture {BaseTexture} Texture object to destroy - */ -SpineTextureLoader.prototype.unload = function (texture) { - texture.destroy(true); -}; - -},{"../core":9}],91:[function(require,module,exports){ -var core = require('../core'), - JsonLoader = require('./JsonLoader'); - -/** - * The sprite sheet loader is used to load in JSON sprite sheet data - * To generate the data you can use http://www.codeandweb.com/texturepacker and publish in the 'JSON' format - * There is a free version so thats nice, although the paid version is great value for money. - * It is highly recommended to use Sprite sheets (also know as a 'texture atlas') as it means sprites can be batched and drawn together for highly increased rendering speed. - * Once the data has been loaded the frames are stored in the PIXI texture cache and can be accessed though Texture.fromFrameId() and Sprite.fromFrameId() - * This loader will load the image file that the Spritesheet points to as well as the data. - * When loaded this class will dispatch a 'loaded' event - * - * @class - * @mixes eventTarget - * @namespace PIXI - * @param url {String} The url of the sprite sheet JSON file - * @param crossorigin {boolean} Whether requests should be treated as crossorigin - */ -function SpriteSheetLoader(url, crossorigin) { - - /** - * The url of the atlas data - * - * @member {String} - */ - this.url = url; - - /** - * Whether the requests should be treated as cross origin - * - * @member {boolean} - */ - this.crossorigin = crossorigin; - - /** - * The base url of the bitmap font data - * - * @member {String} - * @readOnly - */ - this.baseUrl = url.replace(/[^\/]*$/, ''); - - /** - * The texture being loaded - * - * @member {Texture} - */ - this.texture = null; - - /** - * The frames of the sprite sheet - * - * @member {object} - */ - this.frames = {}; -} - -// constructor -SpriteSheetLoader.prototype.constructor = SpriteSheetLoader; -module.exports = SpriteSheetLoader; - -core.utils.eventTarget.mixin(SpriteSheetLoader.prototype); - -/** - * This will begin loading the JSON file - * - */ -SpriteSheetLoader.prototype.load = function () { - var scope = this; - var jsonLoader = new JsonLoader(this.url, this.crossorigin); - - jsonLoader.on('loaded', function (event) { - scope.json = event.data.content.json; - scope.onLoaded(); - }); - - jsonLoader.load(); -}; - -/** - * Invoke when all files are loaded (json and texture) - * - * @private - */ -SpriteSheetLoader.prototype.onLoaded = function () { - this.emit('loaded', { - content: this - }); -}; - -},{"../core":9,"./JsonLoader":88}],92:[function(require,module,exports){ -/** - * @file Main export of the PIXI loaders library - * @author Mat Groves - * @copyright 2013-2015 GoodBoyDigital - * @license {@link https://github.com/GoodBoyDigital/pixi.js/blob/master/LICENSE|MIT License} - */ - -/** - * @namespace PIXI - */ -module.exports = { - AtlasLoader: require('./AtlasLoader'), - BitmapFontLoader: require('./BitmapFontLoader'), - ImageLoader: require('./ImageLoader'), - JsonLoader: require('./JsonLoader'), - SpineLoader: require('./SpineLoader'), - SpriteSheetLoader: require('./SpriteSheetLoader') -}; - -},{"./AtlasLoader":85,"./BitmapFontLoader":86,"./ImageLoader":87,"./JsonLoader":88,"./SpineLoader":89,"./SpriteSheetLoader":91}],93:[function(require,module,exports){ -var core = require('../core'), - spine = require('./SpineRuntime'); - -/* Esoteric Software SPINE wrapper for pixi.js */ - -spine.Bone.yDown = true; - -/** - * A class that enables the you to import and run your spine animations in pixi. - * Spine animation data needs to be loaded using the AssetLoader or SpineLoader before it can be used by this class - * See example 12 (http://www.goodboydigital.com/pixijs/examples/12/) to see a working example and check out the source - * - * @class - * @extends DisplayObjectContainer - * @namespace PIXI - * @param url {string} The url of the spine anim file to be used - */ -function Spine(url) { - core.DisplayObjectContainer.call(this); - - this.spineData = core.utils.AnimCache[url]; - - if (!this.spineData) { - throw new Error('Spine data must be preloaded using SpineLoader or AssetLoader: ' + url); - } - - this.skeleton = new spine.Skeleton(this.spineData); - this.skeleton.updateWorldTransform(); - - this.stateData = new spine.AnimationStateData(this.spineData); - this.state = new spine.AnimationState(this.stateData); - - this.slotContainers = []; - - for (var i = 0, n = this.skeleton.drawOrder.length; i < n; i++) { - var slot = this.skeleton.drawOrder[i]; - var attachment = slot.attachment; - var slotContainer = new core.DisplayObjectContainer(); - this.slotContainers.push(slotContainer); - this.addChild(slotContainer); - - if (attachment instanceof spine.RegionAttachment) { - var spriteName = attachment.rendererObject.name; - var sprite = this.createSprite(slot, attachment); - slot.currentSprite = sprite; - slot.currentSpriteName = spriteName; - slotContainer.addChild(sprite); - } - else if (attachment instanceof spine.MeshAttachment) { - var mesh = this.createMesh(slot, attachment); - slot.currentMesh = mesh; - slot.currentMeshName = attachment.name; - slotContainer.addChild(mesh); - } - else { - continue; - } - - } - - this.autoUpdate = true; -} - -Spine.prototype = Object.create(core.DisplayObjectContainer.prototype); -Spine.prototype.constructor = Spine; -module.exports = Spine; - -Object.defineProperties(Spine.prototype, { - /** - * If this flag is set to true, the spine animation will be autoupdated every time - * the object id drawn. The down side of this approach is that the delta time is - * automatically calculated and you could miss out on cool effects like slow motion, - * pause, skip ahead and the sorts. Most of these effects can be achieved even with - * autoupdate enabled but are harder to achieve. - * - * @member {boolean} - * @memberof Spine# - * @default true - */ - autoUpdate: { - get: function () { - return (this.updateTransform === Spine.prototype.autoUpdateTransform); - }, - - set: function (value) { - this.updateTransform = value ? Spine.prototype.autoUpdateTransform : core.DisplayObjectContainer.prototype.updateTransform; - } - } -}); - -/** - * Update the spine skeleton and its animations by delta time (dt) - * - * @param dt {number} Delta time. Time by which the animation should be updated - */ -Spine.prototype.update = function (dt) { - this.state.update(dt); - this.state.apply(this.skeleton); - this.skeleton.updateWorldTransform(); - - var drawOrder = this.skeleton.drawOrder; - for (var i = 0, n = drawOrder.length; i < n; i++) { - var slot = drawOrder[i]; - var attachment = slot.attachment; - var slotContainer = this.slotContainers[i]; - - if (!attachment) { - slotContainer.visible = false; - continue; - } - - var type = attachment.type; - if (type === spine.AttachmentType.region) { - if (attachment.rendererObject) { - if (!slot.currentSpriteName || slot.currentSpriteName !== attachment.rendererObject.name) { - var spriteName = attachment.rendererObject.name; - if (slot.currentSprite !== undefined) { - slot.currentSprite.visible = false; - } - slot.sprites = slot.sprites || {}; - if (slot.sprites[spriteName] !== undefined) { - slot.sprites[spriteName].visible = true; - } - else { - var sprite = this.createSprite(slot, attachment); - slotContainer.addChild(sprite); - } - slot.currentSprite = slot.sprites[spriteName]; - slot.currentSpriteName = spriteName; - } - } - - var bone = slot.bone; - - slotContainer.position.x = bone.worldX + attachment.x * bone.m00 + attachment.y * bone.m01; - slotContainer.position.y = bone.worldY + attachment.x * bone.m10 + attachment.y * bone.m11; - slotContainer.scale.x = bone.worldScaleX; - slotContainer.scale.y = bone.worldScaleY; - - slotContainer.rotation = -(slot.bone.worldRotation * spine.degRad); - - slot.currentSprite.tint = core.utils.rgb2hex([slot.r,slot.g,slot.b]); - } - else if (type === spine.AttachmentType.skinnedmesh) { - if (!slot.currentMeshName || slot.currentMeshName !== attachment.name) { - var meshName = attachment.name; - if (slot.currentMesh !== undefined) { - slot.currentMesh.visible = false; - } - - slot.meshes = slot.meshes || {}; - - if (slot.meshes[meshName] !== undefined) { - slot.meshes[meshName].visible = true; - } - else { - var mesh = this.createMesh(slot, attachment); - slotContainer.addChild(mesh); - } - - slot.currentMesh = slot.meshes[meshName]; - slot.currentMeshName = meshName; - } - - attachment.computeWorldVertices(slot.bone.skeleton.x, slot.bone.skeleton.y, slot, slot.currentMesh.vertices); - - } - else { - slotContainer.visible = false; - continue; - } - slotContainer.visible = true; - - slotContainer.alpha = slot.a; - } -}; - -/** - * When autoupdate is set to yes this function is used as pixi's updateTransform function - * - * @private - */ -Spine.prototype.autoUpdateTransform = function () { - this.lastTime = this.lastTime || Date.now(); - var timeDelta = (Date.now() - this.lastTime) * 0.001; - this.lastTime = Date.now(); - - this.update(timeDelta); - - core.DisplayObjectContainer.prototype.updateTransform.call(this); -}; - -/** - * Create a new sprite to be used with spine.RegionAttachment - * - * @param slot {spine.Slot} The slot to which the attachment is parented - * @param attachment {spine.RegionAttachment} The attachment that the sprite will represent - * @private - */ -Spine.prototype.createSprite = function (slot, attachment) { - var descriptor = attachment.rendererObject; - var baseTexture = descriptor.page.rendererObject; - var spriteRect = new core.math.Rectangle(descriptor.x, - descriptor.y, - descriptor.rotate ? descriptor.height : descriptor.width, - descriptor.rotate ? descriptor.width : descriptor.height); - var spriteTexture = new core.Texture(baseTexture, spriteRect); - var sprite = new core.Sprite(spriteTexture); - - var baseRotation = descriptor.rotate ? Math.PI * 0.5 : 0.0; - sprite.scale.set(descriptor.width / descriptor.originalWidth, descriptor.height / descriptor.originalHeight); - sprite.rotation = baseRotation - (attachment.rotation * spine.degRad); - sprite.anchor.x = sprite.anchor.y = 0.5; - - slot.sprites = slot.sprites || {}; - slot.sprites[descriptor.name] = sprite; - return sprite; -}; - -/** - * - * @param slot {spine.Slot} The slot to which the attachment is parented - * @param attachment {spine.RegionAttachment} The attachment that the sprite will represent - * @private - */ -Spine.prototype.createMesh = function (slot, attachment) { - var descriptor = attachment.rendererObject; - var baseTexture = descriptor.page.rendererObject; - var texture = new core.Texture(baseTexture); - - var strip = new core.Strip(texture); - strip.drawMode = core.Strip.DrawModes.TRIANGLES; - strip.canvasPadding = 1.5; - - strip.vertices = new Float32Array(attachment.uvs.length); - strip.uvs = attachment.uvs; - strip.indices = attachment.triangles; - - slot.meshes = slot.meshes || {}; - slot.meshes[attachment.name] = strip; - - return strip; -}; - -},{"../core":9,"./SpineRuntime":94}],94:[function(require,module,exports){ -/****************************************************************************** - * Spine Runtimes Software License - * Version 2.1 - * - * Copyright (c) 2013, Esoteric Software - * All rights reserved. - * - * You are granted a perpetual, non-exclusive, non-sublicensable and - * non-transferable license to install, execute and perform the Spine Runtimes - * Software (the "Software") solely for internal use. Without the written - * permission of Esoteric Software (typically granted by licensing Spine), you - * may not (a) modify, translate, adapt or otherwise create derivative works, - * improvements of the Software or develop new applications using the Software - * or (b) remove, delete, alter or obscure any trademarks or any copyright, - * trademark, patent or other intellectual property or proprietary rights - * notices on or in the Software, including any copy thereof. Redistributions - * in binary or source form must include this license and terms. - * - * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - *****************************************************************************/ - -var spine = module.exports = { - radDeg: 180 / Math.PI, - degRad: Math.PI / 180, - temp: [], - Float32Array: (typeof(Float32Array) === 'undefined') ? Array : Float32Array, - Uint16Array: (typeof(Uint16Array) === 'undefined') ? Array : Uint16Array -}; - -spine.BoneData = function (name, parent) { - this.name = name; - this.parent = parent; -}; -spine.BoneData.prototype = { - length: 0, - x: 0, y: 0, - rotation: 0, - scaleX: 1, scaleY: 1, - inheritScale: true, - inheritRotation: true, - flipX: false, flipY: false -}; - -spine.SlotData = function (name, boneData) { - this.name = name; - this.boneData = boneData; -}; -spine.SlotData.prototype = { - r: 1, g: 1, b: 1, a: 1, - attachmentName: null, - additiveBlending: false -}; - -spine.IkConstraintData = function (name) { - this.name = name; - this.bones = []; -}; -spine.IkConstraintData.prototype = { - target: null, - bendDirection: 1, - mix: 1 -}; - -spine.Bone = function (boneData, skeleton, parent) { - this.data = boneData; - this.skeleton = skeleton; - this.parent = parent; - this.setToSetupPose(); -}; -spine.Bone.yDown = false; -spine.Bone.prototype = { - x: 0, y: 0, - rotation: 0, rotationIK: 0, - scaleX: 1, scaleY: 1, - flipX: false, flipY: false, - m00: 0, m01: 0, worldX: 0, // a b x - m10: 0, m11: 0, worldY: 0, // c d y - worldRotation: 0, - worldScaleX: 1, worldScaleY: 1, - worldFlipX: false, worldFlipY: false, - updateWorldTransform: function () { - var parent = this.parent; - if (parent) { - this.worldX = this.x * parent.m00 + this.y * parent.m01 + parent.worldX; - this.worldY = this.x * parent.m10 + this.y * parent.m11 + parent.worldY; - if (this.data.inheritScale) { - this.worldScaleX = parent.worldScaleX * this.scaleX; - this.worldScaleY = parent.worldScaleY * this.scaleY; - } else { - this.worldScaleX = this.scaleX; - this.worldScaleY = this.scaleY; - } - this.worldRotation = this.data.inheritRotation ? (parent.worldRotation + this.rotationIK) : this.rotationIK; - this.worldFlipX = parent.worldFlipX != this.flipX; - this.worldFlipY = parent.worldFlipY != this.flipY; - } else { - var skeletonFlipX = this.skeleton.flipX, skeletonFlipY = this.skeleton.flipY; - this.worldX = skeletonFlipX ? -this.x : this.x; - this.worldY = (skeletonFlipY != spine.Bone.yDown) ? -this.y : this.y; - this.worldScaleX = this.scaleX; - this.worldScaleY = this.scaleY; - this.worldRotation = this.rotationIK; - this.worldFlipX = skeletonFlipX != this.flipX; - this.worldFlipY = skeletonFlipY != this.flipY; - } - var radians = this.worldRotation * spine.degRad; - var cos = Math.cos(radians); - var sin = Math.sin(radians); - if (this.worldFlipX) { - this.m00 = -cos * this.worldScaleX; - this.m01 = sin * this.worldScaleY; - } else { - this.m00 = cos * this.worldScaleX; - this.m01 = -sin * this.worldScaleY; - } - if (this.worldFlipY != spine.Bone.yDown) { - this.m10 = -sin * this.worldScaleX; - this.m11 = -cos * this.worldScaleY; - } else { - this.m10 = sin * this.worldScaleX; - this.m11 = cos * this.worldScaleY; - } - }, - setToSetupPose: function () { - var data = this.data; - this.x = data.x; - this.y = data.y; - this.rotation = data.rotation; - this.rotationIK = this.rotation; - this.scaleX = data.scaleX; - this.scaleY = data.scaleY; - this.flipX = data.flipX; - this.flipY = data.flipY; - }, - worldToLocal: function (world) { - var dx = world[0] - this.worldX, dy = world[1] - this.worldY; - var m00 = this.m00, m10 = this.m10, m01 = this.m01, m11 = this.m11; - if (this.worldFlipX != (this.worldFlipY != spine.Bone.yDown)) { - m00 = -m00; - m11 = -m11; - } - var invDet = 1 / (m00 * m11 - m01 * m10); - world[0] = dx * m00 * invDet - dy * m01 * invDet; - world[1] = dy * m11 * invDet - dx * m10 * invDet; - }, - localToWorld: function (local) { - var localX = local[0], localY = local[1]; - local[0] = localX * this.m00 + localY * this.m01 + this.worldX; - local[1] = localX * this.m10 + localY * this.m11 + this.worldY; - } -}; - -spine.Slot = function (slotData, bone) { - this.data = slotData; - this.bone = bone; - this.setToSetupPose(); -}; -spine.Slot.prototype = { - r: 1, g: 1, b: 1, a: 1, - _attachmentTime: 0, - attachment: null, - attachmentVertices: [], - setAttachment: function (attachment) { - this.attachment = attachment; - this._attachmentTime = this.bone.skeleton.time; - this.attachmentVertices.length = 0; - }, - setAttachmentTime: function (time) { - this._attachmentTime = this.bone.skeleton.time - time; - }, - getAttachmentTime: function () { - return this.bone.skeleton.time - this._attachmentTime; - }, - setToSetupPose: function () { - var data = this.data; - this.r = data.r; - this.g = data.g; - this.b = data.b; - this.a = data.a; - - var slotDatas = this.bone.skeleton.data.slots; - for (var i = 0, n = slotDatas.length; i < n; i++) { - if (slotDatas[i] == data) { - this.setAttachment(!data.attachmentName ? null : this.bone.skeleton.getAttachmentBySlotIndex(i, data.attachmentName)); - break; - } - } - } -}; - -spine.IkConstraint = function (data, skeleton) { - this.data = data; - this.mix = data.mix; - this.bendDirection = data.bendDirection; - - this.bones = []; - for (var i = 0, n = data.bones.length; i < n; i++) - this.bones.push(skeleton.findBone(data.bones[i].name)); - this.target = skeleton.findBone(data.target.name); -}; -spine.IkConstraint.prototype = { - apply: function () { - var target = this.target; - var bones = this.bones; - switch (bones.length) { - case 1: - spine.IkConstraint.apply1(bones[0], target.worldX, target.worldY, this.mix); - break; - case 2: - spine.IkConstraint.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.mix); - break; - } - } -}; -/** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world - * coordinate system. */ -spine.IkConstraint.apply1 = function (bone, targetX, targetY, alpha) { - var parentRotation = (!bone.data.inheritRotation || !bone.parent) ? 0 : bone.parent.worldRotation; - var rotation = bone.rotation; - var rotationIK = Math.atan2(targetY - bone.worldY, targetX - bone.worldX) * spine.radDeg - parentRotation; - bone.rotationIK = rotation + (rotationIK - rotation) * alpha; -}; -/** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The - * target is specified in the world coordinate system. - * @param child Any descendant bone of the parent. */ -spine.IkConstraint.apply2 = function (parent, child, targetX, targetY, bendDirection, alpha) { - var childRotation = child.rotation, parentRotation = parent.rotation; - if (!alpha) { - child.rotationIK = childRotation; - parent.rotationIK = parentRotation; - return; - } - var positionX, positionY, tempPosition = spine.temp; - var parentParent = parent.parent; - if (parentParent) { - tempPosition[0] = targetX; - tempPosition[1] = targetY; - parentParent.worldToLocal(tempPosition); - targetX = (tempPosition[0] - parent.x) * parentParent.worldScaleX; - targetY = (tempPosition[1] - parent.y) * parentParent.worldScaleY; - } else { - targetX -= parent.x; - targetY -= parent.y; - } - if (child.parent == parent) { - positionX = child.x; - positionY = child.y; - } else { - tempPosition[0] = child.x; - tempPosition[1] = child.y; - child.parent.localToWorld(tempPosition); - parent.worldToLocal(tempPosition); - positionX = tempPosition[0]; - positionY = tempPosition[1]; - } - var childX = positionX * parent.worldScaleX, childY = positionY * parent.worldScaleY; - var offset = Math.atan2(childY, childX); - var len1 = Math.sqrt(childX * childX + childY * childY), len2 = child.data.length * child.worldScaleX; - // Based on code by Ryan Juckett with permission: Copyright (c) 2008-2009 Ryan Juckett, http://www.ryanjuckett.com/ - var cosDenom = 2 * len1 * len2; - if (cosDenom < 0.0001) { - child.rotationIK = childRotation + (Math.atan2(targetY, targetX) * spine.radDeg - parentRotation - childRotation) * alpha; - return; - } - var cos = (targetX * targetX + targetY * targetY - len1 * len1 - len2 * len2) / cosDenom; - if (cos < -1) - cos = -1; - else if (cos > 1) - cos = 1; - var childAngle = Math.acos(cos) * bendDirection; - var adjacent = len1 + len2 * cos, opposite = len2 * Math.sin(childAngle); - var parentAngle = Math.atan2(targetY * adjacent - targetX * opposite, targetX * adjacent + targetY * opposite); - var rotation = (parentAngle - offset) * spine.radDeg - parentRotation; - if (rotation > 180) - rotation -= 360; - else if (rotation < -180) // - rotation += 360; - parent.rotationIK = parentRotation + rotation * alpha; - rotation = (childAngle + offset) * spine.radDeg - childRotation; - if (rotation > 180) - rotation -= 360; - else if (rotation < -180) // - rotation += 360; - child.rotationIK = childRotation + (rotation + parent.worldRotation - child.parent.worldRotation) * alpha; -}; - -spine.Skin = function (name) { - this.name = name; - this.attachments = {}; -}; -spine.Skin.prototype = { - addAttachment: function (slotIndex, name, attachment) { - this.attachments[slotIndex + ":" + name] = attachment; - }, - getAttachment: function (slotIndex, name) { - return this.attachments[slotIndex + ":" + name]; - }, - _attachAll: function (skeleton, oldSkin) { - for (var key in oldSkin.attachments) { - var colon = key.indexOf(":"); - var slotIndex = parseInt(key.substring(0, colon)); - var name = key.substring(colon + 1); - var slot = skeleton.slots[slotIndex]; - if (slot.attachment && slot.attachment.name == name) { - var attachment = this.getAttachment(slotIndex, name); - if (attachment) slot.setAttachment(attachment); - } - } - } -}; - -spine.Animation = function (name, timelines, duration) { - this.name = name; - this.timelines = timelines; - this.duration = duration; -}; -spine.Animation.prototype = { - apply: function (skeleton, lastTime, time, loop, events) { - if (loop && this.duration != 0) { - time %= this.duration; - lastTime %= this.duration; - } - var timelines = this.timelines; - for (var i = 0, n = timelines.length; i < n; i++) - timelines[i].apply(skeleton, lastTime, time, events, 1); - }, - mix: function (skeleton, lastTime, time, loop, events, alpha) { - if (loop && this.duration != 0) { - time %= this.duration; - lastTime %= this.duration; - } - var timelines = this.timelines; - for (var i = 0, n = timelines.length; i < n; i++) - timelines[i].apply(skeleton, lastTime, time, events, alpha); - } -}; -spine.Animation.binarySearch = function (values, target, step) { - var low = 0; - var high = Math.floor(values.length / step) - 2; - if (!high) return step; - var current = high >>> 1; - while (true) { - if (values[(current + 1) * step] <= target) - low = current + 1; - else - high = current; - if (low == high) return (low + 1) * step; - current = (low + high) >>> 1; - } -}; -spine.Animation.binarySearch1 = function (values, target) { - var low = 0; - var high = values.length - 2; - if (!high) return 1; - var current = high >>> 1; - while (true) { - if (values[current + 1] <= target) - low = current + 1; - else - high = current; - if (low == high) return low + 1; - current = (low + high) >>> 1; - } -}; -spine.Animation.linearSearch = function (values, target, step) { - for (var i = 0, last = values.length - step; i <= last; i += step) - if (values[i] > target) return i; - return -1; -}; - -spine.Curves = function (frameCount) { - this.curves = []; // type, x, y, ... - //this.curves.length = (frameCount - 1) * 19/*BEZIER_SIZE*/; -}; -spine.Curves.prototype = { - setLinear: function (frameIndex) { - this.curves[frameIndex * 19/*BEZIER_SIZE*/] = 0/*LINEAR*/; - }, - setStepped: function (frameIndex) { - this.curves[frameIndex * 19/*BEZIER_SIZE*/] = 1/*STEPPED*/; - }, - /** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. - * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of - * the difference between the keyframe's values. */ - setCurve: function (frameIndex, cx1, cy1, cx2, cy2) { - var subdiv1 = 1 / 10/*BEZIER_SEGMENTS*/, subdiv2 = subdiv1 * subdiv1, subdiv3 = subdiv2 * subdiv1; - var pre1 = 3 * subdiv1, pre2 = 3 * subdiv2, pre4 = 6 * subdiv2, pre5 = 6 * subdiv3; - var tmp1x = -cx1 * 2 + cx2, tmp1y = -cy1 * 2 + cy2, tmp2x = (cx1 - cx2) * 3 + 1, tmp2y = (cy1 - cy2) * 3 + 1; - var dfx = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv3, dfy = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv3; - var ddfx = tmp1x * pre4 + tmp2x * pre5, ddfy = tmp1y * pre4 + tmp2y * pre5; - var dddfx = tmp2x * pre5, dddfy = tmp2y * pre5; - - var i = frameIndex * 19/*BEZIER_SIZE*/; - var curves = this.curves; - curves[i++] = 2/*BEZIER*/; - - var x = dfx, y = dfy; - for (var n = i + 19/*BEZIER_SIZE*/ - 1; i < n; i += 2) { - curves[i] = x; - curves[i + 1] = y; - dfx += ddfx; - dfy += ddfy; - ddfx += dddfx; - ddfy += dddfy; - x += dfx; - y += dfy; - } - }, - getCurvePercent: function (frameIndex, percent) { - percent = percent < 0 ? 0 : (percent > 1 ? 1 : percent); - var curves = this.curves; - var i = frameIndex * 19/*BEZIER_SIZE*/; - var type = curves[i]; - if (type === 0/*LINEAR*/) return percent; - if (type == 1/*STEPPED*/) return 0; - i++; - var x = 0; - for (var start = i, n = i + 19/*BEZIER_SIZE*/ - 1; i < n; i += 2) { - x = curves[i]; - if (x >= percent) { - var prevX, prevY; - if (i == start) { - prevX = 0; - prevY = 0; - } else { - prevX = curves[i - 2]; - prevY = curves[i - 1]; - } - return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX); - } - } - var y = curves[i - 1]; - return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. - } -}; - -spine.RotateTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, angle, ... - this.frames.length = frameCount * 2; -}; -spine.RotateTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 2; - }, - setFrame: function (frameIndex, time, angle) { - frameIndex *= 2; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = angle; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - 2]) { // Time is after last frame. - var amount = bone.data.rotation + frames[frames.length - 1] - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - var frameIndex = spine.Animation.binarySearch(frames, time, 2); - var prevFrameValue = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex - 2/*PREV_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 2 - 1, percent); - - var amount = frames[frameIndex + 1/*FRAME_VALUE*/] - prevFrameValue; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - amount = bone.data.rotation + (prevFrameValue + amount * percent) - bone.rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone.rotation += amount * alpha; - } -}; - -spine.TranslateTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, x, y, ... - this.frames.length = frameCount * 3; -}; -spine.TranslateTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 3; - }, - setFrame: function (frameIndex, time, x, y) { - frameIndex *= 3; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = x; - this.frames[frameIndex + 2] = y; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - 3]) { // Time is after last frame. - bone.x += (bone.data.x + frames[frames.length - 2] - bone.x) * alpha; - bone.y += (bone.data.y + frames[frames.length - 1] - bone.y) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - var frameIndex = spine.Animation.binarySearch(frames, time, 3); - var prevFrameX = frames[frameIndex - 2]; - var prevFrameY = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*PREV_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); - - bone.x += (bone.data.x + prevFrameX + (frames[frameIndex + 1/*FRAME_X*/] - prevFrameX) * percent - bone.x) * alpha; - bone.y += (bone.data.y + prevFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - prevFrameY) * percent - bone.y) * alpha; - } -}; - -spine.ScaleTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, x, y, ... - this.frames.length = frameCount * 3; -}; -spine.ScaleTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 3; - }, - setFrame: function (frameIndex, time, x, y) { - frameIndex *= 3; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = x; - this.frames[frameIndex + 2] = y; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var bone = skeleton.bones[this.boneIndex]; - - if (time >= frames[frames.length - 3]) { // Time is after last frame. - bone.scaleX += (bone.data.scaleX * frames[frames.length - 2] - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY * frames[frames.length - 1] - bone.scaleY) * alpha; - return; - } - - // Interpolate between the previous frame and the current frame. - var frameIndex = spine.Animation.binarySearch(frames, time, 3); - var prevFrameX = frames[frameIndex - 2]; - var prevFrameY = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*PREV_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); - - bone.scaleX += (bone.data.scaleX * (prevFrameX + (frames[frameIndex + 1/*FRAME_X*/] - prevFrameX) * percent) - bone.scaleX) * alpha; - bone.scaleY += (bone.data.scaleY * (prevFrameY + (frames[frameIndex + 2/*FRAME_Y*/] - prevFrameY) * percent) - bone.scaleY) * alpha; - } -}; - -spine.ColorTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, r, g, b, a, ... - this.frames.length = frameCount * 5; -}; -spine.ColorTimeline.prototype = { - slotIndex: 0, - getFrameCount: function () { - return this.frames.length / 5; - }, - setFrame: function (frameIndex, time, r, g, b, a) { - frameIndex *= 5; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = r; - this.frames[frameIndex + 2] = g; - this.frames[frameIndex + 3] = b; - this.frames[frameIndex + 4] = a; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var r, g, b, a; - if (time >= frames[frames.length - 5]) { - // Time is after last frame. - var i = frames.length - 1; - r = frames[i - 3]; - g = frames[i - 2]; - b = frames[i - 1]; - a = frames[i]; - } else { - // Interpolate between the previous frame and the current frame. - var frameIndex = spine.Animation.binarySearch(frames, time, 5); - var prevFrameR = frames[frameIndex - 4]; - var prevFrameG = frames[frameIndex - 3]; - var prevFrameB = frames[frameIndex - 2]; - var prevFrameA = frames[frameIndex - 1]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex - 5/*PREV_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 5 - 1, percent); - - r = prevFrameR + (frames[frameIndex + 1/*FRAME_R*/] - prevFrameR) * percent; - g = prevFrameG + (frames[frameIndex + 2/*FRAME_G*/] - prevFrameG) * percent; - b = prevFrameB + (frames[frameIndex + 3/*FRAME_B*/] - prevFrameB) * percent; - a = prevFrameA + (frames[frameIndex + 4/*FRAME_A*/] - prevFrameA) * percent; - } - var slot = skeleton.slots[this.slotIndex]; - if (alpha < 1) { - slot.r += (r - slot.r) * alpha; - slot.g += (g - slot.g) * alpha; - slot.b += (b - slot.b) * alpha; - slot.a += (a - slot.a) * alpha; - } else { - slot.r = r; - slot.g = g; - slot.b = b; - slot.a = a; - } - } -}; - -spine.AttachmentTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, ... - this.frames.length = frameCount; - this.attachmentNames = []; - this.attachmentNames.length = frameCount; -}; -spine.AttachmentTimeline.prototype = { - slotIndex: 0, - getFrameCount: function () { - return this.frames.length; - }, - setFrame: function (frameIndex, time, attachmentName) { - this.frames[frameIndex] = time; - this.attachmentNames[frameIndex] = attachmentName; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) { - if (lastTime > time) this.apply(skeleton, lastTime, Number.MAX_VALUE, null, 0); - return; - } else if (lastTime > time) // - lastTime = -1; - - var frameIndex = time >= frames[frames.length - 1] ? frames.length - 1 : spine.Animation.binarySearch1(frames, time) - 1; - if (frames[frameIndex] < lastTime) return; - - var attachmentName = this.attachmentNames[frameIndex]; - skeleton.slots[this.slotIndex].setAttachment( - !attachmentName ? null : skeleton.getAttachmentBySlotIndex(this.slotIndex, attachmentName)); - } -}; - -spine.EventTimeline = function (frameCount) { - this.frames = []; // time, ... - this.frames.length = frameCount; - this.events = []; - this.events.length = frameCount; -}; -spine.EventTimeline.prototype = { - getFrameCount: function () { - return this.frames.length; - }, - setFrame: function (frameIndex, time, event) { - this.frames[frameIndex] = time; - this.events[frameIndex] = event; - }, - /** Fires events for frames > lastTime and <= time. */ - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - if (!firedEvents) return; - - var frames = this.frames; - var frameCount = frames.length; - - if (lastTime > time) { // Fire events after last time for looped animations. - this.apply(skeleton, lastTime, Number.MAX_VALUE, firedEvents, alpha); - lastTime = -1; - } else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame. - return; - if (time < frames[0]) return; // Time is before first frame. - - var frameIndex; - if (lastTime < frames[0]) - frameIndex = 0; - else { - frameIndex = spine.Animation.binarySearch1(frames, lastTime); - var frame = frames[frameIndex]; - while (frameIndex > 0) { // Fire multiple events with the same frame. - if (frames[frameIndex - 1] != frame) break; - frameIndex--; - } - } - var events = this.events; - for (; frameIndex < frameCount && time >= frames[frameIndex]; frameIndex++) - firedEvents.push(events[frameIndex]); - } -}; - -spine.DrawOrderTimeline = function (frameCount) { - this.frames = []; // time, ... - this.frames.length = frameCount; - this.drawOrders = []; - this.drawOrders.length = frameCount; -}; -spine.DrawOrderTimeline.prototype = { - getFrameCount: function () { - return this.frames.length; - }, - setFrame: function (frameIndex, time, drawOrder) { - this.frames[frameIndex] = time; - this.drawOrders[frameIndex] = drawOrder; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var frameIndex; - if (time >= frames[frames.length - 1]) // Time is after last frame. - frameIndex = frames.length - 1; - else - frameIndex = spine.Animation.binarySearch1(frames, time) - 1; - - var drawOrder = skeleton.drawOrder; - var slots = skeleton.slots; - var drawOrderToSetupIndex = this.drawOrders[frameIndex]; - if (!drawOrderToSetupIndex) { - for (var i = 0, n = slots.length; i < n; i++) - drawOrder[i] = slots[i]; - } else { - for (var i = 0, n = drawOrderToSetupIndex.length; i < n; i++) - drawOrder[i] = skeleton.slots[drawOrderToSetupIndex[i]]; - } - - } -}; - -spine.FfdTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; - this.frames.length = frameCount; - this.frameVertices = []; - this.frameVertices.length = frameCount; -}; -spine.FfdTimeline.prototype = { - slotIndex: 0, - attachment: 0, - getFrameCount: function () { - return this.frames.length; - }, - setFrame: function (frameIndex, time, vertices) { - this.frames[frameIndex] = time; - this.frameVertices[frameIndex] = vertices; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var slot = skeleton.slots[this.slotIndex]; - if (slot.attachment != this.attachment) return; - - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var frameVertices = this.frameVertices; - var vertexCount = frameVertices[0].length; - - var vertices = slot.attachmentVertices; - if (vertices.length != vertexCount) alpha = 1; - vertices.length = vertexCount; - - if (time >= frames[frames.length - 1]) { // Time is after last frame. - var lastVertices = frameVertices[frames.length - 1]; - if (alpha < 1) { - for (var i = 0; i < vertexCount; i++) - vertices[i] += (lastVertices[i] - vertices[i]) * alpha; - } else { - for (var i = 0; i < vertexCount; i++) - vertices[i] = lastVertices[i]; - } - return; - } - - // Interpolate between the previous frame and the current frame. - var frameIndex = spine.Animation.binarySearch1(frames, time); - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex - 1] - frameTime); - percent = this.curves.getCurvePercent(frameIndex - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); - - var prevVertices = frameVertices[frameIndex - 1]; - var nextVertices = frameVertices[frameIndex]; - - if (alpha < 1) { - for (var i = 0; i < vertexCount; i++) { - var prev = prevVertices[i]; - vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha; - } - } else { - for (var i = 0; i < vertexCount; i++) { - var prev = prevVertices[i]; - vertices[i] = prev + (nextVertices[i] - prev) * percent; - } - } - } -}; - -spine.IkConstraintTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, mix, bendDirection, ... - this.frames.length = frameCount * 3; -}; -spine.IkConstraintTimeline.prototype = { - ikConstraintIndex: 0, - getFrameCount: function () { - return this.frames.length / 3; - }, - setFrame: function (frameIndex, time, mix, bendDirection) { - frameIndex *= 3; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = mix; - this.frames[frameIndex + 2] = bendDirection; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. - - var ikConstraint = skeleton.ikConstraints[this.ikConstraintIndex]; - - if (time >= frames[frames.length - 3]) { // Time is after last frame. - ikConstraint.mix += (frames[frames.length - 2] - ikConstraint.mix) * alpha; - ikConstraint.bendDirection = frames[frames.length - 1]; - return; - } - - // Interpolate between the previous frame and the current frame. - var frameIndex = spine.Animation.binarySearch(frames, time, 3); - var prevFrameMix = frames[frameIndex + -2/*PREV_FRAME_MIX*/]; - var frameTime = frames[frameIndex]; - var percent = 1 - (time - frameTime) / (frames[frameIndex + -3/*PREV_FRAME_TIME*/] - frameTime); - percent = this.curves.getCurvePercent(frameIndex / 3 - 1, percent); - - var mix = prevFrameMix + (frames[frameIndex + 1/*FRAME_MIX*/] - prevFrameMix) * percent; - ikConstraint.mix += (mix - ikConstraint.mix) * alpha; - ikConstraint.bendDirection = frames[frameIndex + -1/*PREV_FRAME_BEND_DIRECTION*/]; - } -}; - -spine.FlipXTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, flip, ... - this.frames.length = frameCount * 2; -}; -spine.FlipXTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 2; - }, - setFrame: function (frameIndex, time, flip) { - frameIndex *= 2; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = flip ? 1 : 0; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) { - if (lastTime > time) this.apply(skeleton, lastTime, Number.MAX_VALUE, null, 0); - return; - } else if (lastTime > time) // - lastTime = -1; - var frameIndex = (time >= frames[frames.length - 2] ? frames.length : spine.Animation.binarySearch(frames, time, 2)) - 2; - if (frames[frameIndex] < lastTime) return; - skeleton.bones[boneIndex].flipX = frames[frameIndex + 1] != 0; - } -}; - -spine.FlipYTimeline = function (frameCount) { - this.curves = new spine.Curves(frameCount); - this.frames = []; // time, flip, ... - this.frames.length = frameCount * 2; -}; -spine.FlipYTimeline.prototype = { - boneIndex: 0, - getFrameCount: function () { - return this.frames.length / 2; - }, - setFrame: function (frameIndex, time, flip) { - frameIndex *= 2; - this.frames[frameIndex] = time; - this.frames[frameIndex + 1] = flip ? 1 : 0; - }, - apply: function (skeleton, lastTime, time, firedEvents, alpha) { - var frames = this.frames; - if (time < frames[0]) { - if (lastTime > time) this.apply(skeleton, lastTime, Number.MAX_VALUE, null, 0); - return; - } else if (lastTime > time) // - lastTime = -1; - var frameIndex = (time >= frames[frames.length - 2] ? frames.length : spine.Animation.binarySearch(frames, time, 2)) - 2; - if (frames[frameIndex] < lastTime) return; - skeleton.bones[boneIndex].flipY = frames[frameIndex + 1] != 0; - } -}; - -spine.SkeletonData = function () { - this.bones = []; - this.slots = []; - this.skins = []; - this.events = []; - this.animations = []; - this.ikConstraints = []; -}; -spine.SkeletonData.prototype = { - name: null, - defaultSkin: null, - width: 0, height: 0, - version: null, hash: null, - /** @return May be null. */ - findBone: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].name == boneName) return bones[i]; - return null; - }, - /** @return -1 if the bone was not found. */ - findBoneIndex: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].name == boneName) return i; - return -1; - }, - /** @return May be null. */ - findSlot: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) { - if (slots[i].name == slotName) return slot[i]; - } - return null; - }, - /** @return -1 if the bone was not found. */ - findSlotIndex: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - if (slots[i].name == slotName) return i; - return -1; - }, - /** @return May be null. */ - findSkin: function (skinName) { - var skins = this.skins; - for (var i = 0, n = skins.length; i < n; i++) - if (skins[i].name == skinName) return skins[i]; - return null; - }, - /** @return May be null. */ - findEvent: function (eventName) { - var events = this.events; - for (var i = 0, n = events.length; i < n; i++) - if (events[i].name == eventName) return events[i]; - return null; - }, - /** @return May be null. */ - findAnimation: function (animationName) { - var animations = this.animations; - for (var i = 0, n = animations.length; i < n; i++) - if (animations[i].name == animationName) return animations[i]; - return null; - }, - /** @return May be null. */ - findIkConstraint: function (ikConstraintName) { - var ikConstraints = this.ikConstraints; - for (var i = 0, n = ikConstraints.length; i < n; i++) - if (ikConstraints[i].name == ikConstraintName) return ikConstraints[i]; - return null; - } -}; - -spine.Skeleton = function (skeletonData) { - this.data = skeletonData; - - this.bones = []; - for (var i = 0, n = skeletonData.bones.length; i < n; i++) { - var boneData = skeletonData.bones[i]; - var parent = !boneData.parent ? null : this.bones[skeletonData.bones.indexOf(boneData.parent)]; - this.bones.push(new spine.Bone(boneData, this, parent)); - } - - this.slots = []; - this.drawOrder = []; - for (var i = 0, n = skeletonData.slots.length; i < n; i++) { - var slotData = skeletonData.slots[i]; - var bone = this.bones[skeletonData.bones.indexOf(slotData.boneData)]; - var slot = new spine.Slot(slotData, bone); - this.slots.push(slot); - this.drawOrder.push(slot); - } - - this.ikConstraints = []; - for (var i = 0, n = skeletonData.ikConstraints.length; i < n; i++) - this.ikConstraints.push(new spine.IkConstraint(skeletonData.ikConstraints[i], this)); - - this.boneCache = []; - this.updateCache(); -}; -spine.Skeleton.prototype = { - x: 0, y: 0, - skin: null, - r: 1, g: 1, b: 1, a: 1, - time: 0, - flipX: false, flipY: false, - /** Caches information about bones and IK constraints. Must be called if bones or IK constraints are added or removed. */ - updateCache: function () { - var ikConstraints = this.ikConstraints; - var ikConstraintsCount = ikConstraints.length; - - var arrayCount = ikConstraintsCount + 1; - var boneCache = this.boneCache; - if (boneCache.length > arrayCount) boneCache.length = arrayCount; - for (var i = 0, n = boneCache.length; i < n; i++) - boneCache[i].length = 0; - while (boneCache.length < arrayCount) - boneCache[boneCache.length] = []; - - var nonIkBones = boneCache[0]; - var bones = this.bones; - - outer: - for (var i = 0, n = bones.length; i < n; i++) { - var bone = bones[i]; - var current = bone; - do { - for (var ii = 0; ii < ikConstraintsCount; ii++) { - var ikConstraint = ikConstraints[ii]; - var parent = ikConstraint.bones[0]; - var child= ikConstraint.bones[ikConstraint.bones.length - 1]; - while (true) { - if (current == child) { - boneCache[ii].push(bone); - boneCache[ii + 1].push(bone); - continue outer; - } - if (child == parent) break; - child = child.parent; - } - } - current = current.parent; - } while (current); - nonIkBones[nonIkBones.length] = bone; - } - }, - /** Updates the world transform for each bone. */ - updateWorldTransform: function () { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) { - var bone = bones[i]; - bone.rotationIK = bone.rotation; - } - var i = 0, last = this.boneCache.length - 1; - while (true) { - var cacheBones = this.boneCache[i]; - for (var ii = 0, nn = cacheBones.length; ii < nn; ii++) - cacheBones[ii].updateWorldTransform(); - if (i == last) break; - this.ikConstraints[i].apply(); - i++; - } - }, - /** Sets the bones and slots to their setup pose values. */ - setToSetupPose: function () { - this.setBonesToSetupPose(); - this.setSlotsToSetupPose(); - }, - setBonesToSetupPose: function () { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - bones[i].setToSetupPose(); - - var ikConstraints = this.ikConstraints; - for (var i = 0, n = ikConstraints.length; i < n; i++) { - var ikConstraint = ikConstraints[i]; - ikConstraint.bendDirection = ikConstraint.data.bendDirection; - ikConstraint.mix = ikConstraint.data.mix; - } - }, - setSlotsToSetupPose: function () { - var slots = this.slots; - var drawOrder = this.drawOrder; - for (var i = 0, n = slots.length; i < n; i++) { - drawOrder[i] = slots[i]; - slots[i].setToSetupPose(i); - } - }, - /** @return May return null. */ - getRootBone: function () { - return this.bones.length ? this.bones[0] : null; - }, - /** @return May be null. */ - findBone: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].data.name == boneName) return bones[i]; - return null; - }, - /** @return -1 if the bone was not found. */ - findBoneIndex: function (boneName) { - var bones = this.bones; - for (var i = 0, n = bones.length; i < n; i++) - if (bones[i].data.name == boneName) return i; - return -1; - }, - /** @return May be null. */ - findSlot: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - if (slots[i].data.name == slotName) return slots[i]; - return null; - }, - /** @return -1 if the bone was not found. */ - findSlotIndex: function (slotName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) - if (slots[i].data.name == slotName) return i; - return -1; - }, - setSkinByName: function (skinName) { - var skin = this.data.findSkin(skinName); - if (!skin) throw "Skin not found: " + skinName; - this.setSkin(skin); - }, - /** Sets the skin used to look up attachments before looking in the {@link SkeletonData#getDefaultSkin() default skin}. - * Attachments from the new skin are attached if the corresponding attachment from the old skin was attached. If there was - * no old skin, each slot's setup mode attachment is attached from the new skin. - * @param newSkin May be null. */ - setSkin: function (newSkin) { - if (newSkin) { - if (this.skin) - newSkin._attachAll(this, this.skin); - else { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) { - var slot = slots[i]; - var name = slot.data.attachmentName; - if (name) { - var attachment = newSkin.getAttachment(i, name); - if (attachment) slot.setAttachment(attachment); - } - } - } - } - this.skin = newSkin; - }, - /** @return May be null. */ - getAttachmentBySlotName: function (slotName, attachmentName) { - return this.getAttachmentBySlotIndex(this.data.findSlotIndex(slotName), attachmentName); - }, - /** @return May be null. */ - getAttachmentBySlotIndex: function (slotIndex, attachmentName) { - if (this.skin) { - var attachment = this.skin.getAttachment(slotIndex, attachmentName); - if (attachment) return attachment; - } - if (this.data.defaultSkin) return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); - return null; - }, - /** @param attachmentName May be null. */ - setAttachment: function (slotName, attachmentName) { - var slots = this.slots; - for (var i = 0, n = slots.length; i < n; i++) { - var slot = slots[i]; - if (slot.data.name == slotName) { - var attachment = null; - if (attachmentName) { - attachment = this.getAttachmentBySlotIndex(i, attachmentName); - if (!attachment) throw "Attachment not found: " + attachmentName + ", for slot: " + slotName; - } - slot.setAttachment(attachment); - return; - } - } - throw "Slot not found: " + slotName; - }, - /** @return May be null. */ - findIkConstraint: function (ikConstraintName) { - var ikConstraints = this.ikConstraints; - for (var i = 0, n = ikConstraints.length; i < n; i++) - if (ikConstraints[i].data.name == ikConstraintName) return ikConstraints[i]; - return null; - }, - update: function (delta) { - this.time += delta; - } -}; - -spine.EventData = function (name) { - this.name = name; -}; -spine.EventData.prototype = { - intValue: 0, - floatValue: 0, - stringValue: null -}; - -spine.Event = function (data) { - this.data = data; -}; -spine.Event.prototype = { - intValue: 0, - floatValue: 0, - stringValue: null -}; - -spine.AttachmentType = { - region: 0, - boundingbox: 1, - mesh: 2, - skinnedmesh: 3 -}; - -spine.RegionAttachment = function (name) { - this.name = name; - this.offset = []; - this.offset.length = 8; - this.uvs = []; - this.uvs.length = 8; -}; -spine.RegionAttachment.prototype = { - type: spine.AttachmentType.region, - x: 0, y: 0, - rotation: 0, - scaleX: 1, scaleY: 1, - width: 0, height: 0, - r: 1, g: 1, b: 1, a: 1, - path: null, - rendererObject: null, - regionOffsetX: 0, regionOffsetY: 0, - regionWidth: 0, regionHeight: 0, - regionOriginalWidth: 0, regionOriginalHeight: 0, - setUVs: function (u, v, u2, v2, rotate) { - var uvs = this.uvs; - if (rotate) { - uvs[2/*X2*/] = u; - uvs[3/*Y2*/] = v2; - uvs[4/*X3*/] = u; - uvs[5/*Y3*/] = v; - uvs[6/*X4*/] = u2; - uvs[7/*Y4*/] = v; - uvs[0/*X1*/] = u2; - uvs[1/*Y1*/] = v2; - } else { - uvs[0/*X1*/] = u; - uvs[1/*Y1*/] = v2; - uvs[2/*X2*/] = u; - uvs[3/*Y2*/] = v; - uvs[4/*X3*/] = u2; - uvs[5/*Y3*/] = v; - uvs[6/*X4*/] = u2; - uvs[7/*Y4*/] = v2; - } - }, - updateOffset: function () { - var regionScaleX = this.width / this.regionOriginalWidth * this.scaleX; - var regionScaleY = this.height / this.regionOriginalHeight * this.scaleY; - var localX = -this.width / 2 * this.scaleX + this.regionOffsetX * regionScaleX; - var localY = -this.height / 2 * this.scaleY + this.regionOffsetY * regionScaleY; - var localX2 = localX + this.regionWidth * regionScaleX; - var localY2 = localY + this.regionHeight * regionScaleY; - var radians = this.rotation * spine.degRad; - var cos = Math.cos(radians); - var sin = Math.sin(radians); - var localXCos = localX * cos + this.x; - var localXSin = localX * sin; - var localYCos = localY * cos + this.y; - var localYSin = localY * sin; - var localX2Cos = localX2 * cos + this.x; - var localX2Sin = localX2 * sin; - var localY2Cos = localY2 * cos + this.y; - var localY2Sin = localY2 * sin; - var offset = this.offset; - offset[0/*X1*/] = localXCos - localYSin; - offset[1/*Y1*/] = localYCos + localXSin; - offset[2/*X2*/] = localXCos - localY2Sin; - offset[3/*Y2*/] = localY2Cos + localXSin; - offset[4/*X3*/] = localX2Cos - localY2Sin; - offset[5/*Y3*/] = localY2Cos + localX2Sin; - offset[6/*X4*/] = localX2Cos - localYSin; - offset[7/*Y4*/] = localYCos + localX2Sin; - }, - computeVertices: function (x, y, bone, vertices) { - x += bone.worldX; - y += bone.worldY; - var m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11; - var offset = this.offset; - vertices[0/*X1*/] = offset[0/*X1*/] * m00 + offset[1/*Y1*/] * m01 + x; - vertices[1/*Y1*/] = offset[0/*X1*/] * m10 + offset[1/*Y1*/] * m11 + y; - vertices[2/*X2*/] = offset[2/*X2*/] * m00 + offset[3/*Y2*/] * m01 + x; - vertices[3/*Y2*/] = offset[2/*X2*/] * m10 + offset[3/*Y2*/] * m11 + y; - vertices[4/*X3*/] = offset[4/*X3*/] * m00 + offset[5/*X3*/] * m01 + x; - vertices[5/*X3*/] = offset[4/*X3*/] * m10 + offset[5/*X3*/] * m11 + y; - vertices[6/*X4*/] = offset[6/*X4*/] * m00 + offset[7/*Y4*/] * m01 + x; - vertices[7/*Y4*/] = offset[6/*X4*/] * m10 + offset[7/*Y4*/] * m11 + y; - } -}; - -spine.MeshAttachment = function (name) { - this.name = name; -}; -spine.MeshAttachment.prototype = { - type: spine.AttachmentType.mesh, - vertices: null, - uvs: null, - regionUVs: null, - triangles: null, - hullLength: 0, - r: 1, g: 1, b: 1, a: 1, - path: null, - rendererObject: null, - regionU: 0, regionV: 0, regionU2: 0, regionV2: 0, regionRotate: false, - regionOffsetX: 0, regionOffsetY: 0, - regionWidth: 0, regionHeight: 0, - regionOriginalWidth: 0, regionOriginalHeight: 0, - edges: null, - width: 0, height: 0, - updateUVs: function () { - var width = this.regionU2 - this.regionU, height = this.regionV2 - this.regionV; - var n = this.regionUVs.length; - if (!this.uvs || this.uvs.length != n) { - this.uvs = new spine.Float32Array(n); - } - if (this.regionRotate) { - for (var i = 0; i < n; i += 2) { - this.uvs[i] = this.regionU + this.regionUVs[i + 1] * width; - this.uvs[i + 1] = this.regionV + height - this.regionUVs[i] * height; - } - } else { - for (var i = 0; i < n; i += 2) { - this.uvs[i] = this.regionU + this.regionUVs[i] * width; - this.uvs[i + 1] = this.regionV + this.regionUVs[i + 1] * height; - } - } - }, - computeWorldVertices: function (x, y, slot, worldVertices) { - var bone = slot.bone; - x += bone.worldX; - y += bone.worldY; - var m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11; - var vertices = this.vertices; - var verticesCount = vertices.length; - if (slot.attachmentVertices.length == verticesCount) vertices = slot.attachmentVertices; - for (var i = 0; i < verticesCount; i += 2) { - var vx = vertices[i]; - var vy = vertices[i + 1]; - worldVertices[i] = vx * m00 + vy * m01 + x; - worldVertices[i + 1] = vx * m10 + vy * m11 + y; - } - } -}; - -spine.SkinnedMeshAttachment = function (name) { - this.name = name; -}; -spine.SkinnedMeshAttachment.prototype = { - type: spine.AttachmentType.skinnedmesh, - bones: null, - weights: null, - uvs: null, - regionUVs: null, - triangles: null, - hullLength: 0, - r: 1, g: 1, b: 1, a: 1, - path: null, - rendererObject: null, - regionU: 0, regionV: 0, regionU2: 0, regionV2: 0, regionRotate: false, - regionOffsetX: 0, regionOffsetY: 0, - regionWidth: 0, regionHeight: 0, - regionOriginalWidth: 0, regionOriginalHeight: 0, - edges: null, - width: 0, height: 0, - updateUVs: function (u, v, u2, v2, rotate) { - var width = this.regionU2 - this.regionU, height = this.regionV2 - this.regionV; - var n = this.regionUVs.length; - if (!this.uvs || this.uvs.length != n) { - this.uvs = new spine.Float32Array(n); - } - if (this.regionRotate) { - for (var i = 0; i < n; i += 2) { - this.uvs[i] = this.regionU + this.regionUVs[i + 1] * width; - this.uvs[i + 1] = this.regionV + height - this.regionUVs[i] * height; - } - } else { - for (var i = 0; i < n; i += 2) { - this.uvs[i] = this.regionU + this.regionUVs[i] * width; - this.uvs[i + 1] = this.regionV + this.regionUVs[i + 1] * height; - } - } - }, - computeWorldVertices: function (x, y, slot, worldVertices) { - var skeletonBones = slot.bone.skeleton.bones; - var weights = this.weights; - var bones = this.bones; - - var w = 0, v = 0, b = 0, f = 0, n = bones.length, nn; - var wx, wy, bone, vx, vy, weight; - if (!slot.attachmentVertices.length) { - for (; v < n; w += 2) { - wx = 0; - wy = 0; - nn = bones[v++] + v; - for (; v < nn; v++, b += 3) { - bone = skeletonBones[bones[v]]; - vx = weights[b]; - vy = weights[b + 1]; - weight = weights[b + 2]; - wx += (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight; - wy += (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight; - } - worldVertices[w] = wx + x; - worldVertices[w + 1] = wy + y; - } - } else { - var ffd = slot.attachmentVertices; - for (; v < n; w += 2) { - wx = 0; - wy = 0; - nn = bones[v++] + v; - for (; v < nn; v++, b += 3, f += 2) { - bone = skeletonBones[bones[v]]; - vx = weights[b] + ffd[f]; - vy = weights[b + 1] + ffd[f + 1]; - weight = weights[b + 2]; - wx += (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight; - wy += (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight; - } - worldVertices[w] = wx + x; - worldVertices[w + 1] = wy + y; - } - } - } -}; - -spine.BoundingBoxAttachment = function (name) { - this.name = name; - this.vertices = []; -}; -spine.BoundingBoxAttachment.prototype = { - type: spine.AttachmentType.boundingbox, - computeWorldVertices: function (x, y, bone, worldVertices) { - x += bone.worldX; - y += bone.worldY; - var m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11; - var vertices = this.vertices; - for (var i = 0, n = vertices.length; i < n; i += 2) { - var px = vertices[i]; - var py = vertices[i + 1]; - worldVertices[i] = px * m00 + py * m01 + x; - worldVertices[i + 1] = px * m10 + py * m11 + y; - } - } -}; - -spine.AnimationStateData = function (skeletonData) { - this.skeletonData = skeletonData; - this.animationToMixTime = {}; -}; -spine.AnimationStateData.prototype = { - defaultMix: 0, - setMixByName: function (fromName, toName, duration) { - var from = this.skeletonData.findAnimation(fromName); - if (!from) throw "Animation not found: " + fromName; - var to = this.skeletonData.findAnimation(toName); - if (!to) throw "Animation not found: " + toName; - this.setMix(from, to, duration); - }, - setMix: function (from, to, duration) { - this.animationToMixTime[from.name + ":" + to.name] = duration; - }, - getMix: function (from, to) { - var key = from.name + ":" + to.name; - return this.animationToMixTime.hasOwnProperty(key) ? this.animationToMixTime[key] : this.defaultMix; - } -}; - -spine.TrackEntry = function () {}; -spine.TrackEntry.prototype = { - next: null, previous: null, - animation: null, - loop: false, - delay: 0, time: 0, lastTime: -1, endTime: 0, - timeScale: 1, - mixTime: 0, mixDuration: 0, mix: 1, - onStart: null, onEnd: null, onComplete: null, onEvent: null -}; - -spine.AnimationState = function (stateData) { - this.data = stateData; - this.tracks = []; - this.events = []; -}; -spine.AnimationState.prototype = { - onStart: null, - onEnd: null, - onComplete: null, - onEvent: null, - timeScale: 1, - update: function (delta) { - delta *= this.timeScale; - for (var i = 0; i < this.tracks.length; i++) { - var current = this.tracks[i]; - if (!current) continue; - - current.time += delta * current.timeScale; - if (current.previous) { - var previousDelta = delta * current.previous.timeScale; - current.previous.time += previousDelta; - current.mixTime += previousDelta; - } - - var next = current.next; - if (next) { - next.time = current.lastTime - next.delay; - if (next.time >= 0) this.setCurrent(i, next); - } else { - // End non-looping animation when it reaches its end time and there is no next entry. - if (!current.loop && current.lastTime >= current.endTime) this.clearTrack(i); - } - } - }, - apply: function (skeleton) { - for (var i = 0; i < this.tracks.length; i++) { - var current = this.tracks[i]; - if (!current) continue; - - this.events.length = 0; - - var time = current.time; - var lastTime = current.lastTime; - var endTime = current.endTime; - var loop = current.loop; - if (!loop && time > endTime) time = endTime; - - var previous = current.previous; - if (!previous) { - if (current.mix == 1) - current.animation.apply(skeleton, current.lastTime, time, loop, this.events); - else - current.animation.mix(skeleton, current.lastTime, time, loop, this.events, current.mix); - } else { - var previousTime = previous.time; - if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; - previous.animation.apply(skeleton, previousTime, previousTime, previous.loop, null); - - var alpha = current.mixTime / current.mixDuration * current.mix; - if (alpha >= 1) { - alpha = 1; - current.previous = null; - } - current.animation.mix(skeleton, current.lastTime, time, loop, this.events, alpha); - } - - for (var ii = 0, nn = this.events.length; ii < nn; ii++) { - var event = this.events[ii]; - if (current.onEvent) current.onEvent(i, event); - if (this.onEvent) this.onEvent(i, event); - } - - // Check if completed the animation or a loop iteration. - if (loop ? (lastTime % endTime > time % endTime) : (lastTime < endTime && time >= endTime)) { - var count = Math.floor(time / endTime); - if (current.onComplete) current.onComplete(i, count); - if (this.onComplete) this.onComplete(i, count); - } - - current.lastTime = current.time; - } - }, - clearTracks: function () { - for (var i = 0, n = this.tracks.length; i < n; i++) - this.clearTrack(i); - this.tracks.length = 0; - }, - clearTrack: function (trackIndex) { - if (trackIndex >= this.tracks.length) return; - var current = this.tracks[trackIndex]; - if (!current) return; - - if (current.onEnd) current.onEnd(trackIndex); - if (this.onEnd) this.onEnd(trackIndex); - - this.tracks[trackIndex] = null; - }, - _expandToIndex: function (index) { - if (index < this.tracks.length) return this.tracks[index]; - while (index >= this.tracks.length) - this.tracks.push(null); - return null; - }, - setCurrent: function (index, entry) { - var current = this._expandToIndex(index); - if (current) { - var previous = current.previous; - current.previous = null; - - if (current.onEnd) current.onEnd(index); - if (this.onEnd) this.onEnd(index); - - entry.mixDuration = this.data.getMix(current.animation, entry.animation); - if (entry.mixDuration > 0) { - entry.mixTime = 0; - // If a mix is in progress, mix from the closest animation. - if (previous && current.mixTime / current.mixDuration < 0.5) - entry.previous = previous; - else - entry.previous = current; - } - } - - this.tracks[index] = entry; - - if (entry.onStart) entry.onStart(index); - if (this.onStart) this.onStart(index); - }, - setAnimationByName: function (trackIndex, animationName, loop) { - var animation = this.data.skeletonData.findAnimation(animationName); - if (!animation) throw "Animation not found: " + animationName; - return this.setAnimation(trackIndex, animation, loop); - }, - /** Set the current animation. Any queued animations are cleared. */ - setAnimation: function (trackIndex, animation, loop) { - var entry = new spine.TrackEntry(); - entry.animation = animation; - entry.loop = loop; - entry.endTime = animation.duration; - this.setCurrent(trackIndex, entry); - return entry; - }, - addAnimationByName: function (trackIndex, animationName, loop, delay) { - var animation = this.data.skeletonData.findAnimation(animationName); - if (!animation) throw "Animation not found: " + animationName; - return this.addAnimation(trackIndex, animation, loop, delay); - }, - /** Adds an animation to be played delay seconds after the current or last queued animation. - * @param delay May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. */ - addAnimation: function (trackIndex, animation, loop, delay) { - var entry = new spine.TrackEntry(); - entry.animation = animation; - entry.loop = loop; - entry.endTime = animation.duration; - - var last = this._expandToIndex(trackIndex); - if (last) { - while (last.next) - last = last.next; - last.next = entry; - } else - this.tracks[trackIndex] = entry; - - if (delay <= 0) { - if (last) - delay += last.endTime - this.data.getMix(last.animation, animation); - else - delay = 0; - } - entry.delay = delay; - - return entry; - }, - /** May be null. */ - getCurrent: function (trackIndex) { - if (trackIndex >= this.tracks.length) return null; - return this.tracks[trackIndex]; - } -}; - -spine.SkeletonJson = function (attachmentLoader) { - this.attachmentLoader = attachmentLoader; -}; -spine.SkeletonJson.prototype = { - scale: 1, - readSkeletonData: function (root, name) { - var skeletonData = new spine.SkeletonData(); - skeletonData.name = name; - - // Skeleton. - var skeletonMap = root["skeleton"]; - if (skeletonMap) { - skeletonData.hash = skeletonMap["hash"]; - skeletonData.version = skeletonMap["spine"]; - skeletonData.width = skeletonMap["width"] || 0; - skeletonData.height = skeletonMap["height"] || 0; - } - - // Bones. - var bones = root["bones"]; - for (var i = 0, n = bones.length; i < n; i++) { - var boneMap = bones[i]; - var parent = null; - if (boneMap["parent"]) { - parent = skeletonData.findBone(boneMap["parent"]); - if (!parent) throw "Parent bone not found: " + boneMap["parent"]; - } - var boneData = new spine.BoneData(boneMap["name"], parent); - boneData.length = (boneMap["length"] || 0) * this.scale; - boneData.x = (boneMap["x"] || 0) * this.scale; - boneData.y = (boneMap["y"] || 0) * this.scale; - boneData.rotation = (boneMap["rotation"] || 0); - boneData.scaleX = boneMap.hasOwnProperty("scaleX") ? boneMap["scaleX"] : 1; - boneData.scaleY = boneMap.hasOwnProperty("scaleY") ? boneMap["scaleY"] : 1; - boneData.inheritScale = boneMap.hasOwnProperty("inheritScale") ? boneMap["inheritScale"] : true; - boneData.inheritRotation = boneMap.hasOwnProperty("inheritRotation") ? boneMap["inheritRotation"] : true; - skeletonData.bones.push(boneData); - } - - // IK constraints. - var ik = root["ik"]; - if (ik) { - for (var i = 0, n = ik.length; i < n; i++) { - var ikMap = ik[i]; - var ikConstraintData = new spine.IkConstraintData(ikMap["name"]); - - var bones = ikMap["bones"]; - for (var ii = 0, nn = bones.length; ii < nn; ii++) { - var bone = skeletonData.findBone(bones[ii]); - if (!bone) throw "IK bone not found: " + bones[ii]; - ikConstraintData.bones.push(bone); - } - - ikConstraintData.target = skeletonData.findBone(ikMap["target"]); - if (!ikConstraintData.target) throw "Target bone not found: " + ikMap["target"]; - - ikConstraintData.bendDirection = (!ikMap.hasOwnProperty("bendPositive") || ikMap["bendPositive"]) ? 1 : -1; - ikConstraintData.mix = ikMap.hasOwnProperty("mix") ? ikMap["mix"] : 1; - - skeletonData.ikConstraints.push(ikConstraintData); - } - } - - // Slots. - var slots = root["slots"]; - for (var i = 0, n = slots.length; i < n; i++) { - var slotMap = slots[i]; - var boneData = skeletonData.findBone(slotMap["bone"]); - if (!boneData) throw "Slot bone not found: " + slotMap["bone"]; - var slotData = new spine.SlotData(slotMap["name"], boneData); - - var color = slotMap["color"]; - if (color) { - slotData.r = this.toColor(color, 0); - slotData.g = this.toColor(color, 1); - slotData.b = this.toColor(color, 2); - slotData.a = this.toColor(color, 3); - } - - slotData.attachmentName = slotMap["attachment"]; - slotData.additiveBlending = slotMap["additive"] && slotMap["additive"] == "true"; - - skeletonData.slots.push(slotData); - } - - // Skins. - var skins = root["skins"]; - for (var skinName in skins) { - if (!skins.hasOwnProperty(skinName)) continue; - var skinMap = skins[skinName]; - var skin = new spine.Skin(skinName); - for (var slotName in skinMap) { - if (!skinMap.hasOwnProperty(slotName)) continue; - var slotIndex = skeletonData.findSlotIndex(slotName); - var slotEntry = skinMap[slotName]; - for (var attachmentName in slotEntry) { - if (!slotEntry.hasOwnProperty(attachmentName)) continue; - var attachment = this.readAttachment(skin, attachmentName, slotEntry[attachmentName]); - if (attachment) skin.addAttachment(slotIndex, attachmentName, attachment); - } - } - skeletonData.skins.push(skin); - if (skin.name == "default") skeletonData.defaultSkin = skin; - } - - // Events. - var events = root["events"]; - for (var eventName in events) { - if (!events.hasOwnProperty(eventName)) continue; - var eventMap = events[eventName]; - var eventData = new spine.EventData(eventName); - eventData.intValue = eventMap["int"] || 0; - eventData.floatValue = eventMap["float"] || 0; - eventData.stringValue = eventMap["string"] || null; - skeletonData.events.push(eventData); - } - - // Animations. - var animations = root["animations"]; - for (var animationName in animations) { - if (!animations.hasOwnProperty(animationName)) continue; - this.readAnimation(animationName, animations[animationName], skeletonData); - } - - return skeletonData; - }, - readAttachment: function (skin, name, map) { - name = map["name"] || name; - - var type = spine.AttachmentType[map["type"] || "region"]; - var path = map["path"] || name; - - var scale = this.scale; - if (type == spine.AttachmentType.region) { - var region = this.attachmentLoader.newRegionAttachment(skin, name, path); - if (!region) return null; - region.path = path; - region.x = (map["x"] || 0) * scale; - region.y = (map["y"] || 0) * scale; - region.scaleX = map.hasOwnProperty("scaleX") ? map["scaleX"] : 1; - region.scaleY = map.hasOwnProperty("scaleY") ? map["scaleY"] : 1; - region.rotation = map["rotation"] || 0; - region.width = (map["width"] || 0) * scale; - region.height = (map["height"] || 0) * scale; - - var color = map["color"]; - if (color) { - region.r = this.toColor(color, 0); - region.g = this.toColor(color, 1); - region.b = this.toColor(color, 2); - region.a = this.toColor(color, 3); - } - - region.updateOffset(); - return region; - } else if (type == spine.AttachmentType.mesh) { - var mesh = this.attachmentLoader.newMeshAttachment(skin, name, path); - if (!mesh) return null; - mesh.path = path; - mesh.vertices = this.getFloatArray(map, "vertices", scale); - mesh.triangles = this.getIntArray(map, "triangles"); - mesh.regionUVs = this.getFloatArray(map, "uvs", 1); - mesh.updateUVs(); - - color = map["color"]; - if (color) { - mesh.r = this.toColor(color, 0); - mesh.g = this.toColor(color, 1); - mesh.b = this.toColor(color, 2); - mesh.a = this.toColor(color, 3); - } - - mesh.hullLength = (map["hull"] || 0) * 2; - if (map["edges"]) mesh.edges = this.getIntArray(map, "edges"); - mesh.width = (map["width"] || 0) * scale; - mesh.height = (map["height"] || 0) * scale; - return mesh; - } else if (type == spine.AttachmentType.skinnedmesh) { - var mesh = this.attachmentLoader.newSkinnedMeshAttachment(skin, name, path); - if (!mesh) return null; - mesh.path = path; - - var uvs = this.getFloatArray(map, "uvs", 1); - var vertices = this.getFloatArray(map, "vertices", 1); - var weights = []; - var bones = []; - for (var i = 0, n = vertices.length; i < n; ) { - var boneCount = vertices[i++] | 0; - bones[bones.length] = boneCount; - for (var nn = i + boneCount * 4; i < nn; ) { - bones[bones.length] = vertices[i]; - weights[weights.length] = vertices[i + 1] * scale; - weights[weights.length] = vertices[i + 2] * scale; - weights[weights.length] = vertices[i + 3]; - i += 4; - } - } - mesh.bones = bones; - mesh.weights = weights; - mesh.triangles = this.getIntArray(map, "triangles"); - mesh.regionUVs = uvs; - mesh.updateUVs(); - - color = map["color"]; - if (color) { - mesh.r = this.toColor(color, 0); - mesh.g = this.toColor(color, 1); - mesh.b = this.toColor(color, 2); - mesh.a = this.toColor(color, 3); - } - - mesh.hullLength = (map["hull"] || 0) * 2; - if (map["edges"]) mesh.edges = this.getIntArray(map, "edges"); - mesh.width = (map["width"] || 0) * scale; - mesh.height = (map["height"] || 0) * scale; - return mesh; - } else if (type == spine.AttachmentType.boundingbox) { - var attachment = this.attachmentLoader.newBoundingBoxAttachment(skin, name); - var vertices = map["vertices"]; - for (var i = 0, n = vertices.length; i < n; i++) - attachment.vertices.push(vertices[i] * scale); - return attachment; - } - throw "Unknown attachment type: " + type; - }, - readAnimation: function (name, map, skeletonData) { - var timelines = []; - var duration = 0; - - var slots = map["slots"]; - for (var slotName in slots) { - if (!slots.hasOwnProperty(slotName)) continue; - var slotMap = slots[slotName]; - var slotIndex = skeletonData.findSlotIndex(slotName); - - for (var timelineName in slotMap) { - if (!slotMap.hasOwnProperty(timelineName)) continue; - var values = slotMap[timelineName]; - if (timelineName == "color") { - var timeline = new spine.ColorTimeline(values.length); - timeline.slotIndex = slotIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - var color = valueMap["color"]; - var r = this.toColor(color, 0); - var g = this.toColor(color, 1); - var b = this.toColor(color, 2); - var a = this.toColor(color, 3); - timeline.setFrame(frameIndex, valueMap["time"], r, g, b, a); - this.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 5 - 5]); - - } else if (timelineName == "attachment") { - var timeline = new spine.AttachmentTimeline(values.length); - timeline.slotIndex = slotIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - timeline.setFrame(frameIndex++, valueMap["time"], valueMap["name"]); - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); - - } else - throw "Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"; - } - } - - var bones = map["bones"]; - for (var boneName in bones) { - if (!bones.hasOwnProperty(boneName)) continue; - var boneIndex = skeletonData.findBoneIndex(boneName); - if (boneIndex == -1) throw "Bone not found: " + boneName; - var boneMap = bones[boneName]; - - for (var timelineName in boneMap) { - if (!boneMap.hasOwnProperty(timelineName)) continue; - var values = boneMap[timelineName]; - if (timelineName == "rotate") { - var timeline = new spine.RotateTimeline(values.length); - timeline.boneIndex = boneIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - timeline.setFrame(frameIndex, valueMap["time"], valueMap["angle"]); - this.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 2 - 2]); - - } else if (timelineName == "translate" || timelineName == "scale") { - var timeline; - var timelineScale = 1; - if (timelineName == "scale") - timeline = new spine.ScaleTimeline(values.length); - else { - timeline = new spine.TranslateTimeline(values.length); - timelineScale = this.scale; - } - timeline.boneIndex = boneIndex; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - var x = (valueMap["x"] || 0) * timelineScale; - var y = (valueMap["y"] || 0) * timelineScale; - timeline.setFrame(frameIndex, valueMap["time"], x, y); - this.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 3 - 3]); - - } else if (timelineName == "flipX" || timelineName == "flipY") { - var x = timelineName == "flipX"; - var timeline = x ? new spine.FlipXTimeline(values.length) : new spine.FlipYTimeline(values.length); - timeline.boneIndex = boneIndex; - - var field = x ? "x" : "y"; - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - timeline.setFrame(frameIndex, valueMap["time"], valueMap[field] || false); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() * 2 - 2]); - } else - throw "Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"; - } - } - - var ikMap = map["ik"]; - for (var ikConstraintName in ikMap) { - if (!ikMap.hasOwnProperty(ikConstraintName)) continue; - var ikConstraint = skeletonData.findIkConstraint(ikConstraintName); - var values = ikMap[ikConstraintName]; - var timeline = new spine.IkConstraintTimeline(values.length); - timeline.ikConstraintIndex = skeletonData.ikConstraints.indexOf(ikConstraint); - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - var mix = valueMap.hasOwnProperty("mix") ? valueMap["mix"] : 1; - var bendDirection = (!valueMap.hasOwnProperty("bendPositive") || valueMap["bendPositive"]) ? 1 : -1; - timeline.setFrame(frameIndex, valueMap["time"], mix, bendDirection); - this.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.frameCount * 3 - 3]); - } - - var ffd = map["ffd"]; - for (var skinName in ffd) { - var skin = skeletonData.findSkin(skinName); - var slotMap = ffd[skinName]; - for (slotName in slotMap) { - var slotIndex = skeletonData.findSlotIndex(slotName); - var meshMap = slotMap[slotName]; - for (var meshName in meshMap) { - var values = meshMap[meshName]; - var timeline = new spine.FfdTimeline(values.length); - var attachment = skin.getAttachment(slotIndex, meshName); - if (!attachment) throw "FFD attachment not found: " + meshName; - timeline.slotIndex = slotIndex; - timeline.attachment = attachment; - - var isMesh = attachment.type == spine.AttachmentType.mesh; - var vertexCount; - if (isMesh) - vertexCount = attachment.vertices.length; - else - vertexCount = attachment.weights.length / 3 * 2; - - var frameIndex = 0; - for (var i = 0, n = values.length; i < n; i++) { - var valueMap = values[i]; - var vertices; - if (!valueMap["vertices"]) { - if (isMesh) - vertices = attachment.vertices; - else { - vertices = []; - vertices.length = vertexCount; - } - } else { - var verticesValue = valueMap["vertices"]; - var vertices = []; - vertices.length = vertexCount; - var start = valueMap["offset"] || 0; - var nn = verticesValue.length; - if (this.scale == 1) { - for (var ii = 0; ii < nn; ii++) - vertices[ii + start] = verticesValue[ii]; - } else { - for (var ii = 0; ii < nn; ii++) - vertices[ii + start] = verticesValue[ii] * this.scale; - } - if (isMesh) { - var meshVertices = attachment.vertices; - for (var ii = 0, nn = vertices.length; ii < nn; ii++) - vertices[ii] += meshVertices[ii]; - } - } - - timeline.setFrame(frameIndex, valueMap["time"], vertices); - this.readCurve(timeline, frameIndex, valueMap); - frameIndex++; - } - timelines[timelines.length] = timeline; - duration = Math.max(duration, timeline.frames[timeline.frameCount - 1]); - } - } - } - - var drawOrderValues = map["drawOrder"]; - if (!drawOrderValues) drawOrderValues = map["draworder"]; - if (drawOrderValues) { - var timeline = new spine.DrawOrderTimeline(drawOrderValues.length); - var slotCount = skeletonData.slots.length; - var frameIndex = 0; - for (var i = 0, n = drawOrderValues.length; i < n; i++) { - var drawOrderMap = drawOrderValues[i]; - var drawOrder = null; - if (drawOrderMap["offsets"]) { - drawOrder = []; - drawOrder.length = slotCount; - for (var ii = slotCount - 1; ii >= 0; ii--) - drawOrder[ii] = -1; - var offsets = drawOrderMap["offsets"]; - var unchanged = []; - unchanged.length = slotCount - offsets.length; - var originalIndex = 0, unchangedIndex = 0; - for (var ii = 0, nn = offsets.length; ii < nn; ii++) { - var offsetMap = offsets[ii]; - var slotIndex = skeletonData.findSlotIndex(offsetMap["slot"]); - if (slotIndex == -1) throw "Slot not found: " + offsetMap["slot"]; - // Collect unchanged items. - while (originalIndex != slotIndex) - unchanged[unchangedIndex++] = originalIndex++; - // Set changed items. - drawOrder[originalIndex + offsetMap["offset"]] = originalIndex++; - } - // Collect remaining unchanged items. - while (originalIndex < slotCount) - unchanged[unchangedIndex++] = originalIndex++; - // Fill in unchanged items. - for (var ii = slotCount - 1; ii >= 0; ii--) - if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex]; - } - timeline.setFrame(frameIndex++, drawOrderMap["time"], drawOrder); - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); - } - - var events = map["events"]; - if (events) { - var timeline = new spine.EventTimeline(events.length); - var frameIndex = 0; - for (var i = 0, n = events.length; i < n; i++) { - var eventMap = events[i]; - var eventData = skeletonData.findEvent(eventMap["name"]); - if (!eventData) throw "Event not found: " + eventMap["name"]; - var event = new spine.Event(eventData); - event.intValue = eventMap.hasOwnProperty("int") ? eventMap["int"] : eventData.intValue; - event.floatValue = eventMap.hasOwnProperty("float") ? eventMap["float"] : eventData.floatValue; - event.stringValue = eventMap.hasOwnProperty("string") ? eventMap["string"] : eventData.stringValue; - timeline.setFrame(frameIndex++, eventMap["time"], event); - } - timelines.push(timeline); - duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); - } - - skeletonData.animations.push(new spine.Animation(name, timelines, duration)); - }, - readCurve: function (timeline, frameIndex, valueMap) { - var curve = valueMap["curve"]; - if (!curve) - timeline.curves.setLinear(frameIndex); - else if (curve == "stepped") - timeline.curves.setStepped(frameIndex); - else if (curve instanceof Array) - timeline.curves.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); - }, - toColor: function (hexString, colorIndex) { - if (hexString.length != 8) throw "Color hexidecimal length must be 8, recieved: " + hexString; - return parseInt(hexString.substring(colorIndex * 2, (colorIndex * 2) + 2), 16) / 255; - }, - getFloatArray: function (map, name, scale) { - var list = map[name]; - var values = new spine.Float32Array(list.length); - var i = 0, n = list.length; - if (scale == 1) { - for (; i < n; i++) - values[i] = list[i]; - } else { - for (; i < n; i++) - values[i] = list[i] * scale; - } - return values; - }, - getIntArray: function (map, name) { - var list = map[name]; - var values = new spine.Uint16Array(list.length); - for (var i = 0, n = list.length; i < n; i++) - values[i] = list[i] | 0; - return values; - } -}; - -spine.Atlas = function (atlasText, textureLoader) { - this.textureLoader = textureLoader; - this.pages = []; - this.regions = []; - - var reader = new spine.AtlasReader(atlasText); - var tuple = []; - tuple.length = 4; - var page = null; - while (true) { - var line = reader.readLine(); - if (line === null) break; - line = reader.trim(line); - if (!line.length) - page = null; - else if (!page) { - page = new spine.AtlasPage(); - page.name = line; - - if (reader.readTuple(tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker. - page.width = parseInt(tuple[0]); - page.height = parseInt(tuple[1]); - reader.readTuple(tuple); - } - page.format = spine.Atlas.Format[tuple[0]]; - - reader.readTuple(tuple); - page.minFilter = spine.Atlas.TextureFilter[tuple[0]]; - page.magFilter = spine.Atlas.TextureFilter[tuple[1]]; - - var direction = reader.readValue(); - page.uWrap = spine.Atlas.TextureWrap.clampToEdge; - page.vWrap = spine.Atlas.TextureWrap.clampToEdge; - if (direction == "x") - page.uWrap = spine.Atlas.TextureWrap.repeat; - else if (direction == "y") - page.vWrap = spine.Atlas.TextureWrap.repeat; - else if (direction == "xy") - page.uWrap = page.vWrap = spine.Atlas.TextureWrap.repeat; - - textureLoader.load(page, line, this); - - this.pages.push(page); - - } else { - var region = new spine.AtlasRegion(); - region.name = line; - region.page = page; - - region.rotate = reader.readValue() == "true"; - - reader.readTuple(tuple); - var x = parseInt(tuple[0]); - var y = parseInt(tuple[1]); - - reader.readTuple(tuple); - var width = parseInt(tuple[0]); - var height = parseInt(tuple[1]); - - region.u = x / page.width; - region.v = y / page.height; - if (region.rotate) { - region.u2 = (x + height) / page.width; - region.v2 = (y + width) / page.height; - } else { - region.u2 = (x + width) / page.width; - region.v2 = (y + height) / page.height; - } - region.x = x; - region.y = y; - region.width = Math.abs(width); - region.height = Math.abs(height); - - if (reader.readTuple(tuple) == 4) { // split is optional - region.splits = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; - - if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits - region.pads = [parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3])]; - - reader.readTuple(tuple); - } - } - - region.originalWidth = parseInt(tuple[0]); - region.originalHeight = parseInt(tuple[1]); - - reader.readTuple(tuple); - region.offsetX = parseInt(tuple[0]); - region.offsetY = parseInt(tuple[1]); - - region.index = parseInt(reader.readValue()); - - this.regions.push(region); - } - } -}; -spine.Atlas.prototype = { - findRegion: function (name) { - var regions = this.regions; - for (var i = 0, n = regions.length; i < n; i++) - if (regions[i].name == name) return regions[i]; - return null; - }, - dispose: function () { - var pages = this.pages; - for (var i = 0, n = pages.length; i < n; i++) - this.textureLoader.unload(pages[i].rendererObject); - }, - updateUVs: function (page) { - var regions = this.regions; - for (var i = 0, n = regions.length; i < n; i++) { - var region = regions[i]; - if (region.page != page) continue; - region.u = region.x / page.width; - region.v = region.y / page.height; - if (region.rotate) { - region.u2 = (region.x + region.height) / page.width; - region.v2 = (region.y + region.width) / page.height; - } else { - region.u2 = (region.x + region.width) / page.width; - region.v2 = (region.y + region.height) / page.height; - } - } - } -}; - -spine.Atlas.Format = { - alpha: 0, - intensity: 1, - luminanceAlpha: 2, - rgb565: 3, - rgba4444: 4, - rgb888: 5, - rgba8888: 6 -}; - -spine.Atlas.TextureFilter = { - nearest: 0, - linear: 1, - mipMap: 2, - mipMapNearestNearest: 3, - mipMapLinearNearest: 4, - mipMapNearestLinear: 5, - mipMapLinearLinear: 6 -}; - -spine.Atlas.TextureWrap = { - mirroredRepeat: 0, - clampToEdge: 1, - repeat: 2 -}; - -spine.AtlasPage = function () {}; -spine.AtlasPage.prototype = { - name: null, - format: null, - minFilter: null, - magFilter: null, - uWrap: null, - vWrap: null, - rendererObject: null, - width: 0, - height: 0 -}; - -spine.AtlasRegion = function () {}; -spine.AtlasRegion.prototype = { - page: null, - name: null, - x: 0, y: 0, - width: 0, height: 0, - u: 0, v: 0, u2: 0, v2: 0, - offsetX: 0, offsetY: 0, - originalWidth: 0, originalHeight: 0, - index: 0, - rotate: false, - splits: null, - pads: null -}; - -spine.AtlasReader = function (text) { - this.lines = text.split(/\r\n|\r|\n/); -}; -spine.AtlasReader.prototype = { - index: 0, - trim: function (value) { - return value.replace(/^\s+|\s+$/g, ""); - }, - readLine: function () { - if (this.index >= this.lines.length) return null; - return this.lines[this.index++]; - }, - readValue: function () { - var line = this.readLine(); - var colon = line.indexOf(":"); - if (colon == -1) throw "Invalid line: " + line; - return this.trim(line.substring(colon + 1)); - }, - /** Returns the number of tuple values read (1, 2 or 4). */ - readTuple: function (tuple) { - var line = this.readLine(); - var colon = line.indexOf(":"); - if (colon == -1) throw "Invalid line: " + line; - var i = 0, lastMatch = colon + 1; - for (; i < 3; i++) { - var comma = line.indexOf(",", lastMatch); - if (comma == -1) break; - tuple[i] = this.trim(line.substr(lastMatch, comma - lastMatch)); - lastMatch = comma + 1; - } - tuple[i] = this.trim(line.substring(lastMatch)); - return i + 1; - } -}; - -spine.AtlasAttachmentLoader = function (atlas) { - this.atlas = atlas; -}; -spine.AtlasAttachmentLoader.prototype = { - newRegionAttachment: function (skin, name, path) { - var region = this.atlas.findRegion(path); - if (!region) throw "Region not found in atlas: " + path + " (region attachment: " + name + ")"; - var attachment = new spine.RegionAttachment(name); - attachment.rendererObject = region; - attachment.setUVs(region.u, region.v, region.u2, region.v2, region.rotate); - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - return attachment; - }, - newMeshAttachment: function (skin, name, path) { - var region = this.atlas.findRegion(path); - if (!region) throw "Region not found in atlas: " + path + " (mesh attachment: " + name + ")"; - var attachment = new spine.MeshAttachment(name); - attachment.rendererObject = region; - attachment.regionU = region.u; - attachment.regionV = region.v; - attachment.regionU2 = region.u2; - attachment.regionV2 = region.v2; - attachment.regionRotate = region.rotate; - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - return attachment; - }, - newSkinnedMeshAttachment: function (skin, name, path) { - var region = this.atlas.findRegion(path); - if (!region) throw "Region not found in atlas: " + path + " (skinned mesh attachment: " + name + ")"; - var attachment = new spine.SkinnedMeshAttachment(name); - attachment.rendererObject = region; - attachment.regionU = region.u; - attachment.regionV = region.v; - attachment.regionU2 = region.u2; - attachment.regionV2 = region.v2; - attachment.regionRotate = region.rotate; - attachment.regionOffsetX = region.offsetX; - attachment.regionOffsetY = region.offsetY; - attachment.regionWidth = region.width; - attachment.regionHeight = region.height; - attachment.regionOriginalWidth = region.originalWidth; - attachment.regionOriginalHeight = region.originalHeight; - return attachment; - }, - newBoundingBoxAttachment: function (skin, name) { - return new spine.BoundingBoxAttachment(name); - } -}; - -spine.SkeletonBounds = function () { - this.polygonPool = []; - this.polygons = []; - this.boundingBoxes = []; -}; -spine.SkeletonBounds.prototype = { - minX: 0, minY: 0, maxX: 0, maxY: 0, - update: function (skeleton, updateAabb) { - var slots = skeleton.slots; - var slotCount = slots.length; - var x = skeleton.x, y = skeleton.y; - var boundingBoxes = this.boundingBoxes; - var polygonPool = this.polygonPool; - var polygons = this.polygons; - - boundingBoxes.length = 0; - for (var i = 0, n = polygons.length; i < n; i++) - polygonPool.push(polygons[i]); - polygons.length = 0; - - for (var i = 0; i < slotCount; i++) { - var slot = slots[i]; - var boundingBox = slot.attachment; - if (boundingBox.type != spine.AttachmentType.boundingbox) continue; - boundingBoxes.push(boundingBox); - - var poolCount = polygonPool.length, polygon; - if (poolCount > 0) { - polygon = polygonPool[poolCount - 1]; - polygonPool.splice(poolCount - 1, 1); - } else - polygon = []; - polygons.push(polygon); - - polygon.length = boundingBox.vertices.length; - boundingBox.computeWorldVertices(x, y, slot.bone, polygon); - } - - if (updateAabb) this.aabbCompute(); - }, - aabbCompute: function () { - var polygons = this.polygons; - var minX = Number.MAX_VALUE, minY = Number.MAX_VALUE, maxX = Number.MIN_VALUE, maxY = Number.MIN_VALUE; - for (var i = 0, n = polygons.length; i < n; i++) { - var vertices = polygons[i]; - for (var ii = 0, nn = vertices.length; ii < nn; ii += 2) { - var x = vertices[ii]; - var y = vertices[ii + 1]; - minX = Math.min(minX, x); - minY = Math.min(minY, y); - maxX = Math.max(maxX, x); - maxY = Math.max(maxY, y); - } - } - this.minX = minX; - this.minY = minY; - this.maxX = maxX; - this.maxY = maxY; - }, - /** Returns true if the axis aligned bounding box contains the point. */ - aabbContainsPoint: function (x, y) { - return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY; - }, - /** Returns true if the axis aligned bounding box intersects the line segment. */ - aabbIntersectsSegment: function (x1, y1, x2, y2) { - var minX = this.minX, minY = this.minY, maxX = this.maxX, maxY = this.maxY; - if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) - return false; - var m = (y2 - y1) / (x2 - x1); - var y = m * (minX - x1) + y1; - if (y > minY && y < maxY) return true; - y = m * (maxX - x1) + y1; - if (y > minY && y < maxY) return true; - var x = (minY - y1) / m + x1; - if (x > minX && x < maxX) return true; - x = (maxY - y1) / m + x1; - if (x > minX && x < maxX) return true; - return false; - }, - /** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ - aabbIntersectsSkeleton: function (bounds) { - return this.minX < bounds.maxX && this.maxX > bounds.minX && this.minY < bounds.maxY && this.maxY > bounds.minY; - }, - /** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more - * efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */ - containsPoint: function (x, y) { - var polygons = this.polygons; - for (var i = 0, n = polygons.length; i < n; i++) - if (this.polygonContainsPoint(polygons[i], x, y)) return this.boundingBoxes[i]; - return null; - }, - /** Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually - * more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true. */ - intersectsSegment: function (x1, y1, x2, y2) { - var polygons = this.polygons; - for (var i = 0, n = polygons.length; i < n; i++) - if (polygons[i].intersectsSegment(x1, y1, x2, y2)) return this.boundingBoxes[i]; - return null; - }, - /** Returns true if the polygon contains the point. */ - polygonContainsPoint: function (polygon, x, y) { - var nn = polygon.length; - var prevIndex = nn - 2; - var inside = false; - for (var ii = 0; ii < nn; ii += 2) { - var vertexY = polygon[ii + 1]; - var prevY = polygon[prevIndex + 1]; - if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { - var vertexX = polygon[ii]; - if (vertexX + (y - vertexY) / (prevY - vertexY) * (polygon[prevIndex] - vertexX) < x) inside = !inside; - } - prevIndex = ii; - } - return inside; - }, - /** Returns true if the polygon contains the line segment. */ - polygonIntersectsSegment: function (polygon, x1, y1, x2, y2) { - var nn = polygon.length; - var width12 = x1 - x2, height12 = y1 - y2; - var det1 = x1 * y2 - y1 * x2; - var x3 = polygon[nn - 2], y3 = polygon[nn - 1]; - for (var ii = 0; ii < nn; ii += 2) { - var x4 = polygon[ii], y4 = polygon[ii + 1]; - var det2 = x3 * y4 - y3 * x4; - var width34 = x3 - x4, height34 = y3 - y4; - var det3 = width12 * height34 - height12 * width34; - var x = (det1 * width34 - width12 * det2) / det3; - if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { - var y = (det1 * height34 - height12 * det2) / det3; - if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; - } - x3 = x4; - y3 = y4; - } - return false; - }, - getPolygon: function (attachment) { - var index = this.boundingBoxes.indexOf(attachment); - return index == -1 ? null : this.polygons[index]; - }, - getWidth: function () { - return this.maxX - this.minX; - }, - getHeight: function () { - return this.maxY - this.minY; - } -}; - -},{}],95:[function(require,module,exports){ -/** - * @file Main export of the PIXI spine library - * @author Mat Groves - * @copyright 2013-2015 GoodBoyDigital - * @license {@link https://github.com/GoodBoyDigital/pixi.js/blob/master/LICENSE|MIT License} - */ - -/** - * @namespace PIXI - */ -module.exports = { - Spine: require('./Spine') -}; - -},{"./Spine":93}],96:[function(require,module,exports){ -var core = require('../core'); - -/** - * A BitmapText object will create a line or multiple lines of text using bitmap font. To - * split a line you can use '\n', '\r' or '\r\n' in your string. You can generate the fnt files using: - * - * http://www.angelcode.com/products/bmfont/ for windows or - * http://www.bmglyph.com/ for mac. - * - * @class - * @extends DisplayObjectContainer - * @namespace PIXI - * @param text {string} The copy that you would like the text to display - * @param style {object} The style parameters - * @param style.font {string} The size (optional) and bitmap font id (required) eq 'Arial' or '20px Arial' (must have loaded previously) - * @param [style.align='left'] {string} Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text - */ -function BitmapText(text, style) { - core.DisplayObjectContainer.call(this); - - /** - * The width of the overall text, different from fontSize, - * which is defined in the style object - * - * @member {number} - * @readOnly - */ - this.textWidth = 0; - - /** - * The height of the overall text, different from fontSize, - * which is defined in the style object - * - * @member {number} - * @readOnly - */ - this.textHeight = 0; - - /** - * Private tracker for the letter sprite pool. - * - * @member {Sprite[]} - * @private - */ - this._pool = []; - - /** - * Private tracker for the current style. - * - * @member {object} - * @private - */ - this._style = { - tint: style.tint, - align: style.align, - fontName: null, - fontSize: 0 - }; - this.font = style.font; // run font setter - - /** - * Private tracker for the current text. - * - * @member {string} - * @private - */ - this._text = text; - - /** - * The dirty state of this object. - * - * @member {boolean} - */ - this.dirty = false; - - this.updateText(); -} - -// constructor -BitmapText.prototype = Object.create(core.DisplayObjectContainer.prototype); -BitmapText.prototype.constructor = BitmapText; -module.exports = BitmapText; - -Object.defineProperties(BitmapText.prototype, { - /** - * The tint of the BitmapText object - * - * @member {number} - * @memberof BitmapText# - */ - tint: { - get: function () { - return this._style.tint; - }, - set: function (value) { - this._style.tint = (typeof value === 'number' && value >= 0) ? value : 0xFFFFFF; - - this.dirty = true; - } - }, - - /** - * The tint of the BitmapText object - * - * @member {string} - * @default 'left' - * @memberof BitmapText# - */ - align: { - get: function () { - return this._style.align; - }, - set: function (value) { - this._style.align = value; - - this.dirty = true; - } - }, - - /** - * The tint of the BitmapText object - * - * @member {Font} - * @memberof BitmapText# - */ - font: { - get: function () { - return this._style.font; - }, - set: function (value) { - value = value.split(' '); - - // TODO - This should be object-based not string based like it has been. - this._style.fontName = value[value.length - 1]; - this._style.fontSize = value.length >= 2 ? parseInt(value[value.length - 2], 10) : BitmapText.fonts[this.fontName].size; - - this.dirty = true; - } - }, - - /** - * The text of the BitmapText object - * - * @member {string} - * @memberof BitmapText# - */ - text: { - get: function () { - return this._text; - }, - set: function (value) { - this._text = value; - - this.dirty = true; - } - } -}); - -/** - * Renders text and updates it when needed - * - * @private - */ -BitmapText.prototype.updateText = function () { - var data = BitmapText.fonts[this.fontName]; - var pos = new core.math.Point(); - var prevCharCode = null; - var chars = []; - var maxLineWidth = 0; - var lineWidths = []; - var line = 0; - var scale = this.fontSize / data.size; - - for (var i = 0; i < this.text.length; i++) { - var charCode = this.text.charCodeAt(i); - - if (/(?:\r\n|\r|\n)/.test(this.text.charAt(i))) { - lineWidths.push(pos.x); - maxLineWidth = Math.max(maxLineWidth, pos.x); - line++; - - pos.x = 0; - pos.y += data.lineHeight; - prevCharCode = null; - continue; - } - - var charData = data.chars[charCode]; - - if (!charData) { - continue; - } - - if (prevCharCode && charData.kerning[prevCharCode]) { - pos.x += charData.kerning[prevCharCode]; - } - - chars.push({texture:charData.texture, line: line, charCode: charCode, position: new core.math.Point(pos.x + charData.xOffset, pos.y + charData.yOffset)}); - pos.x += charData.xAdvance; - - prevCharCode = charCode; - } - - lineWidths.push(pos.x); - maxLineWidth = Math.max(maxLineWidth, pos.x); - - var lineAlignOffsets = []; - - for (i = 0; i <= line; i++) { - var alignOffset = 0; - - if (this.style.align === 'right') { - alignOffset = maxLineWidth - lineWidths[i]; - } - else if (this.style.align === 'center') { - alignOffset = (maxLineWidth - lineWidths[i]) / 2; - } - - lineAlignOffsets.push(alignOffset); - } - - var lenChildren = this.children.length; - var lenChars = chars.length; - var tint = this.tint; - - for (i = 0; i < lenChars; i++) { - var c = i < lenChildren ? this.children[i] : this._pool.pop(); // get old child if have. if not - take from pool. - - if (c) { - c.setTexture(chars[i].texture); // check if got one before. - } - else { - c = new core.Sprite(chars[i].texture); // if no create new one. - } - - c.position.x = (chars[i].position.x + lineAlignOffsets[chars[i].line]) * scale; - c.position.y = chars[i].position.y * scale; - c.scale.x = c.scale.y = scale; - c.tint = tint; - - if (!c.parent) { - this.addChild(c); - } - } - - // remove unnecessary children. - // and put their into the pool. - while(this.children.length > lenChars) { - var child = this.getChildAt(this.children.length - 1); - this._pool.push(child); - this.removeChild(child); - } - - this.textWidth = maxLineWidth * scale; - this.textHeight = (pos.y + data.lineHeight) * scale; -}; - -/** - * Updates the transform of this object - * - * @private - */ -BitmapText.prototype.updateTransform = function () { - if (this.dirty) { - this.updateText(); - this.dirty = false; - } - - this.displayObjectContainerUpdateTransform(); -}; - -BitmapText.fonts = {}; - -},{"../core":9}],97:[function(require,module,exports){ -var core = require('../core'); - -/** - * A Text Object will create a line or multiple lines of text. To split a line you can use '\n' in your text string, - * or add a wordWrap property set to true and and wordWrapWidth property with a value in the style object. - * - * @class - * @extends Sprite - * @namespace PIXI - * @param text {string} The copy that you would like the text to display - * @param [style] {object} The style parameters - * @param [style.font] {string} default 'bold 20px Arial' The style and size of the font - * @param [style.fill='black'] {String|Number} A canvas fillstyle that will be used on the text e.g 'red', '#00FF00' - * @param [style.align='left'] {string} Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text - * @param [style.stroke] {String|Number} A canvas fillstyle that will be used on the text stroke e.g 'blue', '#FCFF00' - * @param [style.strokeThickness=0] {number} A number that represents the thickness of the stroke. Default is 0 (no stroke) - * @param [style.wordWrap=false] {boolean} Indicates if word wrap should be used - * @param [style.wordWrapWidth=100] {number} The width at which text will wrap, it needs wordWrap to be set to true - * @param [style.dropShadow=false] {boolean} Set a drop shadow for the text - * @param [style.dropShadowColor='#000000'] {string} A fill style to be used on the dropshadow e.g 'red', '#00FF00' - * @param [style.dropShadowAngle=Math.PI/4] {number} Set a angle of the drop shadow - * @param [style.dropShadowDistance=5] {number} Set a distance of the drop shadow - */ -function Text(text, style) { - /** - * The canvas element that everything is drawn to - * - * @member {HTMLCanvasElement} - */ - this.canvas = document.createElement('canvas'); - - /** - * The canvas 2d context that everything is drawn with - * @member {HTMLCanvasElement} - */ - this.context = this.canvas.getContext('2d'); - - /** - * The resolution of the canvas. - * @member {number} - */ - this.resolution = 1; - - core.Sprite.call(this, core.Texture.fromCanvas(this.canvas)); - - this.setText(text); - this.setStyle(style); -} - -// constructor -Text.prototype = Object.create(core.Sprite.prototype); -Text.prototype.constructor = Text; -module.exports = Text; - -Object.defineProperties(Text.prototype, { - /** - * The width of the Text, setting this will actually modify the scale to achieve the value set - * - * @member {number} - * @memberof Text# - */ - width: { - get: function () { - if (this.dirty) { - this.updateText(); - this.dirty = false; - } - - return this.scale.x * this.texture.frame.width; - }, - set: function (value) { - this.scale.x = value / this.texture.frame.width; - this._width = value; - } - }, - - /** - * The height of the Text, setting this will actually modify the scale to achieve the value set - * - * @member {number} - * @memberof Text# - */ - height: { - get: function () { - if (this.dirty) { - this.updateText(); - this.dirty = false; - } - - return this.scale.y * this.texture.frame.height; - }, - set: function (value) { - this.scale.y = value / this.texture.frame.height; - this._height = value; - } - } -}); - -/** - * Set the style of the text - * - * @param [style] {object} The style parameters - * @param [style.font='bold 20pt Arial'] {string} The style and size of the font - * @param [style.fill='black'] {object} A canvas fillstyle that will be used on the text eg 'red', '#00FF00' - * @param [style.align='left'] {string} Alignment for multiline text ('left', 'center' or 'right'), does not affect single line text - * @param [style.stroke='black'] {string} A canvas fillstyle that will be used on the text stroke eg 'blue', '#FCFF00' - * @param [style.strokeThickness=0] {number} A number that represents the thickness of the stroke. Default is 0 (no stroke) - * @param [style.wordWrap=false] {boolean} Indicates if word wrap should be used - * @param [style.wordWrapWidth=100] {number} The width at which text will wrap - * @param [style.dropShadow=false] {boolean} Set a drop shadow for the text - * @param [style.dropShadowColor='#000000'] {string} A fill style to be used on the dropshadow e.g 'red', '#00FF00' - * @param [style.dropShadowAngle=Math.PI/4] {number} Set a angle of the drop shadow - * @param [style.dropShadowDistance=5] {number} Set a distance of the drop shadow - */ -Text.prototype.setStyle = function (style) { - style = style || {}; - style.font = style.font || 'bold 20pt Arial'; - style.fill = style.fill || 'black'; - style.align = style.align || 'left'; - style.stroke = style.stroke || 'black'; //provide a default, see: https://github.com/GoodBoyDigital/pixi.js/issues/136 - style.strokeThickness = style.strokeThickness || 0; - style.wordWrap = style.wordWrap || false; - style.wordWrapWidth = style.wordWrapWidth || 100; - - style.dropShadow = style.dropShadow || false; - style.dropShadowAngle = style.dropShadowAngle || Math.PI / 6; - style.dropShadowDistance = style.dropShadowDistance || 4; - style.dropShadowColor = style.dropShadowColor || 'black'; - - this.style = style; - this.dirty = true; -}; - -/** - * Set the copy for the text object. To split a line you can use '\n'. - * - * @param text {string} The copy that you would like the text to display - */ -Text.prototype.setText = function (text) { - this.text = text.toString() || ' '; - this.dirty = true; -}; - -/** - * Renders text and updates it when needed - * - * @private - */ -Text.prototype.updateText = function () { - this.texture.baseTexture.resolution = this.resolution; - - this.context.font = this.style.font; - - var outputText = this.text; - - // word wrap - // preserve original text - if (this.style.wordWrap) { - outputText = this.wordWrap(this.text); - } - - //split text into lines - var lines = outputText.split(/(?:\r\n|\r|\n)/); - - //calculate text width - var lineWidths = []; - var maxLineWidth = 0; - var fontProperties = this.determineFontProperties(this.style.font); - for (var i = 0; i < lines.length; i++) { - var lineWidth = this.context.measureText(lines[i]).width; - lineWidths[i] = lineWidth; - maxLineWidth = Math.max(maxLineWidth, lineWidth); - } - - var width = maxLineWidth + this.style.strokeThickness; - if (this.style.dropShadow) { - width += this.style.dropShadowDistance; - } - - this.canvas.width = ( width + this.context.lineWidth ) * this.resolution; - - //calculate text height - var lineHeight = fontProperties.fontSize + this.style.strokeThickness; - - var height = lineHeight * lines.length; - if (this.style.dropShadow) { - height += this.style.dropShadowDistance; - } - - this.canvas.height = height * this.resolution; - - this.context.scale( this.resolution, this.resolution); - - if (navigator.isCocoonJS) { - this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); - } - - // used for debugging.. - //this.context.fillStyle ="#FF0000" - //this.context.fillRect(0, 0, this.canvas.width,this.canvas.height); - - this.context.font = this.style.font; - this.context.strokeStyle = this.style.stroke; - this.context.lineWidth = this.style.strokeThickness; - this.context.textBaseline = 'alphabetic'; - //this.context.lineJoin = 'round'; - - var linePositionX; - var linePositionY; - - if (this.style.dropShadow) { - this.context.fillStyle = this.style.dropShadowColor; - - var xShadowOffset = Math.cos(this.style.dropShadowAngle) * this.style.dropShadowDistance; - var yShadowOffset = Math.sin(this.style.dropShadowAngle) * this.style.dropShadowDistance; - - for (i = 0; i < lines.length; i++) { - linePositionX = this.style.strokeThickness / 2; - linePositionY = (this.style.strokeThickness / 2 + i * lineHeight) + fontProperties.ascent; - - if (this.style.align === 'right') { - linePositionX += maxLineWidth - lineWidths[i]; - } - else if (this.style.align === 'center') { - linePositionX += (maxLineWidth - lineWidths[i]) / 2; - } - - if (this.style.fill) { - this.context.fillText(lines[i], linePositionX + xShadowOffset, linePositionY + yShadowOffset); - } - - // if (dropShadow) - } - } - - //set canvas text styles - this.context.fillStyle = this.style.fill; - - //draw lines line by line - for (i = 0; i < lines.length; i++) { - linePositionX = this.style.strokeThickness / 2; - linePositionY = (this.style.strokeThickness / 2 + i * lineHeight) + fontProperties.ascent; - - if (this.style.align === 'right') { - linePositionX += maxLineWidth - lineWidths[i]; - } - else if (this.style.align === 'center') { - linePositionX += (maxLineWidth - lineWidths[i]) / 2; - } - - if (this.style.stroke && this.style.strokeThickness) { - this.context.strokeText(lines[i], linePositionX, linePositionY); - } - - if (this.style.fill) { - this.context.fillText(lines[i], linePositionX, linePositionY); - } - - // if (dropShadow) - } - - this.updateTexture(); -}; - -/** - * Updates texture size based on canvas size - * - * @private - */ -Text.prototype.updateTexture = function () { - this.texture.baseTexture.width = this.canvas.width; - this.texture.baseTexture.height = this.canvas.height; - this.texture.crop.width = this.texture.frame.width = this.canvas.width; - this.texture.crop.height = this.texture.frame.height = this.canvas.height; - - this._width = this.canvas.width; - this._height = this.canvas.height; - - // update the dirty base textures - this.texture.baseTexture.dirty(); -}; - -/** - * Renders the object using the WebGL renderer -* - * @param renderer {WebGLRenderer} - */ -Text.prototype.renderWebGL = function (renderer) { - if (this.dirty) { - this.resolution = renderer.resolution; - - this.updateText(); - this.dirty = false; - } - - core.Sprite.prototype.renderWebGL.call(this, renderer); -}; - -/** - * Renders the object using the Canvas renderer -* - * @param renderer {CanvasRenderer} - */ -Text.prototype.renderCanvas = function (renderer) { - if (this.dirty) { - this.resolution = renderer.resolution; - - this.updateText(); - this.dirty = false; - } - - core.Sprite.prototype.renderCanvas.call(this, renderer); -}; - -/** - * Calculates the ascent, descent and fontSize of a given fontStyle -* - * @param fontStyle {object} - * @private - */ -Text.prototype.determineFontProperties = function (fontStyle) { - var properties = Text.fontPropertiesCache[fontStyle]; - - if (!properties) { - properties = {}; - - var canvas = Text.fontPropertiesCanvas; - var context = Text.fontPropertiesContext; - - context.font = fontStyle; - - var width = Math.ceil(context.measureText('|Mq').width); - var baseline = Math.ceil(context.measureText('M').width); - var height = 2 * baseline; - - baseline = baseline * 1.4 | 0; - - canvas.width = width; - canvas.height = height; - - context.fillStyle = '#f00'; - context.fillRect(0, 0, width, height); - - context.font = fontStyle; - - context.textBaseline = 'alphabetic'; - context.fillStyle = '#000'; - context.fillText('|MÉq', 0, baseline); - - var imagedata = context.getImageData(0, 0, width, height).data; - var pixels = imagedata.length; - var line = width * 4; - - var i, j; - - var idx = 0; - var stop = false; - - // ascent. scan from top to bottom until we find a non red pixel - for (i = 0; i < baseline; i++) { - for (j = 0; j < line; j += 4) { - if (imagedata[idx + j] !== 255) { - stop = true; - break; - } - } - if (!stop) { - idx += line; - } - else { - break; - } - } - - properties.ascent = baseline - i; - - idx = pixels - line; - stop = false; - - // descent. scan from bottom to top until we find a non red pixel - for (i = height; i > baseline; i--) { - for (j = 0; j < line; j += 4) { - if (imagedata[idx + j] !== 255) { - stop = true; - break; - } - } - if (!stop) { - idx -= line; - } - else { - break; - } - } - - properties.descent = i - baseline; - //TODO might need a tweak. kind of a temp fix! - properties.descent += 6; - properties.fontSize = properties.ascent + properties.descent; - - Text.fontPropertiesCache[fontStyle] = properties; - } - - return properties; -}; - -/** - * Applies newlines to a string to have it optimally fit into the horizontal - * bounds set by the Text object's wordWrapWidth property. - * - * @param text {string} - * @private - */ -Text.prototype.wordWrap = function (text) { - // Greedy wrapping algorithm that will wrap words as the line grows longer - // than its horizontal bounds. - var result = ''; - var lines = text.split('\n'); - for (var i = 0; i < lines.length; i++) { - var spaceLeft = this.style.wordWrapWidth; - var words = lines[i].split(' '); - for (var j = 0; j < words.length; j++) { - var wordWidth = this.context.measureText(words[j]).width; - var wordWidthWithSpace = wordWidth + this.context.measureText(' ').width; - if (j === 0 || wordWidthWithSpace > spaceLeft) { - // Skip printing the newline if it's the first word of the line that is - // greater than the word wrap width. - if (j > 0) { - result += '\n'; - } - result += words[j]; - spaceLeft = this.style.wordWrapWidth - wordWidth; - } - else { - spaceLeft -= wordWidthWithSpace; - result += ' ' + words[j]; - } - } - - if (i < lines.length-1) { - result += '\n'; - } - } - return result; -}; - -/** - * Returns the bounds of the Text as a rectangle. The bounds calculation takes the worldTransform into account. - * - * @param matrix {Matrix} the transformation matrix of the Text - * @return {Rectangle} the framing rectangle - */ -Text.prototype.getBounds = function (matrix) { - if (this.dirty) { - this.updateText(); - this.dirty = false; - } - - return core.Sprite.prototype.getBounds.call(this, matrix); -}; - -/** - * Destroys this text object. - * - * @param destroyBaseTexture {boolean} whether to destroy the base texture as well - */ -Text.prototype.destroy = function (destroyBaseTexture) { - // make sure to reset the the context and canvas.. dont want this hanging around in memory! - this.context = null; - this.canvas = null; - - this.texture.destroy(destroyBaseTexture === undefined ? true : destroyBaseTexture); -}; - -Text.fontPropertiesCache = {}; -Text.fontPropertiesCanvas = document.createElement('canvas'); -Text.fontPropertiesContext = Text.fontPropertiesCanvas.getContext('2d'); - -},{"../core":9}],98:[function(require,module,exports){ -/** - * @file Main export of the PIXI text library - * @author Mat Groves - * @copyright 2013-2015 GoodBoyDigital - * @license {@link https://github.com/GoodBoyDigital/pixi.js/blob/master/LICENSE|MIT License} - */ - -/** - * @namespace PIXI - */ -module.exports = { - Text: require('./Text'), - BitmapText: require('./BitmapText') -}; - -},{"./BitmapText":96,"./Text":97}]},{},[1])(1) -}); -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvaW5kZXgiLCJub2RlX21vZHVsZXMvd2ViZ2wtZW5hYmxlZC9pbmRleC5qcyIsInBhY2thZ2UuanNvbiIsInNyYy9jb3JlL2NvbnN0LmpzIiwic3JjL2NvcmUvZGlzcGxheS9EaXNwbGF5T2JqZWN0LmpzIiwic3JjL2NvcmUvZGlzcGxheS9EaXNwbGF5T2JqZWN0Q29udGFpbmVyLmpzIiwic3JjL2NvcmUvZGlzcGxheS9TcHJpdGUuanMiLCJzcmMvY29yZS9kaXNwbGF5L1Nwcml0ZUJhdGNoLmpzIiwic3JjL2NvcmUvaW5kZXguanMiLCJzcmMvY29yZS9tYXRoL01hdHJpeC5qcyIsInNyYy9jb3JlL21hdGgvUG9pbnQuanMiLCJzcmMvY29yZS9tYXRoL2luZGV4LmpzIiwic3JjL2NvcmUvbWF0aC9zaGFwZXMvQ2lyY2xlLmpzIiwic3JjL2NvcmUvbWF0aC9zaGFwZXMvRWxsaXBzZS5qcyIsInNyYy9jb3JlL21hdGgvc2hhcGVzL1BvbHlnb24uanMiLCJzcmMvY29yZS9tYXRoL3NoYXBlcy9SZWN0YW5nbGUuanMiLCJzcmMvY29yZS9tYXRoL3NoYXBlcy9Sb3VuZGVkUmVjdGFuZ2xlLmpzIiwic3JjL2NvcmUvcHJpbWl0aXZlcy9HcmFwaGljcy5qcyIsInNyYy9jb3JlL3ByaW1pdGl2ZXMvR3JhcGhpY3NEYXRhLmpzIiwic3JjL2NvcmUvcmVuZGVyZXJzL2NhbnZhcy9DYW52YXNSZW5kZXJlci5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy9jYW52YXMvdXRpbHMvQ2FudmFzQnVmZmVyLmpzIiwic3JjL2NvcmUvcmVuZGVyZXJzL2NhbnZhcy91dGlscy9DYW52YXNHcmFwaGljcy5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy9jYW52YXMvdXRpbHMvQ2FudmFzTWFza01hbmFnZXIuanMiLCJzcmMvY29yZS9yZW5kZXJlcnMvY2FudmFzL3V0aWxzL0NhbnZhc1RpbnRlci5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy93ZWJnbC9XZWJHTFJlbmRlcmVyLmpzIiwic3JjL2NvcmUvcmVuZGVyZXJzL3dlYmdsL21hbmFnZXJzL1dlYkdMQmxlbmRNb2RlTWFuYWdlci5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy93ZWJnbC9tYW5hZ2Vycy9XZWJHTEZpbHRlck1hbmFnZXIuanMiLCJzcmMvY29yZS9yZW5kZXJlcnMvd2ViZ2wvbWFuYWdlcnMvV2ViR0xNYW5hZ2VyLmpzIiwic3JjL2NvcmUvcmVuZGVyZXJzL3dlYmdsL21hbmFnZXJzL1dlYkdMTWFza01hbmFnZXIuanMiLCJzcmMvY29yZS9yZW5kZXJlcnMvd2ViZ2wvbWFuYWdlcnMvV2ViR0xTaGFkZXJNYW5hZ2VyLmpzIiwic3JjL2NvcmUvcmVuZGVyZXJzL3dlYmdsL21hbmFnZXJzL1dlYkdMU3RlbmNpbE1hbmFnZXIuanMiLCJzcmMvY29yZS9yZW5kZXJlcnMvd2ViZ2wvc2hhZGVycy9Db21wbGV4UHJpbWl0aXZlU2hhZGVyLmpzIiwic3JjL2NvcmUvcmVuZGVyZXJzL3dlYmdsL3NoYWRlcnMvRmFzdFNoYWRlci5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy93ZWJnbC9zaGFkZXJzL1ByaW1pdGl2ZVNoYWRlci5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy93ZWJnbC9zaGFkZXJzL1NoYWRlci5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy93ZWJnbC9zaGFkZXJzL1N0cmlwU2hhZGVyLmpzIiwic3JjL2NvcmUvcmVuZGVyZXJzL3dlYmdsL3V0aWxzL0ZpbHRlclRleHR1cmUuanMiLCJzcmMvY29yZS9yZW5kZXJlcnMvd2ViZ2wvdXRpbHMvV2ViR0xGYXN0U3ByaXRlQmF0Y2guanMiLCJzcmMvY29yZS9yZW5kZXJlcnMvd2ViZ2wvdXRpbHMvV2ViR0xHcmFwaGljcy5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy93ZWJnbC91dGlscy9XZWJHTEdyYXBoaWNzRGF0YS5qcyIsInNyYy9jb3JlL3JlbmRlcmVycy93ZWJnbC91dGlscy9XZWJHTFNwcml0ZUJhdGNoLmpzIiwic3JjL2NvcmUvdGV4dHVyZXMvQmFzZVRleHR1cmUuanMiLCJzcmMvY29yZS90ZXh0dXJlcy9SZW5kZXJUZXh0dXJlLmpzIiwic3JjL2NvcmUvdGV4dHVyZXMvVGV4dHVyZS5qcyIsInNyYy9jb3JlL3RleHR1cmVzL1RleHR1cmVVdnMuanMiLCJzcmMvY29yZS90ZXh0dXJlcy9WaWRlb0Jhc2VUZXh0dXJlLmpzIiwic3JjL2NvcmUvdXRpbHMvRXZlbnREYXRhLmpzIiwic3JjL2NvcmUvdXRpbHMvUG9seUsuanMiLCJzcmMvY29yZS91dGlscy9ldmVudFRhcmdldC5qcyIsInNyYy9jb3JlL3V0aWxzL2luZGV4LmpzIiwic3JjL2V4dHJhcy9Nb3ZpZUNsaXAuanMiLCJzcmMvZXh0cmFzL1JvcGUuanMiLCJzcmMvZXh0cmFzL1N0cmlwLmpzIiwic3JjL2V4dHJhcy9UaWxpbmdTcHJpdGUuanMiLCJzcmMvZXh0cmFzL2luZGV4LmpzIiwic3JjL2ZpbHRlcnMvQWJzdHJhY3RGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9BbHBoYU1hc2tGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9Bc2NpaUZpbHRlci5qcyIsInNyYy9maWx0ZXJzL0JsdXJGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9CbHVyWEZpbHRlci5qcyIsInNyYy9maWx0ZXJzL0JsdXJZRmlsdGVyLmpzIiwic3JjL2ZpbHRlcnMvQ29sb3JNYXRyaXhGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9Db2xvclN0ZXBGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9Db252b2x1dGlvbkZpbHRlci5qcyIsInNyYy9maWx0ZXJzL0Nyb3NzSGF0Y2hGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9EaXNwbGFjZW1lbnRGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9Eb3RTY3JlZW5GaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9GaWx0ZXJCbG9jay5qcyIsInNyYy9maWx0ZXJzL0dyYXlGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9JbnZlcnRGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9Ob2lzZUZpbHRlci5qcyIsInNyYy9maWx0ZXJzL05vcm1hbE1hcEZpbHRlci5qcyIsInNyYy9maWx0ZXJzL1BpeGVsYXRlRmlsdGVyLmpzIiwic3JjL2ZpbHRlcnMvUkdCU3BsaXRGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9TZXBpYUZpbHRlci5qcyIsInNyYy9maWx0ZXJzL1NtYXJ0Qmx1ckZpbHRlci5qcyIsInNyYy9maWx0ZXJzL1RpbHRTaGlmdEZpbHRlci5qcyIsInNyYy9maWx0ZXJzL1RpbHRTaGlmdFhGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9UaWx0U2hpZnRZRmlsdGVyLmpzIiwic3JjL2ZpbHRlcnMvVHdpc3RGaWx0ZXIuanMiLCJzcmMvZmlsdGVycy9pbmRleC5qcyIsInNyYy9pbnRlcmFjdGlvbi9JbnRlcmFjdGlvbkRhdGEuanMiLCJzcmMvaW50ZXJhY3Rpb24vSW50ZXJhY3Rpb25NYW5hZ2VyLmpzIiwic3JjL2ludGVyYWN0aW9uL2luZGV4LmpzIiwic3JjL2xvYWRlcnMvQXRsYXNMb2FkZXIuanMiLCJzcmMvbG9hZGVycy9CaXRtYXBGb250TG9hZGVyLmpzIiwic3JjL2xvYWRlcnMvSW1hZ2VMb2FkZXIuanMiLCJzcmMvbG9hZGVycy9Kc29uTG9hZGVyLmpzIiwic3JjL2xvYWRlcnMvU3BpbmVMb2FkZXIuanMiLCJzcmMvbG9hZGVycy9TcGluZVRleHR1cmVMb2FkZXIuanMiLCJzcmMvbG9hZGVycy9TcHJpdGVTaGVldExvYWRlci5qcyIsInNyYy9sb2FkZXJzL2luZGV4LmpzIiwic3JjL3NwaW5lL1NwaW5lLmpzIiwic3JjL3NwaW5lL1NwaW5lUnVudGltZS5qcyIsInNyYy9zcGluZS9pbmRleC5qcyIsInNyYy90ZXh0L0JpdG1hcFRleHQuanMiLCJzcmMvdGV4dC9UZXh0LmpzIiwic3JjL3RleHQvaW5kZXguanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNUQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL1lBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVrQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDamFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25GQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM2lDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNVVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcFRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdOQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9pQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6Y0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hRQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyY0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbGJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxeEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNtQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6WkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0VEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqY0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqYkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25FQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5R0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2h4QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUxBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbE9BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25QQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xrRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNiQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaFJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwibW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgY29yZTogICAgICAgICAgIHJlcXVpcmUoJy4vY29yZScpLFxuICAgIGV4dHJhczogICAgICAgICByZXF1aXJlKCcuL2V4dHJhcycpLFxuICAgIGZpbHRlcnM6ICAgICAgICByZXF1aXJlKCcuL2ZpbHRlcnMnKSxcbiAgICBpbnRlcmFjdGlvbjogICAgcmVxdWlyZSgnLi9pbnRlcmFjdGlvbicpLFxuICAgIGxvYWRlcnM6ICAgICAgICByZXF1aXJlKCcuL2xvYWRlcnMnKSxcbiAgICBzcGluZTogICAgICAgICAgcmVxdWlyZSgnLi9zcGluZScpLFxuICAgIHRleHQ6ICAgICAgICAgICByZXF1aXJlKCcuL3RleHQnKVxufTtcbiIsIm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gd2ViZ2xFbmFibGVkKCkge1xuICB0cnkge1xuICAgIHZhciBjYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcbiAgICByZXR1cm4gISEod2luZG93LldlYkdMUmVuZGVyaW5nQ29udGV4dCAmJiAoY2FudmFzLmdldENvbnRleHQoJ3dlYmdsJykgfHwgY2FudmFzLmdldENvbnRleHQoJ2V4cGVyaW1lbnRhbC13ZWJnbCcpKSk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn07XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gIFwibmFtZVwiOiBcInBpeGkuanNcIixcbiAgXCJ2ZXJzaW9uXCI6IFwiMy4wLjBcIixcbiAgXCJkZXNjcmlwdGlvblwiOiBcIlBpeGkuanMgaXMgYSBmYXN0IGxpZ2h0d2VpZ2h0IDJEIGxpYnJhcnkgdGhhdCB3b3JrcyBhY3Jvc3MgYWxsIGRldmljZXMuXCIsXG4gIFwiYXV0aG9yXCI6IFwiTWF0IEdyb3Zlc1wiLFxuICBcImNvbnRyaWJ1dG9yc1wiOiBbXG4gICAgXCJDaGFkIEVuZ2xlciA8Y2hhZEBwYW50aGVyZGV2LmNvbT5cIixcbiAgICBcIlJpY2hhcmQgRGF2ZXkgPHJkYXZleUBnbWFpbC5jb20+XCJcbiAgXSxcbiAgXCJtYWluXCI6IFwiLi9zcmMvaW5kZXguanNcIixcbiAgXCJob21lcGFnZVwiOiBcImh0dHA6Ly9nb29kYm95ZGlnaXRhbC5jb20vXCIsXG4gIFwiYnVnc1wiOiBcImh0dHBzOi8vZ2l0aHViLmNvbS9Hb29kQm95RGlnaXRhbC9waXhpLmpzL2lzc3Vlc1wiLFxuICBcImxpY2Vuc2VcIjogXCJNSVRcIixcbiAgXCJyZXBvc2l0b3J5XCI6IHtcbiAgICBcInR5cGVcIjogXCJnaXRcIixcbiAgICBcInVybFwiOiBcImh0dHBzOi8vZ2l0aHViLmNvbS9Hb29kQm95RGlnaXRhbC9waXhpLmpzLmdpdFwiXG4gIH0sXG4gIFwic2NyaXB0c1wiOiB7XG4gICAgXCJ0ZXN0XCI6IFwiZ3VscCB0ZXN0XCIsXG4gICAgXCJkb2NzXCI6IFwiLi9ub2RlX21vZHVsZXMvLmJpbi9qc2RvYyAtYyAuL2d1bHAvdXRpbC9qc2RvYy5jb25mLmpzb25cIlxuICB9LFxuICBcImRldkRlcGVuZGVuY2llc1wiOiB7XG4gICAgXCJicm93c2VyaWZ5XCI6IFwiXjguMC4yXCIsXG4gICAgXCJjaGFpXCI6IFwiXjEuMTAuMFwiLFxuICAgIFwiZGVsXCI6IFwiXjEuMS4wXCIsXG4gICAgXCJndWxwXCI6IFwiXjMuOC4xMFwiLFxuICAgIFwiZ3VscC1qc2hpbnRcIjogXCJeMS45LjBcIixcbiAgICBcImd1bHAtcGx1bWJlclwiOiBcIl4wLjYuNlwiLFxuICAgIFwiZ3VscC1yZW5hbWVcIjogXCJeMS4yLjBcIixcbiAgICBcImd1bHAtdWdsaWZ5XCI6IFwiXjEuMC4yXCIsXG4gICAgXCJndWxwLXV0aWxcIjogXCJeMy4wLjFcIixcbiAgICBcImluay1kb2NzdHJhcFwiOiBcIl4wLjQuMTJcIixcbiAgICBcImpzZG9jXCI6IFwiXjMuMy4wLWFscGhhMTNcIixcbiAgICBcImpzaGludC1zdW1tYXJ5XCI6IFwiXjAuNC4wXCIsXG4gICAgXCJrYXJtYVwiOiBcIl4wLjEyLjI4XCIsXG4gICAgXCJrYXJtYS1maXJlZm94LWxhdW5jaGVyXCI6IFwiXjAuMS4wXCIsXG4gICAgXCJrYXJtYS1tb2NoYVwiOiBcIl4wLjEuMTBcIixcbiAgICBcImthcm1hLXNwZWMtcmVwb3J0ZXJcIjogXCJeMC4wLjE2XCIsXG4gICAgXCJtb2NoYVwiOiBcIl4yLjEuMFwiLFxuICAgIFwicmVxdWlyZS1kaXJcIjogXCJeMC4xLjBcIixcbiAgICBcInJ1bi1zZXF1ZW5jZVwiOiBcIl4xLjAuMlwiLFxuICAgIFwidmlueWwtYnVmZmVyXCI6IFwiXjEuMC4wXCIsXG4gICAgXCJ2aW55bC1zb3VyY2Utc3RyZWFtXCI6IFwiXjEuMC4wXCIsXG4gICAgXCJ3YXRjaGlmeVwiOiBcIl4yLjIuMVwiXG4gIH0sXG4gIFwiZGVwZW5kZW5jaWVzXCI6IHtcbiAgICBcIndlYmdsLWVuYWJsZWRcIjogXCJeMS4wLjJcIlxuICB9XG59XG4iLCIvKipcbiAqIENvbnN0YW50IHZhbHVlcyB1c2VkIGluIHBpeGlcbiAqXG4gKiBAbWl4aW4gY29uc3RcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgLyoqXG4gICAgICogQ29uc3RhbnQgdG8gaWRlbnRpZnkgdGhlIFdFQkdMIFJlbmRlcmVyIFR5cGVcbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAY29uc3RhbnRcbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gV0VCR0xfUkVOREVSRVJcbiAgICAgKi9cbiAgICBXRUJHTF9SRU5ERVJFUjogMSxcblxuICAgIC8qKlxuICAgICAqIENvbnN0YW50IHRvIGlkZW50aWZ5IHRoZSBDQU5WQVMgUmVuZGVyZXIgVHlwZVxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBjb25zdGFudFxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBDQU5WQVNfUkVOREVSRVJcbiAgICAgKi9cbiAgICBDQU5WQVNfUkVOREVSRVI6IDIsXG5cbiAgICAvKipcbiAgICAgKiBTdHJpbmcgb2YgdGhlIGN1cnJlbnQgUElYSSB2ZXJzaW9uXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQGNvbnN0YW50XG4gICAgICogQHByb3BlcnR5IHtzdHJpbmd9IFZFUlNJT05cbiAgICAgKi9cbiAgICBWRVJTSU9OOiByZXF1aXJlKCcuLi8uLi9wYWNrYWdlLmpzb24nKS52ZXJzaW9uLFxuXG4gICAgLyoqXG4gICAgICogVmFyaW91cyBibGVuZCBtb2RlcyBzdXBwb3J0ZWQgYnkgUElYSS4gSU1QT1JUQU5UIC0gVGhlIFdlYkdMIHJlbmRlcmVyIG9ubHkgc3VwcG9ydHNcbiAgICAgKiB0aGUgTk9STUFMLCBBREQsIE1VTFRJUExZIGFuZCBTQ1JFRU4gYmxlbmQgbW9kZXMuIEFueXRoaW5nIGVsc2Ugd2lsbCBzaWxlbnRseSBhY3QgbGlrZVxuICAgICAqIE5PUk1BTC5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAY29uc3RhbnRcbiAgICAgKiBAcHJvcGVydHkge29iamVjdH0gYmxlbmRNb2Rlc1xuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibGVuZE1vZGVzLk5PUk1BTFxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibGVuZE1vZGVzLkFERFxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibGVuZE1vZGVzLk1VTFRJUExZXG4gICAgICogQHByb3BlcnR5IHtudW1iZXJ9IGJsZW5kTW9kZXMuU0NSRUVOXG4gICAgICogQHByb3BlcnR5IHtudW1iZXJ9IGJsZW5kTW9kZXMuT1ZFUkxBWVxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibGVuZE1vZGVzLkRBUktFTlxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibGVuZE1vZGVzLkxJR0hURU5cbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gYmxlbmRNb2Rlcy5DT0xPUl9ET0RHRVxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibGVuZE1vZGVzLkNPTE9SX0JVUk5cbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gYmxlbmRNb2Rlcy5IQVJEX0xJR0hUXG4gICAgICogQHByb3BlcnR5IHtudW1iZXJ9IGJsZW5kTW9kZXMuU09GVF9MSUdIVFxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBibGVuZE1vZGVzLkRJRkZFUkVOQ0VcbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gYmxlbmRNb2Rlcy5FWENMVVNJT05cbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gYmxlbmRNb2Rlcy5IVUVcbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gYmxlbmRNb2Rlcy5TQVRVUkFUSU9OXG4gICAgICogQHByb3BlcnR5IHtudW1iZXJ9IGJsZW5kTW9kZXMuQ09MT1JcbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gYmxlbmRNb2Rlcy5MVU1JTk9TSVRZXG4gICAgICovXG4gICAgYmxlbmRNb2Rlczoge1xuICAgICAgICBOT1JNQUw6ICAgICAgICAgMCxcbiAgICAgICAgQUREOiAgICAgICAgICAgIDEsXG4gICAgICAgIE1VTFRJUExZOiAgICAgICAyLFxuICAgICAgICBTQ1JFRU46ICAgICAgICAgMyxcbiAgICAgICAgT1ZFUkxBWTogICAgICAgIDQsXG4gICAgICAgIERBUktFTjogICAgICAgICA1LFxuICAgICAgICBMSUdIVEVOOiAgICAgICAgNixcbiAgICAgICAgQ09MT1JfRE9ER0U6ICAgIDcsXG4gICAgICAgIENPTE9SX0JVUk46ICAgICA4LFxuICAgICAgICBIQVJEX0xJR0hUOiAgICAgOSxcbiAgICAgICAgU09GVF9MSUdIVDogICAgIDEwLFxuICAgICAgICBESUZGRVJFTkNFOiAgICAgMTEsXG4gICAgICAgIEVYQ0xVU0lPTjogICAgICAxMixcbiAgICAgICAgSFVFOiAgICAgICAgICAgIDEzLFxuICAgICAgICBTQVRVUkFUSU9OOiAgICAgMTQsXG4gICAgICAgIENPTE9SOiAgICAgICAgICAxNSxcbiAgICAgICAgTFVNSU5PU0lUWTogICAgIDE2XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBzY2FsZSBtb2RlcyB0aGF0IGFyZSBzdXBwb3J0ZWQgYnkgcGl4aS5cbiAgICAgKlxuICAgICAqIFRoZSBERUZBVUxUIHNjYWxlIG1vZGUgYWZmZWN0cyB0aGUgZGVmYXVsdCBzY2FsaW5nIG1vZGUgb2YgZnV0dXJlIG9wZXJhdGlvbnMuXG4gICAgICogSXQgY2FuIGJlIHJlLWFzc2lnbmVkIHRvIGVpdGhlciBMSU5FQVIgb3IgTkVBUkVTVCwgZGVwZW5kaW5nIHVwb24gc3VpdGFiaWxpdHkuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQGNvbnN0YW50XG4gICAgICogQHByb3BlcnR5IHtvYmplY3R9IHNjYWxlTW9kZXNcbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gc2NhbGVNb2Rlcy5ERUZBVUxUPUxJTkVBUlxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBzY2FsZU1vZGVzLkxJTkVBUiBTbW9vdGggc2NhbGluZ1xuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBzY2FsZU1vZGVzLk5FQVJFU1QgUGl4ZWxhdGluZyBzY2FsaW5nXG4gICAgICovXG4gICAgc2NhbGVNb2Rlczoge1xuICAgICAgICBERUZBVUxUOiAgICAwLFxuICAgICAgICBMSU5FQVI6ICAgICAwLFxuICAgICAgICBORUFSRVNUOiAgICAxXG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBwcmVmaXggdGhhdCBkZW5vdGVzIGEgVVJMIGlzIGZvciBhIHJldGluYSBhc3NldFxuICAgICAqXG4gICAgICogQHN0YXRpY1xuICAgICAqIEBjb25zdGFudFxuICAgICAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBSRVRJTkFfUFJFRklYXG4gICAgICovXG4gICAgUkVUSU5BX1BSRUZJWDogJ0AyeCcsXG5cbiAgICAvKipcbiAgICAgKiBUaGUgZGVmYXVsdCByZW5kZXIgb3B0aW9ucyBpZiBub25lIGFyZSBzdXBwbGllZCB0byB7QGxpbmsgUElYSS5XZWJHTFJlbmRlcmVyfVxuICAgICAqIG9yIHtAbGluayBQSVhJLkNhbnZhc1JlbmRlcmVyfS5cbiAgICAgKlxuICAgICAqIEBzdGF0aWNcbiAgICAgKiBAY29uc3RhbnRcbiAgICAgKiBAcHJvcGVydHkge29iamVjdH0gZGVmYXVsdFJlbmRlck9wdGlvbnNcbiAgICAgKiBAcHJvcGVydHkge0hUTUxDYW52YXNFbGVtZW50fSBkZWZhdWx0UmVuZGVyT3B0aW9ucy52aWV3PW51bGxcbiAgICAgKiBAcHJvcGVydHkge2Jvb2xlYW59IGRlZmF1bHRSZW5kZXJPcHRpb25zLnRyYW5zcGFyZW50PWZhbHNlXG4gICAgICogQHByb3BlcnR5IHtib29sZWFufSBkZWZhdWx0UmVuZGVyT3B0aW9ucy5hbnRpYWxpYXM9ZmFsc2VcbiAgICAgKiBAcHJvcGVydHkge2Jvb2xlYW59IGRlZmF1bHRSZW5kZXJPcHRpb25zLnByZXNlcnZlRHJhd2luZ0J1ZmZlcj1mYWxzZVxuICAgICAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBkZWZhdWx0UmVuZGVyT3B0aW9ucy5yZXNvbHV0aW9uPTFcbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gZGVmYXVsdFJlbmRlck9wdGlvbnMuYmFja2dyb3VuZENvbG9yPTB4MDAwMDAwXG4gICAgICogQHByb3BlcnR5IHtib29sZWFufSBkZWZhdWx0UmVuZGVyT3B0aW9ucy5jbGVhckJlZm9yZVJlbmRlcj10cnVlXG4gICAgICogQHByb3BlcnR5IHtib29sZWFufSBkZWZhdWx0UmVuZGVyT3B0aW9ucy5hdXRvUmVzaXplPWZhbHNlXG4gICAgICovXG4gICAgZGVmYXVsdFJlbmRlck9wdGlvbnM6IHtcbiAgICAgICAgdmlldzogbnVsbCxcbiAgICAgICAgcmVzb2x1dGlvbjogMSxcbiAgICAgICAgYW50aWFsaWFzOiBmYWxzZSxcbiAgICAgICAgYXV0b1Jlc2l6ZTogZmFsc2UsXG4gICAgICAgIHRyYW5zcGFyZW50OiBmYWxzZSxcbiAgICAgICAgYmFja2dyb3VuZENvbG9yOiAweDAwMDAwMCxcbiAgICAgICAgY2xlYXJCZWZvcmVSZW5kZXI6IHRydWUsXG4gICAgICAgIHByZXNlcnZlRHJhd2luZ0J1ZmZlcjogZmFsc2VcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQ29uc3RhbnRzIHRoYXQgaWRlbnRpZnkgc2hhcGVzLCBtYWlubHkgdG8gcHJldmVudCBgaW5zdGFuY2VvZmAgY2FsbHMuXG4gICAgICpcbiAgICAgKiBAc3RhdGljXG4gICAgICogQGNvbnN0YW50XG4gICAgICogQHByb3BlcnR5IHtvYmplY3R9IFNIQVBFU1xuICAgICAqIEBwcm9wZXJ0eSB7b2JqZWN0fSBTSEFQRVMuUE9MWT0wXG4gICAgICogQHByb3BlcnR5IHtvYmplY3R9IFNIQVBFUy5SRUNUPTFcbiAgICAgKiBAcHJvcGVydHkge29iamVjdH0gU0hBUEVTLkNJUkM9MlxuICAgICAqIEBwcm9wZXJ0eSB7b2JqZWN0fSBTSEFQRVMuRUxJUD0zXG4gICAgICogQHByb3BlcnR5IHtvYmplY3R9IFNIQVBFUy5SUkVDPTRcbiAgICAgKi9cbiAgICBTSEFQRVM6IHtcbiAgICAgICAgUE9MWTogMCxcbiAgICAgICAgUkVDVDogMSxcbiAgICAgICAgQ0lSQzogMixcbiAgICAgICAgRUxJUDogMyxcbiAgICAgICAgUlJFQzogNFxuICAgIH1cbn07XG4iLCJ2YXIgbWF0aCA9IHJlcXVpcmUoJy4uL21hdGgnKTtcblxuLyoqXG4gKiBUaGUgYmFzZSBjbGFzcyBmb3IgYWxsIG9iamVjdHMgdGhhdCBhcmUgcmVuZGVyZWQgb24gdGhlIHNjcmVlbi5cbiAqIFRoaXMgaXMgYW4gYWJzdHJhY3QgY2xhc3MgYW5kIHNob3VsZCBub3QgYmUgdXNlZCBvbiBpdHMgb3duIHJhdGhlciBpdCBzaG91bGQgYmUgZXh0ZW5kZWQuXG4gKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gRGlzcGxheU9iamVjdCgpIHtcbiAgICAvKipcbiAgICAgKiBUaGUgY29vcmRpbmF0ZSBvZiB0aGUgb2JqZWN0IHJlbGF0aXZlIHRvIHRoZSBsb2NhbCBjb29yZGluYXRlcyBvZiB0aGUgcGFyZW50LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICovXG4gICAgdGhpcy5wb3NpdGlvbiA9IG5ldyBtYXRoLlBvaW50KCk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgc2NhbGUgZmFjdG9yIG9mIHRoZSBvYmplY3QuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKi9cbiAgICB0aGlzLnNjYWxlID0gbmV3IG1hdGguUG9pbnQoMSwgMSk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgcGl2b3QgcG9pbnQgb2YgdGhlIGRpc3BsYXlPYmplY3QgdGhhdCBpdCByb3RhdGVzIGFyb3VuZFxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICovXG4gICAgdGhpcy5waXZvdCA9IG5ldyBtYXRoLlBvaW50KDAsIDApO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHJvdGF0aW9uIG9mIHRoZSBvYmplY3QgaW4gcmFkaWFucy5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLnJvdGF0aW9uID0gMDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBvcGFjaXR5IG9mIHRoZSBvYmplY3QuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5hbHBoYSA9IDE7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdmlzaWJpbGl0eSBvZiB0aGUgb2JqZWN0LiBJZiBmYWxzZSB0aGUgb2JqZWN0IHdpbGwgbm90IGJlIGRyYXduLCBhbmRcbiAgICAgKiB0aGUgdXBkYXRlVHJhbnNmb3JtIGZ1bmN0aW9uIHdpbGwgbm90IGJlIGNhbGxlZC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy52aXNpYmxlID0gdHJ1ZTtcblxuICAgIC8qKlxuICAgICAqIENhbiB0aGlzIG9iamVjdCBiZSByZW5kZXJlZCwgaWYgZmFsc2UgdGhlIG9iamVjdCB3aWxsIG5vdCBiZSBkcmF3biBidXQgdGhlIHVwZGF0ZVRyYW5zZm9ybVxuICAgICAqIG1ldGhvZHMgd2lsbCBzdGlsbCBiZSBjYWxsZWQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMucmVuZGVyYWJsZSA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGRpc3BsYXkgb2JqZWN0IGNvbnRhaW5lciB0aGF0IGNvbnRhaW5zIHRoaXMgZGlzcGxheSBvYmplY3QuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtEaXNwbGF5T2JqZWN0Q29udGFpbmVyfVxuICAgICAqIEByZWFkT25seVxuICAgICAqL1xuICAgIHRoaXMucGFyZW50ID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBtdWx0aXBsaWVkIGFscGhhIG9mIHRoZSBkaXNwbGF5T2JqZWN0XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQHJlYWRPbmx5XG4gICAgICovXG4gICAgdGhpcy53b3JsZEFscGhhID0gMTtcblxuICAgIC8qKlxuICAgICAqIEN1cnJlbnQgdHJhbnNmb3JtIG9mIHRoZSBvYmplY3QgYmFzZWQgb24gd29ybGQgKHBhcmVudCkgZmFjdG9yc1xuICAgICAqXG4gICAgICogQG1lbWJlciB7TWF0cml4fVxuICAgICAqIEByZWFkT25seVxuICAgICAqL1xuICAgIHRoaXMud29ybGRUcmFuc2Zvcm0gPSBuZXcgbWF0aC5NYXRyaXgoKTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBhcmVhIHRoZSBmaWx0ZXIgaXMgYXBwbGllZCB0by4gVGhpcyBpcyB1c2VkIGFzIG1vcmUgb2YgYW4gb3B0aW1pc2F0aW9uXG4gICAgICogcmF0aGVyIHRoYW4gZmlndXJpbmcgb3V0IHRoZSBkaW1lbnNpb25zIG9mIHRoZSBkaXNwbGF5T2JqZWN0IGVhY2ggZnJhbWUgeW91IGNhbiBzZXQgdGhpcyByZWN0YW5nbGVcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1JlY3RhbmdsZX1cbiAgICAgKi9cbiAgICB0aGlzLmZpbHRlckFyZWEgPSBudWxsO1xuXG4gICAgLyoqXG4gICAgICogY2FjaGVkIHNpbiByb3RhdGlvblxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fc3IgPSAwO1xuXG4gICAgLyoqXG4gICAgICogY2FjaGVkIGNvcyByb3RhdGlvblxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fY3IgPSAxO1xuXG4gICAgLyoqXG4gICAgICogVGhlIG9yaWdpbmFsLCBjYWNoZWQgYm91bmRzIG9mIHRoZSBvYmplY3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1JlY3RhbmdsZX1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuX2JvdW5kcyA9IG5ldyBtYXRoLlJlY3RhbmdsZSgwLCAwLCAxLCAxKTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBtb3N0IHVwLXRvLWRhdGUgYm91bmRzIG9mIHRoZSBvYmplY3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1JlY3RhbmdsZX1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuX2N1cnJlbnRCb3VuZHMgPSBudWxsO1xuXG4gICAgLyoqXG4gICAgICogVGhlIG9yaWdpbmFsLCBjYWNoZWQgbWFzayBvZiB0aGUgb2JqZWN0XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtSZWN0YW5nbGV9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl9tYXNrID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqIENhY2hlZCBpbnRlcm5hbCBmbGFnLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuX2NhY2hlSXNEaXJ0eSA9IGZhbHNlO1xufVxuXG4vLyBjb25zdHJ1Y3RvclxuRGlzcGxheU9iamVjdC5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBEaXNwbGF5T2JqZWN0O1xubW9kdWxlLmV4cG9ydHMgPSBEaXNwbGF5T2JqZWN0O1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhEaXNwbGF5T2JqZWN0LnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSBwb3NpdGlvbiBvZiB0aGUgZGlzcGxheU9iamVjdCBvbiB0aGUgeCBheGlzIHJlbGF0aXZlIHRvIHRoZSBsb2NhbCBjb29yZGluYXRlcyBvZiB0aGUgcGFyZW50LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBEaXNwbGF5T2JqZWN0I1xuICAgICAqL1xuICAgIHg6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5wb3NpdGlvbi54O1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy5wb3NpdGlvbi54ID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIHBvc2l0aW9uIG9mIHRoZSBkaXNwbGF5T2JqZWN0IG9uIHRoZSB5IGF4aXMgcmVsYXRpdmUgdG8gdGhlIGxvY2FsIGNvb3JkaW5hdGVzIG9mIHRoZSBwYXJlbnQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIERpc3BsYXlPYmplY3QjXG4gICAgICovXG4gICAgeToge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnBvc2l0aW9uLnk7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnBvc2l0aW9uLnkgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBJbmRpY2F0ZXMgaWYgdGhlIHNwcml0ZSBpcyBnbG9iYWxseSB2aXNpYmxlLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAbWVtYmVyb2YgRGlzcGxheU9iamVjdCNcbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKi9cbiAgICB3b3JsZFZpc2libGU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgaXRlbSA9IHRoaXM7XG5cbiAgICAgICAgICAgIGRvIHtcbiAgICAgICAgICAgICAgICBpZiAoIWl0ZW0udmlzaWJsZSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaXRlbSA9IGl0ZW0ucGFyZW50O1xuICAgICAgICAgICAgfSB3aGlsZShpdGVtKTtcblxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU2V0cyBhIG1hc2sgZm9yIHRoZSBkaXNwbGF5T2JqZWN0LiBBIG1hc2sgaXMgYW4gb2JqZWN0IHRoYXQgbGltaXRzIHRoZSB2aXNpYmlsaXR5IG9mIGFuIG9iamVjdCB0byB0aGUgc2hhcGUgb2YgdGhlIG1hc2sgYXBwbGllZCB0byBpdC5cbiAgICAgKiBJbiBQSVhJIGEgcmVndWxhciBtYXNrIG11c3QgYmUgYSBQSVhJLkdyYXBoaWNzIG9iamVjdC4gVGhpcyBhbGxvd3MgZm9yIG11Y2ggZmFzdGVyIG1hc2tpbmcgaW4gY2FudmFzIGFzIGl0IHV0aWxpc2VzIHNoYXBlIGNsaXBwaW5nLlxuICAgICAqIFRvIHJlbW92ZSBhIG1hc2ssIHNldCB0aGlzIHByb3BlcnR5IHRvIG51bGwuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtHcmFwaGljc31cbiAgICAgKiBAbWVtYmVyb2YgRGlzcGxheU9iamVjdCNcbiAgICAgKi9cbiAgICBtYXNrOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX21hc2s7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICAgICAgICAgIHRoaXMuX21hc2suaXNNYXNrID0gZmFsc2U7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuX21hc2sgPSB2YWx1ZTtcblxuICAgICAgICAgICAgaWYgKHRoaXMuX21hc2spIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9tYXNrLmlzTWFzayA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgZmlsdGVycyBmb3IgdGhlIGRpc3BsYXlPYmplY3QuXG4gICAgICogKiBJTVBPUlRBTlQ6IFRoaXMgaXMgYSB3ZWJHTCBvbmx5IGZlYXR1cmUgYW5kIHdpbGwgYmUgaWdub3JlZCBieSB0aGUgY2FudmFzIHJlbmRlcmVyLlxuICAgICAqIFRvIHJlbW92ZSBmaWx0ZXJzIHNpbXBseSBzZXQgdGhpcyBwcm9wZXJ0eSB0byAnbnVsbCdcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0ZpbHRlcltdfVxuICAgICAqIEBtZW1iZXJvZiBEaXNwbGF5T2JqZWN0I1xuICAgICAqL1xuICAgIGZpbHRlcnM6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fZmlsdGVycztcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIGlmICh2YWx1ZSkge1xuICAgICAgICAgICAgICAgIC8vIG5vdyBwdXQgYWxsIHRoZSBwYXNzZXMgaW4gb25lIHBsYWNlLi5cbiAgICAgICAgICAgICAgICB2YXIgcGFzc2VzID0gW107XG5cbiAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZhbHVlLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBmaWx0ZXJQYXNzZXMgPSB2YWx1ZVtpXS5wYXNzZXM7XG5cbiAgICAgICAgICAgICAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBmaWx0ZXJQYXNzZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhc3Nlcy5wdXNoKGZpbHRlclBhc3Nlc1tqXSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBUT0RPIGNoYW5nZSB0aGlzIGFzIGl0IGlzIGxlZ2FjeVxuICAgICAgICAgICAgICAgIHRoaXMuX2ZpbHRlckJsb2NrID0geyB0YXJnZXQ6IHRoaXMsIGZpbHRlclBhc3NlczogcGFzc2VzIH07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuX2ZpbHRlcnMgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG4vKlxuICogVXBkYXRlcyB0aGUgb2JqZWN0IHRyYW5zZm9ybSBmb3IgcmVuZGVyaW5nXG4gKlxuICogVE9ETyAtIE9wdGltaXphdGlvbiBwYXNzIVxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkRpc3BsYXlPYmplY3QucHJvdG90eXBlLnVwZGF0ZVRyYW5zZm9ybSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoIXRoaXMucGFyZW50KSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBjcmVhdGUgc29tZSBtYXRyaXggcmVmcyBmb3IgZWFzeSBhY2Nlc3NcbiAgICB2YXIgcHQgPSB0aGlzLnBhcmVudC53b3JsZFRyYW5zZm9ybTtcbiAgICB2YXIgd3QgPSB0aGlzLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgLy8gdGVtcG9yYXJ5IG1hdHJpeCB2YXJpYWJsZXNcbiAgICB2YXIgYSwgYiwgYywgZCwgdHgsIHR5O1xuXG4gICAgLy8gc28gaWYgcm90YXRpb24gaXMgYmV0d2VlbiAwIHRoZW4gd2UgY2FuIHNpbXBsaWZ5IHRoZSBtdWx0aXBsaWNhdGlvbiBwcm9jZXNzLi5cbiAgICBpZiAodGhpcy5yb3RhdGlvbiAlIG1hdGguUElfMikge1xuICAgICAgICAvLyBjaGVjayB0byBzZWUgaWYgdGhlIHJvdGF0aW9uIGlzIHRoZSBzYW1lIGFzIHRoZSBwcmV2aW91cyByZW5kZXIuIFRoaXMgbWVhbnMgd2Ugb25seSBuZWVkIHRvIHVzZSBzaW4gYW5kIGNvcyB3aGVuIHJvdGF0aW9uIGFjdHVhbGx5IGNoYW5nZXNcbiAgICAgICAgaWYgKHRoaXMucm90YXRpb24gIT09IHRoaXMucm90YXRpb25DYWNoZSkge1xuICAgICAgICAgICAgdGhpcy5yb3RhdGlvbkNhY2hlID0gdGhpcy5yb3RhdGlvbjtcbiAgICAgICAgICAgIHRoaXMuX3NyID0gTWF0aC5zaW4odGhpcy5yb3RhdGlvbik7XG4gICAgICAgICAgICB0aGlzLl9jciA9IE1hdGguY29zKHRoaXMucm90YXRpb24pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZ2V0IHRoZSBtYXRyaXggdmFsdWVzIG9mIHRoZSBkaXNwbGF5b2JqZWN0IGJhc2VkIG9uIGl0cyB0cmFuc2Zvcm0gcHJvcGVydGllcy4uXG4gICAgICAgIGEgID0gIHRoaXMuX2NyICogdGhpcy5zY2FsZS54O1xuICAgICAgICBiICA9ICB0aGlzLl9zciAqIHRoaXMuc2NhbGUueDtcbiAgICAgICAgYyAgPSAtdGhpcy5fc3IgKiB0aGlzLnNjYWxlLnk7XG4gICAgICAgIGQgID0gIHRoaXMuX2NyICogdGhpcy5zY2FsZS55O1xuICAgICAgICB0eCA9ICB0aGlzLnBvc2l0aW9uLng7XG4gICAgICAgIHR5ID0gIHRoaXMucG9zaXRpb24ueTtcblxuICAgICAgICAvLyBjaGVjayBmb3IgcGl2b3QuLiBub3Qgb2Z0ZW4gdXNlZCBzbyBnZWFyZWQgdG93YXJkcyB0aGF0IGZhY3QhXG4gICAgICAgIGlmICh0aGlzLnBpdm90LnggfHwgdGhpcy5waXZvdC55KSB7XG4gICAgICAgICAgICB0eCAtPSB0aGlzLnBpdm90LnggKiBhICsgdGhpcy5waXZvdC55ICogYztcbiAgICAgICAgICAgIHR5IC09IHRoaXMucGl2b3QueCAqIGIgKyB0aGlzLnBpdm90LnkgKiBkO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gY29uY2F0IHRoZSBwYXJlbnQgbWF0cml4IHdpdGggdGhlIG9iamVjdHMgdHJhbnNmb3JtLlxuICAgICAgICB3dC5hICA9IGEgICogcHQuYSArIGIgICogcHQuYztcbiAgICAgICAgd3QuYiAgPSBhICAqIHB0LmIgKyBiICAqIHB0LmQ7XG4gICAgICAgIHd0LmMgID0gYyAgKiBwdC5hICsgZCAgKiBwdC5jO1xuICAgICAgICB3dC5kICA9IGMgICogcHQuYiArIGQgICogcHQuZDtcbiAgICAgICAgd3QudHggPSB0eCAqIHB0LmEgKyB0eSAqIHB0LmMgKyBwdC50eDtcbiAgICAgICAgd3QudHkgPSB0eCAqIHB0LmIgKyB0eSAqIHB0LmQgKyBwdC50eTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIC8vIGxldHMgZG8gdGhlIGZhc3QgdmVyc2lvbiBhcyB3ZSBrbm93IHRoZXJlIGlzIG5vIHJvdGF0aW9uLi5cbiAgICAgICAgYSAgPSB0aGlzLnNjYWxlLng7XG4gICAgICAgIGQgID0gdGhpcy5zY2FsZS55O1xuXG4gICAgICAgIHR4ID0gdGhpcy5wb3NpdGlvbi54IC0gdGhpcy5waXZvdC54ICogYTtcbiAgICAgICAgdHkgPSB0aGlzLnBvc2l0aW9uLnkgLSB0aGlzLnBpdm90LnkgKiBkO1xuXG4gICAgICAgIHd0LmEgID0gYSAgKiBwdC5hO1xuICAgICAgICB3dC5iICA9IGEgICogcHQuYjtcbiAgICAgICAgd3QuYyAgPSBkICAqIHB0LmM7XG4gICAgICAgIHd0LmQgID0gZCAgKiBwdC5kO1xuICAgICAgICB3dC50eCA9IHR4ICogcHQuYSArIHR5ICogcHQuYyArIHB0LnR4O1xuICAgICAgICB3dC50eSA9IHR4ICogcHQuYiArIHR5ICogcHQuZCArIHB0LnR5O1xuICAgIH1cblxuICAgIC8vIG11bHRpcGx5IHRoZSBhbHBoYXMuLlxuICAgIHRoaXMud29ybGRBbHBoYSA9IHRoaXMuYWxwaGEgKiB0aGlzLnBhcmVudC53b3JsZEFscGhhO1xufTtcblxuLy8gcGVyZm9ybWFuY2UgaW5jcmVhc2UgdG8gYXZvaWQgdXNpbmcgY2FsbC4uICgxMHggZmFzdGVyKVxuRGlzcGxheU9iamVjdC5wcm90b3R5cGUuZGlzcGxheU9iamVjdFVwZGF0ZVRyYW5zZm9ybSA9IERpc3BsYXlPYmplY3QucHJvdG90eXBlLnVwZGF0ZVRyYW5zZm9ybTtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIGJvdW5kcyBvZiB0aGUgZGlzcGxheU9iamVjdCBhcyBhIHJlY3RhbmdsZSBvYmplY3RcbiAqXG4gKiBAcGFyYW0gbWF0cml4IHtNYXRyaXh9XG4gKiBAcmV0dXJuIHtSZWN0YW5nbGV9IHRoZSByZWN0YW5ndWxhciBib3VuZGluZyBhcmVhXG4gKi9cbkRpc3BsYXlPYmplY3QucHJvdG90eXBlLmdldEJvdW5kcyA9IGZ1bmN0aW9uICgvKiBtYXRyaXggKi8pIHtcbiAgICByZXR1cm4gbWF0aC5SZWN0YW5nbGUuRU1QVFk7XG59O1xuXG4vKipcbiAqIFJldHJpZXZlcyB0aGUgbG9jYWwgYm91bmRzIG9mIHRoZSBkaXNwbGF5T2JqZWN0IGFzIGEgcmVjdGFuZ2xlIG9iamVjdFxuICpcbiAqIEByZXR1cm4ge1JlY3RhbmdsZX0gdGhlIHJlY3Rhbmd1bGFyIGJvdW5kaW5nIGFyZWFcbiAqL1xuRGlzcGxheU9iamVjdC5wcm90b3R5cGUuZ2V0TG9jYWxCb3VuZHMgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0Qm91bmRzKG1hdGguTWF0cml4LklERU5USVRZKTtcbn07XG5cbi8qKlxuICogQ2FsY3VsYXRlcyB0aGUgZ2xvYmFsIHBvc2l0aW9uIG9mIHRoZSBkaXNwbGF5IG9iamVjdFxuICpcbiAqIEBwYXJhbSBwb3NpdGlvbiB7UG9pbnR9IFRoZSB3b3JsZCBvcmlnaW4gdG8gY2FsY3VsYXRlIGZyb21cbiAqIEByZXR1cm4ge1BvaW50fSBBIHBvaW50IG9iamVjdCByZXByZXNlbnRpbmcgdGhlIHBvc2l0aW9uIG9mIHRoaXMgb2JqZWN0XG4gKi9cbkRpc3BsYXlPYmplY3QucHJvdG90eXBlLnRvR2xvYmFsID0gZnVuY3Rpb24gKHBvc2l0aW9uKSB7XG4gICAgLy8gZG9uJ3QgbmVlZCB0byB1W2RhdGUgdGhlIGxvdFxuICAgIHRoaXMuZGlzcGxheU9iamVjdFVwZGF0ZVRyYW5zZm9ybSgpO1xuICAgIHJldHVybiB0aGlzLndvcmxkVHJhbnNmb3JtLmFwcGx5KHBvc2l0aW9uKTtcbn07XG5cbi8qKlxuICogQ2FsY3VsYXRlcyB0aGUgbG9jYWwgcG9zaXRpb24gb2YgdGhlIGRpc3BsYXkgb2JqZWN0IHJlbGF0aXZlIHRvIGFub3RoZXIgcG9pbnRcbiAqXG4gKiBAcGFyYW0gcG9zaXRpb24ge1BvaW50fSBUaGUgd29ybGQgb3JpZ2luIHRvIGNhbGN1bGF0ZSBmcm9tXG4gKiBAcGFyYW0gW2Zyb21dIHtEaXNwbGF5T2JqZWN0fSBUaGUgRGlzcGxheU9iamVjdCB0byBjYWxjdWxhdGUgdGhlIGdsb2JhbCBwb3NpdGlvbiBmcm9tXG4gKiBAcmV0dXJuIHtQb2ludH0gQSBwb2ludCBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSBwb3NpdGlvbiBvZiB0aGlzIG9iamVjdFxuICovXG5EaXNwbGF5T2JqZWN0LnByb3RvdHlwZS50b0xvY2FsID0gZnVuY3Rpb24gKHBvc2l0aW9uLCBmcm9tKSB7XG4gICAgaWYgKGZyb20pIHtcbiAgICAgICAgcG9zaXRpb24gPSBmcm9tLnRvR2xvYmFsKHBvc2l0aW9uKTtcbiAgICB9XG5cbiAgICAvLyBkb24ndCBuZWVkIHRvIHVwZGF0ZSB0aGUgbG90XG4gICAgdGhpcy5kaXNwbGF5T2JqZWN0VXBkYXRlVHJhbnNmb3JtKCk7XG4gICAgcmV0dXJuIHRoaXMud29ybGRUcmFuc2Zvcm0uYXBwbHlJbnZlcnNlKHBvc2l0aW9uKTtcbn07XG5cbi8qKlxuICogUmVuZGVycyB0aGUgb2JqZWN0IHVzaW5nIHRoZSBXZWJHTCByZW5kZXJlclxuICpcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcn0gVGhlIHJlbmRlcmVyXG4gKiBAcHJpdmF0ZVxuICovXG5EaXNwbGF5T2JqZWN0LnByb3RvdHlwZS5yZW5kZXJXZWJHTCA9IGZ1bmN0aW9uICgvKiByZW5kZXJlciAqLykge1xuICAgIC8vIE9WRVJXUklURTtcbn07XG5cbi8qKlxuICogUmVuZGVycyB0aGUgb2JqZWN0IHVzaW5nIHRoZSBDYW52YXMgcmVuZGVyZXJcbiAqXG4gKiBAcGFyYW0gcmVuZGVyZXIge0NhbnZhc1JlbmRlcmVyfSBUaGUgcmVuZGVyZXJcbiAqIEBwcml2YXRlXG4gKi9cbkRpc3BsYXlPYmplY3QucHJvdG90eXBlLnJlbmRlckNhbnZhcyA9IGZ1bmN0aW9uICgvKiByZW5kZXJlciAqLykge1xuICAgIC8vIE9WRVJXUklURTtcbn07XG4iLCJ2YXIgbWF0aCA9IHJlcXVpcmUoJy4uL21hdGgnKSxcbiAgICBEaXNwbGF5T2JqZWN0ID0gcmVxdWlyZSgnLi9EaXNwbGF5T2JqZWN0JyksXG4gICAgUmVuZGVyVGV4dHVyZSA9IHJlcXVpcmUoJy4uL3RleHR1cmVzL1JlbmRlclRleHR1cmUnKSxcbiAgICAvLyBTcHJpdGUgPSByZXF1aXJlKCcuL1Nwcml0ZScpLFxuICAgIF90ZW1wTWF0cml4ID0gbmV3IG1hdGguTWF0cml4KCk7XG5cbi8qKlxuICogQSBEaXNwbGF5T2JqZWN0Q29udGFpbmVyIHJlcHJlc2VudHMgYSBjb2xsZWN0aW9uIG9mIGRpc3BsYXkgb2JqZWN0cy5cbiAqIEl0IGlzIHRoZSBiYXNlIGNsYXNzIG9mIGFsbCBkaXNwbGF5IG9iamVjdHMgdGhhdCBhY3QgYXMgYSBjb250YWluZXIgZm9yIG90aGVyIG9iamVjdHMuXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBEaXNwbGF5T2JqZWN0XG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gRGlzcGxheU9iamVjdENvbnRhaW5lcigpIHtcbiAgICBEaXNwbGF5T2JqZWN0LmNhbGwodGhpcyk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgYXJyYXkgb2YgY2hpbGRyZW4gb2YgdGhpcyBjb250YWluZXIuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtEaXNwbGF5T2JqZWN0W119XG4gICAgICogQHJlYWRvbmx5XG4gICAgICovXG4gICAgdGhpcy5jaGlsZHJlbiA9IFtdO1xuXG4gICAgLyoqXG4gICAgICogQ2FjaGVkIGludGVybmFsIGZsYWcuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fY2FjaGVBc0JpdG1hcCA9IGZhbHNlO1xuXG4gICAgdGhpcy5fY2FjaGVkU3ByaXRlID0gbnVsbDtcbn1cblxuLy8gY29uc3RydWN0b3JcbkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShEaXNwbGF5T2JqZWN0LnByb3RvdHlwZSk7XG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IERpc3BsYXlPYmplY3RDb250YWluZXI7XG5tb2R1bGUuZXhwb3J0cyA9IERpc3BsYXlPYmplY3RDb250YWluZXI7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKERpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHdpZHRoIG9mIHRoZSBkaXNwbGF5T2JqZWN0Q29udGFpbmVyLCBzZXR0aW5nIHRoaXMgd2lsbCBhY3R1YWxseSBtb2RpZnkgdGhlIHNjYWxlIHRvIGFjaGlldmUgdGhlIHZhbHVlIHNldFxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBEaXNwbGF5T2JqZWN0Q29udGFpbmVyI1xuICAgICAqL1xuICAgIHdpZHRoOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuc2NhbGUueCAqIHRoaXMuZ2V0TG9jYWxCb3VuZHMoKS53aWR0aDtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcblxuICAgICAgICAgICAgdmFyIHdpZHRoID0gdGhpcy5nZXRMb2NhbEJvdW5kcygpLndpZHRoO1xuXG4gICAgICAgICAgICBpZih3aWR0aCAhPT0gMCkge1xuICAgICAgICAgICAgICAgIHRoaXMuc2NhbGUueCA9IHZhbHVlIC8gd2lkdGg7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNjYWxlLnggPSAxO1xuICAgICAgICAgICAgfVxuXG5cbiAgICAgICAgICAgIHRoaXMuX3dpZHRoID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIGhlaWdodCBvZiB0aGUgZGlzcGxheU9iamVjdENvbnRhaW5lciwgc2V0dGluZyB0aGlzIHdpbGwgYWN0dWFsbHkgbW9kaWZ5IHRoZSBzY2FsZSB0byBhY2hpZXZlIHRoZSB2YWx1ZSBzZXRcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgRGlzcGxheU9iamVjdENvbnRhaW5lciNcbiAgICAgKi9cbiAgICBoZWlnaHQ6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gIHRoaXMuc2NhbGUueSAqIHRoaXMuZ2V0TG9jYWxCb3VuZHMoKS5oZWlnaHQ7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG5cbiAgICAgICAgICAgIHZhciBoZWlnaHQgPSB0aGlzLmdldExvY2FsQm91bmRzKCkuaGVpZ2h0O1xuXG4gICAgICAgICAgICBpZiAoaGVpZ2h0ICE9PSAwKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zY2FsZS55ID0gdmFsdWUgLyBoZWlnaHQgO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zY2FsZS55ID0gMTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5faGVpZ2h0ID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU2V0IGlmIHRoaXMgZGlzcGxheSBvYmplY3QgaXMgY2FjaGVkIGFzIGEgYml0bWFwLlxuICAgICAqIFRoaXMgYmFzaWNhbGx5IHRha2VzIGEgc25hcCBzaG90IG9mIHRoZSBkaXNwbGF5IG9iamVjdCBhcyBpdCBpcyBhdCB0aGF0IG1vbWVudC4gSXQgY2FuIHByb3ZpZGUgYSBwZXJmb3JtYW5jZSBiZW5lZml0IGZvciBjb21wbGV4IHN0YXRpYyBkaXNwbGF5T2JqZWN0cy5cbiAgICAgKiBUbyByZW1vdmUgc2ltcGx5IHNldCB0aGlzIHByb3BlcnR5IHRvICdudWxsJ1xuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAbWVtYmVyb2YgRGlzcGxheU9iamVjdCNcbiAgICAgKi9cbiAgICBjYWNoZUFzQml0bWFwOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2NhY2hlQXNCaXRtYXA7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5fY2FjaGVBc0JpdG1hcCA9PT0gdmFsdWUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHRoaXMuX2dlbmVyYXRlQ2FjaGVkU3ByaXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9kZXN0cm95Q2FjaGVkU3ByaXRlKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuX2NhY2hlQXNCaXRtYXAgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG4vKipcbiAqIEFkZHMgYSBjaGlsZCB0byB0aGUgY29udGFpbmVyLlxuICpcbiAqIEBwYXJhbSBjaGlsZCB7RGlzcGxheU9iamVjdH0gVGhlIERpc3BsYXlPYmplY3QgdG8gYWRkIHRvIHRoZSBjb250YWluZXJcbiAqIEByZXR1cm4ge0Rpc3BsYXlPYmplY3R9IFRoZSBjaGlsZCB0aGF0IHdhcyBhZGRlZC5cbiAqL1xuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUuYWRkQ2hpbGQgPSBmdW5jdGlvbiAoY2hpbGQpIHtcbiAgICByZXR1cm4gdGhpcy5hZGRDaGlsZEF0KGNoaWxkLCB0aGlzLmNoaWxkcmVuLmxlbmd0aCk7XG59O1xuXG4vKipcbiAqIEFkZHMgYSBjaGlsZCB0byB0aGUgY29udGFpbmVyIGF0IGEgc3BlY2lmaWVkIGluZGV4LiBJZiB0aGUgaW5kZXggaXMgb3V0IG9mIGJvdW5kcyBhbiBlcnJvciB3aWxsIGJlIHRocm93blxuICpcbiAqIEBwYXJhbSBjaGlsZCB7RGlzcGxheU9iamVjdH0gVGhlIGNoaWxkIHRvIGFkZFxuICogQHBhcmFtIGluZGV4IHtOdW1iZXJ9IFRoZSBpbmRleCB0byBwbGFjZSB0aGUgY2hpbGQgaW5cbiAqIEByZXR1cm4ge0Rpc3BsYXlPYmplY3R9IFRoZSBjaGlsZCB0aGF0IHdhcyBhZGRlZC5cbiAqL1xuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUuYWRkQ2hpbGRBdCA9IGZ1bmN0aW9uIChjaGlsZCwgaW5kZXgpIHtcbiAgICAvLyBwcmV2ZW50IGFkZGluZyBzZWxmIGFzIGNoaWxkXG4gICAgaWYgKGNoaWxkID09PSB0aGlzKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoaW5kZXggPj0gMCAmJiBpbmRleCA8PSB0aGlzLmNoaWxkcmVuLmxlbmd0aCkge1xuICAgICAgICBpZiAoY2hpbGQucGFyZW50KSB7XG4gICAgICAgICAgICBjaGlsZC5wYXJlbnQucmVtb3ZlQ2hpbGQoY2hpbGQpO1xuICAgICAgICB9XG5cbiAgICAgICAgY2hpbGQucGFyZW50ID0gdGhpcztcblxuICAgICAgICB0aGlzLmNoaWxkcmVuLnNwbGljZShpbmRleCwgMCwgY2hpbGQpO1xuXG4gICAgICAgIHJldHVybiBjaGlsZDtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihjaGlsZCArICdhZGRDaGlsZEF0OiBUaGUgaW5kZXggJysgaW5kZXggKycgc3VwcGxpZWQgaXMgb3V0IG9mIGJvdW5kcyAnICsgdGhpcy5jaGlsZHJlbi5sZW5ndGgpO1xuICAgIH1cbn07XG5cbi8qKlxuICogU3dhcHMgdGhlIHBvc2l0aW9uIG9mIDIgRGlzcGxheSBPYmplY3RzIHdpdGhpbiB0aGlzIGNvbnRhaW5lci5cbiAqXG4gKiBAcGFyYW0gY2hpbGQge0Rpc3BsYXlPYmplY3R9XG4gKiBAcGFyYW0gY2hpbGQyIHtEaXNwbGF5T2JqZWN0fVxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5zd2FwQ2hpbGRyZW4gPSBmdW5jdGlvbiAoY2hpbGQsIGNoaWxkMikge1xuICAgIGlmIChjaGlsZCA9PT0gY2hpbGQyKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgaW5kZXgxID0gdGhpcy5nZXRDaGlsZEluZGV4KGNoaWxkKTtcbiAgICB2YXIgaW5kZXgyID0gdGhpcy5nZXRDaGlsZEluZGV4KGNoaWxkMik7XG5cbiAgICBpZiAoaW5kZXgxIDwgMCB8fCBpbmRleDIgPCAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignc3dhcENoaWxkcmVuOiBCb3RoIHRoZSBzdXBwbGllZCBEaXNwbGF5T2JqZWN0cyBtdXN0IGJlIGEgY2hpbGQgb2YgdGhlIGNhbGxlci4nKTtcbiAgICB9XG5cbiAgICB0aGlzLmNoaWxkcmVuW2luZGV4MV0gPSBjaGlsZDI7XG4gICAgdGhpcy5jaGlsZHJlbltpbmRleDJdID0gY2hpbGQ7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdGhlIGluZGV4IHBvc2l0aW9uIG9mIGEgY2hpbGQgRGlzcGxheU9iamVjdCBpbnN0YW5jZVxuICpcbiAqIEBwYXJhbSBjaGlsZCB7RGlzcGxheU9iamVjdH0gVGhlIERpc3BsYXlPYmplY3QgaW5zdGFuY2UgdG8gaWRlbnRpZnlcbiAqIEByZXR1cm4ge051bWJlcn0gVGhlIGluZGV4IHBvc2l0aW9uIG9mIHRoZSBjaGlsZCBkaXNwbGF5IG9iamVjdCB0byBpZGVudGlmeVxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5nZXRDaGlsZEluZGV4ID0gZnVuY3Rpb24gKGNoaWxkKSB7XG4gICAgdmFyIGluZGV4ID0gdGhpcy5jaGlsZHJlbi5pbmRleE9mKGNoaWxkKTtcblxuICAgIGlmIChpbmRleCA9PT0gLTEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdUaGUgc3VwcGxpZWQgRGlzcGxheU9iamVjdCBtdXN0IGJlIGEgY2hpbGQgb2YgdGhlIGNhbGxlcicpO1xuICAgIH1cblxuICAgIHJldHVybiBpbmRleDtcbn07XG5cbi8qKlxuICogQ2hhbmdlcyB0aGUgcG9zaXRpb24gb2YgYW4gZXhpc3RpbmcgY2hpbGQgaW4gdGhlIGRpc3BsYXkgb2JqZWN0IGNvbnRhaW5lclxuICpcbiAqIEBwYXJhbSBjaGlsZCB7RGlzcGxheU9iamVjdH0gVGhlIGNoaWxkIERpc3BsYXlPYmplY3QgaW5zdGFuY2UgZm9yIHdoaWNoIHlvdSB3YW50IHRvIGNoYW5nZSB0aGUgaW5kZXggbnVtYmVyXG4gKiBAcGFyYW0gaW5kZXgge051bWJlcn0gVGhlIHJlc3VsdGluZyBpbmRleCBudW1iZXIgZm9yIHRoZSBjaGlsZCBkaXNwbGF5IG9iamVjdFxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5zZXRDaGlsZEluZGV4ID0gZnVuY3Rpb24gKGNoaWxkLCBpbmRleCkge1xuICAgIGlmIChpbmRleCA8IDAgfHwgaW5kZXggPj0gdGhpcy5jaGlsZHJlbi5sZW5ndGgpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdUaGUgc3VwcGxpZWQgaW5kZXggaXMgb3V0IG9mIGJvdW5kcycpO1xuICAgIH1cblxuICAgIHZhciBjdXJyZW50SW5kZXggPSB0aGlzLmdldENoaWxkSW5kZXgoY2hpbGQpO1xuXG4gICAgdGhpcy5jaGlsZHJlbi5zcGxpY2UoY3VycmVudEluZGV4LCAxKTsgLy9yZW1vdmUgZnJvbSBvbGQgcG9zaXRpb25cbiAgICB0aGlzLmNoaWxkcmVuLnNwbGljZShpbmRleCwgMCwgY2hpbGQpOyAvL2FkZCBhdCBuZXcgcG9zaXRpb25cbn07XG5cbi8qKlxuICogUmV0dXJucyB0aGUgY2hpbGQgYXQgdGhlIHNwZWNpZmllZCBpbmRleFxuICpcbiAqIEBwYXJhbSBpbmRleCB7TnVtYmVyfSBUaGUgaW5kZXggdG8gZ2V0IHRoZSBjaGlsZCBmcm9tXG4gKiBAcmV0dXJuIHtEaXNwbGF5T2JqZWN0fSBUaGUgY2hpbGQgYXQgdGhlIGdpdmVuIGluZGV4LCBpZiBhbnkuXG4gKi9cbkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLmdldENoaWxkQXQgPSBmdW5jdGlvbiAoaW5kZXgpIHtcbiAgICBpZiAoaW5kZXggPCAwIHx8IGluZGV4ID49IHRoaXMuY2hpbGRyZW4ubGVuZ3RoKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignZ2V0Q2hpbGRBdDogU3VwcGxpZWQgaW5kZXggJyArIGluZGV4ICsgJyBkb2VzIG5vdCBleGlzdCBpbiB0aGUgY2hpbGQgbGlzdCwgb3IgdGhlIHN1cHBsaWVkIERpc3BsYXlPYmplY3QgbXVzdCBiZSBhIGNoaWxkIG9mIHRoZSBjYWxsZXInKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5jaGlsZHJlbltpbmRleF07XG59O1xuXG4vKipcbiAqIFJlbW92ZXMgYSBjaGlsZCBmcm9tIHRoZSBjb250YWluZXIuXG4gKlxuICogQHBhcmFtIGNoaWxkIHtEaXNwbGF5T2JqZWN0fSBUaGUgRGlzcGxheU9iamVjdCB0byByZW1vdmVcbiAqIEByZXR1cm4ge0Rpc3BsYXlPYmplY3R9IFRoZSBjaGlsZCB0aGF0IHdhcyByZW1vdmVkLlxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5yZW1vdmVDaGlsZCA9IGZ1bmN0aW9uIChjaGlsZCkge1xuICAgIHZhciBpbmRleCA9IHRoaXMuY2hpbGRyZW4uaW5kZXhPZihjaGlsZCk7XG5cbiAgICBpZiAoaW5kZXggPT09IC0xKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5yZW1vdmVDaGlsZEF0KGluZGV4KTtcbn07XG5cbi8qKlxuICogUmVtb3ZlcyBhIGNoaWxkIGZyb20gdGhlIHNwZWNpZmllZCBpbmRleCBwb3NpdGlvbi5cbiAqXG4gKiBAcGFyYW0gaW5kZXgge051bWJlcn0gVGhlIGluZGV4IHRvIGdldCB0aGUgY2hpbGQgZnJvbVxuICogQHJldHVybiB7RGlzcGxheU9iamVjdH0gVGhlIGNoaWxkIHRoYXQgd2FzIHJlbW92ZWQuXG4gKi9cbkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLnJlbW92ZUNoaWxkQXQgPSBmdW5jdGlvbiAoaW5kZXgpIHtcbiAgICB2YXIgY2hpbGQgPSB0aGlzLmdldENoaWxkQXQoaW5kZXgpO1xuXG4gICAgY2hpbGQucGFyZW50ID0gbnVsbDtcbiAgICB0aGlzLmNoaWxkcmVuLnNwbGljZShpbmRleCwgMSk7XG5cbiAgICByZXR1cm4gY2hpbGQ7XG59O1xuXG4vKipcbiAqIFJlbW92ZXMgYWxsIGNoaWxkcmVuIGZyb20gdGhpcyBjb250YWluZXIgdGhhdCBhcmUgd2l0aGluIHRoZSBiZWdpbiBhbmQgZW5kIGluZGV4ZXMuXG4gKlxuICogQHBhcmFtIGJlZ2luSW5kZXgge051bWJlcn0gVGhlIGJlZ2lubmluZyBwb3NpdGlvbi4gRGVmYXVsdCB2YWx1ZSBpcyAwLlxuICogQHBhcmFtIGVuZEluZGV4IHtOdW1iZXJ9IFRoZSBlbmRpbmcgcG9zaXRpb24uIERlZmF1bHQgdmFsdWUgaXMgc2l6ZSBvZiB0aGUgY29udGFpbmVyLlxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5yZW1vdmVDaGlsZHJlbiA9IGZ1bmN0aW9uIChiZWdpbkluZGV4LCBlbmRJbmRleCkge1xuICAgIHZhciBiZWdpbiA9IGJlZ2luSW5kZXggfHwgMDtcbiAgICB2YXIgZW5kID0gdHlwZW9mIGVuZEluZGV4ID09PSAnbnVtYmVyJyA/IGVuZEluZGV4IDogdGhpcy5jaGlsZHJlbi5sZW5ndGg7XG4gICAgdmFyIHJhbmdlID0gZW5kIC0gYmVnaW47XG5cbiAgICBpZiAocmFuZ2UgPiAwICYmIHJhbmdlIDw9IGVuZCkge1xuICAgICAgICB2YXIgcmVtb3ZlZCA9IHRoaXMuY2hpbGRyZW4uc3BsaWNlKGJlZ2luLCByYW5nZSk7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByZW1vdmVkLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICByZW1vdmVkW2ldLnBhcmVudCA9IG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVtb3ZlZDtcbiAgICB9XG4gICAgZWxzZSBpZiAocmFuZ2UgPT09IDAgJiYgdGhpcy5jaGlsZHJlbi5sZW5ndGggPT09IDApIHtcbiAgICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoJ3JlbW92ZUNoaWxkcmVuOiBudW1lcmljIHZhbHVlcyBhcmUgb3V0c2lkZSB0aGUgYWNjZXB0YWJsZSByYW5nZS4nKTtcbiAgICB9XG59O1xuXG4vKipcbiAqIEdlbmVyYXRlcyBhbmQgdXBkYXRlcyB0aGUgY2FjaGVkIHNwcml0ZSBmb3IgdGhpcyBvYmplY3QuXG4gKlxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS51cGRhdGVDYWNoZWRTcHJpdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5fZ2VuZXJhdGVDYWNoZWRTcHJpdGUoKTtcbn07XG5cbi8qKlxuICogVXNlZnVsIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhIHRleHR1cmUgb2YgdGhlIGRpc3BsYXlPYmplY3Qgb2JqZWN0IHRoYXQgY2FuIHRoZW4gYmUgdXNlZCB0byBjcmVhdGUgc3ByaXRlc1xuICogVGhpcyBjYW4gYmUgcXVpdGUgdXNlZnVsIGlmIHlvdXIgZGlzcGxheU9iamVjdCBpcyBzdGF0aWMgLyBjb21wbGljYXRlZCBhbmQgbmVlZHMgdG8gYmUgcmV1c2VkIG11bHRpcGxlIHRpbWVzLlxuICpcbiAqIEBwYXJhbSByZXNvbHV0aW9uIHtOdW1iZXJ9IFRoZSByZXNvbHV0aW9uIG9mIHRoZSB0ZXh0dXJlIGJlaW5nIGdlbmVyYXRlZFxuICogQHBhcmFtIHNjYWxlTW9kZSB7TnVtYmVyfSBTZWUge3sjY3Jvc3NMaW5rIFwiUElYSS9zY2FsZU1vZGVzOnByb3BlcnR5XCJ9fVBJWEkuc2NhbGVNb2Rlc3t7L2Nyb3NzTGlua319IGZvciBwb3NzaWJsZSB2YWx1ZXNcbiAqIEBwYXJhbSByZW5kZXJlciB7Q2FudmFzUmVuZGVyZXJ8V2ViR0xSZW5kZXJlcn0gVGhlIHJlbmRlcmVyIHVzZWQgdG8gZ2VuZXJhdGUgdGhlIHRleHR1cmUuXG4gKiBAcmV0dXJuIHtUZXh0dXJlfSBhIHRleHR1cmUgb2YgdGhlIGdyYXBoaWNzIG9iamVjdFxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5nZW5lcmF0ZVRleHR1cmUgPSBmdW5jdGlvbiAocmVzb2x1dGlvbiwgc2NhbGVNb2RlLCByZW5kZXJlcikge1xuICAgIHZhciBib3VuZHMgPSB0aGlzLmdldExvY2FsQm91bmRzKCk7XG5cbiAgICB2YXIgcmVuZGVyVGV4dHVyZSA9IG5ldyBSZW5kZXJUZXh0dXJlKHJlbmRlcmVyLCBib3VuZHMud2lkdGggfCAwLCBib3VuZHMuaGVpZ2h0IHwgMCwgcmVuZGVyZXIsIHNjYWxlTW9kZSwgcmVzb2x1dGlvbik7XG5cbiAgICBfdGVtcE1hdHJpeC50eCA9IC1ib3VuZHMueDtcbiAgICBfdGVtcE1hdHJpeC50eSA9IC1ib3VuZHMueTtcblxuICAgIHJlbmRlclRleHR1cmUucmVuZGVyKHRoaXMsIF90ZW1wTWF0cml4KTtcblxuICAgIHJldHVybiByZW5kZXJUZXh0dXJlO1xufTtcblxuLypcbiAqIFVwZGF0ZXMgdGhlIHRyYW5zZm9ybSBvbiBhbGwgY2hpbGRyZW4gb2YgdGhpcyBjb250YWluZXIgZm9yIHJlbmRlcmluZ1xuICpcbiAqIEBwcml2YXRlXG4gKi9cbkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLnVwZGF0ZVRyYW5zZm9ybSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoIXRoaXMudmlzaWJsZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5kaXNwbGF5T2JqZWN0VXBkYXRlVHJhbnNmb3JtKCk7XG5cbiAgICBpZiAodGhpcy5fY2FjaGVBc0JpdG1hcCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgZm9yICh2YXIgaSA9IDAsIGogPSB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGo7ICsraSkge1xuICAgICAgICB0aGlzLmNoaWxkcmVuW2ldLnVwZGF0ZVRyYW5zZm9ybSgpO1xuICAgIH1cbn07XG5cbi8vIHBlcmZvcm1hbmNlIGluY3JlYXNlIHRvIGF2b2lkIHVzaW5nIGNhbGwuLiAoMTB4IGZhc3RlcilcbkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLmRpc3BsYXlPYmplY3RDb250YWluZXJVcGRhdGVUcmFuc2Zvcm0gPSBEaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS51cGRhdGVUcmFuc2Zvcm07XG5cbi8qKlxuICogUmV0cmlldmVzIHRoZSBib3VuZHMgb2YgdGhlIGRpc3BsYXlPYmplY3RDb250YWluZXIgYXMgYSByZWN0YW5nbGUuIFRoZSBib3VuZHMgY2FsY3VsYXRpb24gdGFrZXMgYWxsIHZpc2libGUgY2hpbGRyZW4gaW50byBjb25zaWRlcmF0aW9uLlxuICpcbiAqIEByZXR1cm4ge1JlY3RhbmdsZX0gVGhlIHJlY3Rhbmd1bGFyIGJvdW5kaW5nIGFyZWFcbiAqL1xuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUuZ2V0Qm91bmRzID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICh0aGlzLmNoaWxkcmVuLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gbWF0aC5SZWN0YW5nbGUuRU1QVFk7XG4gICAgfVxuXG4gICAgLy8gVE9ETyB0aGUgYm91bmRzIGhhdmUgYWxyZWFkeSBiZWVuIGNhbGN1bGF0ZWQgdGhpcyByZW5kZXIgc2Vzc2lvbiBzbyByZXR1cm4gd2hhdCB3ZSBoYXZlXG5cbiAgICB2YXIgbWluWCA9IEluZmluaXR5O1xuICAgIHZhciBtaW5ZID0gSW5maW5pdHk7XG5cbiAgICB2YXIgbWF4WCA9IC1JbmZpbml0eTtcbiAgICB2YXIgbWF4WSA9IC1JbmZpbml0eTtcblxuICAgIHZhciBjaGlsZEJvdW5kcztcbiAgICB2YXIgY2hpbGRNYXhYO1xuICAgIHZhciBjaGlsZE1heFk7XG5cbiAgICB2YXIgY2hpbGRWaXNpYmxlID0gZmFsc2U7XG5cbiAgICBmb3IgKHZhciBpID0gMCwgaiA9IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgKytpKSB7XG4gICAgICAgIHZhciBjaGlsZCA9IHRoaXMuY2hpbGRyZW5baV07XG5cbiAgICAgICAgaWYgKCFjaGlsZC52aXNpYmxlKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNoaWxkVmlzaWJsZSA9IHRydWU7XG5cbiAgICAgICAgY2hpbGRCb3VuZHMgPSB0aGlzLmNoaWxkcmVuW2ldLmdldEJvdW5kcygpO1xuXG4gICAgICAgIG1pblggPSBtaW5YIDwgY2hpbGRCb3VuZHMueCA/IG1pblggOiBjaGlsZEJvdW5kcy54O1xuICAgICAgICBtaW5ZID0gbWluWSA8IGNoaWxkQm91bmRzLnkgPyBtaW5ZIDogY2hpbGRCb3VuZHMueTtcblxuICAgICAgICBjaGlsZE1heFggPSBjaGlsZEJvdW5kcy53aWR0aCArIGNoaWxkQm91bmRzLng7XG4gICAgICAgIGNoaWxkTWF4WSA9IGNoaWxkQm91bmRzLmhlaWdodCArIGNoaWxkQm91bmRzLnk7XG5cbiAgICAgICAgbWF4WCA9IG1heFggPiBjaGlsZE1heFggPyBtYXhYIDogY2hpbGRNYXhYO1xuICAgICAgICBtYXhZID0gbWF4WSA+IGNoaWxkTWF4WSA/IG1heFkgOiBjaGlsZE1heFk7XG4gICAgfVxuXG4gICAgaWYgKCFjaGlsZFZpc2libGUpIHtcbiAgICAgICAgcmV0dXJuIG1hdGguUmVjdGFuZ2xlLkVNUFRZO1xuICAgIH1cblxuICAgIHRoaXMuX2JvdW5kcy54ID0gbWluWDtcbiAgICB0aGlzLl9ib3VuZHMueSA9IG1pblk7XG4gICAgdGhpcy5fYm91bmRzLndpZHRoID0gbWF4WCAtIG1pblg7XG4gICAgdGhpcy5fYm91bmRzLmhlaWdodCA9IG1heFkgLSBtaW5ZO1xuXG4gICAgLy8gVE9ETzogc3RvcmUgYSByZWZlcmVuY2Ugc28gdGhhdCBpZiB0aGlzIGZ1bmN0aW9uIGdldHMgY2FsbGVkIGFnYWluIGluIHRoZSByZW5kZXIgY3ljbGUgd2UgZG8gbm90IGhhdmUgdG8gcmVjYWxjdWxhdGVcbiAgICAvL3RoaXMuX2N1cnJlbnRCb3VuZHMgPSBib3VuZHM7XG5cbiAgICByZXR1cm4gdGhpcy5fYm91bmRzO1xufTtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIG5vbi1nbG9iYWwgbG9jYWwgYm91bmRzIG9mIHRoZSBkaXNwbGF5T2JqZWN0Q29udGFpbmVyIGFzIGEgcmVjdGFuZ2xlLlxuICogVGhlIGNhbGN1bGF0aW9uIHRha2VzIGFsbCB2aXNpYmxlIGNoaWxkcmVuIGludG8gY29uc2lkZXJhdGlvbi5cbiAqXG4gKiBAcmV0dXJuIHtSZWN0YW5nbGV9IFRoZSByZWN0YW5ndWxhciBib3VuZGluZyBhcmVhXG4gKi9cbkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLmdldExvY2FsQm91bmRzID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBtYXRyaXhDYWNoZSA9IHRoaXMud29ybGRUcmFuc2Zvcm07XG5cbiAgICB0aGlzLndvcmxkVHJhbnNmb3JtID0gbWF0aC5NYXRyaXguSURFTlRJVFk7XG5cbiAgICBmb3IgKHZhciBpID0gMCwgaiA9IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgKytpKSB7XG4gICAgICAgIHRoaXMuY2hpbGRyZW5baV0udXBkYXRlVHJhbnNmb3JtKCk7XG4gICAgfVxuXG4gICAgdGhpcy53b3JsZFRyYW5zZm9ybSA9IG1hdHJpeENhY2hlO1xuXG4gICAgcmV0dXJuIHRoaXMuZ2V0Qm91bmRzKCk7XG59O1xuXG4vKipcbiAqIFJlbmRlcnMgdGhlIG9iamVjdCB1c2luZyB0aGUgV2ViR0wgcmVuZGVyZXJcbiAqXG4gKiBUT0RPIC0gT3B0aW1pemF0aW9uIHBhc3MhXG4gKlxuICogQHBhcmFtIHJlbmRlcmVyIHtXZWJHTFJlbmRlcmVyfSBUaGUgcmVuZGVyZXJcbiAqL1xuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUucmVuZGVyV2ViR0wgPSBmdW5jdGlvbiAocmVuZGVyZXIpIHtcbiAgICAvLyBpZiB0aGUgb2JqZWN0IGlzIG5vdCB2aXNpYmxlIG9yIHRoZSBhbHBoYSBpcyAwIHRoZW4gbm8gbmVlZCB0byByZW5kZXIgdGhpcyBlbGVtZW50XG4gICAgaWYgKCF0aGlzLnZpc2libGUgfHwgdGhpcy5hbHBoYSA8PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fY2FjaGVBc0JpdG1hcCkge1xuICAgICAgICB0aGlzLl9yZW5kZXJDYWNoZWRTcHJpdGUocmVuZGVyZXIpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIGksIGo7XG5cbiAgICAvLyBkbyBhIHF1aWNrIGNoZWNrIHRvIHNlZSBpZiB0aGlzIGVsZW1lbnQgaGFzIGEgbWFzayBvciBhIGZpbHRlci5cbiAgICBpZiAodGhpcy5fbWFzayB8fCB0aGlzLl9maWx0ZXJzKSB7XG4gICAgICAgIC8vIHB1c2ggZmlsdGVyIGZpcnN0IGFzIHdlIG5lZWQgdG8gZW5zdXJlIHRoZSBzdGVuY2lsIGJ1ZmZlciBpcyBjb3JyZWN0IGZvciBhbnkgbWFza2luZ1xuICAgICAgICBpZiAodGhpcy5fZmlsdGVycykge1xuICAgICAgICAgICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guZmx1c2goKTtcbiAgICAgICAgICAgIHJlbmRlcmVyLmZpbHRlck1hbmFnZXIucHVzaEZpbHRlcih0aGlzLl9maWx0ZXJCbG9jayk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICAgICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guc3RvcCgpO1xuICAgICAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucHVzaE1hc2sodGhpcy5tYXNrLCByZW5kZXJlcik7XG4gICAgICAgICAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5zdGFydCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gYWRkIHRoaXMgb2JqZWN0IHRvIHRoZSBiYXRjaCwgb25seSByZW5kZXJlZCBpZiBpdCBoYXMgYSB0ZXh0dXJlLlxuICAgICAgICBpZiAodGhpcy50ZXh0dXJlKSB7XG4gICAgICAgICAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5yZW5kZXIodGhpcyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBub3cgbG9vcCB0aHJvdWdoIHRoZSBjaGlsZHJlbiBhbmQgbWFrZSBzdXJlIHRoZXkgZ2V0IHJlbmRlcmVkXG4gICAgICAgIGZvciAoaSA9IDAsIGogPSB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuICAgICAgICAgICAgdGhpcy5jaGlsZHJlbltpXS5yZW5kZXJXZWJHTChyZW5kZXJlcik7XG4gICAgICAgIH1cblxuICAgICAgICAvLyB0aW1lIHRvIHN0b3AgdGhlIHNwcml0ZSBiYXRjaCBhcyBlaXRoZXIgYSBtYXNrIGVsZW1lbnQgb3IgYSBmaWx0ZXIgZHJhdyB3aWxsIGhhcHBlbiBuZXh0XG4gICAgICAgIHJlbmRlcmVyLnNwcml0ZUJhdGNoLnN0b3AoKTtcblxuICAgICAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucG9wTWFzayh0aGlzLl9tYXNrLCByZW5kZXJlcik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5fZmlsdGVycykge1xuICAgICAgICAgICAgcmVuZGVyZXIuZmlsdGVyTWFuYWdlci5wb3BGaWx0ZXIoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlbmRlcmVyLnNwcml0ZUJhdGNoLnN0YXJ0KCk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBpZiAodGhpcy50ZXh0dXJlKSB7XG4gICAgICAgICAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5yZW5kZXIodGhpcyk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBzaW1wbGUgcmVuZGVyIGNoaWxkcmVuIVxuICAgICAgICBmb3IgKGkgPSAwLCBqID0gdGhpcy5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyArK2kpIHtcbiAgICAgICAgICAgIHRoaXMuY2hpbGRyZW5baV0ucmVuZGVyV2ViR0wocmVuZGVyZXIpO1xuICAgICAgICB9XG5cbiAgICB9XG59O1xuXG4vKipcbiAqIFJlbmRlcnMgdGhlIG9iamVjdCB1c2luZyB0aGUgQ2FudmFzIHJlbmRlcmVyXG4gKlxuICogQHBhcmFtIHJlbmRlcmVyIHtDYW52YXNSZW5kZXJlcn0gVGhlIHJlbmRlcmVyXG4gKi9cbkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLnJlbmRlckNhbnZhcyA9IGZ1bmN0aW9uIChyZW5kZXJlcikge1xuICAgIGlmICghdGhpcy52aXNpYmxlIHx8IHRoaXMuYWxwaGEgPD0gMCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX2NhY2hlQXNCaXRtYXApIHtcbiAgICAgICAgdGhpcy5fcmVuZGVyQ2FjaGVkU3ByaXRlKHJlbmRlcmVyKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0aGlzLl9tYXNrKSB7XG4gICAgICAgIHJlbmRlcmVyLm1hc2tNYW5hZ2VyLnB1c2hNYXNrKHRoaXMuX21hc2ssIHJlbmRlcmVyKTtcbiAgICB9XG5cbiAgICBmb3IgKHZhciBpID0gMCwgaiA9IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgKytpKSB7XG4gICAgICAgIHRoaXMuY2hpbGRyZW5baV0ucmVuZGVyQ2FudmFzKHJlbmRlcmVyKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICByZW5kZXJlci5tYXNrTWFuYWdlci5wb3BNYXNrKHJlbmRlcmVyKTtcbiAgICB9XG59O1xuXG4vKipcbiAqIEludGVybmFsIG1ldGhvZC5cbiAqXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ8Q2FudmFzUmVuZGVyZXJ9IFRoZSByZW5kZXJlclxuICogQHByaXZhdGVcbiAqL1xuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUuX3JlbmRlckNhY2hlZFNwcml0ZSA9IGZ1bmN0aW9uIChyZW5kZXJlcikge1xuICAgIHRoaXMuX2NhY2hlZFNwcml0ZS53b3JsZEFscGhhID0gdGhpcy53b3JsZEFscGhhO1xuXG4gICAgaWYgKHJlbmRlcmVyLmdsKSB7XG4gICAgICAgIHRoaXMuX2NhY2hlZFNwcml0ZS5yZW5kZXJXZWJHTChyZW5kZXJlcik7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLl9jYWNoZWRTcHJpdGUucmVuZGVyQ2FudmFzKHJlbmRlcmVyKTtcbiAgICB9XG59O1xuXG4vKipcbiAqIEludGVybmFsIG1ldGhvZC5cbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5fZ2VuZXJhdGVDYWNoZWRTcHJpdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGJvdW5kcyA9IHRoaXMuZ2V0TG9jYWxCb3VuZHMoKTtcblxuICAgIGlmICghdGhpcy5fY2FjaGVkU3ByaXRlKSB7XG4gICAgICAgIC8vIFRPRE8gLSBSZW5kZXJUZXh0dXJlIG5vdyAqcmVxdWlyZXMqIGEgcmVuZGVyZXIgaW5zdGFuY2UsIHNvIHRoaXMgaXMgbGlrZSBicm9rZW5cbiAgICAgICAgLy8gYmVjYXVzZSBgcmVuZGVyZXJgIGlzbid0IGFjdHVhbGx5IGluIHNjb3BlIGhlcmUgOlBcbiAgICAgICAgdmFyIHJlbmRlclRleHR1cmUgPSBuZXcgUmVuZGVyVGV4dHVyZShyZW5kZXJlciwgYm91bmRzLndpZHRoIHwgMCwgYm91bmRzLmhlaWdodCB8IDApO1xuXG4gICAgICAgIHRoaXMuX2NhY2hlZFNwcml0ZSA9IG5ldyBTcHJpdGUocmVuZGVyVGV4dHVyZSk7XG4gICAgICAgIHRoaXMuX2NhY2hlZFNwcml0ZS53b3JsZFRyYW5zZm9ybSA9IHRoaXMud29ybGRUcmFuc2Zvcm07XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLl9jYWNoZWRTcHJpdGUudGV4dHVyZS5yZXNpemUoYm91bmRzLndpZHRoIHwgMCwgYm91bmRzLmhlaWdodCB8IDApO1xuICAgIH1cblxuICAgIHZhciB0ZW1wRmlsdGVycyA9IHRoaXMuX2ZpbHRlcnM7XG4gICAgdGhpcy5fZmlsdGVycyA9IG51bGw7XG5cbiAgICB0aGlzLl9jYWNoZWRTcHJpdGUuZmlsdGVycyA9IHRlbXBGaWx0ZXJzO1xuXG4gICAgX3RlbXBNYXRyaXgudHggPSAtYm91bmRzLng7XG4gICAgX3RlbXBNYXRyaXgudHkgPSAtYm91bmRzLnk7XG5cbiAgICB0aGlzLl9jYWNoZWRTcHJpdGUudGV4dHVyZS5yZW5kZXIodGhpcywgX3RlbXBNYXRyaXgsIHRydWUpO1xuXG4gICAgdGhpcy5fY2FjaGVkU3ByaXRlLmFuY2hvci54ID0gLShib3VuZHMueCAvIGJvdW5kcy53aWR0aCk7XG4gICAgdGhpcy5fY2FjaGVkU3ByaXRlLmFuY2hvci55ID0gLShib3VuZHMueSAvIGJvdW5kcy5oZWlnaHQpO1xuXG4gICAgdGhpcy5fZmlsdGVycyA9IHRlbXBGaWx0ZXJzO1xufTtcblxuLyoqXG4gKiBEZXN0cm95cyB0aGUgY2FjaGVkIHNwcml0ZS5cbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZS5fZGVzdHJveUNhY2hlZFNwcml0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoIXRoaXMuX2NhY2hlZFNwcml0ZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gVE9ETzogUG9vbCB0aGlzIHNwcml0ZVxuICAgIHRoaXMuX2NhY2hlZFNwcml0ZS5kZXN0cm95KHRydWUsIHRydWUpO1xuICAgIHRoaXMuX2NhY2hlZFNwcml0ZSA9IG51bGw7XG59O1xuIiwidmFyIG1hdGggPSByZXF1aXJlKCcuLi9tYXRoJyksXG4gICAgVGV4dHVyZSA9IHJlcXVpcmUoJy4uL3RleHR1cmVzL1RleHR1cmUnKSxcbiAgICBEaXNwbGF5T2JqZWN0Q29udGFpbmVyID0gcmVxdWlyZSgnLi9EaXNwbGF5T2JqZWN0Q29udGFpbmVyJyksXG4gICAgQ2FudmFzVGludGVyID0gcmVxdWlyZSgnLi4vcmVuZGVyZXJzL2NhbnZhcy91dGlscy9DYW52YXNUaW50ZXInKSxcbiAgICB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzJyksXG4gICAgQ09OU1QgPSByZXF1aXJlKCcuLi9jb25zdCcpO1xuXG4vKipcbiAqIFRoZSBTcHJpdGUgb2JqZWN0IGlzIHRoZSBiYXNlIGZvciBhbGwgdGV4dHVyZWQgb2JqZWN0cyB0aGF0IGFyZSByZW5kZXJlZCB0byB0aGUgc2NyZWVuXG4gKlxuICogQSBzcHJpdGUgY2FuIGJlIGNyZWF0ZWQgZGlyZWN0bHkgZnJvbSBhbiBpbWFnZSBsaWtlIHRoaXM6XG4gKlxuICogYGBganNcbiAqIHZhciBzcHJpdGUgPSBuZXcgU3ByaXRlLmZyb21JbWFnZSgnYXNzZXRzL2ltYWdlLnBuZycpO1xuICogYGBgXG4gKlxuICogQGNsYXNzIFNwcml0ZVxuICogQGV4dGVuZHMgRGlzcGxheU9iamVjdENvbnRhaW5lclxuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gdGV4dHVyZSB7VGV4dHVyZX0gVGhlIHRleHR1cmUgZm9yIHRoaXMgc3ByaXRlXG4gKi9cbmZ1bmN0aW9uIFNwcml0ZSh0ZXh0dXJlKSB7XG4gICAgRGlzcGxheU9iamVjdENvbnRhaW5lci5jYWxsKHRoaXMpO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGFuY2hvciBzZXRzIHRoZSBvcmlnaW4gcG9pbnQgb2YgdGhlIHRleHR1cmUuXG4gICAgICogVGhlIGRlZmF1bHQgaXMgMCwwIHRoaXMgbWVhbnMgdGhlIHRleHR1cmUncyBvcmlnaW4gaXMgdGhlIHRvcCBsZWZ0XG4gICAgICogU2V0dGluZyB0aGFuIGFuY2hvciB0byAwLjUsMC41IG1lYW5zIHRoZSB0ZXh0dXJlcyBvcmlnaW4gaXMgY2VudGVyZWRcbiAgICAgKiBTZXR0aW5nIHRoZSBhbmNob3IgdG8gMSwxIHdvdWxkIG1lYW4gdGhlIHRleHR1cmVzIG9yaWdpbiBwb2ludHMgd2lsbCBiZSB0aGUgYm90dG9tIHJpZ2h0IGNvcm5lclxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICovXG4gICAgdGhpcy5hbmNob3IgPSBuZXcgbWF0aC5Qb2ludCgpO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHRleHR1cmUgdGhhdCB0aGUgc3ByaXRlIGlzIHVzaW5nXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtUZXh0dXJlfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fdGV4dHVyZSA9IG51bGw7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgd2lkdGggb2YgdGhlIHNwcml0ZSAodGhpcyBpcyBpbml0aWFsbHkgc2V0IGJ5IHRoZSB0ZXh0dXJlKVxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fd2lkdGggPSAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGhlaWdodCBvZiB0aGUgc3ByaXRlICh0aGlzIGlzIGluaXRpYWxseSBzZXQgYnkgdGhlIHRleHR1cmUpXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl9oZWlnaHQgPSAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHRpbnQgYXBwbGllZCB0byB0aGUgc3ByaXRlLiBUaGlzIGlzIGEgaGV4IHZhbHVlLiBBIHZhbHVlIG9mIDB4RkZGRkZGIHdpbGwgcmVtb3ZlIGFueSB0aW50IGVmZmVjdC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAweEZGRkZGRlxuICAgICAqL1xuICAgIHRoaXMudGludCA9IDB4RkZGRkZGO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGJsZW5kIG1vZGUgdG8gYmUgYXBwbGllZCB0byB0aGUgc3ByaXRlLiBTZXQgdG8gQ09OU1QuYmxlbmRNb2Rlcy5OT1JNQUwgdG8gcmVtb3ZlIGFueSBibGVuZCBtb2RlLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IENPTlNULmJsZW5kTW9kZXMuTk9STUFMO1xuICAgICAqL1xuICAgIHRoaXMuYmxlbmRNb2RlID0gQ09OU1QuYmxlbmRNb2Rlcy5OT1JNQUw7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgc2hhZGVyIHRoYXQgd2lsbCBiZSB1c2VkIHRvIHJlbmRlciB0aGUgc3ByaXRlLiBTZXQgdG8gbnVsbCB0byByZW1vdmUgYSBjdXJyZW50IHNoYWRlci5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0Fic3RyYWN0RmlsdGVyfVxuICAgICAqL1xuICAgIHRoaXMuc2hhZGVyID0gbnVsbDtcblxuICAgIHRoaXMucmVuZGVyYWJsZSA9IHRydWU7XG5cbiAgICAvLyBjYWxsIHRleHR1cmUgc2V0dGVyXG4gICAgdGhpcy50ZXh0dXJlID0gdGV4dHVyZSB8fCBUZXh0dXJlLkVNUFRZO1xufVxuXG5TcHJpdGUucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoZGVzdHJveVRleHR1cmUsIGRlc3Ryb3lCYXNlVGV4dHVyZSkge1xuICAgIERpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlLmRlc3Ryb3kuY2FsbCh0aGlzKTtcblxuICAgIHRoaXMuYW5jaG9yID0gbnVsbDtcblxuICAgIGlmIChkZXN0cm95VGV4dHVyZSkge1xuICAgICAgICB0aGlzLl90ZXh0dXJlLmRlc3Ryb3koZGVzdHJveUJhc2VUZXh0dXJlKTtcbiAgICB9XG5cbiAgICB0aGlzLl90ZXh0dXJlID0gbnVsbDtcbiAgICB0aGlzLnNoYWRlciA9IG51bGw7XG59O1xuXG4vLyBjb25zdHJ1Y3RvclxuU3ByaXRlLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUpO1xuU3ByaXRlLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFNwcml0ZTtcbm1vZHVsZS5leHBvcnRzID0gU3ByaXRlO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhTcHJpdGUucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHdpZHRoIG9mIHRoZSBzcHJpdGUsIHNldHRpbmcgdGhpcyB3aWxsIGFjdHVhbGx5IG1vZGlmeSB0aGUgc2NhbGUgdG8gYWNoaWV2ZSB0aGUgdmFsdWUgc2V0XG4gICAgICpcbiAgICAgKiBAbWVtYmVyXG4gICAgICogQG1lbWJlcm9mIFNwcml0ZSNcbiAgICAgKi9cbiAgICB3aWR0aDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnNjYWxlLnggKiB0aGlzLnRleHR1cmUuZnJhbWUud2lkdGg7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnNjYWxlLnggPSB2YWx1ZSAvIHRoaXMudGV4dHVyZS5mcmFtZS53aWR0aDtcbiAgICAgICAgICAgIHRoaXMuX3dpZHRoID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIGhlaWdodCBvZiB0aGUgc3ByaXRlLCBzZXR0aW5nIHRoaXMgd2lsbCBhY3R1YWxseSBtb2RpZnkgdGhlIHNjYWxlIHRvIGFjaGlldmUgdGhlIHZhbHVlIHNldFxuICAgICAqXG4gICAgICogQG1lbWJlclxuICAgICAqIEBtZW1iZXJvZiBTcHJpdGUjXG4gICAgICovXG4gICAgaGVpZ2h0OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuICB0aGlzLnNjYWxlLnkgKiB0aGlzLnRleHR1cmUuZnJhbWUuaGVpZ2h0O1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy5zY2FsZS55ID0gdmFsdWUgLyB0aGlzLnRleHR1cmUuZnJhbWUuaGVpZ2h0O1xuICAgICAgICAgICAgdGhpcy5faGVpZ2h0ID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIGhlaWdodCBvZiB0aGUgc3ByaXRlLCBzZXR0aW5nIHRoaXMgd2lsbCBhY3R1YWxseSBtb2RpZnkgdGhlIHNjYWxlIHRvIGFjaGlldmUgdGhlIHZhbHVlIHNldFxuICAgICAqXG4gICAgICogQG1lbWJlclxuICAgICAqIEBtZW1iZXJvZiBTcHJpdGUjXG4gICAgICovXG4gICAgdGV4dHVyZToge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiAgdGhpcy5fdGV4dHVyZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLl90ZXh0dXJlID09PSB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5fdGV4dHVyZSA9IHZhbHVlO1xuICAgICAgICAgICAgdGhpcy5jYWNoZWRUaW50ID0gMHhGRkZGRkY7XG5cbiAgICAgICAgICAgIGlmICh2YWx1ZSkge1xuICAgICAgICAgICAgICAgIC8vIHdhaXQgZm9yIHRoZSB0ZXh0dXJlIHRvIGxvYWRcbiAgICAgICAgICAgICAgICBpZiAodmFsdWUuYmFzZVRleHR1cmUuaGFzTG9hZGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX29uVGV4dHVyZVVwZGF0ZSgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUub25jZSgndXBkYXRlJywgdGhpcy5fb25UZXh0dXJlVXBkYXRlLmJpbmQodGhpcykpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0sXG59KTtcblxuLyoqXG4gKiBXaGVuIHRoZSB0ZXh0dXJlIGlzIHVwZGF0ZWQsIHRoaXMgZXZlbnQgd2lsbCBmaXJlIHRvIHVwZGF0ZSB0aGUgc2NhbGUgYW5kIGZyYW1lXG4gKlxuICogQHByaXZhdGVcbiAqL1xuU3ByaXRlLnByb3RvdHlwZS5fb25UZXh0dXJlVXBkYXRlID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIHNvIGlmIF93aWR0aCBpcyAwIHRoZW4gd2lkdGggd2FzIG5vdCBzZXQuLlxuICAgIGlmICh0aGlzLl93aWR0aCkge1xuICAgICAgICB0aGlzLnNjYWxlLnggPSB0aGlzLl93aWR0aCAvIHRoaXMudGV4dHVyZS5mcmFtZS53aWR0aDtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5faGVpZ2h0KSB7XG4gICAgICAgIHRoaXMuc2NhbGUueSA9IHRoaXMuX2hlaWdodCAvIHRoaXMudGV4dHVyZS5mcmFtZS5oZWlnaHQ7XG4gICAgfVxufTtcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBib3VuZHMgb2YgdGhlIFNwcml0ZSBhcyBhIHJlY3RhbmdsZS4gVGhlIGJvdW5kcyBjYWxjdWxhdGlvbiB0YWtlcyB0aGUgd29ybGRUcmFuc2Zvcm0gaW50byBhY2NvdW50LlxuICpcbiAqIEBwYXJhbSBtYXRyaXgge01hdHJpeH0gdGhlIHRyYW5zZm9ybWF0aW9uIG1hdHJpeCBvZiB0aGUgc3ByaXRlXG4gKiBAcmV0dXJuIHtSZWN0YW5nbGV9IHRoZSBmcmFtaW5nIHJlY3RhbmdsZVxuICovXG5TcHJpdGUucHJvdG90eXBlLmdldEJvdW5kcyA9IGZ1bmN0aW9uIChtYXRyaXgpIHtcbiAgICB2YXIgd2lkdGggPSB0aGlzLnRleHR1cmUuZnJhbWUud2lkdGg7XG4gICAgdmFyIGhlaWdodCA9IHRoaXMudGV4dHVyZS5mcmFtZS5oZWlnaHQ7XG5cbiAgICB2YXIgdzAgPSB3aWR0aCAqICgxLXRoaXMuYW5jaG9yLngpO1xuICAgIHZhciB3MSA9IHdpZHRoICogLXRoaXMuYW5jaG9yLng7XG5cbiAgICB2YXIgaDAgPSBoZWlnaHQgKiAoMS10aGlzLmFuY2hvci55KTtcbiAgICB2YXIgaDEgPSBoZWlnaHQgKiAtdGhpcy5hbmNob3IueTtcblxuICAgIHZhciB3b3JsZFRyYW5zZm9ybSA9IG1hdHJpeCB8fCB0aGlzLndvcmxkVHJhbnNmb3JtIDtcblxuICAgIHZhciBhID0gd29ybGRUcmFuc2Zvcm0uYTtcbiAgICB2YXIgYiA9IHdvcmxkVHJhbnNmb3JtLmI7XG4gICAgdmFyIGMgPSB3b3JsZFRyYW5zZm9ybS5jO1xuICAgIHZhciBkID0gd29ybGRUcmFuc2Zvcm0uZDtcbiAgICB2YXIgdHggPSB3b3JsZFRyYW5zZm9ybS50eDtcbiAgICB2YXIgdHkgPSB3b3JsZFRyYW5zZm9ybS50eTtcblxuICAgIHZhciBtaW5YLFxuICAgICAgICBtYXhYLFxuICAgICAgICBtaW5ZLFxuICAgICAgICBtYXhZO1xuXG4gICAgaWYoYiA9PT0gMCAmJiBjID09PSAwKVxuICAgIHtcbiAgICAgICAgLy8gc2NhbGUgbWF5IGJlIG5lZ2F0aXZlIVxuICAgICAgICBpZiAoYSA8IDApIHtcbiAgICAgICAgICAgIGEgKj0gLTE7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZCA8IDApIHtcbiAgICAgICAgICAgIGQgKj0gLTE7XG4gICAgICAgIH1cblxuICAgICAgICAvLyB0aGlzIG1lYW5zIHRoZXJlIGlzIG5vIHJvdGF0aW9uIGdvaW5nIG9uIHJpZ2h0PyBSSUdIVD9cbiAgICAgICAgLy8gaWYgdGhhdHMgdGhlIGNhc2UgdGhlbiB3ZSBjYW4gYXZvaWQgY2hlY2tpbmcgdGhlIGJvdW5kIHZhbHVlcyEgeWF5XG4gICAgICAgIG1pblggPSBhICogdzEgKyB0eDtcbiAgICAgICAgbWF4WCA9IGEgKiB3MCArIHR4O1xuICAgICAgICBtaW5ZID0gZCAqIGgxICsgdHk7XG4gICAgICAgIG1heFkgPSBkICogaDAgKyB0eTtcbiAgICB9XG4gICAgZWxzZVxuICAgIHtcbiAgICAgICAgdmFyIHgxID0gYSAqIHcxICsgYyAqIGgxICsgdHg7XG4gICAgICAgIHZhciB5MSA9IGQgKiBoMSArIGIgKiB3MSArIHR5O1xuXG4gICAgICAgIHZhciB4MiA9IGEgKiB3MCArIGMgKiBoMSArIHR4O1xuICAgICAgICB2YXIgeTIgPSBkICogaDEgKyBiICogdzAgKyB0eTtcblxuICAgICAgICB2YXIgeDMgPSBhICogdzAgKyBjICogaDAgKyB0eDtcbiAgICAgICAgdmFyIHkzID0gZCAqIGgwICsgYiAqIHcwICsgdHk7XG5cbiAgICAgICAgdmFyIHg0ID0gIGEgKiB3MSArIGMgKiBoMCArIHR4O1xuICAgICAgICB2YXIgeTQgPSAgZCAqIGgwICsgYiAqIHcxICsgdHk7XG5cbiAgICAgICAgbWluWCA9IHgxO1xuICAgICAgICBtaW5YID0geDIgPCBtaW5YID8geDIgOiBtaW5YO1xuICAgICAgICBtaW5YID0geDMgPCBtaW5YID8geDMgOiBtaW5YO1xuICAgICAgICBtaW5YID0geDQgPCBtaW5YID8geDQgOiBtaW5YO1xuXG4gICAgICAgIG1pblkgPSB5MTtcbiAgICAgICAgbWluWSA9IHkyIDwgbWluWSA/IHkyIDogbWluWTtcbiAgICAgICAgbWluWSA9IHkzIDwgbWluWSA/IHkzIDogbWluWTtcbiAgICAgICAgbWluWSA9IHk0IDwgbWluWSA/IHk0IDogbWluWTtcblxuICAgICAgICBtYXhYID0geDE7XG4gICAgICAgIG1heFggPSB4MiA+IG1heFggPyB4MiA6IG1heFg7XG4gICAgICAgIG1heFggPSB4MyA+IG1heFggPyB4MyA6IG1heFg7XG4gICAgICAgIG1heFggPSB4NCA+IG1heFggPyB4NCA6IG1heFg7XG5cbiAgICAgICAgbWF4WSA9IHkxO1xuICAgICAgICBtYXhZID0geTIgPiBtYXhZID8geTIgOiBtYXhZO1xuICAgICAgICBtYXhZID0geTMgPiBtYXhZID8geTMgOiBtYXhZO1xuICAgICAgICBtYXhZID0geTQgPiBtYXhZID8geTQgOiBtYXhZO1xuICAgIH1cblxuICAgIHZhciBib3VuZHMgPSB0aGlzLl9ib3VuZHM7XG5cbiAgICBib3VuZHMueCA9IG1pblg7XG4gICAgYm91bmRzLndpZHRoID0gbWF4WCAtIG1pblg7XG5cbiAgICBib3VuZHMueSA9IG1pblk7XG4gICAgYm91bmRzLmhlaWdodCA9IG1heFkgLSBtaW5ZO1xuXG4gICAgLy8gc3RvcmUgYSByZWZlcmVuY2Ugc28gdGhhdCBpZiB0aGlzIGZ1bmN0aW9uIGdldHMgY2FsbGVkIGFnYWluIGluIHRoZSByZW5kZXIgY3ljbGUgd2UgZG8gbm90IGhhdmUgdG8gcmVjYWxjdWxhdGVcbiAgICB0aGlzLl9jdXJyZW50Qm91bmRzID0gYm91bmRzO1xuXG4gICAgcmV0dXJuIGJvdW5kcztcbn07XG5cbi8qKlxuKiBSZW5kZXJzIHRoZSBvYmplY3QgdXNpbmcgdGhlIENhbnZhcyByZW5kZXJlclxuKlxuKiBAcGFyYW0gcmVuZGVyZXIge0NhbnZhc1JlbmRlcmVyfSBUaGUgcmVuZGVyZXJcbiovXG5TcHJpdGUucHJvdG90eXBlLnJlbmRlckNhbnZhcyA9IGZ1bmN0aW9uIChyZW5kZXJlcikge1xuICAgIGlmICghdGhpcy52aXNpYmxlIHx8IHRoaXMuYWxwaGEgPD0gMCB8fCB0aGlzLnRleHR1cmUuY3JvcC53aWR0aCA8PSAwIHx8IHRoaXMudGV4dHVyZS5jcm9wLmhlaWdodCA8PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5ibGVuZE1vZGUgIT09IHJlbmRlcmVyLmN1cnJlbnRCbGVuZE1vZGUpIHtcbiAgICAgICAgcmVuZGVyZXIuY3VycmVudEJsZW5kTW9kZSA9IHRoaXMuYmxlbmRNb2RlO1xuICAgICAgICByZW5kZXJlci5jb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9IHJlbmRlcmVyLmJsZW5kTW9kZXNbcmVuZGVyZXIuY3VycmVudEJsZW5kTW9kZV07XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX21hc2spIHtcbiAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucHVzaE1hc2sodGhpcy5fbWFzaywgcmVuZGVyZXIpO1xuICAgIH1cblxuICAgIC8vICBJZ25vcmUgbnVsbCBzb3VyY2VzXG4gICAgaWYgKHRoaXMudGV4dHVyZS52YWxpZCkge1xuICAgICAgICB2YXIgcmVzb2x1dGlvbiA9IHRoaXMudGV4dHVyZS5iYXNlVGV4dHVyZS5yZXNvbHV0aW9uIC8gcmVuZGVyZXIucmVzb2x1dGlvbjtcblxuICAgICAgICByZW5kZXJlci5jb250ZXh0Lmdsb2JhbEFscGhhID0gdGhpcy53b3JsZEFscGhhO1xuXG4gICAgICAgIC8vIElmIHNtb290aGluZ0VuYWJsZWQgaXMgc3VwcG9ydGVkIGFuZCB3ZSBuZWVkIHRvIGNoYW5nZSB0aGUgc21vb3RoaW5nIHByb3BlcnR5IGZvciB0aGlzIHRleHR1cmVcbiAgICAgICAgaWYgKHJlbmRlcmVyLnNtb290aFByb3BlcnR5ICYmIHJlbmRlcmVyLnNjYWxlTW9kZSAhPT0gdGhpcy50ZXh0dXJlLmJhc2VUZXh0dXJlLnNjYWxlTW9kZSkge1xuICAgICAgICAgICAgcmVuZGVyZXIuc2NhbGVNb2RlID0gdGhpcy50ZXh0dXJlLmJhc2VUZXh0dXJlLnNjYWxlTW9kZTtcbiAgICAgICAgICAgIHJlbmRlcmVyLmNvbnRleHRbcmVuZGVyZXIuc21vb3RoUHJvcGVydHldID0gKHJlbmRlcmVyLnNjYWxlTW9kZSA9PT0gQ09OU1Quc2NhbGVNb2Rlcy5MSU5FQVIpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSWYgdGhlIHRleHR1cmUgaXMgdHJpbW1lZCB3ZSBvZmZzZXQgYnkgdGhlIHRyaW0geC95LCBvdGhlcndpc2Ugd2UgdXNlIHRoZSBmcmFtZSBkaW1lbnNpb25zXG4gICAgICAgIHZhciBkeCA9ICh0aGlzLnRleHR1cmUudHJpbSA/IHRoaXMudGV4dHVyZS50cmltLnggOiAwKSAtICh0aGlzLmFuY2hvci54ICogdGhpcy50ZXh0dXJlLnRyaW0ud2lkdGgpO1xuICAgICAgICB2YXIgZHkgPSAodGhpcy50ZXh0dXJlLnRyaW0gPyB0aGlzLnRleHR1cmUudHJpbS55IDogMCkgLSAodGhpcy5hbmNob3IueSAqIHRoaXMudGV4dHVyZS50cmltLmhlaWdodCk7XG5cbiAgICAgICAgLy8gQWxsb3cgZm9yIHBpeGVsIHJvdW5kaW5nXG4gICAgICAgIGlmIChyZW5kZXJlci5yb3VuZFBpeGVscykge1xuICAgICAgICAgICAgcmVuZGVyZXIuY29udGV4dC5zZXRUcmFuc2Zvcm0oXG4gICAgICAgICAgICAgICAgdGhpcy53b3JsZFRyYW5zZm9ybS5hLFxuICAgICAgICAgICAgICAgIHRoaXMud29ybGRUcmFuc2Zvcm0uYixcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkVHJhbnNmb3JtLmMsXG4gICAgICAgICAgICAgICAgdGhpcy53b3JsZFRyYW5zZm9ybS5kLFxuICAgICAgICAgICAgICAgICh0aGlzLndvcmxkVHJhbnNmb3JtLnR4ICogcmVuZGVyZXIucmVzb2x1dGlvbikgfCAwLFxuICAgICAgICAgICAgICAgICh0aGlzLndvcmxkVHJhbnNmb3JtLnR5ICogcmVuZGVyZXIucmVzb2x1dGlvbikgfCAwXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICBkeCA9IGR4IHwgMDtcbiAgICAgICAgICAgIGR5ID0gZHkgfCAwO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmVuZGVyZXIuY29udGV4dC5zZXRUcmFuc2Zvcm0oXG4gICAgICAgICAgICAgICAgdGhpcy53b3JsZFRyYW5zZm9ybS5hLFxuICAgICAgICAgICAgICAgIHRoaXMud29ybGRUcmFuc2Zvcm0uYixcbiAgICAgICAgICAgICAgICB0aGlzLndvcmxkVHJhbnNmb3JtLmMsXG4gICAgICAgICAgICAgICAgdGhpcy53b3JsZFRyYW5zZm9ybS5kLFxuICAgICAgICAgICAgICAgIHRoaXMud29ybGRUcmFuc2Zvcm0udHggKiByZW5kZXJlci5yZXNvbHV0aW9uLFxuICAgICAgICAgICAgICAgIHRoaXMud29ybGRUcmFuc2Zvcm0udHkgKiByZW5kZXJlci5yZXNvbHV0aW9uXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMudGludCAhPT0gMHhGRkZGRkYpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLmNhY2hlZFRpbnQgIT09IHRoaXMudGludCkge1xuICAgICAgICAgICAgICAgIHRoaXMuY2FjaGVkVGludCA9IHRoaXMudGludDtcblxuICAgICAgICAgICAgICAgIC8vIFRPRE8gY2xlYW4gdXAgY2FjaGluZyAtIGhvdyB0byBjbGVhbiB1cCB0aGUgY2FjaGVzP1xuICAgICAgICAgICAgICAgIHRoaXMudGludGVkVGV4dHVyZSA9IENhbnZhc1RpbnRlci5nZXRUaW50ZWRUZXh0dXJlKHRoaXMsIHRoaXMudGludCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJlbmRlcmVyLmNvbnRleHQuZHJhd0ltYWdlKFxuICAgICAgICAgICAgICAgIHRoaXMudGludGVkVGV4dHVyZSxcbiAgICAgICAgICAgICAgICAwLFxuICAgICAgICAgICAgICAgIDAsXG4gICAgICAgICAgICAgICAgdGhpcy50ZXh0dXJlLmNyb3Aud2lkdGgsXG4gICAgICAgICAgICAgICAgdGhpcy50ZXh0dXJlLmNyb3AuaGVpZ2h0LFxuICAgICAgICAgICAgICAgIGR4IC8gcmVzb2x1dGlvbixcbiAgICAgICAgICAgICAgICBkeSAvIHJlc29sdXRpb24sXG4gICAgICAgICAgICAgICAgdGhpcy50ZXh0dXJlLmNyb3Aud2lkdGggLyByZXNvbHV0aW9uLFxuICAgICAgICAgICAgICAgIHRoaXMudGV4dHVyZS5jcm9wLmhlaWdodCAvIHJlc29sdXRpb25cbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZW5kZXJlci5jb250ZXh0LmRyYXdJbWFnZShcbiAgICAgICAgICAgICAgICB0aGlzLnRleHR1cmUuYmFzZVRleHR1cmUuc291cmNlLFxuICAgICAgICAgICAgICAgIHRoaXMudGV4dHVyZS5jcm9wLngsXG4gICAgICAgICAgICAgICAgdGhpcy50ZXh0dXJlLmNyb3AueSxcbiAgICAgICAgICAgICAgICB0aGlzLnRleHR1cmUuY3JvcC53aWR0aCxcbiAgICAgICAgICAgICAgICB0aGlzLnRleHR1cmUuY3JvcC5oZWlnaHQsXG4gICAgICAgICAgICAgICAgZHggLyByZXNvbHV0aW9uLFxuICAgICAgICAgICAgICAgIGR5IC8gcmVzb2x1dGlvbixcbiAgICAgICAgICAgICAgICB0aGlzLnRleHR1cmUuY3JvcC53aWR0aCAvIHJlc29sdXRpb24sXG4gICAgICAgICAgICAgICAgdGhpcy50ZXh0dXJlLmNyb3AuaGVpZ2h0IC8gcmVzb2x1dGlvblxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZvciAodmFyIGkgPSAwLCBqID0gdGhpcy5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyBpKyspIHtcbiAgICAgICAgdGhpcy5jaGlsZHJlbltpXS5yZW5kZXJDYW52YXMocmVuZGVyZXIpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLl9tYXNrKSB7XG4gICAgICAgIHJlbmRlcmVyLm1hc2tNYW5hZ2VyLnBvcE1hc2socmVuZGVyZXIpO1xuICAgIH1cbn07XG5cbi8vIHNvbWUgaGVscGVyIGZ1bmN0aW9ucy4uXG5cbi8qKlxuICogSGVscGVyIGZ1bmN0aW9uIHRoYXQgY3JlYXRlcyBhIHNwcml0ZSB0aGF0IHdpbGwgY29udGFpbiBhIHRleHR1cmUgZnJvbSB0aGUgVGV4dHVyZUNhY2hlIGJhc2VkIG9uIHRoZSBmcmFtZUlkXG4gKiBUaGUgZnJhbWUgaWRzIGFyZSBjcmVhdGVkIHdoZW4gYSBUZXh0dXJlIHBhY2tlciBmaWxlIGhhcyBiZWVuIGxvYWRlZFxuICpcbiAqIEBzdGF0aWNcbiAqIEBwYXJhbSBmcmFtZUlkIHtTdHJpbmd9IFRoZSBmcmFtZSBJZCBvZiB0aGUgdGV4dHVyZSBpbiB0aGUgY2FjaGVcbiAqIEByZXR1cm4ge1Nwcml0ZX0gQSBuZXcgU3ByaXRlIHVzaW5nIGEgdGV4dHVyZSBmcm9tIHRoZSB0ZXh0dXJlIGNhY2hlIG1hdGNoaW5nIHRoZSBmcmFtZUlkXG4gKi9cblNwcml0ZS5mcm9tRnJhbWUgPSBmdW5jdGlvbiAoZnJhbWVJZCkge1xuICAgIHZhciB0ZXh0dXJlID0gdXRpbHMuVGV4dHVyZUNhY2hlW2ZyYW1lSWRdO1xuXG4gICAgaWYgKCF0ZXh0dXJlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVGhlIGZyYW1lSWQgXCInICsgZnJhbWVJZCArICdcIiBkb2VzIG5vdCBleGlzdCBpbiB0aGUgdGV4dHVyZSBjYWNoZScgKyB0aGlzKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IFNwcml0ZSh0ZXh0dXJlKTtcbn07XG5cbi8qKlxuICogSGVscGVyIGZ1bmN0aW9uIHRoYXQgY3JlYXRlcyBhIHNwcml0ZSB0aGF0IHdpbGwgY29udGFpbiBhIHRleHR1cmUgYmFzZWQgb24gYW4gaW1hZ2UgdXJsXG4gKiBJZiB0aGUgaW1hZ2UgaXMgbm90IGluIHRoZSB0ZXh0dXJlIGNhY2hlIGl0IHdpbGwgYmUgbG9hZGVkXG4gKlxuICogQHN0YXRpY1xuICogQHBhcmFtIGltYWdlSWQge1N0cmluZ30gVGhlIGltYWdlIHVybCBvZiB0aGUgdGV4dHVyZVxuICogQHJldHVybiB7U3ByaXRlfSBBIG5ldyBTcHJpdGUgdXNpbmcgYSB0ZXh0dXJlIGZyb20gdGhlIHRleHR1cmUgY2FjaGUgbWF0Y2hpbmcgdGhlIGltYWdlIGlkXG4gKi9cblNwcml0ZS5mcm9tSW1hZ2UgPSBmdW5jdGlvbiAoaW1hZ2VJZCwgY3Jvc3NvcmlnaW4sIHNjYWxlTW9kZSkge1xuICAgIHJldHVybiBuZXcgU3ByaXRlKFRleHR1cmUuZnJvbUltYWdlKGltYWdlSWQsIGNyb3Nzb3JpZ2luLCBzY2FsZU1vZGUpKTtcbn07XG4iLCJ2YXIgRGlzcGxheU9iamVjdENvbnRhaW5lciA9IHJlcXVpcmUoJy4vRGlzcGxheU9iamVjdENvbnRhaW5lcicpLFxuICAgIFdlYkdMRmFzdFNwcml0ZUJhdGNoID0gcmVxdWlyZSgnLi4vcmVuZGVyZXJzL3dlYmdsL3V0aWxzL1dlYkdMRmFzdFNwcml0ZUJhdGNoJyk7XG5cbi8qKlxuICogVGhlIFNwcml0ZUJhdGNoIGNsYXNzIGlzIGEgcmVhbGx5IGZhc3QgdmVyc2lvbiBvZiB0aGUgRGlzcGxheU9iamVjdENvbnRhaW5lciBidWlsdCBzb2xlbHkgZm9yIHNwZWVkLFxuICogc28gdXNlIHdoZW4geW91IG5lZWQgYSBsb3Qgb2Ygc3ByaXRlcyBvciBwYXJ0aWNsZXMuIFRoZSB0cmFkZW9mZiBvZiB0aGUgU3ByaXRlQmF0Y2ggaXMgdGhhdCBhZHZhbmNlZFxuICogZnVuY3Rpb25hbGl0eSB3aWxsIG5vdCB3b3JrLiBTcHJpdGVCYXRjaCBpbXBsZW1lbnRzIG9ubHkgdGhlIGJhc2ljIG9iamVjdCB0cmFuc2Zvcm0gKHBvc2l0aW9uLCBzY2FsZSwgcm90YXRpb24pLlxuICogQW55IG90aGVyIGZ1bmN0aW9uYWxpdHkgbGlrZSB0aW50aW5nLCBtYXNraW5nLCBldGMgd2lsbCBub3Qgd29yayBvbiBzcHJpdGVzIGluIHRoaXMgYmF0Y2guXG4gKlxuICogSXQncyBleHRyZW1lbHkgZWFzeSB0byB1c2UgOlxuICpcbiAqIGBgYGpzXG4gKiB2YXIgY29udGFpbmVyID0gbmV3IFNwcml0ZUJhdGNoKCk7XG4gKlxuICogZm9yKHZhciBpID0gMDsgaSA8IDEwMDsgKytpKSB7XG4gKiAgICAgdmFyIHNwcml0ZSA9IG5ldyBQSVhJLlNwcml0ZS5mcm9tSW1hZ2UoXCJteUltYWdlLnBuZ1wiKTtcbiAqICAgICBjb250YWluZXIuYWRkQ2hpbGQoc3ByaXRlKTtcbiAqIH1cbiAqIGBgYFxuICpcbiAqIEFuZCBoZXJlIHlvdSBoYXZlIGEgaHVuZHJlZCBzcHJpdGVzIHRoYXQgd2lsbCBiZSByZW5kZXJlciBhdCB0aGUgc3BlZWQgb2YgbGlnaHQuXG4gKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuXG4vL1RPRE8gUkVOQU1FIHRvIFBBUlRJQ0xFIENPTlRBSU5FUj9cbmZ1bmN0aW9uIFNwcml0ZUJhdGNoKCkge1xuICAgIERpc3BsYXlPYmplY3RDb250YWluZXIuY2FsbCh0aGlzKTtcbn1cblxuU3ByaXRlQmF0Y2gucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShEaXNwbGF5T2JqZWN0Q29udGFpbmVyLnByb3RvdHlwZSk7XG5TcHJpdGVCYXRjaC5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBTcHJpdGVCYXRjaDtcbm1vZHVsZS5leHBvcnRzID0gU3ByaXRlQmF0Y2g7XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgb2JqZWN0IHRyYW5zZm9ybSBmb3IgcmVuZGVyaW5nXG4gKlxuICogQHByaXZhdGVcbiAqL1xuU3ByaXRlQmF0Y2gucHJvdG90eXBlLnVwZGF0ZVRyYW5zZm9ybSA9IGZ1bmN0aW9uICgpIHtcbiAgICAvLyBUT0RPIGRvbid0IG5lZWQgdG8hXG4gICAgdGhpcy5kaXNwbGF5T2JqZWN0VXBkYXRlVHJhbnNmb3JtKCk7XG4gICAgLy8gIFBJWEkuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUudXBkYXRlVHJhbnNmb3JtLmNhbGwoIHRoaXMgKTtcbn07XG5cbi8qKlxuICogUmVuZGVycyB0aGUgb2JqZWN0IHVzaW5nIHRoZSBXZWJHTCByZW5kZXJlclxuICpcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcn0gVGhlIHdlYmdsIHJlbmRlcmVyXG4gKiBAcHJpdmF0ZVxuICovXG5TcHJpdGVCYXRjaC5wcm90b3R5cGUucmVuZGVyV2ViR0wgPSBmdW5jdGlvbiAocmVuZGVyZXIpIHtcbiAgICBpZiAoIXRoaXMudmlzaWJsZSB8fCB0aGlzLmFscGhhIDw9IDAgfHwgIXRoaXMuY2hpbGRyZW4ubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5zdG9wKCk7XG5cbiAgICByZW5kZXJlci5zaGFkZXJNYW5hZ2VyLnNldFNoYWRlcihyZW5kZXJlci5zaGFkZXJNYW5hZ2VyLmZhc3RTaGFkZXIpO1xuXG4gICAgcmVuZGVyZXIuZmFzdFNwcml0ZUJhdGNoLmJlZ2luKHRoaXMpO1xuICAgIHJlbmRlcmVyLmZhc3RTcHJpdGVCYXRjaC5yZW5kZXIodGhpcyk7XG5cbiAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5zdGFydCgpO1xufTtcblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBvYmplY3QgdXNpbmcgdGhlIENhbnZhcyByZW5kZXJlclxuICpcbiAqIEBwYXJhbSByZW5kZXJlciB7Q2FudmFzUmVuZGVyZXJ9IFRoZSBjYW52YXMgcmVuZGVyZXJcbiAqIEBwcml2YXRlXG4gKi9cblNwcml0ZUJhdGNoLnByb3RvdHlwZS5yZW5kZXJDYW52YXMgPSBmdW5jdGlvbiAocmVuZGVyZXIpIHtcbiAgICBpZiAoIXRoaXMudmlzaWJsZSB8fCB0aGlzLmFscGhhIDw9IDAgfHwgIXRoaXMuY2hpbGRyZW4ubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgY29udGV4dCA9IHJlbmRlcmVyLmNvbnRleHQ7XG4gICAgdmFyIHRyYW5zZm9ybSA9IHRoaXMud29ybGRUcmFuc2Zvcm07XG4gICAgdmFyIGlzUm90YXRlZCA9IHRydWU7XG5cbiAgICBjb250ZXh0Lmdsb2JhbEFscGhhID0gdGhpcy53b3JsZEFscGhhO1xuXG4gICAgdGhpcy5kaXNwbGF5T2JqZWN0VXBkYXRlVHJhbnNmb3JtKCk7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgdmFyIGNoaWxkID0gdGhpcy5jaGlsZHJlbltpXTtcblxuICAgICAgICBpZiAoIWNoaWxkLnZpc2libGUpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGZyYW1lID0gY2hpbGQudGV4dHVyZS5mcmFtZTtcblxuICAgICAgICBjb250ZXh0Lmdsb2JhbEFscGhhID0gdGhpcy53b3JsZEFscGhhICogY2hpbGQuYWxwaGE7XG5cbiAgICAgICAgaWYgKGNoaWxkLnJvdGF0aW9uICUgKE1hdGguUEkgKiAyKSA9PT0gMCkge1xuICAgICAgICAgICAgLy8gdGhpcyBpcyB0aGUgZmFzdGVzdCAgd2F5IHRvIG9wdGltaXNlISAtIGlmIHJvdGF0aW9uIGlzIDAgdGhlbiB3ZSBjYW4gYXZvaWQgYW55IGtpbmQgb2Ygc2V0VHJhbnNmb3JtIGNhbGxcbiAgICAgICAgICAgIGlmIChpc1JvdGF0ZWQpIHtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnNldFRyYW5zZm9ybShcbiAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtLmEsXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybS5iLFxuICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0uYyxcbiAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtLmQsXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybS50eCxcbiAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtLnR5XG4gICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgIGlzUm90YXRlZCA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb250ZXh0LmRyYXdJbWFnZShcbiAgICAgICAgICAgICAgICBjaGlsZC50ZXh0dXJlLmJhc2VUZXh0dXJlLnNvdXJjZSxcbiAgICAgICAgICAgICAgICBmcmFtZS54LFxuICAgICAgICAgICAgICAgIGZyYW1lLnksXG4gICAgICAgICAgICAgICAgZnJhbWUud2lkdGgsXG4gICAgICAgICAgICAgICAgZnJhbWUuaGVpZ2h0LFxuICAgICAgICAgICAgICAgICgoY2hpbGQuYW5jaG9yLngpICogKC1mcmFtZS53aWR0aCAqIGNoaWxkLnNjYWxlLngpICsgY2hpbGQucG9zaXRpb24ueCAgKyAwLjUpIHwgMCxcbiAgICAgICAgICAgICAgICAoKGNoaWxkLmFuY2hvci55KSAqICgtZnJhbWUuaGVpZ2h0ICogY2hpbGQuc2NhbGUueSkgKyBjaGlsZC5wb3NpdGlvbi55ICArIDAuNSkgfCAwLFxuICAgICAgICAgICAgICAgIGZyYW1lLndpZHRoICogY2hpbGQuc2NhbGUueCxcbiAgICAgICAgICAgICAgICBmcmFtZS5oZWlnaHQgKiBjaGlsZC5zY2FsZS55XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgaWYgKCFpc1JvdGF0ZWQpIHtcbiAgICAgICAgICAgICAgICBpc1JvdGF0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjaGlsZC5kaXNwbGF5T2JqZWN0VXBkYXRlVHJhbnNmb3JtKCk7XG5cbiAgICAgICAgICAgIHZhciBjaGlsZFRyYW5zZm9ybSA9IGNoaWxkLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgICAgICAgICBpZiAocmVuZGVyZXIucm91bmRQaXhlbHMpIHtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnNldFRyYW5zZm9ybShcbiAgICAgICAgICAgICAgICAgICAgY2hpbGRUcmFuc2Zvcm0uYSxcbiAgICAgICAgICAgICAgICAgICAgY2hpbGRUcmFuc2Zvcm0uYixcbiAgICAgICAgICAgICAgICAgICAgY2hpbGRUcmFuc2Zvcm0uYyxcbiAgICAgICAgICAgICAgICAgICAgY2hpbGRUcmFuc2Zvcm0uZCxcbiAgICAgICAgICAgICAgICAgICAgY2hpbGRUcmFuc2Zvcm0udHggfCAwLFxuICAgICAgICAgICAgICAgICAgICBjaGlsZFRyYW5zZm9ybS50eSB8IDBcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5zZXRUcmFuc2Zvcm0oXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkVHJhbnNmb3JtLmEsXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkVHJhbnNmb3JtLmIsXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkVHJhbnNmb3JtLmMsXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkVHJhbnNmb3JtLmQsXG4gICAgICAgICAgICAgICAgICAgIGNoaWxkVHJhbnNmb3JtLnR4LFxuICAgICAgICAgICAgICAgICAgICBjaGlsZFRyYW5zZm9ybS50eVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnRleHQuZHJhd0ltYWdlKFxuICAgICAgICAgICAgICAgIGNoaWxkLnRleHR1cmUuYmFzZVRleHR1cmUuc291cmNlLFxuICAgICAgICAgICAgICAgIGZyYW1lLngsXG4gICAgICAgICAgICAgICAgZnJhbWUueSxcbiAgICAgICAgICAgICAgICBmcmFtZS53aWR0aCxcbiAgICAgICAgICAgICAgICBmcmFtZS5oZWlnaHQsXG4gICAgICAgICAgICAgICAgKChjaGlsZC5hbmNob3IueCkgKiAoLWZyYW1lLndpZHRoKSArIDAuNSkgfCAwLFxuICAgICAgICAgICAgICAgICgoY2hpbGQuYW5jaG9yLnkpICogKC1mcmFtZS5oZWlnaHQpICsgMC41KSB8IDAsXG4gICAgICAgICAgICAgICAgZnJhbWUud2lkdGgsXG4gICAgICAgICAgICAgICAgZnJhbWUuaGVpZ2h0XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxufTtcbiIsIi8qKlxuICogQGZpbGUgICAgICAgIE1haW4gZXhwb3J0IG9mIHRoZSBQSVhJIGNvcmUgbGlicmFyeVxuICogQGF1dGhvciAgICAgIE1hdCBHcm92ZXMgPG1hdEBnb29kYm95ZGlnaXRhbC5jb20+XG4gKiBAY29weXJpZ2h0ICAgMjAxMy0yMDE1IEdvb2RCb3lEaWdpdGFsXG4gKiBAbGljZW5zZSAgICAge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9Hb29kQm95RGlnaXRhbC9waXhpLmpzL2Jsb2IvbWFzdGVyL0xJQ0VOU0V8TUlUIExpY2Vuc2V9XG4gKi9cblxuLyoqXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xudmFyIGNvcmUgPSBtb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBDT05TVDogcmVxdWlyZSgnLi9jb25zdCcpLFxuXG4gICAgLy8gdXRpbHNcbiAgICB1dGlsczogcmVxdWlyZSgnLi91dGlscycpLFxuICAgIG1hdGg6IHJlcXVpcmUoJy4vbWF0aCcpLFxuXG4gICAgLy8gZGlzcGxheVxuICAgIERpc3BsYXlPYmplY3Q6ICAgICAgICAgIHJlcXVpcmUoJy4vZGlzcGxheS9EaXNwbGF5T2JqZWN0JyksXG4gICAgRGlzcGxheU9iamVjdENvbnRhaW5lcjogcmVxdWlyZSgnLi9kaXNwbGF5L0Rpc3BsYXlPYmplY3RDb250YWluZXInKSxcbiAgICBTcHJpdGU6ICAgICAgICAgICAgICAgICByZXF1aXJlKCcuL2Rpc3BsYXkvU3ByaXRlJyksXG4gICAgU3ByaXRlQmF0Y2g6ICAgICAgICAgICAgcmVxdWlyZSgnLi9kaXNwbGF5L1Nwcml0ZUJhdGNoJyksXG5cbiAgICAvLyBwcmltaXRpdmVzXG4gICAgR3JhcGhpY3M6ICAgICAgICAgICAgICAgcmVxdWlyZSgnLi9wcmltaXRpdmVzL0dyYXBoaWNzJyksXG4gICAgR3JhcGhpY3NEYXRhOiAgICAgICAgICAgcmVxdWlyZSgnLi9wcmltaXRpdmVzL0dyYXBoaWNzRGF0YScpLFxuXG4gICAgLy8gdGV4dHVyZXNcbiAgICBUZXh0dXJlOiAgICAgICAgICAgICAgICByZXF1aXJlKCcuL3RleHR1cmVzL1RleHR1cmUnKSxcbiAgICBCYXNlVGV4dHVyZTogICAgICAgICAgICByZXF1aXJlKCcuL3RleHR1cmVzL0Jhc2VUZXh0dXJlJyksXG4gICAgUmVuZGVyVGV4dHVyZTogICAgICAgICAgcmVxdWlyZSgnLi90ZXh0dXJlcy9SZW5kZXJUZXh0dXJlJyksXG4gICAgVmlkZW9CYXNlVGV4dHVyZTogICAgICAgcmVxdWlyZSgnLi90ZXh0dXJlcy9WaWRlb0Jhc2VUZXh0dXJlJyksXG5cbiAgICAvLyByZW5kZXJlcnMgLSBjYW52YXNcbiAgICBDYW52YXNSZW5kZXJlcjogICAgICAgICByZXF1aXJlKCcuL3JlbmRlcmVycy9jYW52YXMvQ2FudmFzUmVuZGVyZXInKSxcbiAgICBDYW52YXNHcmFwaGljczogICAgICAgICByZXF1aXJlKCcuL3JlbmRlcmVycy9jYW52YXMvdXRpbHMvQ2FudmFzR3JhcGhpY3MnKSxcbiAgICBDYW52YXNCdWZmZXI6ICAgICAgICAgICByZXF1aXJlKCcuL3JlbmRlcmVycy9jYW52YXMvdXRpbHMvQ2FudmFzQnVmZmVyJyksXG5cbiAgICAvLyByZW5kZXJlcnMgLSB3ZWJnbFxuICAgIFdlYkdMUmVuZGVyZXI6ICAgICAgICAgcmVxdWlyZSgnLi9yZW5kZXJlcnMvd2ViZ2wvV2ViR0xSZW5kZXJlcicpLFxuICAgIFdlYkdMR3JhcGhpY3M6ICAgICAgICAgcmVxdWlyZSgnLi9yZW5kZXJlcnMvd2ViZ2wvdXRpbHMvV2ViR0xHcmFwaGljcycpLFxuXG4gICAgLyoqXG4gICAgICogVGhpcyBoZWxwZXIgZnVuY3Rpb24gd2lsbCBhdXRvbWF0aWNhbGx5IGRldGVjdCB3aGljaCByZW5kZXJlciB5b3Ugc2hvdWxkIGJlIHVzaW5nLlxuICAgICAqIFdlYkdMIGlzIHRoZSBwcmVmZXJyZWQgcmVuZGVyZXIgYXMgaXQgaXMgYSBsb3QgZmFzdGVyLiBJZiB3ZWJHTCBpcyBub3Qgc3VwcG9ydGVkIGJ5XG4gICAgICogdGhlIGJyb3dzZXIgdGhlbiB0aGlzIGZ1bmN0aW9uIHdpbGwgcmV0dXJuIGEgY2FudmFzIHJlbmRlcmVyXG4gICAgICpcbiAgICAgKiBAcGFyYW0gd2lkdGg9ODAwIHtudW1iZXJ9IHRoZSB3aWR0aCBvZiB0aGUgcmVuZGVyZXJzIHZpZXdcbiAgICAgKiBAcGFyYW0gaGVpZ2h0PTYwMCB7bnVtYmVyfSB0aGUgaGVpZ2h0IG9mIHRoZSByZW5kZXJlcnMgdmlld1xuICAgICAqIEBwYXJhbSBbb3B0aW9uc10ge29iamVjdH0gVGhlIG9wdGlvbmFsIHJlbmRlcmVyIHBhcmFtZXRlcnNcbiAgICAgKiBAcGFyYW0gW29wdGlvbnMudmlld10ge0hUTUxDYW52YXNFbGVtZW50fSB0aGUgY2FudmFzIHRvIHVzZSBhcyBhIHZpZXcsIG9wdGlvbmFsXG4gICAgICogQHBhcmFtIFtvcHRpb25zLnRyYW5zcGFyZW50PWZhbHNlXSB7Ym9vbGVhbn0gSWYgdGhlIHJlbmRlciB2aWV3IGlzIHRyYW5zcGFyZW50LCBkZWZhdWx0IGZhbHNlXG4gICAgICogQHBhcmFtIFtvcHRpb25zLmFudGlhbGlhcz1mYWxzZV0ge2Jvb2xlYW59IHNldHMgYW50aWFsaWFzIChvbmx5IGFwcGxpY2FibGUgaW4gY2hyb21lIGF0IHRoZSBtb21lbnQpXG4gICAgICogQHBhcmFtIFtvcHRpb25zLnByZXNlcnZlRHJhd2luZ0J1ZmZlcj1mYWxzZV0ge2Jvb2xlYW59IGVuYWJsZXMgZHJhd2luZyBidWZmZXIgcHJlc2VydmF0aW9uLCBlbmFibGUgdGhpcyBpZiB5b3VcbiAgICAgKiAgICAgIG5lZWQgdG8gY2FsbCB0b0RhdGFVcmwgb24gdGhlIHdlYmdsIGNvbnRleHRcbiAgICAgKiBAcGFyYW0gW29wdGlvbnMucmVzb2x1dGlvbj0xXSB7bnVtYmVyfSB0aGUgcmVzb2x1dGlvbiBvZiB0aGUgcmVuZGVyZXIgcmV0aW5hIHdvdWxkIGJlIDJcbiAgICAgKiBAcGFyYW0gW25vV2ViR0w9ZmFsc2VdIHtCb29sZWFufSBwcmV2ZW50cyBzZWxlY3Rpb24gb2YgV2ViR0wgcmVuZGVyZXIsIGV2ZW4gaWYgc3VjaCBpcyBwcmVzZW50XG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHtXZWJHTFJlbmRlcmVyfENhbnZhc1JlbmRlcmVyfSBSZXR1cm5zIFdlYkdMIHJlbmRlcmVyIGlmIGF2YWlsYWJsZSwgb3RoZXJ3aXNlIENhbnZhc1JlbmRlcmVyXG4gICAgICovXG4gICAgYXV0b0RldGVjdFJlbmRlcmVyOiBmdW5jdGlvbiAod2lkdGgsIGhlaWdodCwgb3B0aW9ucywgbm9XZWJHTCkge1xuICAgICAgICB3aWR0aCA9IHdpZHRoIHx8IDgwMDtcbiAgICAgICAgaGVpZ2h0ID0gaGVpZ2h0IHx8IDYwMDtcblxuICAgICAgICBpZiAoIW5vV2ViR0wgJiYgcmVxdWlyZSgnd2ViZ2wtZW5hYmxlZCcpKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgY29yZS5XZWJHTFJlbmRlcmVyKHdpZHRoLCBoZWlnaHQsIG9wdGlvbnMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5ldyBjb3JlLkNhbnZhc1JlbmRlcmVyKHdpZHRoLCBoZWlnaHQsIG9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGlzIGhlbHBlciBmdW5jdGlvbiB3aWxsIGF1dG9tYXRpY2FsbHkgZGV0ZWN0IHdoaWNoIHJlbmRlcmVyIHlvdSBzaG91bGQgYmUgdXNpbmcuIFRoaXMgZnVuY3Rpb24gaXMgdmVyeVxuICAgICAqIHNpbWlsYXIgdG8gdGhlIGF1dG9EZXRlY3RSZW5kZXJlciBmdW5jdGlvbiBleGNlcHQgdGhhdCBpcyB3aWxsIHJldHVybiBhIGNhbnZhcyByZW5kZXJlciBmb3IgYW5kcm9pZC5cbiAgICAgKiBFdmVuIHRob3VnaHQgYm90aCBhbmRyb2lkIGNocm9tZSBzdXBwb3J0cyB3ZWJHTCB0aGUgY2FudmFzIGltcGxlbWVudGF0aW9uIHBlcmZvcm0gYmV0dGVyIGF0IHRoZSB0aW1lIG9mIHdyaXRpbmcuXG4gICAgICogVGhpcyBmdW5jdGlvbiB3aWxsIGxpa2VseSBjaGFuZ2UgYW5kIHVwZGF0ZSBhcyB3ZWJHTCBwZXJmb3JtYW5jZSBpbXByb3ZlcyBvbiB0aGVzZSBkZXZpY2VzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHdpZHRoPTgwMCB7bnVtYmVyfSB0aGUgd2lkdGggb2YgdGhlIHJlbmRlcmVycyB2aWV3XG4gICAgICogQHBhcmFtIGhlaWdodD02MDAge251bWJlcn0gdGhlIGhlaWdodCBvZiB0aGUgcmVuZGVyZXJzIHZpZXdcbiAgICAgKiBAcGFyYW0gW29wdGlvbnNdIHtvYmplY3R9IFRoZSBvcHRpb25hbCByZW5kZXJlciBwYXJhbWV0ZXJzXG4gICAgICogQHBhcmFtIFtvcHRpb25zLnZpZXddIHtIVE1MQ2FudmFzRWxlbWVudH0gdGhlIGNhbnZhcyB0byB1c2UgYXMgYSB2aWV3LCBvcHRpb25hbFxuICAgICAqIEBwYXJhbSBbb3B0aW9ucy50cmFuc3BhcmVudD1mYWxzZV0ge2Jvb2xlYW59IElmIHRoZSByZW5kZXIgdmlldyBpcyB0cmFuc3BhcmVudCwgZGVmYXVsdCBmYWxzZVxuICAgICAqIEBwYXJhbSBbb3B0aW9ucy5hbnRpYWxpYXM9ZmFsc2VdIHtib29sZWFufSBzZXRzIGFudGlhbGlhcyAob25seSBhcHBsaWNhYmxlIGluIGNocm9tZSBhdCB0aGUgbW9tZW50KVxuICAgICAqIEBwYXJhbSBbb3B0aW9ucy5wcmVzZXJ2ZURyYXdpbmdCdWZmZXI9ZmFsc2VdIHtib29sZWFufSBlbmFibGVzIGRyYXdpbmcgYnVmZmVyIHByZXNlcnZhdGlvbiwgZW5hYmxlIHRoaXMgaWYgeW91XG4gICAgICogICAgICBuZWVkIHRvIGNhbGwgdG9EYXRhVXJsIG9uIHRoZSB3ZWJnbCBjb250ZXh0XG4gICAgICogQHBhcmFtIFtvcHRpb25zLnJlc29sdXRpb249MV0ge251bWJlcn0gdGhlIHJlc29sdXRpb24gb2YgdGhlIHJlbmRlcmVyIHJldGluYSB3b3VsZCBiZSAyXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHtXZWJHTFJlbmRlcmVyfENhbnZhc1JlbmRlcmVyfSBSZXR1cm5zIFdlYkdMIHJlbmRlcmVyIGlmIGF2YWlsYWJsZSwgb3RoZXJ3aXNlIENhbnZhc1JlbmRlcmVyXG4gICAgICovXG4gICAgYXV0b0RldGVjdFJlY29tbWVuZGVkUmVuZGVyZXI6IGZ1bmN0aW9uICh3aWR0aCwgaGVpZ2h0LCBvcHRpb25zKSB7XG4gICAgICAgIHZhciBpc0FuZHJvaWQgPSAvQW5kcm9pZC9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCk7XG5cbiAgICAgICAgcmV0dXJuIGNvcmUuYXV0b0RldGVjdFJlbmRlcmVyKHdpZHRoLCBoZWlnaHQsIG9wdGlvbnMsIGlzQW5kcm9pZCk7XG4gICAgfVxufTtcbiIsInZhciBQb2ludCA9IHJlcXVpcmUoJy4vUG9pbnQnKTtcblxuLyoqXG4gKiBUaGUgTWF0cml4IGNsYXNzIGlzIG5vdyBhbiBvYmplY3QsIHdoaWNoIG1ha2VzIGl0IGEgbG90IGZhc3RlcixcbiAqIGhlcmUgaXMgYSByZXByZXNlbnRhdGlvbiBvZiBpdCA6XG4gKiB8IGEgfCBiIHwgdHh8XG4gKiB8IGMgfCBkIHwgdHl8XG4gKiB8IDAgfCAwIHwgMSB8XG4gKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gTWF0cml4KCkge1xuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAxXG4gICAgICovXG4gICAgdGhpcy5hID0gMTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy5iID0gMDtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy5jID0gMDtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAxXG4gICAgICovXG4gICAgdGhpcy5kID0gMTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy50eCA9IDA7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMudHkgPSAwO1xufVxuXG5NYXRyaXgucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gTWF0cml4O1xubW9kdWxlLmV4cG9ydHMgPSBNYXRyaXg7XG5cbi8qKlxuICogQ3JlYXRlcyBhIE1hdHJpeCBvYmplY3QgYmFzZWQgb24gdGhlIGdpdmVuIGFycmF5LiBUaGUgRWxlbWVudCB0byBNYXRyaXggbWFwcGluZyBvcmRlciBpcyBhcyBmb2xsb3dzOlxuICpcbiAqIGEgPSBhcnJheVswXVxuICogYiA9IGFycmF5WzFdXG4gKiBjID0gYXJyYXlbM11cbiAqIGQgPSBhcnJheVs0XVxuICogdHggPSBhcnJheVsyXVxuICogdHkgPSBhcnJheVs1XVxuICpcbiAqIEBwYXJhbSBhcnJheSB7bnVtYmVyW119IFRoZSBhcnJheSB0aGF0IHRoZSBtYXRyaXggd2lsbCBiZSBwb3B1bGF0ZWQgZnJvbS5cbiAqL1xuTWF0cml4LnByb3RvdHlwZS5mcm9tQXJyYXkgPSBmdW5jdGlvbiAoYXJyYXkpIHtcbiAgICB0aGlzLmEgPSBhcnJheVswXTtcbiAgICB0aGlzLmIgPSBhcnJheVsxXTtcbiAgICB0aGlzLmMgPSBhcnJheVszXTtcbiAgICB0aGlzLmQgPSBhcnJheVs0XTtcbiAgICB0aGlzLnR4ID0gYXJyYXlbMl07XG4gICAgdGhpcy50eSA9IGFycmF5WzVdO1xufTtcblxuLyoqXG4gKiBDcmVhdGVzIGFuIGFycmF5IGZyb20gdGhlIGN1cnJlbnQgTWF0cml4IG9iamVjdC5cbiAqXG4gKiBAcGFyYW0gdHJhbnNwb3NlIHtib29sZWFufSBXaGV0aGVyIHdlIG5lZWQgdG8gdHJhbnNwb3NlIHRoZSBtYXRyaXggb3Igbm90XG4gKiBAcmV0dXJuIHtudW1iZXJbXX0gdGhlIG5ld2x5IGNyZWF0ZWQgYXJyYXkgd2hpY2ggY29udGFpbnMgdGhlIG1hdHJpeFxuICovXG5NYXRyaXgucHJvdG90eXBlLnRvQXJyYXkgPSBmdW5jdGlvbiAodHJhbnNwb3NlKSB7XG4gICAgaWYgKCF0aGlzLmFycmF5KSB7XG4gICAgICAgIHRoaXMuYXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KDkpO1xuICAgIH1cblxuICAgIHZhciBhcnJheSA9IHRoaXMuYXJyYXk7XG5cbiAgICBpZiAodHJhbnNwb3NlKSB7XG4gICAgICAgIGFycmF5WzBdID0gdGhpcy5hO1xuICAgICAgICBhcnJheVsxXSA9IHRoaXMuYjtcbiAgICAgICAgYXJyYXlbMl0gPSAwO1xuICAgICAgICBhcnJheVszXSA9IHRoaXMuYztcbiAgICAgICAgYXJyYXlbNF0gPSB0aGlzLmQ7XG4gICAgICAgIGFycmF5WzVdID0gMDtcbiAgICAgICAgYXJyYXlbNl0gPSB0aGlzLnR4O1xuICAgICAgICBhcnJheVs3XSA9IHRoaXMudHk7XG4gICAgICAgIGFycmF5WzhdID0gMTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGFycmF5WzBdID0gdGhpcy5hO1xuICAgICAgICBhcnJheVsxXSA9IHRoaXMuYztcbiAgICAgICAgYXJyYXlbMl0gPSB0aGlzLnR4O1xuICAgICAgICBhcnJheVszXSA9IHRoaXMuYjtcbiAgICAgICAgYXJyYXlbNF0gPSB0aGlzLmQ7XG4gICAgICAgIGFycmF5WzVdID0gdGhpcy50eTtcbiAgICAgICAgYXJyYXlbNl0gPSAwO1xuICAgICAgICBhcnJheVs3XSA9IDA7XG4gICAgICAgIGFycmF5WzhdID0gMTtcbiAgICB9XG5cbiAgICByZXR1cm4gYXJyYXk7XG59O1xuXG4vKipcbiAqIEdldCBhIG5ldyBwb3NpdGlvbiB3aXRoIHRoZSBjdXJyZW50IHRyYW5zZm9ybWF0aW9uIGFwcGxpZWQuXG4gKiBDYW4gYmUgdXNlZCB0byBnbyBmcm9tIGEgY2hpbGQncyBjb29yZGluYXRlIHNwYWNlIHRvIHRoZSB3b3JsZCBjb29yZGluYXRlIHNwYWNlLiAoZS5nLiByZW5kZXJpbmcpXG4gKlxuICogQHBhcmFtIHBvcyB7UG9pbnR9IFRoZSBvcmlnaW5cbiAqIEBwYXJhbSBbbmV3UG9zXSB7UG9pbnR9IFRoZSBwb2ludCB0aGF0IHRoZSBuZXcgcG9zaXRpb24gaXMgYXNzaWduZWQgdG8gKGFsbG93ZWQgdG8gYmUgc2FtZSBhcyBpbnB1dClcbiAqIEByZXR1cm4ge1BvaW50fSBUaGUgbmV3IHBvaW50LCB0cmFuc2Zvcm1lZCB0aHJvdWdoIHRoaXMgbWF0cml4XG4gKi9cbk1hdHJpeC5wcm90b3R5cGUuYXBwbHkgPSBmdW5jdGlvbiAocG9zLCBuZXdQb3MpIHtcbiAgICBuZXdQb3MgPSBuZXdQb3MgfHwgbmV3IFBvaW50KCk7XG5cbiAgICBuZXdQb3MueCA9IHRoaXMuYSAqIHBvcy54ICsgdGhpcy5jICogcG9zLnkgKyB0aGlzLnR4O1xuICAgIG5ld1Bvcy55ID0gdGhpcy5iICogcG9zLnggKyB0aGlzLmQgKiBwb3MueSArIHRoaXMudHk7XG5cbiAgICByZXR1cm4gbmV3UG9zO1xufTtcblxuLyoqXG4gKiBHZXQgYSBuZXcgcG9zaXRpb24gd2l0aCB0aGUgaW52ZXJzZSBvZiB0aGUgY3VycmVudCB0cmFuc2Zvcm1hdGlvbiBhcHBsaWVkLlxuICogQ2FuIGJlIHVzZWQgdG8gZ28gZnJvbSB0aGUgd29ybGQgY29vcmRpbmF0ZSBzcGFjZSB0byBhIGNoaWxkJ3MgY29vcmRpbmF0ZSBzcGFjZS4gKGUuZy4gaW5wdXQpXG4gKlxuICogQHBhcmFtIHBvcyB7UG9pbnR9IFRoZSBvcmlnaW5cbiAqIEBwYXJhbSBbbmV3UG9zXSB7UG9pbnR9IFRoZSBwb2ludCB0aGF0IHRoZSBuZXcgcG9zaXRpb24gaXMgYXNzaWduZWQgdG8gKGFsbG93ZWQgdG8gYmUgc2FtZSBhcyBpbnB1dClcbiAqIEByZXR1cm4ge1BvaW50fSBUaGUgbmV3IHBvaW50LCBpbnZlcnNlLXRyYW5zZm9ybWVkIHRocm91Z2ggdGhpcyBtYXRyaXhcbiAqL1xuTWF0cml4LnByb3RvdHlwZS5hcHBseUludmVyc2UgPSBmdW5jdGlvbiAocG9zLCBuZXdQb3MpIHtcbiAgICBuZXdQb3MgPSBuZXdQb3MgfHwgbmV3IFBvaW50KCk7XG5cbiAgICB2YXIgaWQgPSAxIC8gKHRoaXMuYSAqIHRoaXMuZCArIHRoaXMuYyAqIC10aGlzLmIpO1xuXG4gICAgbmV3UG9zLnggPSB0aGlzLmQgKiBpZCAqIHBvcy54ICsgLXRoaXMuYyAqIGlkICogcG9zLnkgKyAodGhpcy50eSAqIHRoaXMuYyAtIHRoaXMudHggKiB0aGlzLmQpICogaWQ7XG4gICAgbmV3UG9zLnkgPSB0aGlzLmEgKiBpZCAqIHBvcy55ICsgLXRoaXMuYiAqIGlkICogcG9zLnggKyAoLXRoaXMudHkgKiB0aGlzLmEgKyB0aGlzLnR4ICogdGhpcy5iKSAqIGlkO1xuXG4gICAgcmV0dXJuIG5ld1Bvcztcbn07XG5cbi8qKlxuICogVHJhbnNsYXRlcyB0aGUgbWF0cml4IG9uIHRoZSB4IGFuZCB5LlxuICpcbiAqIEBwYXJhbSB7bnVtYmVyfSB4XG4gKiBAcGFyYW0ge251bWJlcn0geVxuICogQHJldHVybiB7TWF0cml4fSBUaGlzIG1hdHJpeC4gR29vZCBmb3IgY2hhaW5pbmcgbWV0aG9kIGNhbGxzLlxuICovXG5NYXRyaXgucHJvdG90eXBlLnRyYW5zbGF0ZSA9IGZ1bmN0aW9uICh4LCB5KSB7XG4gICAgdGhpcy50eCArPSB4O1xuICAgIHRoaXMudHkgKz0geTtcblxuICAgIHJldHVybiB0aGlzO1xufTtcblxuLyoqXG4gKiBBcHBsaWVzIGEgc2NhbGUgdHJhbnNmb3JtYXRpb24gdG8gdGhlIG1hdHJpeC5cbiAqXG4gKiBAcGFyYW0ge251bWJlcn0geCBUaGUgYW1vdW50IHRvIHNjYWxlIGhvcml6b250YWxseVxuICogQHBhcmFtIHtudW1iZXJ9IHkgVGhlIGFtb3VudCB0byBzY2FsZSB2ZXJ0aWNhbGx5XG4gKiBAcmV0dXJuIHtNYXRyaXh9IFRoaXMgbWF0cml4LiBHb29kIGZvciBjaGFpbmluZyBtZXRob2QgY2FsbHMuXG4gKi9cbk1hdHJpeC5wcm90b3R5cGUuc2NhbGUgPSBmdW5jdGlvbiAoeCwgeSkge1xuICAgIHRoaXMuYSAqPSB4O1xuICAgIHRoaXMuZCAqPSB5O1xuICAgIHRoaXMuYyAqPSB4O1xuICAgIHRoaXMuYiAqPSB5O1xuICAgIHRoaXMudHggKj0geDtcbiAgICB0aGlzLnR5ICo9IHk7XG5cbiAgICByZXR1cm4gdGhpcztcbn07XG5cblxuLyoqXG4gKiBBcHBsaWVzIGEgcm90YXRpb24gdHJhbnNmb3JtYXRpb24gdG8gdGhlIG1hdHJpeC5cbiAqXG4gKiBAcGFyYW0ge251bWJlcn0gYW5nbGUgLSBUaGUgYW5nbGUgaW4gcmFkaWFucy5cbiAqIEByZXR1cm4ge01hdHJpeH0gVGhpcyBtYXRyaXguIEdvb2QgZm9yIGNoYWluaW5nIG1ldGhvZCBjYWxscy5cbiAqL1xuTWF0cml4LnByb3RvdHlwZS5yb3RhdGUgPSBmdW5jdGlvbiAoYW5nbGUpIHtcbiAgICB2YXIgY29zID0gTWF0aC5jb3MoIGFuZ2xlICk7XG4gICAgdmFyIHNpbiA9IE1hdGguc2luKCBhbmdsZSApO1xuXG4gICAgdmFyIGExID0gdGhpcy5hO1xuICAgIHZhciBjMSA9IHRoaXMuYztcbiAgICB2YXIgdHgxID0gdGhpcy50eDtcblxuICAgIHRoaXMuYSA9IGExICogY29zLXRoaXMuYiAqIHNpbjtcbiAgICB0aGlzLmIgPSBhMSAqIHNpbit0aGlzLmIgKiBjb3M7XG4gICAgdGhpcy5jID0gYzEgKiBjb3MtdGhpcy5kICogc2luO1xuICAgIHRoaXMuZCA9IGMxICogc2luK3RoaXMuZCAqIGNvcztcbiAgICB0aGlzLnR4ID0gdHgxICogY29zIC0gdGhpcy50eSAqIHNpbjtcbiAgICB0aGlzLnR5ID0gdHgxICogc2luICsgdGhpcy50eSAqIGNvcztcblxuICAgIHJldHVybiB0aGlzO1xufTtcblxuLyoqXG4gKiBBcHBlbmRzIHRoZSBnaXZlbiBNYXRyaXggdG8gdGhpcyBNYXRyaXguXG4gKlxuICogQHBhcmFtIHtNYXRyaXh9IG1hdHJpeFxuICogQHJldHVybiB7TWF0cml4fSBUaGlzIG1hdHJpeC4gR29vZCBmb3IgY2hhaW5pbmcgbWV0aG9kIGNhbGxzLlxuICovXG5NYXRyaXgucHJvdG90eXBlLmFwcGVuZCA9IGZ1bmN0aW9uIChtYXRyaXgpIHtcbiAgICB2YXIgYTEgPSB0aGlzLmE7XG4gICAgdmFyIGIxID0gdGhpcy5iO1xuICAgIHZhciBjMSA9IHRoaXMuYztcbiAgICB2YXIgZDEgPSB0aGlzLmQ7XG5cbiAgICB0aGlzLmEgID0gbWF0cml4LmEgKiBhMSArIG1hdHJpeC5iICogYzE7XG4gICAgdGhpcy5iICA9IG1hdHJpeC5hICogYjEgKyBtYXRyaXguYiAqIGQxO1xuICAgIHRoaXMuYyAgPSBtYXRyaXguYyAqIGExICsgbWF0cml4LmQgKiBjMTtcbiAgICB0aGlzLmQgID0gbWF0cml4LmMgKiBiMSArIG1hdHJpeC5kICogZDE7XG5cbiAgICB0aGlzLnR4ID0gbWF0cml4LnR4ICogYTEgKyBtYXRyaXgudHkgKiBjMSArIHRoaXMudHg7XG4gICAgdGhpcy50eSA9IG1hdHJpeC50eCAqIGIxICsgbWF0cml4LnR5ICogZDEgKyB0aGlzLnR5O1xuXG4gICAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqIFJlc2V0cyB0aGlzIE1hdGl4IHRvIGFuIGlkZW50aXR5IChkZWZhdWx0KSBtYXRyaXguXG4gKlxuICogQHJldHVybiB7TWF0cml4fSBUaGlzIG1hdHJpeC4gR29vZCBmb3IgY2hhaW5pbmcgbWV0aG9kIGNhbGxzLlxuICovXG5NYXRyaXgucHJvdG90eXBlLmlkZW50aXR5ID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuYSA9IDE7XG4gICAgdGhpcy5iID0gMDtcbiAgICB0aGlzLmMgPSAwO1xuICAgIHRoaXMuZCA9IDE7XG4gICAgdGhpcy50eCA9IDA7XG4gICAgdGhpcy50eSA9IDA7XG5cbiAgICByZXR1cm4gdGhpcztcbn07XG5cbk1hdHJpeC5JREVOVElUWSA9IG5ldyBNYXRyaXgoKTtcbiIsIi8qKlxuICogVGhlIFBvaW50IG9iamVjdCByZXByZXNlbnRzIGEgbG9jYXRpb24gaW4gYSB0d28tZGltZW5zaW9uYWwgY29vcmRpbmF0ZSBzeXN0ZW0sIHdoZXJlIHggcmVwcmVzZW50c1xuICogdGhlIGhvcml6b250YWwgYXhpcyBhbmQgeSByZXByZXNlbnRzIHRoZSB2ZXJ0aWNhbCBheGlzLlxuICpcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gW3g9MF0ge251bWJlcn0gcG9zaXRpb24gb2YgdGhlIHBvaW50IG9uIHRoZSB4IGF4aXNcbiAqIEBwYXJhbSBbeT0wXSB7bnVtYmVyfSBwb3NpdGlvbiBvZiB0aGUgcG9pbnQgb24gdGhlIHkgYXhpc1xuICovXG5mdW5jdGlvbiBQb2ludCh4LCB5KSB7XG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDBcbiAgICAgKi9cbiAgICB0aGlzLnggPSB4IHx8IDA7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMueSA9IHkgfHwgMDtcbn1cblxuUG9pbnQucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gUG9pbnQ7XG5tb2R1bGUuZXhwb3J0cyA9IFBvaW50O1xuXG4vKipcbiAqIENyZWF0ZXMgYSBjbG9uZSBvZiB0aGlzIHBvaW50XG4gKlxuICogQHJldHVybiB7UG9pbnR9IGEgY29weSBvZiB0aGUgcG9pbnRcbiAqL1xuUG9pbnQucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBuZXcgUG9pbnQodGhpcy54LCB0aGlzLnkpO1xufTtcblxuLyoqXG4gKiBTZXRzIHRoZSBwb2ludCB0byBhIG5ldyB4IGFuZCB5IHBvc2l0aW9uLlxuICogSWYgeSBpcyBvbWl0dGVkLCBib3RoIHggYW5kIHkgd2lsbCBiZSBzZXQgdG8geC5cbiAqXG4gKiBAcGFyYW0gW3g9MF0ge251bWJlcn0gcG9zaXRpb24gb2YgdGhlIHBvaW50IG9uIHRoZSB4IGF4aXNcbiAqIEBwYXJhbSBbeT0wXSB7bnVtYmVyfSBwb3NpdGlvbiBvZiB0aGUgcG9pbnQgb24gdGhlIHkgYXhpc1xuICovXG5Qb2ludC5wcm90b3R5cGUuc2V0ID0gZnVuY3Rpb24gKHgsIHkpIHtcbiAgICB0aGlzLnggPSB4IHx8IDA7XG4gICAgdGhpcy55ID0geSB8fCAoICh5ICE9PSAwKSA/IHRoaXMueCA6IDAgKSA7XG59O1xuIiwiLyoqXG4gKiBAbmFtZXNwYWNlIFBJWEkubWF0aFxuICovXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICAvKipcbiAgICAgKiBAcHJvcGVydHkge251bWJlcn0gUElfMiAtIE1hdGguUEkgeCAyXG4gICAgICogQGNvbnN0YW50XG4gICAgICogQHN0YXRpY1xuICAgICAqL1xuICAgIFBJXzI6IE1hdGguUEkgKiAyLFxuXG4gICAgLyoqXG4gICAgICogQHByb3BlcnR5IHtudW1iZXJ9IFJBRF9UT19ERUcgLSBDb25zdGFudCBjb252ZXJzaW9uIGZhY3RvciBmb3IgY29udmVydGluZyByYWRpYW5zIHRvIGRlZ3JlZXNcbiAgICAgKiBAY29uc3RhbnRcbiAgICAgKiBAc3RhdGljXG4gICAgICovXG4gICAgUkFEX1RPX0RFRzogMTgwIC8gTWF0aC5QSSxcblxuICAgIC8qKlxuICAgICAqIEBwcm9wZXJ0eSB7TnVtYmVyfSBERUdfVE9fUkFEIC0gQ29uc3RhbnQgY29udmVyc2lvbiBmYWN0b3IgZm9yIGNvbnZlcnRpbmcgZGVncmVlcyB0byByYWRpYW5zXG4gICAgICogQGNvbnN0YW50XG4gICAgICogQHN0YXRpY1xuICAgICAqL1xuICAgIERFR19UT19SQUQ6IE1hdGguUEkgLyAxODAsXG5cbiAgICBQb2ludDogICAgICByZXF1aXJlKCcuL1BvaW50JyksXG4gICAgTWF0cml4OiAgICAgcmVxdWlyZSgnLi9NYXRyaXgnKSxcblxuICAgIENpcmNsZTogICAgIHJlcXVpcmUoJy4vc2hhcGVzL0NpcmNsZScpLFxuICAgIEVsbGlwc2U6ICAgIHJlcXVpcmUoJy4vc2hhcGVzL0VsbGlwc2UnKSxcbiAgICBQb2x5Z29uOiAgICByZXF1aXJlKCcuL3NoYXBlcy9Qb2x5Z29uJyksXG4gICAgUmVjdGFuZ2xlOiAgcmVxdWlyZSgnLi9zaGFwZXMvUmVjdGFuZ2xlJyksXG4gICAgUm91bmRlZFJlY3RhbmdsZTogcmVxdWlyZSgnLi9zaGFwZXMvUm91bmRlZFJlY3RhbmdsZScpXG59O1xuIiwidmFyIFJlY3RhbmdsZSA9IHJlcXVpcmUoJy4vUmVjdGFuZ2xlJyksXG4gICAgQ09OU1QgPSByZXF1aXJlKCcuLi8uLi9jb25zdCcpO1xuXG4vKipcbiAqIFRoZSBDaXJjbGUgb2JqZWN0IGNhbiBiZSB1c2VkIHRvIHNwZWNpZnkgYSBoaXQgYXJlYSBmb3IgZGlzcGxheU9iamVjdHNcbiAqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmRpbmF0ZSBvZiB0aGUgY2VudGVyIG9mIHRoaXMgY2lyY2xlXG4gKiBAcGFyYW0geSB7bnVtYmVyfSBUaGUgWSBjb29yZGluYXRlIG9mIHRoZSBjZW50ZXIgb2YgdGhpcyBjaXJjbGVcbiAqIEBwYXJhbSByYWRpdXMge251bWJlcn0gVGhlIHJhZGl1cyBvZiB0aGUgY2lyY2xlXG4gKi9cbmZ1bmN0aW9uIENpcmNsZSh4LCB5LCByYWRpdXMpIHtcbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMueCA9IHggfHwgMDtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy55ID0geSB8fCAwO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDBcbiAgICAgKi9cbiAgICB0aGlzLnJhZGl1cyA9IHJhZGl1cyB8fCAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHR5cGUgb2YgdGhlIG9iamVjdCwgbWFpbmx5IHVzZWQgdG8gYXZvaWQgYGluc3RhbmNlb2ZgIGNoZWNrc1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMudHlwZSA9IENPTlNULlNIQVBFUy5DSVJDO1xufVxuXG5DaXJjbGUucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQ2lyY2xlO1xubW9kdWxlLmV4cG9ydHMgPSBDaXJjbGU7XG5cbi8qKlxuICogQ3JlYXRlcyBhIGNsb25lIG9mIHRoaXMgQ2lyY2xlIGluc3RhbmNlXG4gKlxuICogQG1ldGhvZCBjbG9uZVxuICogQHJldHVybiB7Q2lyY2xlfSBhIGNvcHkgb2YgdGhlIENpcmNsZVxuICovXG5DaXJjbGUucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBuZXcgQ2lyY2xlKHRoaXMueCwgdGhpcy55LCB0aGlzLnJhZGl1cyk7XG59O1xuXG4vKipcbiAqIENoZWNrcyB3aGV0aGVyIHRoZSB4IGFuZCB5IGNvb3JkaW5hdGVzIGdpdmVuIGFyZSBjb250YWluZWQgd2l0aGluIHRoaXMgY2lyY2xlXG4gKlxuICogQG1ldGhvZCBjb250YWluc1xuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHBhcmFtIHkge251bWJlcn0gVGhlIFkgY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHJldHVybiB7Ym9vbGVhbn0gV2hldGhlciB0aGUgeC95IGNvb3JkaW5hdGVzIGFyZSB3aXRoaW4gdGhpcyBDaXJjbGVcbiAqL1xuQ2lyY2xlLnByb3RvdHlwZS5jb250YWlucyA9IGZ1bmN0aW9uICh4LCB5KSB7XG4gICAgaWYgKHRoaXMucmFkaXVzIDw9IDApIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHZhciBkeCA9ICh0aGlzLnggLSB4KSxcbiAgICAgICAgZHkgPSAodGhpcy55IC0geSksXG4gICAgICAgIHIyID0gdGhpcy5yYWRpdXMgKiB0aGlzLnJhZGl1cztcblxuICAgIGR4ICo9IGR4O1xuICAgIGR5ICo9IGR5O1xuXG4gICAgcmV0dXJuIChkeCArIGR5IDw9IHIyKTtcbn07XG5cbi8qKlxuKiBSZXR1cm5zIHRoZSBmcmFtaW5nIHJlY3RhbmdsZSBvZiB0aGUgY2lyY2xlIGFzIGEgUmVjdGFuZ2xlIG9iamVjdFxuKlxuKiBAbWV0aG9kIGdldEJvdW5kc1xuKiBAcmV0dXJuIHtSZWN0YW5nbGV9IHRoZSBmcmFtaW5nIHJlY3RhbmdsZVxuKi9cbkNpcmNsZS5wcm90b3R5cGUuZ2V0Qm91bmRzID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBuZXcgUmVjdGFuZ2xlKHRoaXMueCAtIHRoaXMucmFkaXVzLCB0aGlzLnkgLSB0aGlzLnJhZGl1cywgdGhpcy5yYWRpdXMgKiAyLCB0aGlzLnJhZGl1cyAqIDIpO1xufTtcbiIsInZhciBSZWN0YW5nbGUgPSByZXF1aXJlKCcuL1JlY3RhbmdsZScpLFxuICAgIENPTlNUID0gcmVxdWlyZSgnLi4vLi4vY29uc3QnKTtcblxuLyoqXG4gKiBUaGUgRWxsaXBzZSBvYmplY3QgY2FuIGJlIHVzZWQgdG8gc3BlY2lmeSBhIGhpdCBhcmVhIGZvciBkaXNwbGF5T2JqZWN0c1xuICpcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0geCB7bnVtYmVyfSBUaGUgWCBjb29yZGluYXRlIG9mIHRoZSBjZW50ZXIgb2YgdGhlIGVsbGlwc2VcbiAqIEBwYXJhbSB5IHtudW1iZXJ9IFRoZSBZIGNvb3JkaW5hdGUgb2YgdGhlIGNlbnRlciBvZiB0aGUgZWxsaXBzZVxuICogQHBhcmFtIHdpZHRoIHtudW1iZXJ9IFRoZSBoYWxmIHdpZHRoIG9mIHRoaXMgZWxsaXBzZVxuICogQHBhcmFtIGhlaWdodCB7bnVtYmVyfSBUaGUgaGFsZiBoZWlnaHQgb2YgdGhpcyBlbGxpcHNlXG4gKi9cbmZ1bmN0aW9uIEVsbGlwc2UoeCwgeSwgd2lkdGgsIGhlaWdodCkge1xuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy54ID0geCB8fCAwO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDBcbiAgICAgKi9cbiAgICB0aGlzLnkgPSB5IHx8IDA7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMud2lkdGggPSB3aWR0aCB8fCAwO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDBcbiAgICAgKi9cbiAgICB0aGlzLmhlaWdodCA9IGhlaWdodCB8fCAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHR5cGUgb2YgdGhlIG9iamVjdCwgbWFpbmx5IHVzZWQgdG8gYXZvaWQgYGluc3RhbmNlb2ZgIGNoZWNrc1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMudHlwZSA9IENPTlNULlNIQVBFUy5FTElQO1xufVxuXG5FbGxpcHNlLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEVsbGlwc2U7XG5tb2R1bGUuZXhwb3J0cyA9IEVsbGlwc2U7XG5cbi8qKlxuICogQ3JlYXRlcyBhIGNsb25lIG9mIHRoaXMgRWxsaXBzZSBpbnN0YW5jZVxuICpcbiAqIEBtZXRob2QgY2xvbmVcbiAqIEByZXR1cm4ge0VsbGlwc2V9IGEgY29weSBvZiB0aGUgZWxsaXBzZVxuICovXG5FbGxpcHNlLnByb3RvdHlwZS5jbG9uZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gbmV3IEVsbGlwc2UodGhpcy54LCB0aGlzLnksIHRoaXMud2lkdGgsIHRoaXMuaGVpZ2h0KTtcbn07XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgdGhlIHggYW5kIHkgY29vcmRpbmF0ZXMgZ2l2ZW4gYXJlIGNvbnRhaW5lZCB3aXRoaW4gdGhpcyBlbGxpcHNlXG4gKlxuICogQG1ldGhvZCBjb250YWluc1xuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHBhcmFtIHkge251bWJlcn0gVGhlIFkgY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHJldHVybiB7Ym9vbGVhbn0gV2hldGhlciB0aGUgeC95IGNvb3JkcyBhcmUgd2l0aGluIHRoaXMgZWxsaXBzZVxuICovXG5FbGxpcHNlLnByb3RvdHlwZS5jb250YWlucyA9IGZ1bmN0aW9uICh4LCB5KSB7XG4gICAgaWYgKHRoaXMud2lkdGggPD0gMCB8fCB0aGlzLmhlaWdodCA8PSAwKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvL25vcm1hbGl6ZSB0aGUgY29vcmRzIHRvIGFuIGVsbGlwc2Ugd2l0aCBjZW50ZXIgMCwwXG4gICAgdmFyIG5vcm14ID0gKCh4IC0gdGhpcy54KSAvIHRoaXMud2lkdGgpLFxuICAgICAgICBub3JteSA9ICgoeSAtIHRoaXMueSkgLyB0aGlzLmhlaWdodCk7XG5cbiAgICBub3JteCAqPSBub3JteDtcbiAgICBub3JteSAqPSBub3JteTtcblxuICAgIHJldHVybiAobm9ybXggKyBub3JteSA8PSAxKTtcbn07XG5cbi8qKlxuKiBSZXR1cm5zIHRoZSBmcmFtaW5nIHJlY3RhbmdsZSBvZiB0aGUgZWxsaXBzZSBhcyBhIFJlY3RhbmdsZSBvYmplY3RcbipcbiogQG1ldGhvZCBnZXRCb3VuZHNcbiogQHJldHVybiB7UmVjdGFuZ2xlfSB0aGUgZnJhbWluZyByZWN0YW5nbGVcbiovXG5FbGxpcHNlLnByb3RvdHlwZS5nZXRCb3VuZHMgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIG5ldyBSZWN0YW5nbGUodGhpcy54IC0gdGhpcy53aWR0aCwgdGhpcy55IC0gdGhpcy5oZWlnaHQsIHRoaXMud2lkdGgsIHRoaXMuaGVpZ2h0KTtcbn07XG4iLCJ2YXIgUG9pbnQgPSByZXF1aXJlKCcuLi9Qb2ludCcpLFxuICAgIENPTlNUID0gcmVxdWlyZSgnLi4vLi4vY29uc3QnKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHBvaW50cyoge1BvaW50W118bnVtYmVyW118UG9pbnQuLi58bnVtYmVyLi4ufSBUaGlzIGNhbiBiZSBhbiBhcnJheSBvZiBQb2ludHMgdGhhdCBmb3JtIHRoZSBwb2x5Z29uLFxuICogICAgICBhIGZsYXQgYXJyYXkgb2YgbnVtYmVycyB0aGF0IHdpbGwgYmUgaW50ZXJwcmV0ZWQgYXMgW3gseSwgeCx5LCAuLi5dLCBvciB0aGUgYXJndW1lbnRzIHBhc3NlZCBjYW4gYmVcbiAqICAgICAgYWxsIHRoZSBwb2ludHMgb2YgdGhlIHBvbHlnb24gZS5nLiBgbmV3IFBvbHlnb24obmV3IFBvaW50KCksIG5ldyBQb2ludCgpLCAuLi4pYCwgb3IgdGhlXG4gKiAgICAgIGFyZ3VtZW50cyBwYXNzZWQgY2FuIGJlIGZsYXQgeCx5IHZhbHVlcyBlLmcuIGBuZXcgUG9seWdvbih4LHksIHgseSwgeCx5LCAuLi4pYCB3aGVyZSBgeGAgYW5kIGB5YCBhcmVcbiAqICAgICAgTnVtYmVycy5cbiAqL1xuZnVuY3Rpb24gUG9seWdvbihwb2ludHMpIHtcbiAgICAvL2lmIHBvaW50cyBpc24ndCBhbiBhcnJheSwgdXNlIGFyZ3VtZW50cyBhcyB0aGUgYXJyYXlcbiAgICBpZiAoIShwb2ludHMgaW5zdGFuY2VvZiBBcnJheSkpIHtcbiAgICAgICAgcG9pbnRzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICB9XG5cbiAgICAvL2lmIHRoaXMgaXMgYSBmbGF0IGFycmF5IG9mIG51bWJlcnMsIGNvbnZlcnQgaXQgdG8gcG9pbnRzXG4gICAgaWYgKHBvaW50c1swXSBpbnN0YW5jZW9mIFBvaW50KSB7XG4gICAgICAgIHZhciBwID0gW107XG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBpbCA9IHBvaW50cy5sZW5ndGg7IGkgPCBpbDsgaSsrKSB7XG4gICAgICAgICAgICBwLnB1c2gocG9pbnRzW2ldLngsIHBvaW50c1tpXS55KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHBvaW50cyA9IHA7XG4gICAgfVxuXG4gICAgdGhpcy5jbG9zZWQgPSB0cnVlO1xuXG4gICAgLyoqXG4gICAgICogQW4gYXJyYXkgb2YgdGhlIHBvaW50cyBvZiB0aGlzIHBvbHlnb25cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1BvaW50W119XG4gICAgICovXG4gICAgdGhpcy5wb2ludHMgPSBwb2ludHM7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdHlwZSBvZiB0aGUgb2JqZWN0LCBtYWlubHkgdXNlZCB0byBhdm9pZCBgaW5zdGFuY2VvZmAgY2hlY2tzXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy50eXBlID0gQ09OU1QuU0hBUEVTLlBPTFk7XG59XG5cblBvbHlnb24ucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gUG9seWdvbjtcbm1vZHVsZS5leHBvcnRzID0gUG9seWdvbjtcblxuLyoqXG4gKiBDcmVhdGVzIGEgY2xvbmUgb2YgdGhpcyBwb2x5Z29uXG4gKlxuICogQHJldHVybiB7UG9seWdvbn0gYSBjb3B5IG9mIHRoZSBwb2x5Z29uXG4gKi9cblBvbHlnb24ucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBuZXcgUG9seWdvbih0aGlzLnBvaW50cy5zbGljZSgpKTtcbn07XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgdGhlIHggYW5kIHkgY29vcmRpbmF0ZXMgcGFzc2VkIHRvIHRoaXMgZnVuY3Rpb24gYXJlIGNvbnRhaW5lZCB3aXRoaW4gdGhpcyBwb2x5Z29uXG4gKlxuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHBhcmFtIHkge251bWJlcn0gVGhlIFkgY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHJldHVybiB7Ym9vbGVhbn0gV2hldGhlciB0aGUgeC95IGNvb3JkaW5hdGVzIGFyZSB3aXRoaW4gdGhpcyBwb2x5Z29uXG4gKi9cblBvbHlnb24ucHJvdG90eXBlLmNvbnRhaW5zID0gZnVuY3Rpb24gKHgsIHkpIHtcbiAgICB2YXIgaW5zaWRlID0gZmFsc2U7XG5cbiAgICAvLyB1c2Ugc29tZSByYXljYXN0aW5nIHRvIHRlc3QgaGl0c1xuICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9zdWJzdGFjay9wb2ludC1pbi1wb2x5Z29uL2Jsb2IvbWFzdGVyL2luZGV4LmpzXG4gICAgdmFyIGxlbmd0aCA9IHRoaXMucG9pbnRzLmxlbmd0aCAvIDI7XG5cbiAgICBmb3IgKHZhciBpID0gMCwgaiA9IGxlbmd0aCAtIDE7IGkgPCBsZW5ndGg7IGogPSBpKyspIHtcbiAgICAgICAgdmFyIHhpID0gdGhpcy5wb2ludHNbaSAqIDJdLCB5aSA9IHRoaXMucG9pbnRzW2kgKiAyICsgMV0sXG4gICAgICAgICAgICB4aiA9IHRoaXMucG9pbnRzW2ogKiAyXSwgeWogPSB0aGlzLnBvaW50c1tqICogMiArIDFdLFxuICAgICAgICAgICAgaW50ZXJzZWN0ID0gKCh5aSA+IHkpICE9PSAoeWogPiB5KSkgJiYgKHggPCAoeGogLSB4aSkgKiAoeSAtIHlpKSAvICh5aiAtIHlpKSArIHhpKTtcblxuICAgICAgICBpZiAoaW50ZXJzZWN0KSB7XG4gICAgICAgICAgICBpbnNpZGUgPSAhaW5zaWRlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGluc2lkZTtcbn07XG4iLCJ2YXIgQ09OU1QgPSByZXF1aXJlKCcuLi8uLi9jb25zdCcpO1xuXG4vKipcbiAqIHRoZSBSZWN0YW5nbGUgb2JqZWN0IGlzIGFuIGFyZWEgZGVmaW5lZCBieSBpdHMgcG9zaXRpb24sIGFzIGluZGljYXRlZCBieSBpdHMgdG9wLWxlZnQgY29ybmVyIHBvaW50ICh4LCB5KSBhbmQgYnkgaXRzIHdpZHRoIGFuZCBpdHMgaGVpZ2h0LlxuICpcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0geCB7bnVtYmVyfSBUaGUgWCBjb29yZGluYXRlIG9mIHRoZSB1cHBlci1sZWZ0IGNvcm5lciBvZiB0aGUgcmVjdGFuZ2xlXG4gKiBAcGFyYW0geSB7bnVtYmVyfSBUaGUgWSBjb29yZGluYXRlIG9mIHRoZSB1cHBlci1sZWZ0IGNvcm5lciBvZiB0aGUgcmVjdGFuZ2xlXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gVGhlIG92ZXJhbGwgd2lkdGggb2YgdGhpcyByZWN0YW5nbGVcbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gVGhlIG92ZXJhbGwgaGVpZ2h0IG9mIHRoaXMgcmVjdGFuZ2xlXG4gKi9cbmZ1bmN0aW9uIFJlY3RhbmdsZSh4LCB5LCB3aWR0aCwgaGVpZ2h0KSB7XG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDBcbiAgICAgKi9cbiAgICB0aGlzLnggPSB4IHx8IDA7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMueSA9IHkgfHwgMDtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy53aWR0aCA9IHdpZHRoIHx8IDA7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0IHx8IDA7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdHlwZSBvZiB0aGUgb2JqZWN0LCBtYWlubHkgdXNlZCB0byBhdm9pZCBgaW5zdGFuY2VvZmAgY2hlY2tzXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy50eXBlID0gQ09OU1QuU0hBUEVTLlJFQ1Q7XG59XG5cblJlY3RhbmdsZS5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBSZWN0YW5nbGU7XG5tb2R1bGUuZXhwb3J0cyA9IFJlY3RhbmdsZTtcblxuLyoqXG4gKiBBIGNvbnN0YW50IGVtcHR5IHJlY3RhbmdsZS5cbiAqXG4gKiBAc3RhdGljXG4gKiBAY29uc3RhbnRcbiAqL1xuUmVjdGFuZ2xlLkVNUFRZID0gbmV3IFJlY3RhbmdsZSgwLCAwLCAwLCAwKTtcblxuXG4vKipcbiAqIENyZWF0ZXMgYSBjbG9uZSBvZiB0aGlzIFJlY3RhbmdsZVxuICpcbiAqIEByZXR1cm4ge1JlY3RhbmdsZX0gYSBjb3B5IG9mIHRoZSByZWN0YW5nbGVcbiAqL1xuUmVjdGFuZ2xlLnByb3RvdHlwZS5jbG9uZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gbmV3IFJlY3RhbmdsZSh0aGlzLngsIHRoaXMueSwgdGhpcy53aWR0aCwgdGhpcy5oZWlnaHQpO1xufTtcblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciB0aGUgeCBhbmQgeSBjb29yZGluYXRlcyBnaXZlbiBhcmUgY29udGFpbmVkIHdpdGhpbiB0aGlzIFJlY3RhbmdsZVxuICpcbiAqIEBwYXJhbSB4IHtudW1iZXJ9IFRoZSBYIGNvb3JkaW5hdGUgb2YgdGhlIHBvaW50IHRvIHRlc3RcbiAqIEBwYXJhbSB5IHtudW1iZXJ9IFRoZSBZIGNvb3JkaW5hdGUgb2YgdGhlIHBvaW50IHRvIHRlc3RcbiAqIEByZXR1cm4ge2Jvb2xlYW59IFdoZXRoZXIgdGhlIHgveSBjb29yZGluYXRlcyBhcmUgd2l0aGluIHRoaXMgUmVjdGFuZ2xlXG4gKi9cblJlY3RhbmdsZS5wcm90b3R5cGUuY29udGFpbnMgPSBmdW5jdGlvbiAoeCwgeSkge1xuICAgIGlmICh0aGlzLndpZHRoIDw9IDAgfHwgdGhpcy5oZWlnaHQgPD0gMCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKHggPj0gdGhpcy54ICYmIHggPD0gdGhpcy54ICsgdGhpcy53aWR0aCkge1xuICAgICAgICBpZiAoeSA+PSB0aGlzLnkgJiYgeSA8PSB0aGlzLnkgKyB0aGlzLmhlaWdodCkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2U7XG59O1xuIiwidmFyIENPTlNUID0gcmVxdWlyZSgnLi4vLi4vY29uc3QnKTtcblxuLyoqXG4gKiBUaGUgUm91bmRlZCBSZWN0YW5nbGUgb2JqZWN0IGlzIGFuIGFyZWEgZGVmaW5lZCBieSBpdHMgcG9zaXRpb24gYW5kIGhhcyBuaWNlIHJvdW5kZWQgY29ybmVycywgYXMgaW5kaWNhdGVkIGJ5IGl0cyB0b3AtbGVmdCBjb3JuZXIgcG9pbnQgKHgsIHkpIGFuZCBieSBpdHMgd2lkdGggYW5kIGl0cyBoZWlnaHQuXG4gKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSB4IHtudW1iZXJ9IFRoZSBYIGNvb3JkaW5hdGUgb2YgdGhlIHVwcGVyLWxlZnQgY29ybmVyIG9mIHRoZSByb3VuZGVkIHJlY3RhbmdsZVxuICogQHBhcmFtIHkge251bWJlcn0gVGhlIFkgY29vcmRpbmF0ZSBvZiB0aGUgdXBwZXItbGVmdCBjb3JuZXIgb2YgdGhlIHJvdW5kZWQgcmVjdGFuZ2xlXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gVGhlIG92ZXJhbGwgd2lkdGggb2YgdGhpcyByb3VuZGVkIHJlY3RhbmdsZVxuICogQHBhcmFtIGhlaWdodCB7bnVtYmVyfSBUaGUgb3ZlcmFsbCBoZWlnaHQgb2YgdGhpcyByb3VuZGVkIHJlY3RhbmdsZVxuICogQHBhcmFtIHJhZGl1cyB7bnVtYmVyfSBDb250cm9scyB0aGUgcmFkaXVzIG9mIHRoZSByb3VuZGVkIGNvcm5lcnNcbiAqL1xuZnVuY3Rpb24gUm91bmRlZFJlY3RhbmdsZSh4LCB5LCB3aWR0aCwgaGVpZ2h0LCByYWRpdXMpIHtcbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMueCA9IHggfHwgMDtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy55ID0geSB8fCAwO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDBcbiAgICAgKi9cbiAgICB0aGlzLndpZHRoID0gd2lkdGggfHwgMDtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICovXG4gICAgdGhpcy5oZWlnaHQgPSBoZWlnaHQgfHwgMDtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAZGVmYXVsdCAyMFxuICAgICAqL1xuICAgIHRoaXMucmFkaXVzID0gcmFkaXVzIHx8IDIwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHR5cGUgb2YgdGhlIG9iamVjdCwgbWFpbmx5IHVzZWQgdG8gYXZvaWQgYGluc3RhbmNlb2ZgIGNoZWNrc1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMudHlwZSA9IENPTlNULlNIQVBFUy5SUkVDO1xufVxuXG5Sb3VuZGVkUmVjdGFuZ2xlLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFJvdW5kZWRSZWN0YW5nbGU7XG5tb2R1bGUuZXhwb3J0cyA9IFJvdW5kZWRSZWN0YW5nbGU7XG5cbi8qKlxuICogQ3JlYXRlcyBhIGNsb25lIG9mIHRoaXMgUm91bmRlZCBSZWN0YW5nbGVcbiAqXG4gKiBAcmV0dXJuIHtSb3VuZGVkUmVjdGFuZ2xlfSBhIGNvcHkgb2YgdGhlIHJvdW5kZWQgcmVjdGFuZ2xlXG4gKi9cblJvdW5kZWRSZWN0YW5nbGUucHJvdG90eXBlLmNsb25lID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBuZXcgUm91bmRlZFJlY3RhbmdsZSh0aGlzLngsIHRoaXMueSwgdGhpcy53aWR0aCwgdGhpcy5oZWlnaHQsIHRoaXMucmFkaXVzKTtcbn07XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgdGhlIHggYW5kIHkgY29vcmRpbmF0ZXMgZ2l2ZW4gYXJlIGNvbnRhaW5lZCB3aXRoaW4gdGhpcyBSb3VuZGVkIFJlY3RhbmdsZVxuICpcbiAqIEBwYXJhbSB4IHtudW1iZXJ9IFRoZSBYIGNvb3JkaW5hdGUgb2YgdGhlIHBvaW50IHRvIHRlc3RcbiAqIEBwYXJhbSB5IHtudW1iZXJ9IFRoZSBZIGNvb3JkaW5hdGUgb2YgdGhlIHBvaW50IHRvIHRlc3RcbiAqIEByZXR1cm4ge2Jvb2xlYW59IFdoZXRoZXIgdGhlIHgveSBjb29yZGluYXRlcyBhcmUgd2l0aGluIHRoaXMgUm91bmRlZCBSZWN0YW5nbGVcbiAqL1xuUm91bmRlZFJlY3RhbmdsZS5wcm90b3R5cGUuY29udGFpbnMgPSBmdW5jdGlvbiAoeCwgeSkge1xuICAgIGlmICh0aGlzLndpZHRoIDw9IDAgfHwgdGhpcy5oZWlnaHQgPD0gMCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKHggPj0gdGhpcy54ICYmIHggPD0gdGhpcy54ICsgdGhpcy53aWR0aCkge1xuICAgICAgICBpZiAoeSA+PSB0aGlzLnkgJiYgeSA8PSB0aGlzLnkgKyB0aGlzLmhlaWdodCkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2U7XG59O1xuIiwidmFyIERpc3BsYXlPYmplY3RDb250YWluZXIgPSByZXF1aXJlKCcuLi9kaXNwbGF5L0Rpc3BsYXlPYmplY3RDb250YWluZXInKSxcbiAgICBTcHJpdGUgPSByZXF1aXJlKCcuLi9kaXNwbGF5L1Nwcml0ZScpLFxuICAgIFRleHR1cmUgPSByZXF1aXJlKCcuLi90ZXh0dXJlcy9UZXh0dXJlJyksXG4gICAgQ2FudmFzQnVmZmVyID0gcmVxdWlyZSgnLi4vcmVuZGVyZXJzL2NhbnZhcy91dGlscy9DYW52YXNCdWZmZXInKSxcbiAgICBDYW52YXNHcmFwaGljcyA9IHJlcXVpcmUoJy4uL3JlbmRlcmVycy9jYW52YXMvdXRpbHMvQ2FudmFzR3JhcGhpY3MnKSxcbiAgICBXZWJHTEdyYXBoaWNzID0gcmVxdWlyZSgnLi4vcmVuZGVyZXJzL3dlYmdsL3V0aWxzL1dlYkdMR3JhcGhpY3MnKSxcbiAgICBHcmFwaGljc0RhdGEgPSByZXF1aXJlKCcuL0dyYXBoaWNzRGF0YScpLFxuICAgIG1hdGggPSByZXF1aXJlKCcuLi9tYXRoJyksXG4gICAgQ09OU1QgPSByZXF1aXJlKCcuLi9jb25zdCcpO1xuXG4vKipcbiAqIFRoZSBHcmFwaGljcyBjbGFzcyBjb250YWlucyBtZXRob2RzIHVzZWQgdG8gZHJhdyBwcmltaXRpdmUgc2hhcGVzIHN1Y2ggYXMgbGluZXMsIGNpcmNsZXMgYW5kXG4gKiByZWN0YW5nbGVzIHRvIHRoZSBkaXNwbGF5LCBhbmQgY29sb3IgYW5kIGZpbGwgdGhlbS5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIERpc3BsYXlPYmplY3RDb250YWluZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBHcmFwaGljcygpIHtcbiAgICBEaXNwbGF5T2JqZWN0Q29udGFpbmVyLmNhbGwodGhpcyk7XG5cbiAgICB0aGlzLnJlbmRlcmFibGUgPSB0cnVlO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGFscGhhIHZhbHVlIHVzZWQgd2hlbiBmaWxsaW5nIHRoZSBHcmFwaGljcyBvYmplY3QuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMVxuICAgICAqL1xuICAgIHRoaXMuZmlsbEFscGhhID0gMTtcblxuICAgIC8qKlxuICAgICAqIFRoZSB3aWR0aCAodGhpY2tuZXNzKSBvZiBhbnkgbGluZXMgZHJhd24uXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMubGluZVdpZHRoID0gMDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBjb2xvciBvZiBhbnkgbGluZXMgZHJhd24uXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtzdHJpbmd9XG4gICAgICogQGRlZmF1bHQgMFxuICAgICAqL1xuICAgIHRoaXMubGluZUNvbG9yID0gMDtcblxuICAgIC8qKlxuICAgICAqIEdyYXBoaWNzIGRhdGFcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0dyYXBoaWNzRGF0YVtdfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5ncmFwaGljc0RhdGEgPSBbXTtcblxuICAgIC8qKlxuICAgICAqIFRoZSB0aW50IGFwcGxpZWQgdG8gdGhlIGdyYXBoaWMgc2hhcGUuIFRoaXMgaXMgYSBoZXggdmFsdWUuIEFwcGx5IGEgdmFsdWUgb2YgMHhGRkZGRkYgdG8gcmVzZXQgdGhlIHRpbnQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMHhGRkZGRkZcbiAgICAgKi9cbiAgICB0aGlzLnRpbnQgPSAweEZGRkZGRjtcblxuICAgIC8qKlxuICAgICAqIFRoZSBibGVuZCBtb2RlIHRvIGJlIGFwcGxpZWQgdG8gdGhlIGdyYXBoaWMgc2hhcGUuIEFwcGx5IGEgdmFsdWUgb2YgYmxlbmRNb2Rlcy5OT1JNQUwgdG8gcmVzZXQgdGhlIGJsZW5kIG1vZGUuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgQ09OU1QuYmxlbmRNb2Rlcy5OT1JNQUw7XG4gICAgICovXG4gICAgdGhpcy5ibGVuZE1vZGUgPSBDT05TVC5ibGVuZE1vZGVzLk5PUk1BTDtcblxuICAgIC8qKlxuICAgICAqIEN1cnJlbnQgcGF0aFxuICAgICAqXG4gICAgICogQG1lbWJlciB7R3JhcGhpY3NEYXRhfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5jdXJyZW50UGF0aCA9IG51bGw7XG5cbiAgICAvKipcbiAgICAgKiBBcnJheSBjb250YWluaW5nIHNvbWUgV2ViR0wtcmVsYXRlZCBwcm9wZXJ0aWVzIHVzZWQgYnkgdGhlIFdlYkdMIHJlbmRlcmVyLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7b2JqZWN0PG51bWJlciwgb2JqZWN0Pn1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIC8vIFRPRE8gLSBfd2ViZ2wgc2hvdWxkIHVzZSBhIHByb3RvdHlwZSBvYmplY3QsIG5vdCBhIHJhbmRvbSB1bmRvY3VtZW50ZWQgb2JqZWN0Li4uXG4gICAgdGhpcy5fd2ViR0wgPSB7fTtcblxuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgdGhpcyBzaGFwZSBpcyBiZWluZyB1c2VkIGFzIGEgbWFzay5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5pc01hc2sgPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBib3VuZHMnIHBhZGRpbmcgdXNlZCBmb3IgYm91bmRzIGNhbGN1bGF0aW9uLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMuYm91bmRzUGFkZGluZyA9IDA7XG5cbiAgICAvKipcbiAgICAgKiBBIGNhY2hlIG9mIHRoZSBsb2NhbCBib3VuZHMgdG8gcHJldmVudCByZWNhbGN1bGF0aW9uLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7UmVjdGFuZ2xlfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fbG9jYWxCb3VuZHMgPSBuZXcgbWF0aC5SZWN0YW5nbGUoMCwwLDEsMSk7XG5cbiAgICAvKipcbiAgICAgKiBVc2VkIHRvIGRldGVjdCBpZiB0aGUgZ3JhcGhpY3Mgb2JqZWN0IGhhcyBjaGFuZ2VkLiBJZiB0aGlzIGlzIHNldCB0byB0cnVlIHRoZW4gdGhlIGdyYXBoaWNzXG4gICAgICogb2JqZWN0IHdpbGwgYmUgcmVjYWxjdWxhdGVkLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuXG4gICAgLyoqXG4gICAgICogVXNlZCB0byBkZXRlY3QgaWYgdGhlIFdlYkdMIGdyYXBoaWNzIG9iamVjdCBoYXMgY2hhbmdlZC4gSWYgdGhpcyBpcyBzZXQgdG8gdHJ1ZSB0aGVuIHRoZVxuICAgICAqIGdyYXBoaWNzIG9iamVjdCB3aWxsIGJlIHJlY2FsY3VsYXRlZC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLmdsRGlydHkgPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqIFVzZWQgdG8gZGV0ZWN0IGlmIHRoZSBjYWNoZWQgc3ByaXRlIG9iamVjdCBuZWVkcyB0byBiZSB1cGRhdGVkLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuY2FjaGVkU3ByaXRlRGlydHkgPSBmYWxzZTtcbn1cblxuLy8gY29uc3RydWN0b3JcbkdyYXBoaWNzLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUpO1xuR3JhcGhpY3MucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gR3JhcGhpY3M7XG5tb2R1bGUuZXhwb3J0cyA9IEdyYXBoaWNzO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhHcmFwaGljcy5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBXaGVuIGNhY2hlQXNCaXRtYXAgaXMgc2V0IHRvIHRydWUgdGhlIGdyYXBoaWNzIG9iamVjdCB3aWxsIGJlIHJlbmRlcmVkIGFzIGlmIGl0IHdhcyBhIHNwcml0ZS5cbiAgICAgKiBUaGlzIGlzIHVzZWZ1bCBpZiB5b3VyIGdyYXBoaWNzIGVsZW1lbnQgZG9lcyBub3QgY2hhbmdlIG9mdGVuLCBhcyBpdCB3aWxsIHNwZWVkIHVwIHRoZSByZW5kZXJpbmdcbiAgICAgKiBvZiB0aGUgb2JqZWN0IGluIGV4Y2hhbmdlIGZvciB0YWtpbmcgdXAgdGV4dHVyZSBtZW1vcnkuIEl0IGlzIGFsc28gdXNlZnVsIGlmIHlvdSBuZWVkIHRoZSBncmFwaGljc1xuICAgICAqIG9iamVjdCB0byBiZSBhbnRpLWFsaWFzZWQsIGJlY2F1c2UgaXQgd2lsbCBiZSByZW5kZXJlZCB1c2luZyBjYW52YXMuIFRoaXMgaXMgbm90IHJlY29tbWVuZGVkIGlmXG4gICAgICogeW91IGFyZSBjb25zdGFudGx5IHJlZHJhd2luZyB0aGUgZ3JhcGhpY3MgZWxlbWVudC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICogQG1lbWJlcm9mIEdyYXBoaWNzI1xuICAgICAqIEBkZWZhdWx0IGZhbHNlXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBjYWNoZUFzQml0bWFwOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2NhY2hlQXNCaXRtYXA7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLl9jYWNoZUFzQml0bWFwID0gdmFsdWU7XG5cbiAgICAgICAgICAgIGlmICh0aGlzLl9jYWNoZUFzQml0bWFwKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fZ2VuZXJhdGVDYWNoZWRTcHJpdGUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuZGVzdHJveUNhY2hlZFNwcml0ZSgpO1xuICAgICAgICAgICAgICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufSk7XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldyBHcmFwaGljcyBvYmplY3Qgd2l0aCB0aGUgc2FtZSB2YWx1ZXMgYXMgdGhpcyBvbmUuXG4gKlxuICogQHJldHVybiB7R3JhcGhpY3N9XG4gKi9cbkdyYXBoaWNzRGF0YS5wcm90b3R5cGUuY2xvbmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGNsb25lID0gbmV3IEdyYXBoaWNzKCk7XG5cbiAgICBjbG9uZS5yZW5kZXJhYmxlICAgID0gdGhpcy5yZW5kZXJhYmxlO1xuICAgIGNsb25lLmZpbGxBbHBoYSAgICAgPSB0aGlzLmZpbGxBbHBoYTtcbiAgICBjbG9uZS5saW5lV2lkdGggICAgID0gdGhpcy5saW5lV2lkdGg7XG4gICAgY2xvbmUubGluZUNvbG9yICAgICA9IHRoaXMubGluZUNvbG9yO1xuICAgIGNsb25lLnRpbnQgICAgICAgICAgPSB0aGlzLnRpbnQ7XG4gICAgY2xvbmUuYmxlbmRNb2RlICAgICA9IHRoaXMuYmxlbmRNb2RlO1xuICAgIGNsb25lLmlzTWFzayAgICAgICAgPSB0aGlzLmlzTWFzaztcbiAgICBjbG9uZS5ib3VuZHNQYWRkaW5nID0gdGhpcy5ib3VuZHNQYWRkaW5nO1xuICAgIGNsb25lLmRpcnR5ICAgICAgICAgPSB0aGlzLmRpcnR5O1xuICAgIGNsb25lLmdsRGlydHkgICAgICAgPSB0aGlzLmdsRGlydHk7XG4gICAgY2xvbmUuY2FjaGVkU3ByaXRlRGlydHkgPSB0aGlzLmNhY2hlZFNwcml0ZURpcnR5O1xuXG4gICAgLy8gY29weSBncmFwaGljcyBkYXRhXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmdyYXBoaWNzRGF0YS5sZW5ndGg7ICsraSkge1xuICAgICAgICBjbG9uZS5ncmFwaGljc0RhdGEucHVzaCh0aGlzLmdyYXBoaWNzRGF0YS5jbG9uZSgpKTtcbiAgICB9XG5cbiAgICBjbG9uZS5jdXJyZW50UGF0aCA9IGNsb25lLmdyYXBoaWNzRGF0YVtjbG9uZS5ncmFwaGljc0RhdGEubGVuZ3RoIC0gMV07XG5cbiAgICBjbG9uZS51cGRhdGVMb2NhbEJvdW5kcygpO1xuXG4gICAgcmV0dXJuIGNsb25lO1xufTtcblxuLyoqXG4gKiBTcGVjaWZpZXMgdGhlIGxpbmUgc3R5bGUgdXNlZCBmb3Igc3Vic2VxdWVudCBjYWxscyB0byBHcmFwaGljcyBtZXRob2RzIHN1Y2ggYXMgdGhlIGxpbmVUbygpIG1ldGhvZCBvciB0aGUgZHJhd0NpcmNsZSgpIG1ldGhvZC5cbiAqXG4gKiBAcGFyYW0gbGluZVdpZHRoIHtudW1iZXJ9IHdpZHRoIG9mIHRoZSBsaW5lIHRvIGRyYXcsIHdpbGwgdXBkYXRlIHRoZSBvYmplY3RzIHN0b3JlZCBzdHlsZVxuICogQHBhcmFtIGNvbG9yIHtudW1iZXJ9IGNvbG9yIG9mIHRoZSBsaW5lIHRvIGRyYXcsIHdpbGwgdXBkYXRlIHRoZSBvYmplY3RzIHN0b3JlZCBzdHlsZVxuICogQHBhcmFtIGFscGhhIHtudW1iZXJ9IGFscGhhIG9mIHRoZSBsaW5lIHRvIGRyYXcsIHdpbGwgdXBkYXRlIHRoZSBvYmplY3RzIHN0b3JlZCBzdHlsZVxuICogQHJldHVybiB7R3JhcGhpY3N9XG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5saW5lU3R5bGUgPSBmdW5jdGlvbiAobGluZVdpZHRoLCBjb2xvciwgYWxwaGEpIHtcbiAgICB0aGlzLmxpbmVXaWR0aCA9IGxpbmVXaWR0aCB8fCAwO1xuICAgIHRoaXMubGluZUNvbG9yID0gY29sb3IgfHwgMDtcbiAgICB0aGlzLmxpbmVBbHBoYSA9IChhcmd1bWVudHMubGVuZ3RoIDwgMykgPyAxIDogYWxwaGE7XG5cbiAgICBpZiAodGhpcy5jdXJyZW50UGF0aCkge1xuICAgICAgICBpZiAodGhpcy5jdXJyZW50UGF0aC5zaGFwZS5wb2ludHMubGVuZ3RoKSB7XG4gICAgICAgICAgICAvLyBoYWxmd2F5IHRocm91Z2ggYSBsaW5lPyBzdGFydCBhIG5ldyBvbmUhXG4gICAgICAgICAgICB0aGlzLmRyYXdTaGFwZSggbmV3IG1hdGguUG9seWdvbiggdGhpcy5jdXJyZW50UGF0aC5zaGFwZS5wb2ludHMuc2xpY2UoLTIpICkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy8gb3RoZXJ3aXNlIGl0cyBlbXB0eSBzbyBsZXRzIGp1c3Qgc2V0IHRoZSBsaW5lIHByb3BlcnRpZXNcbiAgICAgICAgICAgIHRoaXMuY3VycmVudFBhdGgubGluZVdpZHRoID0gdGhpcy5saW5lV2lkdGg7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRQYXRoLmxpbmVDb2xvciA9IHRoaXMubGluZUNvbG9yO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50UGF0aC5saW5lQWxwaGEgPSB0aGlzLmxpbmVBbHBoYTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xufTtcblxuLyoqXG4gKiBNb3ZlcyB0aGUgY3VycmVudCBkcmF3aW5nIHBvc2l0aW9uIHRvIHgsIHkuXG4gKlxuICogQHBhcmFtIHgge251bWJlcn0gdGhlIFggY29vcmRpbmF0ZSB0byBtb3ZlIHRvXG4gKiBAcGFyYW0geSB7bnVtYmVyfSB0aGUgWSBjb29yZGluYXRlIHRvIG1vdmUgdG9cbiAqIEByZXR1cm4ge0dyYXBoaWNzfVxuICAqL1xuR3JhcGhpY3MucHJvdG90eXBlLm1vdmVUbyA9IGZ1bmN0aW9uICh4LCB5KSB7XG4gICAgdGhpcy5kcmF3U2hhcGUobmV3IG1hdGguUG9seWdvbihbeCx5XSkpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqIERyYXdzIGEgbGluZSB1c2luZyB0aGUgY3VycmVudCBsaW5lIHN0eWxlIGZyb20gdGhlIGN1cnJlbnQgZHJhd2luZyBwb3NpdGlvbiB0byAoeCwgeSk7XG4gKiBUaGUgY3VycmVudCBkcmF3aW5nIHBvc2l0aW9uIGlzIHRoZW4gc2V0IHRvICh4LCB5KS5cbiAqXG4gKiBAcGFyYW0geCB7bnVtYmVyfSB0aGUgWCBjb29yZGluYXRlIHRvIGRyYXcgdG9cbiAqIEBwYXJhbSB5IHtudW1iZXJ9IHRoZSBZIGNvb3JkaW5hdGUgdG8gZHJhdyB0b1xuICogQHJldHVybiB7R3JhcGhpY3N9XG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5saW5lVG8gPSBmdW5jdGlvbiAoeCwgeSkge1xuICAgIHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzLnB1c2goeCwgeSk7XG4gICAgdGhpcy5kaXJ0eSA9IHRydWU7XG5cbiAgICByZXR1cm4gdGhpcztcbn07XG5cbi8qKlxuICogQ2FsY3VsYXRlIHRoZSBwb2ludHMgZm9yIGEgcXVhZHJhdGljIGJlemllciBjdXJ2ZSBhbmQgdGhlbiBkcmF3cyBpdC5cbiAqIEJhc2VkIG9uOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy83ODUwOTcvaG93LWRvLWktaW1wbGVtZW50LWEtYmV6aWVyLWN1cnZlLWluLWNcbiAqXG4gKiBAcGFyYW0gY3BYIHtudW1iZXJ9IENvbnRyb2wgcG9pbnQgeFxuICogQHBhcmFtIGNwWSB7bnVtYmVyfSBDb250cm9sIHBvaW50IHlcbiAqIEBwYXJhbSB0b1gge251bWJlcn0gRGVzdGluYXRpb24gcG9pbnQgeFxuICogQHBhcmFtIHRvWSB7bnVtYmVyfSBEZXN0aW5hdGlvbiBwb2ludCB5XG4gKiBAcmV0dXJuIHtHcmFwaGljc31cbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLnF1YWRyYXRpY0N1cnZlVG8gPSBmdW5jdGlvbiAoY3BYLCBjcFksIHRvWCwgdG9ZKSB7XG4gICAgaWYgKHRoaXMuY3VycmVudFBhdGgpIHtcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50UGF0aC5zaGFwZS5wb2ludHMgPSBbMCwgMF07XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHRoaXMubW92ZVRvKDAsMCk7XG4gICAgfVxuXG4gICAgdmFyIHhhLFxuICAgICAgICB5YSxcbiAgICAgICAgbiA9IDIwLFxuICAgICAgICBwb2ludHMgPSB0aGlzLmN1cnJlbnRQYXRoLnNoYXBlLnBvaW50cztcblxuICAgIGlmIChwb2ludHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHRoaXMubW92ZVRvKDAsIDApO1xuICAgIH1cblxuICAgIHZhciBmcm9tWCA9IHBvaW50c1twb2ludHMubGVuZ3RoLTJdO1xuICAgIHZhciBmcm9tWSA9IHBvaW50c1twb2ludHMubGVuZ3RoLTFdO1xuXG4gICAgdmFyIGogPSAwO1xuICAgIGZvciAodmFyIGkgPSAxOyBpIDw9IG47ICsraSkge1xuICAgICAgICBqID0gaSAvIG47XG5cbiAgICAgICAgeGEgPSBmcm9tWCArICggKGNwWCAtIGZyb21YKSAqIGogKTtcbiAgICAgICAgeWEgPSBmcm9tWSArICggKGNwWSAtIGZyb21ZKSAqIGogKTtcblxuICAgICAgICBwb2ludHMucHVzaCggeGEgKyAoICgoY3BYICsgKCAodG9YIC0gY3BYKSAqIGogKSkgLSB4YSkgKiBqICksXG4gICAgICAgICAgICAgICAgICAgICB5YSArICggKChjcFkgKyAoICh0b1kgLSBjcFkpICogaiApKSAtIHlhKSAqIGogKSApO1xuICAgIH1cblxuICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqIENhbGN1bGF0ZSB0aGUgcG9pbnRzIGZvciBhIGJlemllciBjdXJ2ZSBhbmQgdGhlbiBkcmF3cyBpdC5cbiAqXG4gKiBAcGFyYW0gY3BYIHtudW1iZXJ9IENvbnRyb2wgcG9pbnQgeFxuICogQHBhcmFtIGNwWSB7bnVtYmVyfSBDb250cm9sIHBvaW50IHlcbiAqIEBwYXJhbSBjcFgyIHtudW1iZXJ9IFNlY29uZCBDb250cm9sIHBvaW50IHhcbiAqIEBwYXJhbSBjcFkyIHtudW1iZXJ9IFNlY29uZCBDb250cm9sIHBvaW50IHlcbiAqIEBwYXJhbSB0b1gge251bWJlcn0gRGVzdGluYXRpb24gcG9pbnQgeFxuICogQHBhcmFtIHRvWSB7bnVtYmVyfSBEZXN0aW5hdGlvbiBwb2ludCB5XG4gKiBAcmV0dXJuIHtHcmFwaGljc31cbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLmJlemllckN1cnZlVG8gPSBmdW5jdGlvbiAoY3BYLCBjcFksIGNwWDIsIGNwWTIsIHRvWCwgdG9ZKSB7XG4gICAgaWYgKHRoaXMuY3VycmVudFBhdGgpIHtcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50UGF0aC5zaGFwZS5wb2ludHMgPSBbMCwgMF07XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHRoaXMubW92ZVRvKDAsMCk7XG4gICAgfVxuXG4gICAgdmFyIG4gPSAyMCxcbiAgICAgICAgZHQsXG4gICAgICAgIGR0MixcbiAgICAgICAgZHQzLFxuICAgICAgICB0MixcbiAgICAgICAgdDMsXG4gICAgICAgIHBvaW50cyA9IHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzO1xuXG4gICAgdmFyIGZyb21YID0gcG9pbnRzW3BvaW50cy5sZW5ndGgtMl07XG4gICAgdmFyIGZyb21ZID0gcG9pbnRzW3BvaW50cy5sZW5ndGgtMV07XG5cbiAgICB2YXIgaiA9IDA7XG5cbiAgICBmb3IgKHZhciBpID0gMTsgaSA8PSBuOyArK2kpIHtcbiAgICAgICAgaiA9IGkgLyBuO1xuXG4gICAgICAgIGR0ID0gKDEgLSBqKTtcbiAgICAgICAgZHQyID0gZHQgKiBkdDtcbiAgICAgICAgZHQzID0gZHQyICogZHQ7XG5cbiAgICAgICAgdDIgPSBqICogajtcbiAgICAgICAgdDMgPSB0MiAqIGo7XG5cbiAgICAgICAgcG9pbnRzLnB1c2goIGR0MyAqIGZyb21YICsgMyAqIGR0MiAqIGogKiBjcFggKyAzICogZHQgKiB0MiAqIGNwWDIgKyB0MyAqIHRvWCxcbiAgICAgICAgICAgICAgICAgICAgIGR0MyAqIGZyb21ZICsgMyAqIGR0MiAqIGogKiBjcFkgKyAzICogZHQgKiB0MiAqIGNwWTIgKyB0MyAqIHRvWSk7XG4gICAgfVxuXG4gICAgdGhpcy5kaXJ0eSA9IHRydWU7XG5cbiAgICByZXR1cm4gdGhpcztcbn07XG5cbi8qKlxuICogVGhlIGFyY1RvKCkgbWV0aG9kIGNyZWF0ZXMgYW4gYXJjL2N1cnZlIGJldHdlZW4gdHdvIHRhbmdlbnRzIG9uIHRoZSBjYW52YXMuXG4gKlxuICogXCJib3Jyb3dlZFwiIGZyb20gaHR0cHM6Ly9jb2RlLmdvb2dsZS5jb20vcC9meGNhbnZhcy8gLSB0aGFua3MgZ29vZ2xlIVxuICpcbiAqIEBwYXJhbSB4MSB7bnVtYmVyfSBUaGUgeC1jb29yZGluYXRlIG9mIHRoZSBiZWdpbm5pbmcgb2YgdGhlIGFyY1xuICogQHBhcmFtIHkxIHtudW1iZXJ9IFRoZSB5LWNvb3JkaW5hdGUgb2YgdGhlIGJlZ2lubmluZyBvZiB0aGUgYXJjXG4gKiBAcGFyYW0geDIge251bWJlcn0gVGhlIHgtY29vcmRpbmF0ZSBvZiB0aGUgZW5kIG9mIHRoZSBhcmNcbiAqIEBwYXJhbSB5MiB7bnVtYmVyfSBUaGUgeS1jb29yZGluYXRlIG9mIHRoZSBlbmQgb2YgdGhlIGFyY1xuICogQHBhcmFtIHJhZGl1cyB7bnVtYmVyfSBUaGUgcmFkaXVzIG9mIHRoZSBhcmNcbiAqIEByZXR1cm4ge0dyYXBoaWNzfVxuICovXG5HcmFwaGljcy5wcm90b3R5cGUuYXJjVG8gPSBmdW5jdGlvbiAoeDEsIHkxLCB4MiwgeTIsIHJhZGl1cykge1xuICAgIGlmICh0aGlzLmN1cnJlbnRQYXRoKSB7XG4gICAgICAgIGlmICh0aGlzLmN1cnJlbnRQYXRoLnNoYXBlLnBvaW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzLnB1c2goeDEsIHkxKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdGhpcy5tb3ZlVG8oeDEsIHkxKTtcbiAgICB9XG5cbiAgICB2YXIgcG9pbnRzID0gdGhpcy5jdXJyZW50UGF0aC5zaGFwZS5wb2ludHMsXG4gICAgICAgIGZyb21YID0gcG9pbnRzW3BvaW50cy5sZW5ndGgtMl0sXG4gICAgICAgIGZyb21ZID0gcG9pbnRzW3BvaW50cy5sZW5ndGgtMV0sXG4gICAgICAgIGExID0gZnJvbVkgLSB5MSxcbiAgICAgICAgYjEgPSBmcm9tWCAtIHgxLFxuICAgICAgICBhMiA9IHkyICAgLSB5MSxcbiAgICAgICAgYjIgPSB4MiAgIC0geDEsXG4gICAgICAgIG1tID0gTWF0aC5hYnMoYTEgKiBiMiAtIGIxICogYTIpO1xuXG4gICAgaWYgKG1tIDwgMS4wZS04IHx8IHJhZGl1cyA9PT0gMCkge1xuICAgICAgICBpZiAocG9pbnRzW3BvaW50cy5sZW5ndGgtMl0gIT09IHgxIHx8IHBvaW50c1twb2ludHMubGVuZ3RoLTFdICE9PSB5MSkge1xuICAgICAgICAgICAgcG9pbnRzLnB1c2goeDEsIHkxKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdmFyIGRkID0gYTEgKiBhMSArIGIxICogYjEsXG4gICAgICAgICAgICBjYyA9IGEyICogYTIgKyBiMiAqIGIyLFxuICAgICAgICAgICAgdHQgPSBhMSAqIGEyICsgYjEgKiBiMixcbiAgICAgICAgICAgIGsxID0gcmFkaXVzICogTWF0aC5zcXJ0KGRkKSAvIG1tLFxuICAgICAgICAgICAgazIgPSByYWRpdXMgKiBNYXRoLnNxcnQoY2MpIC8gbW0sXG4gICAgICAgICAgICBqMSA9IGsxICogdHQgLyBkZCxcbiAgICAgICAgICAgIGoyID0gazIgKiB0dCAvIGNjLFxuICAgICAgICAgICAgY3ggPSBrMSAqIGIyICsgazIgKiBiMSxcbiAgICAgICAgICAgIGN5ID0gazEgKiBhMiArIGsyICogYTEsXG4gICAgICAgICAgICBweCA9IGIxICogKGsyICsgajEpLFxuICAgICAgICAgICAgcHkgPSBhMSAqIChrMiArIGoxKSxcbiAgICAgICAgICAgIHF4ID0gYjIgKiAoazEgKyBqMiksXG4gICAgICAgICAgICBxeSA9IGEyICogKGsxICsgajIpLFxuICAgICAgICAgICAgc3RhcnRBbmdsZSA9IE1hdGguYXRhbjIocHkgLSBjeSwgcHggLSBjeCksXG4gICAgICAgICAgICBlbmRBbmdsZSAgID0gTWF0aC5hdGFuMihxeSAtIGN5LCBxeCAtIGN4KTtcblxuICAgICAgICB0aGlzLmFyYyhjeCArIHgxLCBjeSArIHkxLCByYWRpdXMsIHN0YXJ0QW5nbGUsIGVuZEFuZ2xlLCBiMSAqIGEyID4gYjIgKiBhMSk7XG4gICAgfVxuXG4gICAgdGhpcy5kaXJ0eSA9IHRydWU7XG5cbiAgICByZXR1cm4gdGhpcztcbn07XG5cbi8qKlxuICogVGhlIGFyYyBtZXRob2QgY3JlYXRlcyBhbiBhcmMvY3VydmUgKHVzZWQgdG8gY3JlYXRlIGNpcmNsZXMsIG9yIHBhcnRzIG9mIGNpcmNsZXMpLlxuICpcbiAqIEBwYXJhbSBjeCB7bnVtYmVyfSBUaGUgeC1jb29yZGluYXRlIG9mIHRoZSBjZW50ZXIgb2YgdGhlIGNpcmNsZVxuICogQHBhcmFtIGN5IHtudW1iZXJ9IFRoZSB5LWNvb3JkaW5hdGUgb2YgdGhlIGNlbnRlciBvZiB0aGUgY2lyY2xlXG4gKiBAcGFyYW0gcmFkaXVzIHtudW1iZXJ9IFRoZSByYWRpdXMgb2YgdGhlIGNpcmNsZVxuICogQHBhcmFtIHN0YXJ0QW5nbGUge251bWJlcn0gVGhlIHN0YXJ0aW5nIGFuZ2xlLCBpbiByYWRpYW5zICgwIGlzIGF0IHRoZSAzIG8nY2xvY2sgcG9zaXRpb24gb2YgdGhlIGFyYydzIGNpcmNsZSlcbiAqIEBwYXJhbSBlbmRBbmdsZSB7bnVtYmVyfSBUaGUgZW5kaW5nIGFuZ2xlLCBpbiByYWRpYW5zXG4gKiBAcGFyYW0gYW50aWNsb2Nrd2lzZSB7Ym9vbGVhbn0gT3B0aW9uYWwuIFNwZWNpZmllcyB3aGV0aGVyIHRoZSBkcmF3aW5nIHNob3VsZCBiZSBjb3VudGVyY2xvY2t3aXNlIG9yIGNsb2Nrd2lzZS4gRmFsc2UgaXMgZGVmYXVsdCwgYW5kIGluZGljYXRlcyBjbG9ja3dpc2UsIHdoaWxlIHRydWUgaW5kaWNhdGVzIGNvdW50ZXItY2xvY2t3aXNlLlxuICogQHJldHVybiB7R3JhcGhpY3N9XG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5hcmMgPSBmdW5jdGlvbiAoY3gsIGN5LCByYWRpdXMsIHN0YXJ0QW5nbGUsIGVuZEFuZ2xlLCBhbnRpY2xvY2t3aXNlKSB7XG4gICAgdmFyIHN0YXJ0WCA9IGN4ICsgTWF0aC5jb3Moc3RhcnRBbmdsZSkgKiByYWRpdXM7XG4gICAgdmFyIHN0YXJ0WSA9IGN5ICsgTWF0aC5zaW4oc3RhcnRBbmdsZSkgKiByYWRpdXM7XG4gICAgdmFyIHBvaW50cztcblxuICAgIC8vIFRPRE8gLSBUaGlzIGlmLWVsc2UgbWFrZXMgbm8gc2Vuc2UuIEl0IHVzZXMgY3VycmVudFBhdGggaW4gdGhlIGVsc2Ugd2hlcmUgaXQgZG9lc24ndCBleGlzdC4uLlxuICAgIGlmICh0aGlzLmN1cnJlbnRQYXRoKSB7XG4gICAgICAgIHBvaW50cyA9IHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzO1xuXG4gICAgICAgIGlmIChwb2ludHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICBwb2ludHMucHVzaChzdGFydFgsIHN0YXJ0WSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAocG9pbnRzW3BvaW50cy5sZW5ndGgtMl0gIT09IHN0YXJ0WCB8fCBwb2ludHNbcG9pbnRzLmxlbmd0aC0xXSAhPT0gc3RhcnRZKSB7XG4gICAgICAgICAgICBwb2ludHMucHVzaChzdGFydFgsIHN0YXJ0WSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHRoaXMubW92ZVRvKHN0YXJ0WCwgc3RhcnRZKTtcbiAgICAgICAgcG9pbnRzID0gdGhpcy5jdXJyZW50UGF0aC5zaGFwZS5wb2ludHM7XG4gICAgfVxuXG4gICAgaWYgKHN0YXJ0QW5nbGUgPT09IGVuZEFuZ2xlKSB7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIGlmICghYW50aWNsb2Nrd2lzZSAmJiBlbmRBbmdsZSA8PSBzdGFydEFuZ2xlKSB7XG4gICAgICAgIGVuZEFuZ2xlICs9IE1hdGguUEkgKiAyO1xuICAgIH1cbiAgICBlbHNlIGlmIChhbnRpY2xvY2t3aXNlICYmIHN0YXJ0QW5nbGUgPD0gZW5kQW5nbGUpIHtcbiAgICAgICAgc3RhcnRBbmdsZSArPSBNYXRoLlBJICogMjtcbiAgICB9XG5cbiAgICB2YXIgc3dlZXAgPSBhbnRpY2xvY2t3aXNlID8gKHN0YXJ0QW5nbGUgLSBlbmRBbmdsZSkgKi0xIDogKGVuZEFuZ2xlIC0gc3RhcnRBbmdsZSk7XG4gICAgdmFyIHNlZ3MgPSAoTWF0aC5hYnMoc3dlZXApLyAoTWF0aC5QSSAqIDIpKSAqIDQwO1xuXG4gICAgaWYgKHN3ZWVwID09PSAwKSB7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIHZhciB0aGV0YSA9IHN3ZWVwLyhzZWdzKjIpO1xuICAgIHZhciB0aGV0YTIgPSB0aGV0YSoyO1xuXG4gICAgdmFyIGNUaGV0YSA9IE1hdGguY29zKHRoZXRhKTtcbiAgICB2YXIgc1RoZXRhID0gTWF0aC5zaW4odGhldGEpO1xuXG4gICAgdmFyIHNlZ01pbnVzID0gc2VncyAtIDE7XG5cbiAgICB2YXIgcmVtYWluZGVyID0gKCBzZWdNaW51cyAlIDEgKSAvIHNlZ01pbnVzO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPD0gc2VnTWludXM7ICsraSkge1xuICAgICAgICB2YXIgcmVhbCA9ICBpICsgcmVtYWluZGVyICogaTtcbiAgICAgICAgdmFyIGFuZ2xlID0gKCh0aGV0YSkgKyBzdGFydEFuZ2xlICsgKHRoZXRhMiAqIHJlYWwpKTtcblxuICAgICAgICB2YXIgYyA9IE1hdGguY29zKGFuZ2xlKTtcbiAgICAgICAgdmFyIHMgPSAtTWF0aC5zaW4oYW5nbGUpO1xuXG4gICAgICAgIHBvaW50cy5wdXNoKCggKGNUaGV0YSAqICBjKSArIChzVGhldGEgKiBzKSApICogcmFkaXVzICsgY3gsXG4gICAgICAgICAgICAgICAgICAgICggKGNUaGV0YSAqIC1zKSArIChzVGhldGEgKiBjKSApICogcmFkaXVzICsgY3kpO1xuICAgIH1cblxuICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqIFNwZWNpZmllcyBhIHNpbXBsZSBvbmUtY29sb3IgZmlsbCB0aGF0IHN1YnNlcXVlbnQgY2FsbHMgdG8gb3RoZXIgR3JhcGhpY3MgbWV0aG9kc1xuICogKHN1Y2ggYXMgbGluZVRvKCkgb3IgZHJhd0NpcmNsZSgpKSB1c2Ugd2hlbiBkcmF3aW5nLlxuICpcbiAqIEBwYXJhbSBjb2xvciB7bnVtYmVyfSB0aGUgY29sb3Igb2YgdGhlIGZpbGxcbiAqIEBwYXJhbSBhbHBoYSB7bnVtYmVyfSB0aGUgYWxwaGEgb2YgdGhlIGZpbGxcbiAqIEByZXR1cm4ge0dyYXBoaWNzfVxuICovXG5HcmFwaGljcy5wcm90b3R5cGUuYmVnaW5GaWxsID0gZnVuY3Rpb24gKGNvbG9yLCBhbHBoYSkge1xuICAgIHRoaXMuZmlsbGluZyA9IHRydWU7XG4gICAgdGhpcy5maWxsQ29sb3IgPSBjb2xvciB8fCAwO1xuICAgIHRoaXMuZmlsbEFscGhhID0gKGFscGhhID09PSB1bmRlZmluZWQpID8gMSA6IGFscGhhO1xuXG4gICAgaWYgKHRoaXMuY3VycmVudFBhdGgpIHtcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzLmxlbmd0aCA8PSAyKSB7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRQYXRoLmZpbGwgPSB0aGlzLmZpbGxpbmc7XG4gICAgICAgICAgICB0aGlzLmN1cnJlbnRQYXRoLmZpbGxDb2xvciA9IHRoaXMuZmlsbENvbG9yO1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50UGF0aC5maWxsQWxwaGEgPSB0aGlzLmZpbGxBbHBoYTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbn07XG5cbi8qKlxuICogQXBwbGllcyBhIGZpbGwgdG8gdGhlIGxpbmVzIGFuZCBzaGFwZXMgdGhhdCB3ZXJlIGFkZGVkIHNpbmNlIHRoZSBsYXN0IGNhbGwgdG8gdGhlIGJlZ2luRmlsbCgpIG1ldGhvZC5cbiAqXG4gKiBAcmV0dXJuIHtHcmFwaGljc31cbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLmVuZEZpbGwgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5maWxsaW5nID0gZmFsc2U7XG4gICAgdGhpcy5maWxsQ29sb3IgPSBudWxsO1xuICAgIHRoaXMuZmlsbEFscGhhID0gMTtcblxuICAgIHJldHVybiB0aGlzO1xufTtcblxuLyoqXG4gKlxuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmQgb2YgdGhlIHRvcC1sZWZ0IG9mIHRoZSByZWN0YW5nbGVcbiAqIEBwYXJhbSB5IHtudW1iZXJ9IFRoZSBZIGNvb3JkIG9mIHRoZSB0b3AtbGVmdCBvZiB0aGUgcmVjdGFuZ2xlXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gVGhlIHdpZHRoIG9mIHRoZSByZWN0YW5nbGVcbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gVGhlIGhlaWdodCBvZiB0aGUgcmVjdGFuZ2xlXG4gKiBAcmV0dXJuIHtHcmFwaGljc31cbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLmRyYXdSZWN0ID0gZnVuY3Rpb24gKCB4LCB5LCB3aWR0aCwgaGVpZ2h0ICkge1xuICAgIHRoaXMuZHJhd1NoYXBlKG5ldyBtYXRoLlJlY3RhbmdsZSh4LHksIHdpZHRoLCBoZWlnaHQpKTtcblxuICAgIHJldHVybiB0aGlzO1xufTtcblxuLyoqXG4gKlxuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmQgb2YgdGhlIHRvcC1sZWZ0IG9mIHRoZSByZWN0YW5nbGVcbiAqIEBwYXJhbSB5IHtudW1iZXJ9IFRoZSBZIGNvb3JkIG9mIHRoZSB0b3AtbGVmdCBvZiB0aGUgcmVjdGFuZ2xlXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gVGhlIHdpZHRoIG9mIHRoZSByZWN0YW5nbGVcbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gVGhlIGhlaWdodCBvZiB0aGUgcmVjdGFuZ2xlXG4gKiBAcGFyYW0gcmFkaXVzIHtudW1iZXJ9IFJhZGl1cyBvZiB0aGUgcmVjdGFuZ2xlIGNvcm5lcnNcbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLmRyYXdSb3VuZGVkUmVjdCA9IGZ1bmN0aW9uICggeCwgeSwgd2lkdGgsIGhlaWdodCwgcmFkaXVzICkge1xuICAgIHRoaXMuZHJhd1NoYXBlKG5ldyBtYXRoLlJvdW5kZWRSZWN0YW5nbGUoeCwgeSwgd2lkdGgsIGhlaWdodCwgcmFkaXVzKSk7XG5cbiAgICByZXR1cm4gdGhpcztcbn07XG5cbi8qKlxuICogRHJhd3MgYSBjaXJjbGUuXG4gKlxuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmRpbmF0ZSBvZiB0aGUgY2VudGVyIG9mIHRoZSBjaXJjbGVcbiAqIEBwYXJhbSB5IHtudW1iZXJ9IFRoZSBZIGNvb3JkaW5hdGUgb2YgdGhlIGNlbnRlciBvZiB0aGUgY2lyY2xlXG4gKiBAcGFyYW0gcmFkaXVzIHtudW1iZXJ9IFRoZSByYWRpdXMgb2YgdGhlIGNpcmNsZVxuICogQHJldHVybiB7R3JhcGhpY3N9XG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5kcmF3Q2lyY2xlID0gZnVuY3Rpb24gKHgsIHksIHJhZGl1cykge1xuICAgIHRoaXMuZHJhd1NoYXBlKG5ldyBtYXRoLkNpcmNsZSh4LHksIHJhZGl1cykpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqIERyYXdzIGFuIGVsbGlwc2UuXG4gKlxuICogQHBhcmFtIHgge251bWJlcn0gVGhlIFggY29vcmRpbmF0ZSBvZiB0aGUgY2VudGVyIG9mIHRoZSBlbGxpcHNlXG4gKiBAcGFyYW0geSB7bnVtYmVyfSBUaGUgWSBjb29yZGluYXRlIG9mIHRoZSBjZW50ZXIgb2YgdGhlIGVsbGlwc2VcbiAqIEBwYXJhbSB3aWR0aCB7bnVtYmVyfSBUaGUgaGFsZiB3aWR0aCBvZiB0aGUgZWxsaXBzZVxuICogQHBhcmFtIGhlaWdodCB7bnVtYmVyfSBUaGUgaGFsZiBoZWlnaHQgb2YgdGhlIGVsbGlwc2VcbiAqIEByZXR1cm4ge0dyYXBoaWNzfVxuICovXG5HcmFwaGljcy5wcm90b3R5cGUuZHJhd0VsbGlwc2UgPSBmdW5jdGlvbiAoeCwgeSwgd2lkdGgsIGhlaWdodCkge1xuICAgIHRoaXMuZHJhd1NoYXBlKG5ldyBtYXRoLkVsbGlwc2UoeCwgeSwgd2lkdGgsIGhlaWdodCkpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqIERyYXdzIGEgcG9seWdvbiB1c2luZyB0aGUgZ2l2ZW4gcGF0aC5cbiAqXG4gKiBAcGFyYW0gcGF0aCB7QXJyYXl9IFRoZSBwYXRoIGRhdGEgdXNlZCB0byBjb25zdHJ1Y3QgdGhlIHBvbHlnb24uXG4gKiBAcmV0dXJuIHtHcmFwaGljc31cbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLmRyYXdQb2x5Z29uID0gZnVuY3Rpb24gKHBhdGgpIHtcbiAgICBpZiAoIShwYXRoIGluc3RhbmNlb2YgQXJyYXkpKSB7XG4gICAgICAgIHBhdGggPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuICAgIH1cblxuICAgIHRoaXMuZHJhd1NoYXBlKG5ldyBtYXRoLlBvbHlnb24ocGF0aCkpO1xuXG4gICAgcmV0dXJuIHRoaXM7XG59O1xuXG4vKipcbiAqIENsZWFycyB0aGUgZ3JhcGhpY3MgdGhhdCB3ZXJlIGRyYXduIHRvIHRoaXMgR3JhcGhpY3Mgb2JqZWN0LCBhbmQgcmVzZXRzIGZpbGwgYW5kIGxpbmUgc3R5bGUgc2V0dGluZ3MuXG4gKlxuICogQHJldHVybiB7R3JhcGhpY3N9XG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5jbGVhciA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmxpbmVXaWR0aCA9IDA7XG4gICAgdGhpcy5maWxsaW5nID0gZmFsc2U7XG5cbiAgICB0aGlzLmRpcnR5ID0gdHJ1ZTtcbiAgICB0aGlzLmNsZWFyRGlydHkgPSB0cnVlO1xuICAgIHRoaXMuZ3JhcGhpY3NEYXRhID0gW107XG5cbiAgICByZXR1cm4gdGhpcztcbn07XG5cbi8qKlxuICogVXNlZnVsIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhIHRleHR1cmUgb2YgdGhlIGdyYXBoaWNzIG9iamVjdCB0aGF0IGNhbiB0aGVuIGJlIHVzZWQgdG8gY3JlYXRlIHNwcml0ZXNcbiAqIFRoaXMgY2FuIGJlIHF1aXRlIHVzZWZ1bCBpZiB5b3VyIGdlb21ldHJ5IGlzIGNvbXBsaWNhdGVkIGFuZCBuZWVkcyB0byBiZSByZXVzZWQgbXVsdGlwbGUgdGltZXMuXG4gKlxuICogQHBhcmFtIHJlc29sdXRpb24ge251bWJlcn0gVGhlIHJlc29sdXRpb24gb2YgdGhlIHRleHR1cmUgYmVpbmcgZ2VuZXJhdGVkXG4gKiBAcGFyYW0gc2NhbGVNb2RlIHtudW1iZXJ9IFNob3VsZCBiZSBvbmUgb2YgdGhlIHNjYWxlTW9kZSBjb25zdHNcbiAqIEByZXR1cm4ge1RleHR1cmV9IGEgdGV4dHVyZSBvZiB0aGUgZ3JhcGhpY3Mgb2JqZWN0XG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5nZW5lcmF0ZVRleHR1cmUgPSBmdW5jdGlvbiAocmVzb2x1dGlvbiwgc2NhbGVNb2RlKSB7XG4gICAgcmVzb2x1dGlvbiA9IHJlc29sdXRpb24gfHwgMTtcblxuICAgIHZhciBib3VuZHMgPSB0aGlzLmdldEJvdW5kcygpO1xuXG4gICAgdmFyIGNhbnZhc0J1ZmZlciA9IG5ldyBDYW52YXNCdWZmZXIoYm91bmRzLndpZHRoICogcmVzb2x1dGlvbiwgYm91bmRzLmhlaWdodCAqIHJlc29sdXRpb24pO1xuXG4gICAgdmFyIHRleHR1cmUgPSBUZXh0dXJlLmZyb21DYW52YXMoY2FudmFzQnVmZmVyLmNhbnZhcywgc2NhbGVNb2RlKTtcbiAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLnJlc29sdXRpb24gPSByZXNvbHV0aW9uO1xuXG4gICAgY2FudmFzQnVmZmVyLmNvbnRleHQuc2NhbGUocmVzb2x1dGlvbiwgcmVzb2x1dGlvbik7XG5cbiAgICBjYW52YXNCdWZmZXIuY29udGV4dC50cmFuc2xhdGUoLWJvdW5kcy54LC1ib3VuZHMueSk7XG5cbiAgICBDYW52YXNHcmFwaGljcy5yZW5kZXJHcmFwaGljcyh0aGlzLCBjYW52YXNCdWZmZXIuY29udGV4dCk7XG5cbiAgICByZXR1cm4gdGV4dHVyZTtcbn07XG5cbi8qKlxuICogUmVuZGVycyB0aGUgb2JqZWN0IHVzaW5nIHRoZSBXZWJHTCByZW5kZXJlclxuICpcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcn1cbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLnJlbmRlcldlYkdMID0gZnVuY3Rpb24gKHJlbmRlcmVyKSB7XG4gICAgLy8gaWYgdGhlIHNwcml0ZSBpcyBub3QgdmlzaWJsZSBvciB0aGUgYWxwaGEgaXMgMCB0aGVuIG5vIG5lZWQgdG8gcmVuZGVyIHRoaXMgZWxlbWVudFxuICAgIGlmICghdGhpcy52aXNpYmxlIHx8IHRoaXMuYWxwaGEgPD0gMCB8fCB0aGlzLmlzTWFzayA9PT0gdHJ1ZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX2NhY2hlQXNCaXRtYXApIHtcbiAgICAgICAgaWYgKHRoaXMuZGlydHkgfHwgdGhpcy5jYWNoZWRTcHJpdGVEaXJ0eSkge1xuICAgICAgICAgICAgdGhpcy5fZ2VuZXJhdGVDYWNoZWRTcHJpdGUoKTtcblxuICAgICAgICAgICAgLy8gd2Ugd2lsbCBhbHNvIG5lZWQgdG8gdXBkYXRlIHRoZSB0ZXh0dXJlIG9uIHRoZSBncHUgdG9vIVxuICAgICAgICAgICAgdGhpcy51cGRhdGVDYWNoZWRTcHJpdGVUZXh0dXJlKCk7XG5cbiAgICAgICAgICAgIHRoaXMuY2FjaGVkU3ByaXRlRGlydHkgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMuZGlydHkgPSBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuX2NhY2hlZFNwcml0ZS53b3JsZEFscGhhID0gdGhpcy53b3JsZEFscGhhO1xuXG4gICAgICAgIFNwcml0ZS5wcm90b3R5cGUucmVuZGVyV2ViR0wuY2FsbCh0aGlzLl9jYWNoZWRTcHJpdGUsIHJlbmRlcmVyKTtcblxuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5zdG9wKCk7XG4gICAgICAgIHJlbmRlcmVyLmJsZW5kTW9kZU1hbmFnZXIuc2V0QmxlbmRNb2RlKHRoaXMuYmxlbmRNb2RlKTtcblxuICAgICAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucHVzaE1hc2sodGhpcy5fbWFzaywgcmVuZGVyZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuX2ZpbHRlcnMpIHtcbiAgICAgICAgICAgIHJlbmRlcmVyLmZpbHRlck1hbmFnZXIucHVzaEZpbHRlcih0aGlzLl9maWx0ZXJCbG9jayk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBjaGVjayBibGVuZCBtb2RlXG4gICAgICAgIGlmICh0aGlzLmJsZW5kTW9kZSAhPT0gcmVuZGVyZXIuc3ByaXRlQmF0Y2guY3VycmVudEJsZW5kTW9kZSkge1xuICAgICAgICAgICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guY3VycmVudEJsZW5kTW9kZSA9IHRoaXMuYmxlbmRNb2RlO1xuXG4gICAgICAgICAgICB2YXIgYmxlbmRNb2RlV2ViR0wgPSByZW5kZXJlci5ibGVuZE1vZGVzW3JlbmRlcmVyLnNwcml0ZUJhdGNoLmN1cnJlbnRCbGVuZE1vZGVdO1xuXG4gICAgICAgICAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5nbC5ibGVuZEZ1bmMoYmxlbmRNb2RlV2ViR0xbMF0sIGJsZW5kTW9kZVdlYkdMWzFdKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGNoZWNrIGlmIHRoZSB3ZWJnbCBncmFwaGljIG5lZWRzIHRvIGJlIHVwZGF0ZWRcbiAgICAgICAgaWYgKHRoaXMuZ2xEaXJ0eSkge1xuICAgICAgICAgICAgdGhpcy5kaXJ0eSA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLmdsRGlydHkgPSBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIFdlYkdMR3JhcGhpY3MucmVuZGVyR3JhcGhpY3ModGhpcywgcmVuZGVyZXIpO1xuXG4gICAgICAgIC8vIG9ubHkgcmVuZGVyIGlmIGl0IGhhcyBjaGlsZHJlbiFcbiAgICAgICAgaWYgKHRoaXMuY2hpbGRyZW4ubGVuZ3RoKSB7XG4gICAgICAgICAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5zdGFydCgpO1xuXG4gICAgICAgICAgICAgLy8gc2ltcGxlIHJlbmRlciBjaGlsZHJlbiFcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwLCBqID0gdGhpcy5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyArK2kpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNoaWxkcmVuW2ldLnJlbmRlcldlYkdMKHJlbmRlcmVyKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guc3RvcCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuX2ZpbHRlcnMpIHtcbiAgICAgICAgICAgIHJlbmRlcmVyLmZpbHRlck1hbmFnZXIucG9wRmlsdGVyKCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucG9wTWFzayh0aGlzLm1hc2ssIHJlbmRlcmVyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlbmRlcmVyLmRyYXdDb3VudCsrO1xuXG4gICAgICAgIHJlbmRlcmVyLnNwcml0ZUJhdGNoLnN0YXJ0KCk7XG4gICAgfVxufTtcblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBvYmplY3QgdXNpbmcgdGhlIENhbnZhcyByZW5kZXJlclxuICpcbiAqIEBwYXJhbSByZW5kZXJlciB7Q2FudmFzUmVuZGVyZXJ9XG4gKiBAcHJpdmF0ZVxuICovXG5HcmFwaGljcy5wcm90b3R5cGUucmVuZGVyQ2FudmFzID0gZnVuY3Rpb24gKHJlbmRlcmVyKSB7XG4gICAgLy8gaWYgdGhlIHNwcml0ZSBpcyBub3QgdmlzaWJsZSBvciB0aGUgYWxwaGEgaXMgMCB0aGVuIG5vIG5lZWQgdG8gcmVuZGVyIHRoaXMgZWxlbWVudFxuICAgIGlmICghdGhpcy52aXNpYmxlIHx8IHRoaXMuYWxwaGEgPD0gMCB8fCB0aGlzLmlzTWFzayA9PT0gdHJ1ZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX2NhY2hlQXNCaXRtYXApIHtcbiAgICAgICAgaWYgKHRoaXMuZGlydHkgfHwgdGhpcy5jYWNoZWRTcHJpdGVEaXJ0eSkge1xuICAgICAgICAgICAgdGhpcy5fZ2VuZXJhdGVDYWNoZWRTcHJpdGUoKTtcblxuICAgICAgICAgICAgLy8gd2Ugd2lsbCBhbHNvIG5lZWQgdG8gdXBkYXRlIHRoZSB0ZXh0dXJlXG4gICAgICAgICAgICB0aGlzLnVwZGF0ZUNhY2hlZFNwcml0ZVRleHR1cmUoKTtcblxuICAgICAgICAgICAgdGhpcy5jYWNoZWRTcHJpdGVEaXJ0eSA9IGZhbHNlO1xuICAgICAgICAgICAgdGhpcy5kaXJ0eSA9IGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fY2FjaGVkU3ByaXRlLmFscGhhID0gdGhpcy5hbHBoYTtcblxuICAgICAgICBTcHJpdGUucHJvdG90eXBlLnJlbmRlckNhbnZhcy5jYWxsKHRoaXMuX2NhY2hlZFNwcml0ZSwgcmVuZGVyZXIpO1xuXG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHZhciBjb250ZXh0ID0gcmVuZGVyZXIuY29udGV4dDtcbiAgICAgICAgdmFyIHRyYW5zZm9ybSA9IHRoaXMud29ybGRUcmFuc2Zvcm07XG5cbiAgICAgICAgaWYgKHRoaXMuYmxlbmRNb2RlICE9PSByZW5kZXJlci5jdXJyZW50QmxlbmRNb2RlKSB7XG4gICAgICAgICAgICByZW5kZXJlci5jdXJyZW50QmxlbmRNb2RlID0gdGhpcy5ibGVuZE1vZGU7XG4gICAgICAgICAgICBjb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9IHJlbmRlcmVyLmJsZW5kTW9kZXNbcmVuZGVyZXIuY3VycmVudEJsZW5kTW9kZV07XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucHVzaE1hc2sodGhpcy5fbWFzaywgcmVuZGVyZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHJlc29sdXRpb24gPSByZW5kZXJlci5yZXNvbHV0aW9uO1xuICAgICAgICBjb250ZXh0LnNldFRyYW5zZm9ybShcbiAgICAgICAgICAgIHRyYW5zZm9ybS5hICogcmVzb2x1dGlvbixcbiAgICAgICAgICAgIHRyYW5zZm9ybS5iICogcmVzb2x1dGlvbixcbiAgICAgICAgICAgIHRyYW5zZm9ybS5jICogcmVzb2x1dGlvbixcbiAgICAgICAgICAgIHRyYW5zZm9ybS5kICogcmVzb2x1dGlvbixcbiAgICAgICAgICAgIHRyYW5zZm9ybS50eCAqIHJlc29sdXRpb24sXG4gICAgICAgICAgICB0cmFuc2Zvcm0udHkgKiByZXNvbHV0aW9uXG4gICAgICAgICk7XG5cbiAgICAgICAgQ2FudmFzR3JhcGhpY3MucmVuZGVyR3JhcGhpY3ModGhpcywgY29udGV4dCk7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIGogPSB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGo7ICsraSkge1xuICAgICAgICAgICAgdGhpcy5jaGlsZHJlbltpXS5yZW5kZXJDYW52YXMocmVuZGVyZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuX21hc2spIHtcbiAgICAgICAgICAgIHJlbmRlcmVyLm1hc2tNYW5hZ2VyLnBvcE1hc2socmVuZGVyZXIpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIGJvdW5kcyBvZiB0aGUgZ3JhcGhpYyBzaGFwZSBhcyBhIHJlY3RhbmdsZSBvYmplY3RcbiAqXG4gKiBAcmV0dXJuIHtSZWN0YW5nbGV9IHRoZSByZWN0YW5ndWxhciBib3VuZGluZyBhcmVhXG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5nZXRCb3VuZHMgPSBmdW5jdGlvbiAobWF0cml4KSB7XG4gICAgLy8gcmV0dXJuIGFuIGVtcHR5IG9iamVjdCBpZiB0aGUgaXRlbSBpcyBhIG1hc2shXG4gICAgaWYgKHRoaXMuaXNNYXNrKSB7XG4gICAgICAgIHJldHVybiBtYXRoLlJlY3RhbmdsZS5FTVBUWTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnVwZGF0ZUxvY2FsQm91bmRzKCk7XG5cbiAgICAgICAgdGhpcy5nbERpcnR5ID0gdHJ1ZTtcbiAgICAgICAgdGhpcy5jYWNoZWRTcHJpdGVEaXJ0eSA9IHRydWU7XG4gICAgICAgIHRoaXMuZGlydHkgPSBmYWxzZTtcbiAgICB9XG5cbiAgICB2YXIgYm91bmRzID0gdGhpcy5fbG9jYWxCb3VuZHM7XG5cbiAgICB2YXIgdzAgPSBib3VuZHMueDtcbiAgICB2YXIgdzEgPSBib3VuZHMud2lkdGggKyBib3VuZHMueDtcblxuICAgIHZhciBoMCA9IGJvdW5kcy55O1xuICAgIHZhciBoMSA9IGJvdW5kcy5oZWlnaHQgKyBib3VuZHMueTtcblxuICAgIHZhciB3b3JsZFRyYW5zZm9ybSA9IG1hdHJpeCB8fCB0aGlzLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgdmFyIGEgPSB3b3JsZFRyYW5zZm9ybS5hO1xuICAgIHZhciBiID0gd29ybGRUcmFuc2Zvcm0uYjtcbiAgICB2YXIgYyA9IHdvcmxkVHJhbnNmb3JtLmM7XG4gICAgdmFyIGQgPSB3b3JsZFRyYW5zZm9ybS5kO1xuICAgIHZhciB0eCA9IHdvcmxkVHJhbnNmb3JtLnR4O1xuICAgIHZhciB0eSA9IHdvcmxkVHJhbnNmb3JtLnR5O1xuXG4gICAgdmFyIHgxID0gYSAqIHcxICsgYyAqIGgxICsgdHg7XG4gICAgdmFyIHkxID0gZCAqIGgxICsgYiAqIHcxICsgdHk7XG5cbiAgICB2YXIgeDIgPSBhICogdzAgKyBjICogaDEgKyB0eDtcbiAgICB2YXIgeTIgPSBkICogaDEgKyBiICogdzAgKyB0eTtcblxuICAgIHZhciB4MyA9IGEgKiB3MCArIGMgKiBoMCArIHR4O1xuICAgIHZhciB5MyA9IGQgKiBoMCArIGIgKiB3MCArIHR5O1xuXG4gICAgdmFyIHg0ID0gIGEgKiB3MSArIGMgKiBoMCArIHR4O1xuICAgIHZhciB5NCA9ICBkICogaDAgKyBiICogdzEgKyB0eTtcblxuICAgIHZhciBtYXhYID0geDE7XG4gICAgdmFyIG1heFkgPSB5MTtcblxuICAgIHZhciBtaW5YID0geDE7XG4gICAgdmFyIG1pblkgPSB5MTtcblxuICAgIG1pblggPSB4MiA8IG1pblggPyB4MiA6IG1pblg7XG4gICAgbWluWCA9IHgzIDwgbWluWCA/IHgzIDogbWluWDtcbiAgICBtaW5YID0geDQgPCBtaW5YID8geDQgOiBtaW5YO1xuXG4gICAgbWluWSA9IHkyIDwgbWluWSA/IHkyIDogbWluWTtcbiAgICBtaW5ZID0geTMgPCBtaW5ZID8geTMgOiBtaW5ZO1xuICAgIG1pblkgPSB5NCA8IG1pblkgPyB5NCA6IG1pblk7XG5cbiAgICBtYXhYID0geDIgPiBtYXhYID8geDIgOiBtYXhYO1xuICAgIG1heFggPSB4MyA+IG1heFggPyB4MyA6IG1heFg7XG4gICAgbWF4WCA9IHg0ID4gbWF4WCA/IHg0IDogbWF4WDtcblxuICAgIG1heFkgPSB5MiA+IG1heFkgPyB5MiA6IG1heFk7XG4gICAgbWF4WSA9IHkzID4gbWF4WSA/IHkzIDogbWF4WTtcbiAgICBtYXhZID0geTQgPiBtYXhZID8geTQgOiBtYXhZO1xuXG4gICAgdGhpcy5fYm91bmRzLnggPSBtaW5YO1xuICAgIHRoaXMuX2JvdW5kcy53aWR0aCA9IG1heFggLSBtaW5YO1xuXG4gICAgdGhpcy5fYm91bmRzLnkgPSBtaW5ZO1xuICAgIHRoaXMuX2JvdW5kcy5oZWlnaHQgPSBtYXhZIC0gbWluWTtcblxuICAgIHJldHVybiB0aGlzLl9ib3VuZHM7XG59O1xuXG4vKipcbiAqIFVwZGF0ZSB0aGUgYm91bmRzIG9mIHRoZSBvYmplY3RcbiAqXG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS51cGRhdGVMb2NhbEJvdW5kcyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgbWluWCA9IEluZmluaXR5O1xuICAgIHZhciBtYXhYID0gLUluZmluaXR5O1xuXG4gICAgdmFyIG1pblkgPSBJbmZpbml0eTtcbiAgICB2YXIgbWF4WSA9IC1JbmZpbml0eTtcblxuICAgIGlmICh0aGlzLmdyYXBoaWNzRGF0YS5sZW5ndGgpIHtcbiAgICAgICAgdmFyIHNoYXBlLCBwb2ludHMsIHgsIHksIHcsIGg7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmdyYXBoaWNzRGF0YS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIGRhdGEgPSB0aGlzLmdyYXBoaWNzRGF0YVtpXTtcbiAgICAgICAgICAgIHZhciB0eXBlID0gZGF0YS50eXBlO1xuICAgICAgICAgICAgdmFyIGxpbmVXaWR0aCA9IGRhdGEubGluZVdpZHRoO1xuICAgICAgICAgICAgc2hhcGUgPSBkYXRhLnNoYXBlO1xuXG4gICAgICAgICAgICBpZiAodHlwZSA9PT0gQ09OU1QuU0hBUEVTLlJFQ1QgfHwgdHlwZSA9PT0gQ09OU1QuU0hBUEVTLlJSRUMpIHtcbiAgICAgICAgICAgICAgICB4ID0gc2hhcGUueCAtIGxpbmVXaWR0aC8yO1xuICAgICAgICAgICAgICAgIHkgPSBzaGFwZS55IC0gbGluZVdpZHRoLzI7XG4gICAgICAgICAgICAgICAgdyA9IHNoYXBlLndpZHRoICsgbGluZVdpZHRoO1xuICAgICAgICAgICAgICAgIGggPSBzaGFwZS5oZWlnaHQgKyBsaW5lV2lkdGg7XG5cbiAgICAgICAgICAgICAgICBtaW5YID0geCA8IG1pblggPyB4IDogbWluWDtcbiAgICAgICAgICAgICAgICBtYXhYID0geCArIHcgPiBtYXhYID8geCArIHcgOiBtYXhYO1xuXG4gICAgICAgICAgICAgICAgbWluWSA9IHkgPCBtaW5ZID8geSA6IG1pblk7XG4gICAgICAgICAgICAgICAgbWF4WSA9IHkgKyBoID4gbWF4WSA/IHkgKyBoIDogbWF4WTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKHR5cGUgPT09IENPTlNULlNIQVBFUy5DSVJDKSB7XG4gICAgICAgICAgICAgICAgeCA9IHNoYXBlLng7XG4gICAgICAgICAgICAgICAgeSA9IHNoYXBlLnk7XG4gICAgICAgICAgICAgICAgdyA9IHNoYXBlLnJhZGl1cyArIGxpbmVXaWR0aC8yO1xuICAgICAgICAgICAgICAgIGggPSBzaGFwZS5yYWRpdXMgKyBsaW5lV2lkdGgvMjtcblxuICAgICAgICAgICAgICAgIG1pblggPSB4IC0gdyA8IG1pblggPyB4IC0gdyA6IG1pblg7XG4gICAgICAgICAgICAgICAgbWF4WCA9IHggKyB3ID4gbWF4WCA/IHggKyB3IDogbWF4WDtcblxuICAgICAgICAgICAgICAgIG1pblkgPSB5IC0gaCA8IG1pblkgPyB5IC0gaCA6IG1pblk7XG4gICAgICAgICAgICAgICAgbWF4WSA9IHkgKyBoID4gbWF4WSA/IHkgKyBoIDogbWF4WTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKHR5cGUgPT09IENPTlNULlNIQVBFUy5FTElQKSB7XG4gICAgICAgICAgICAgICAgeCA9IHNoYXBlLng7XG4gICAgICAgICAgICAgICAgeSA9IHNoYXBlLnk7XG4gICAgICAgICAgICAgICAgdyA9IHNoYXBlLndpZHRoICsgbGluZVdpZHRoLzI7XG4gICAgICAgICAgICAgICAgaCA9IHNoYXBlLmhlaWdodCArIGxpbmVXaWR0aC8yO1xuXG4gICAgICAgICAgICAgICAgbWluWCA9IHggLSB3IDwgbWluWCA/IHggLSB3IDogbWluWDtcbiAgICAgICAgICAgICAgICBtYXhYID0geCArIHcgPiBtYXhYID8geCArIHcgOiBtYXhYO1xuXG4gICAgICAgICAgICAgICAgbWluWSA9IHkgLSBoIDwgbWluWSA/IHkgLSBoIDogbWluWTtcbiAgICAgICAgICAgICAgICBtYXhZID0geSArIGggPiBtYXhZID8geSArIGggOiBtYXhZO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gUE9MWVxuICAgICAgICAgICAgICAgIHBvaW50cyA9IHNoYXBlLnBvaW50cztcblxuICAgICAgICAgICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgcG9pbnRzLmxlbmd0aDsgaiArPSAyKSB7XG4gICAgICAgICAgICAgICAgICAgIHggPSBwb2ludHNbal07XG4gICAgICAgICAgICAgICAgICAgIHkgPSBwb2ludHNbaisxXTtcblxuICAgICAgICAgICAgICAgICAgICBtaW5YID0geC1saW5lV2lkdGggPCBtaW5YID8geC1saW5lV2lkdGggOiBtaW5YO1xuICAgICAgICAgICAgICAgICAgICBtYXhYID0geCtsaW5lV2lkdGggPiBtYXhYID8geCtsaW5lV2lkdGggOiBtYXhYO1xuXG4gICAgICAgICAgICAgICAgICAgIG1pblkgPSB5LWxpbmVXaWR0aCA8IG1pblkgPyB5LWxpbmVXaWR0aCA6IG1pblk7XG4gICAgICAgICAgICAgICAgICAgIG1heFkgPSB5K2xpbmVXaWR0aCA+IG1heFkgPyB5K2xpbmVXaWR0aCA6IG1heFk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBtaW5YID0gMDtcbiAgICAgICAgbWF4WCA9IDA7XG4gICAgICAgIG1pblkgPSAwO1xuICAgICAgICBtYXhZID0gMDtcbiAgICB9XG5cbiAgICB2YXIgcGFkZGluZyA9IHRoaXMuYm91bmRzUGFkZGluZztcblxuICAgIHRoaXMuX2xvY2FsQm91bmRzLnggPSBtaW5YIC0gcGFkZGluZztcbiAgICB0aGlzLl9sb2NhbEJvdW5kcy53aWR0aCA9IChtYXhYIC0gbWluWCkgKyBwYWRkaW5nICogMjtcblxuICAgIHRoaXMuX2xvY2FsQm91bmRzLnkgPSBtaW5ZIC0gcGFkZGluZztcbiAgICB0aGlzLl9sb2NhbEJvdW5kcy5oZWlnaHQgPSAobWF4WSAtIG1pblkpICsgcGFkZGluZyAqIDI7XG59O1xuXG4vKipcbiAqIEdlbmVyYXRlcyB0aGUgY2FjaGVkIHNwcml0ZSB3aGVuIHRoZSBzcHJpdGUgaGFzIGNhY2hlQXNCaXRtYXAgPSB0cnVlXG4gKlxuICogQHByaXZhdGVcbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLl9nZW5lcmF0ZUNhY2hlZFNwcml0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgYm91bmRzID0gdGhpcy5nZXRMb2NhbEJvdW5kcygpO1xuXG4gICAgaWYgKCF0aGlzLl9jYWNoZWRTcHJpdGUpIHtcbiAgICAgICAgdmFyIGNhbnZhc0J1ZmZlciA9IG5ldyBDYW52YXNCdWZmZXIoYm91bmRzLndpZHRoLCBib3VuZHMuaGVpZ2h0KTtcbiAgICAgICAgdmFyIHRleHR1cmUgPSBUZXh0dXJlLmZyb21DYW52YXMoY2FudmFzQnVmZmVyLmNhbnZhcyk7XG5cbiAgICAgICAgdGhpcy5fY2FjaGVkU3ByaXRlID0gbmV3IFNwcml0ZSh0ZXh0dXJlKTtcbiAgICAgICAgdGhpcy5fY2FjaGVkU3ByaXRlLmJ1ZmZlciA9IGNhbnZhc0J1ZmZlcjtcblxuICAgICAgICB0aGlzLl9jYWNoZWRTcHJpdGUud29ybGRUcmFuc2Zvcm0gPSB0aGlzLndvcmxkVHJhbnNmb3JtO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdGhpcy5fY2FjaGVkU3ByaXRlLmJ1ZmZlci5yZXNpemUoYm91bmRzLndpZHRoLCBib3VuZHMuaGVpZ2h0KTtcbiAgICB9XG5cbiAgICAvLyBsZXZlcmFnZSB0aGUgYW5jaG9yIHRvIGFjY291bnQgZm9yIHRoZSBvZmZzZXQgb2YgdGhlIGVsZW1lbnRcbiAgICB0aGlzLl9jYWNoZWRTcHJpdGUuYW5jaG9yLnggPSAtKCBib3VuZHMueCAvIGJvdW5kcy53aWR0aCApO1xuICAgIHRoaXMuX2NhY2hlZFNwcml0ZS5hbmNob3IueSA9IC0oIGJvdW5kcy55IC8gYm91bmRzLmhlaWdodCApO1xuXG4gICAgLy8gdGhpcy5fY2FjaGVkU3ByaXRlLmJ1ZmZlci5jb250ZXh0LnNhdmUoKTtcbiAgICB0aGlzLl9jYWNoZWRTcHJpdGUuYnVmZmVyLmNvbnRleHQudHJhbnNsYXRlKC1ib3VuZHMueCwtYm91bmRzLnkpO1xuXG4gICAgLy8gbWFrZSBzdXJlIHdlIHNldCB0aGUgYWxwaGEgb2YgdGhlIGdyYXBoaWNzIHRvIDEgZm9yIHRoZSByZW5kZXIuLlxuICAgIHRoaXMud29ybGRBbHBoYSA9IDE7XG5cbiAgICAvLyBub3cgcmVuZGVyIHRoZSBncmFwaGljLi5cbiAgICBDYW52YXNHcmFwaGljcy5yZW5kZXJHcmFwaGljcyh0aGlzLCB0aGlzLl9jYWNoZWRTcHJpdGUuYnVmZmVyLmNvbnRleHQpO1xuXG4gICAgdGhpcy5fY2FjaGVkU3ByaXRlLmFscGhhID0gdGhpcy5hbHBoYTtcbn07XG5cbi8qKlxuICogVXBkYXRlcyB0ZXh0dXJlIHNpemUgYmFzZWQgb24gY2FudmFzIHNpemVcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5HcmFwaGljcy5wcm90b3R5cGUudXBkYXRlQ2FjaGVkU3ByaXRlVGV4dHVyZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgY2FjaGVkU3ByaXRlID0gdGhpcy5fY2FjaGVkU3ByaXRlO1xuICAgIHZhciB0ZXh0dXJlID0gY2FjaGVkU3ByaXRlLnRleHR1cmU7XG4gICAgdmFyIGNhbnZhcyA9IGNhY2hlZFNwcml0ZS5idWZmZXIuY2FudmFzO1xuXG4gICAgdGV4dHVyZS5iYXNlVGV4dHVyZS53aWR0aCA9IGNhbnZhcy53aWR0aDtcbiAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLmhlaWdodCA9IGNhbnZhcy5oZWlnaHQ7XG4gICAgdGV4dHVyZS5jcm9wLndpZHRoID0gdGV4dHVyZS5mcmFtZS53aWR0aCA9IGNhbnZhcy53aWR0aDtcbiAgICB0ZXh0dXJlLmNyb3AuaGVpZ2h0ID0gdGV4dHVyZS5mcmFtZS5oZWlnaHQgPSBjYW52YXMuaGVpZ2h0O1xuXG4gICAgY2FjaGVkU3ByaXRlLl93aWR0aCA9IGNhbnZhcy53aWR0aDtcbiAgICBjYWNoZWRTcHJpdGUuX2hlaWdodCA9IGNhbnZhcy5oZWlnaHQ7XG5cbiAgICAvLyB1cGRhdGUgdGhlIGRpcnR5IGJhc2UgdGV4dHVyZXNcbiAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLmRpcnR5KCk7XG59O1xuXG4vKipcbiAqIERlc3Ryb3lzIGEgcHJldmlvdXMgY2FjaGVkIHNwcml0ZS5cbiAqXG4gKi9cbkdyYXBoaWNzLnByb3RvdHlwZS5kZXN0cm95Q2FjaGVkU3ByaXRlID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuX2NhY2hlZFNwcml0ZS50ZXh0dXJlLmRlc3Ryb3kodHJ1ZSk7XG5cbiAgICAvLyBsZXQgdGhlIGdjIGNvbGxlY3QgdGhlIHVudXNlZCBzcHJpdGVcbiAgICAvLyBUT0RPIGNvdWxkIGJlIG9iamVjdCBwb29sZWQhXG4gICAgdGhpcy5fY2FjaGVkU3ByaXRlID0gbnVsbDtcbn07XG5cbi8qKlxuICogRHJhd3MgdGhlIGdpdmVuIHNoYXBlIHRvIHRoaXMgR3JhcGhpY3Mgb2JqZWN0LiBDYW4gYmUgYW55IG9mIENpcmNsZSwgUmVjdGFuZ2xlLCBFbGxpcHNlLCBMaW5lIG9yIFBvbHlnb24uXG4gKlxuICogQHBhcmFtIHtDaXJjbGV8UmVjdGFuZ2xlfEVsbGlwc2V8TGluZXxQb2x5Z29ufSBzaGFwZSBUaGUgU2hhcGUgb2JqZWN0IHRvIGRyYXcuXG4gKiBAcmV0dXJuIHtHcmFwaGljc0RhdGF9IFRoZSBnZW5lcmF0ZWQgR3JhcGhpY3NEYXRhIG9iamVjdC5cbiAqL1xuR3JhcGhpY3MucHJvdG90eXBlLmRyYXdTaGFwZSA9IGZ1bmN0aW9uIChzaGFwZSkge1xuICAgIGlmICh0aGlzLmN1cnJlbnRQYXRoKSB7XG4gICAgICAgIC8vIGNoZWNrIGN1cnJlbnQgcGF0aCFcbiAgICAgICAgaWYgKHRoaXMuY3VycmVudFBhdGguc2hhcGUucG9pbnRzLmxlbmd0aCA8PSAyKSB7XG4gICAgICAgICAgICB0aGlzLmdyYXBoaWNzRGF0YS5wb3AoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMuY3VycmVudFBhdGggPSBudWxsO1xuXG4gICAgdmFyIGRhdGEgPSBuZXcgR3JhcGhpY3NEYXRhKHRoaXMubGluZVdpZHRoLCB0aGlzLmxpbmVDb2xvciwgdGhpcy5saW5lQWxwaGEsIHRoaXMuZmlsbENvbG9yLCB0aGlzLmZpbGxBbHBoYSwgdGhpcy5maWxsaW5nLCBzaGFwZSk7XG5cbiAgICB0aGlzLmdyYXBoaWNzRGF0YS5wdXNoKGRhdGEpO1xuXG4gICAgaWYgKGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLlBPTFkpIHtcbiAgICAgICAgZGF0YS5zaGFwZS5jbG9zZWQgPSB0aGlzLmZpbGxpbmc7XG4gICAgICAgIHRoaXMuY3VycmVudFBhdGggPSBkYXRhO1xuICAgIH1cblxuICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuXG4gICAgcmV0dXJuIGRhdGE7XG59O1xuIiwiLyoqXG4gKiBBIEdyYXBoaWNzRGF0YSBvYmplY3QuXG4gKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gR3JhcGhpY3NEYXRhKGxpbmVXaWR0aCwgbGluZUNvbG9yLCBsaW5lQWxwaGEsIGZpbGxDb2xvciwgZmlsbEFscGhhLCBmaWxsLCBzaGFwZSkge1xuICAgIHRoaXMubGluZVdpZHRoID0gbGluZVdpZHRoO1xuICAgIHRoaXMubGluZUNvbG9yID0gbGluZUNvbG9yO1xuICAgIHRoaXMubGluZUFscGhhID0gbGluZUFscGhhO1xuICAgIHRoaXMuX2xpbmVUaW50ID0gbGluZUNvbG9yO1xuXG4gICAgdGhpcy5maWxsQ29sb3IgPSBmaWxsQ29sb3I7XG4gICAgdGhpcy5maWxsQWxwaGEgPSBmaWxsQWxwaGE7XG4gICAgdGhpcy5fZmlsbFRpbnQgPSBmaWxsQ29sb3I7XG4gICAgdGhpcy5maWxsID0gZmlsbDtcblxuICAgIHRoaXMuc2hhcGUgPSBzaGFwZTtcbiAgICB0aGlzLnR5cGUgPSBzaGFwZS50eXBlO1xufVxuXG5HcmFwaGljc0RhdGEucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gR3JhcGhpY3NEYXRhO1xubW9kdWxlLmV4cG9ydHMgPSBHcmFwaGljc0RhdGE7XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldyBHcmFwaGljc0RhdGEgb2JqZWN0IHdpdGggdGhlIHNhbWUgdmFsdWVzIGFzIHRoaXMgb25lLlxuICpcbiAqIEByZXR1cm4ge0dyYXBoaWNzRGF0YX1cbiAqL1xuR3JhcGhpY3NEYXRhLnByb3RvdHlwZS5jbG9uZSA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gbmV3IEdyYXBoaWNzRGF0YShcbiAgICAgICAgdGhpcy5saW5lV2lkdGgsXG4gICAgICAgIHRoaXMubGluZUNvbG9yLFxuICAgICAgICB0aGlzLmxpbmVBbHBoYSxcbiAgICAgICAgdGhpcy5maWxsQ29sb3IsXG4gICAgICAgIHRoaXMuZmlsbEFscGhhLFxuICAgICAgICB0aGlzLmZpbGwsXG4gICAgICAgIHRoaXMuc2hhcGVcbiAgICApO1xufTtcbiIsInZhciBDYW52YXNNYXNrTWFuYWdlciA9IHJlcXVpcmUoJy4vdXRpbHMvQ2FudmFzTWFza01hbmFnZXInKSxcbiAgICB1dGlscyA9IHJlcXVpcmUoJy4uLy4uL3V0aWxzJyksXG4gICAgQ09OU1QgPSByZXF1aXJlKCcuLi8uLi9jb25zdCcpO1xuXG4vKipcbiAqIFRoZSBDYW52YXNSZW5kZXJlciBkcmF3cyB0aGUgc2NlbmUgYW5kIGFsbCBpdHMgY29udGVudCBvbnRvIGEgMmQgY2FudmFzLiBUaGlzIHJlbmRlcmVyIHNob3VsZCBiZSB1c2VkIGZvciBicm93c2VycyB0aGF0IGRvIG5vdCBzdXBwb3J0IHdlYkdMLlxuICogRG9uJ3QgZm9yZ2V0IHRvIGFkZCB0aGUgQ2FudmFzUmVuZGVyZXIudmlldyB0byB5b3VyIERPTSBvciB5b3Ugd2lsbCBub3Qgc2VlIGFueXRoaW5nIDopXG4gKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSBbd2lkdGg9ODAwXSB7bnVtYmVyfSB0aGUgd2lkdGggb2YgdGhlIGNhbnZhcyB2aWV3XG4gKiBAcGFyYW0gW2hlaWdodD02MDBdIHtudW1iZXJ9IHRoZSBoZWlnaHQgb2YgdGhlIGNhbnZhcyB2aWV3XG4gKiBAcGFyYW0gW29wdGlvbnNdIHtvYmplY3R9IFRoZSBvcHRpb25hbCByZW5kZXJlciBwYXJhbWV0ZXJzXG4gKiBAcGFyYW0gW29wdGlvbnMudmlld10ge0hUTUxDYW52YXNFbGVtZW50fSB0aGUgY2FudmFzIHRvIHVzZSBhcyBhIHZpZXcsIG9wdGlvbmFsXG4gKiBAcGFyYW0gW29wdGlvbnMudHJhbnNwYXJlbnQ9ZmFsc2VdIHtib29sZWFufSBJZiB0aGUgcmVuZGVyIHZpZXcgaXMgdHJhbnNwYXJlbnQsIGRlZmF1bHQgZmFsc2VcbiAqIEBwYXJhbSBbb3B0aW9ucy5hdXRvUmVzaXplPWZhbHNlXSB7Ym9vbGVhbn0gSWYgdGhlIHJlbmRlciB2aWV3IGlzIGF1dG9tYXRpY2FsbHkgcmVzaXplZCwgZGVmYXVsdCBmYWxzZVxuICogQHBhcmFtIFtvcHRpb25zLnJlc29sdXRpb249MV0ge251bWJlcn0gdGhlIHJlc29sdXRpb24gb2YgdGhlIHJlbmRlcmVyIHJldGluYSB3b3VsZCBiZSAyXG4gKiBAcGFyYW0gW29wdGlvbnMuY2xlYXJCZWZvcmVSZW5kZXI9dHJ1ZV0ge2Jvb2xlYW59IFRoaXMgc2V0cyBpZiB0aGUgQ2FudmFzUmVuZGVyZXIgd2lsbCBjbGVhciB0aGUgY2FudmFzIG9yIG5vdCBiZWZvcmUgdGhlIG5ldyByZW5kZXIgcGFzcy5cbiAqL1xuZnVuY3Rpb24gQ2FudmFzUmVuZGVyZXIod2lkdGgsIGhlaWdodCwgb3B0aW9ucykge1xuICAgIHV0aWxzLnNheUhlbGxvKCdDYW52YXMnKTtcblxuICAgIGlmIChvcHRpb25zKSB7XG4gICAgICAgIGZvciAodmFyIGkgaW4gQ09OU1QuZGVmYXVsdFJlbmRlck9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygb3B0aW9uc1tpXSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zW2ldID0gQ09OU1QuZGVmYXVsdFJlbmRlck9wdGlvbnNbaV07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIG9wdGlvbnMgPSBDT05TVC5kZWZhdWx0UmVuZGVyT3B0aW9ucztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgcmVuZGVyZXIgdHlwZS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLnR5cGUgPSBDT05TVC5DQU5WQVNfUkVOREVSRVI7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgcmVzb2x1dGlvbiBvZiB0aGUgY2FudmFzLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMucmVzb2x1dGlvbiA9IG9wdGlvbnMucmVzb2x1dGlvbjtcblxuICAgIC8qKlxuICAgICAqIFRoaXMgc2V0cyBpZiB0aGUgQ2FudmFzUmVuZGVyZXIgd2lsbCBjbGVhciB0aGUgY2FudmFzIG9yIG5vdCBiZWZvcmUgdGhlIG5ldyByZW5kZXIgcGFzcy5cbiAgICAgKiBJZiB0aGUgc2NlbmUgaXMgTk9UIHRyYW5zcGFyZW50IFBpeGkgd2lsbCB1c2UgYSBjYW52YXMgc2l6ZWQgZmlsbFJlY3Qgb3BlcmF0aW9uIGV2ZXJ5IGZyYW1lIHRvIHNldCB0aGUgY2FudmFzIGJhY2tncm91bmQgY29sb3IuXG4gICAgICogSWYgdGhlIHNjZW5lIGlzIHRyYW5zcGFyZW50IFBpeGkgd2lsbCB1c2UgY2xlYXJSZWN0IHRvIGNsZWFyIHRoZSBjYW52YXMgZXZlcnkgZnJhbWUuXG4gICAgICogRGlzYWJsZSB0aGlzIGJ5IHNldHRpbmcgdGhpcyB0byBmYWxzZS4gRm9yIGV4YW1wbGUgaWYgeW91ciBnYW1lIGhhcyBhIGNhbnZhcyBmaWxsaW5nIGJhY2tncm91bmQgaW1hZ2UgeW91IG9mdGVuIGRvbid0IG5lZWQgdGhpcyBzZXQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqIEBkZWZhdWx0XG4gICAgICovXG4gICAgdGhpcy5jbGVhckJlZm9yZVJlbmRlciA9IG9wdGlvbnMuY2xlYXJCZWZvcmVSZW5kZXI7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgYmFja2dyb3VuZCBjb2xvciBhcyBhIG51bWJlci5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuX2JhY2tncm91bmRDb2xvciA9IDB4MDAwMDAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGJhY2tncm91bmQgY29sb3IgYXMgYSBzdHJpbmcuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtzdHJpbmd9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl9iYWNrZ3JvdW5kQ29sb3JTdHJpbmcgPSAnIzAwMDAwMCc7XG5cbiAgICB0aGlzLmJhY2tncm91bmRDb2xvciA9IG9wdGlvbnMuYmFja2dyb3VuZENvbG9yIHx8IHRoaXMuX2JhY2tncm91bmRDb2xvcjsgLy8gcnVuIGJnIGNvbG9yIHNldHRlclxuXG4gICAgLyoqXG4gICAgICogV2hldGhlciB0aGUgcmVuZGVyIHZpZXcgaXMgdHJhbnNwYXJlbnRcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy50cmFuc3BhcmVudCA9IG9wdGlvbnMudHJhbnNwYXJlbnQ7XG5cbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRoZSByZW5kZXIgdmlldyBzaG91bGQgYmUgcmVzaXplZCBhdXRvbWF0aWNhbGx5XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMuYXV0b1Jlc2l6ZSA9IG9wdGlvbnMuYXV0b1Jlc2l6ZSB8fCBmYWxzZTtcblxuXG4gICAgLyoqXG4gICAgICogVGhlIHdpZHRoIG9mIHRoZSBjYW52YXMgdmlld1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDgwMFxuICAgICAqL1xuICAgIHRoaXMud2lkdGggPSB3aWR0aCB8fCA4MDA7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgaGVpZ2h0IG9mIHRoZSBjYW52YXMgdmlld1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDYwMFxuICAgICAqL1xuICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0IHx8IDYwMDtcblxuICAgIHRoaXMud2lkdGggKj0gdGhpcy5yZXNvbHV0aW9uO1xuICAgIHRoaXMuaGVpZ2h0ICo9IHRoaXMucmVzb2x1dGlvbjtcblxuICAgIC8qKlxuICAgICAqIFRoZSBjYW52YXMgZWxlbWVudCB0aGF0IGV2ZXJ5dGhpbmcgaXMgZHJhd24gdG8uXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtIVE1MQ2FudmFzRWxlbWVudH1cbiAgICAgKi9cbiAgICB0aGlzLnZpZXcgPSBvcHRpb25zLnZpZXcgfHwgZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgY2FudmFzIDJkIGNvbnRleHQgdGhhdCBldmVyeXRoaW5nIGlzIGRyYXduIHdpdGhcbiAgICAgKiBAbWVtYmVyIHtDYW52YXNSZW5kZXJpbmdDb250ZXh0MkR9XG4gICAgICovXG4gICAgdGhpcy5jb250ZXh0ID0gdGhpcy52aWV3LmdldENvbnRleHQoJzJkJywgeyBhbHBoYTogdGhpcy50cmFuc3BhcmVudCB9KTtcblxuICAgIC8qKlxuICAgICAqIEJvb2xlYW4gZmxhZyBjb250cm9sbGluZyBjYW52YXMgcmVmcmVzaC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5yZWZyZXNoID0gdHJ1ZTtcblxuICAgIHRoaXMudmlldy53aWR0aCA9IHRoaXMud2lkdGggKiB0aGlzLnJlc29sdXRpb247XG4gICAgdGhpcy52aWV3LmhlaWdodCA9IHRoaXMuaGVpZ2h0ICogdGhpcy5yZXNvbHV0aW9uO1xuXG4gICAgLyoqXG4gICAgICogSW50ZXJuYWwgdmFyLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMuY291bnQgPSAwO1xuXG4gICAgLyoqXG4gICAgICogSW5zdGFuY2Ugb2YgYSBDYW52YXNNYXNrTWFuYWdlciwgaGFuZGxlcyBtYXNraW5nIHdoZW4gdXNpbmcgdGhlIGNhbnZhcyByZW5kZXJlclxuICAgICAqIEBtZW1iZXIge0NhbnZhc01hc2tNYW5hZ2VyfVxuICAgICAqL1xuICAgIHRoaXMubWFza01hbmFnZXIgPSBuZXcgQ2FudmFzTWFza01hbmFnZXIoKTtcblxuICAgIC8qKlxuICAgICAqIElmIHRydWUgUGl4aSB3aWxsIE1hdGguZmxvb3IoKSB4L3kgdmFsdWVzIHdoZW4gcmVuZGVyaW5nLCBzdG9wcGluZyBwaXhlbCBpbnRlcnBvbGF0aW9uLlxuICAgICAqIEhhbmR5IGZvciBjcmlzcCBwaXhlbCBhcnQgYW5kIHNwZWVkIG9uIGxlZ2FjeSBkZXZpY2VzLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLnJvdW5kUGl4ZWxzID0gZmFsc2U7XG5cbiAgICB0aGlzLnNjYWxlTW9kZSA9IG51bGw7XG5cbiAgICB0aGlzLnNtb290aFByb3BlcnR5ID0gbnVsbDtcblxuICAgIGlmICh0aGlzLmNvbnRleHQuaW1hZ2VTbW9vdGhpbmdFbmFibGVkKSB7XG4gICAgICAgIHRoaXMuc21vb3RoUHJvcGVydHkgPSAnaW1hZ2VTbW9vdGhpbmdFbmFibGVkJztcbiAgICB9XG4gICAgZWxzZSBpZiAodGhpcy5jb250ZXh0LndlYmtpdEltYWdlU21vb3RoaW5nRW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNtb290aFByb3BlcnR5ID0gJ3dlYmtpdEltYWdlU21vb3RoaW5nRW5hYmxlZCc7XG4gICAgfVxuICAgIGVsc2UgaWYgKHRoaXMuY29udGV4dC5tb3pJbWFnZVNtb290aGluZ0VuYWJsZWQpIHtcbiAgICAgICAgdGhpcy5zbW9vdGhQcm9wZXJ0eSA9ICdtb3pJbWFnZVNtb290aGluZ0VuYWJsZWQnO1xuICAgIH1cbiAgICBlbHNlIGlmICh0aGlzLmNvbnRleHQub0ltYWdlU21vb3RoaW5nRW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNtb290aFByb3BlcnR5ID0gJ29JbWFnZVNtb290aGluZ0VuYWJsZWQnO1xuICAgIH1cbiAgICBlbHNlIGlmICh0aGlzLmNvbnRleHQubXNJbWFnZVNtb290aGluZ0VuYWJsZWQpIHtcbiAgICAgICAgdGhpcy5zbW9vdGhQcm9wZXJ0eSA9ICdtc0ltYWdlU21vb3RoaW5nRW5hYmxlZCc7XG4gICAgfVxuXG4gICAgdGhpcy5jdXJyZW50QmxlbmRNb2RlID0gQ09OU1QuYmxlbmRNb2Rlcy5OT1JNQUw7XG5cbiAgICB0aGlzLmJsZW5kTW9kZXMgPSBudWxsO1xuXG4gICAgdGhpcy5fbWFwQmxlbmRNb2RlcygpO1xuXG4gICAgdGhpcy5yZXNpemUod2lkdGgsIGhlaWdodCk7XG59XG5cbi8vIGNvbnN0cnVjdG9yXG5DYW52YXNSZW5kZXJlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDYW52YXNSZW5kZXJlcjtcbm1vZHVsZS5leHBvcnRzID0gQ2FudmFzUmVuZGVyZXI7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKENhbnZhc1JlbmRlcmVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSBiYWNrZ3JvdW5kIGNvbG9yIHRvIGZpbGwgaWYgbm90IHRyYW5zcGFyZW50XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIENhbnZhc1JlbmRlcmVyI1xuICAgICAqL1xuICAgIGJhY2tncm91bmRDb2xvcjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9iYWNrZ3JvdW5kQ29sb3I7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbCkge1xuICAgICAgICAgICAgdGhpcy5fYmFja2dyb3VuZENvbG9yID0gdmFsO1xuICAgICAgICAgICAgdGhpcy5fYmFja2dyb3VuZENvbG9yU3RyaW5nID0gdXRpbHMuaGV4MnN0cmluZyh2YWwpO1xuICAgICAgICB9XG4gICAgfVxufSk7XG5cbi8qKlxuICogUmVuZGVycyB0aGUgb2JqZWN0IHRvIHRoaXMgY2FudmFzIHZpZXdcbiAqXG4gKiBAcGFyYW0gb2JqZWN0IHtEaXNwbGF5T2JqZWN0fSB0aGUgb2JqZWN0IHRvIGJlIHJlbmRlcmVkXG4gKi9cbkNhbnZhc1JlbmRlcmVyLnByb3RvdHlwZS5yZW5kZXIgPSBmdW5jdGlvbiAob2JqZWN0KSB7XG4gICAgb2JqZWN0LnVwZGF0ZVRyYW5zZm9ybSgpO1xuXG4gICAgdGhpcy5jb250ZXh0LnNldFRyYW5zZm9ybSgxLDAsMCwxLDAsMCk7XG5cbiAgICB0aGlzLmNvbnRleHQuZ2xvYmFsQWxwaGEgPSAxO1xuXG4gICAgdGhpcy5jdXJyZW50QmxlbmRNb2RlID0gQ09OU1QuYmxlbmRNb2Rlcy5OT1JNQUw7XG4gICAgdGhpcy5jb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9IHRoaXMuYmxlbmRNb2Rlc1tDT05TVC5ibGVuZE1vZGVzLk5PUk1BTF07XG5cbiAgICBpZiAobmF2aWdhdG9yLmlzQ29jb29uSlMgJiYgdGhpcy52aWV3LnNjcmVlbmNhbnZhcykge1xuICAgICAgICB0aGlzLmNvbnRleHQuZmlsbFN0eWxlID0gJ2JsYWNrJztcbiAgICAgICAgdGhpcy5jb250ZXh0LmNsZWFyKCk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuY2xlYXJCZWZvcmVSZW5kZXIpIHtcbiAgICAgICAgaWYgKHRoaXMudHJhbnNwYXJlbnQpIHtcbiAgICAgICAgICAgIHRoaXMuY29udGV4dC5jbGVhclJlY3QoMCwgMCwgdGhpcy53aWR0aCwgdGhpcy5oZWlnaHQpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5jb250ZXh0LmZpbGxTdHlsZSA9IHRoaXMuX2JhY2tncm91bmRDb2xvclN0cmluZztcbiAgICAgICAgICAgIHRoaXMuY29udGV4dC5maWxsUmVjdCgwLCAwLCB0aGlzLndpZHRoICwgdGhpcy5oZWlnaHQpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5yZW5kZXJEaXNwbGF5T2JqZWN0KG9iamVjdCk7XG59O1xuXG4vKipcbiAqIFJlbW92ZXMgZXZlcnl0aGluZyBmcm9tIHRoZSByZW5kZXJlciBhbmQgb3B0aW9uYWxseSByZW1vdmVzIHRoZSBDYW52YXMgRE9NIGVsZW1lbnQuXG4gKlxuICogQHBhcmFtIFtyZW1vdmVWaWV3PWZhbHNlXSB7Ym9vbGVhbn0gUmVtb3ZlcyB0aGUgQ2FudmFzIGVsZW1lbnQgZnJvbSB0aGUgRE9NLlxuICovXG5DYW52YXNSZW5kZXJlci5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uIChyZW1vdmVWaWV3KSB7XG4gICAgaWYgKHJlbW92ZVZpZXcgJiYgdGhpcy52aWV3LnBhcmVudCkge1xuICAgICAgICB0aGlzLnZpZXcucGFyZW50LnJlbW92ZUNoaWxkKHRoaXMudmlldyk7XG4gICAgfVxuXG4gICAgdGhpcy52aWV3ID0gbnVsbDtcbiAgICB0aGlzLmNvbnRleHQgPSBudWxsO1xuICAgIHRoaXMubWFza01hbmFnZXIgPSBudWxsO1xufTtcblxuLyoqXG4gKiBSZXNpemVzIHRoZSBjYW52YXMgdmlldyB0byB0aGUgc3BlY2lmaWVkIHdpZHRoIGFuZCBoZWlnaHRcbiAqXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gdGhlIG5ldyB3aWR0aCBvZiB0aGUgY2FudmFzIHZpZXdcbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gdGhlIG5ldyBoZWlnaHQgb2YgdGhlIGNhbnZhcyB2aWV3XG4gKi9cbkNhbnZhc1JlbmRlcmVyLnByb3RvdHlwZS5yZXNpemUgPSBmdW5jdGlvbiAod2lkdGgsIGhlaWdodCkge1xuICAgIHRoaXMud2lkdGggPSB3aWR0aCAqIHRoaXMucmVzb2x1dGlvbjtcbiAgICB0aGlzLmhlaWdodCA9IGhlaWdodCAqIHRoaXMucmVzb2x1dGlvbjtcblxuICAgIHRoaXMudmlldy53aWR0aCA9IHRoaXMud2lkdGg7XG4gICAgdGhpcy52aWV3LmhlaWdodCA9IHRoaXMuaGVpZ2h0O1xuXG4gICAgaWYgKHRoaXMuYXV0b1Jlc2l6ZSkge1xuICAgICAgICB0aGlzLnZpZXcuc3R5bGUud2lkdGggPSB0aGlzLndpZHRoIC8gdGhpcy5yZXNvbHV0aW9uICsgJ3B4JztcbiAgICAgICAgdGhpcy52aWV3LnN0eWxlLmhlaWdodCA9IHRoaXMuaGVpZ2h0IC8gdGhpcy5yZXNvbHV0aW9uICsgJ3B4JztcbiAgICB9XG59O1xuXG4vKipcbiAqIFJlbmRlcnMgYSBkaXNwbGF5IG9iamVjdFxuICpcbiAqIEBwYXJhbSBkaXNwbGF5T2JqZWN0IHtEaXNwbGF5T2JqZWN0fSBUaGUgZGlzcGxheU9iamVjdCB0byByZW5kZXJcbiAqIEBwcml2YXRlXG4gKi9cbkNhbnZhc1JlbmRlcmVyLnByb3RvdHlwZS5yZW5kZXJEaXNwbGF5T2JqZWN0ID0gZnVuY3Rpb24gKGRpc3BsYXlPYmplY3QpIHtcbiAgICBkaXNwbGF5T2JqZWN0LnJlbmRlckNhbnZhcyh0aGlzKTtcbn07XG5cbi8qKlxuICogTWFwcyBQaXhpIGJsZW5kIG1vZGVzIHRvIGNhbnZhcyBibGVuZCBtb2Rlcy5cbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5DYW52YXNSZW5kZXJlci5wcm90b3R5cGUuX21hcEJsZW5kTW9kZXMgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKCF0aGlzLmJsZW5kTW9kZXMpIHtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzID0ge307XG5cbiAgICAgICAgaWYgKHV0aWxzLmNhblVzZU5ld0NhbnZhc0JsZW5kTW9kZXMoKSkge1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTk9STUFMXSAgICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQUREXSAgICAgICAgICAgPSAnbGlnaHRlcic7IC8vSVMgVEhJUyBPSz8/P1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTVVMVElQTFldICAgICAgPSAnbXVsdGlwbHknO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuU0NSRUVOXSAgICAgICAgPSAnc2NyZWVuJztcbiAgICAgICAgICAgIHRoaXMuYmxlbmRNb2Rlc1tDT05TVC5ibGVuZE1vZGVzLk9WRVJMQVldICAgICAgID0gJ292ZXJsYXknO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuREFSS0VOXSAgICAgICAgPSAnZGFya2VuJztcbiAgICAgICAgICAgIHRoaXMuYmxlbmRNb2Rlc1tDT05TVC5ibGVuZE1vZGVzLkxJR0hURU5dICAgICAgID0gJ2xpZ2h0ZW4nO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JfRE9ER0VdICAgPSAnY29sb3ItZG9kZ2UnO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JfQlVSTl0gICAgPSAnY29sb3ItYnVybic7XG4gICAgICAgICAgICB0aGlzLmJsZW5kTW9kZXNbQ09OU1QuYmxlbmRNb2Rlcy5IQVJEX0xJR0hUXSAgICA9ICdoYXJkLWxpZ2h0JztcbiAgICAgICAgICAgIHRoaXMuYmxlbmRNb2Rlc1tDT05TVC5ibGVuZE1vZGVzLlNPRlRfTElHSFRdICAgID0gJ3NvZnQtbGlnaHQnO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuRElGRkVSRU5DRV0gICAgPSAnZGlmZmVyZW5jZSc7XG4gICAgICAgICAgICB0aGlzLmJsZW5kTW9kZXNbQ09OU1QuYmxlbmRNb2Rlcy5FWENMVVNJT05dICAgICA9ICdleGNsdXNpb24nO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuSFVFXSAgICAgICAgICAgPSAnaHVlJztcbiAgICAgICAgICAgIHRoaXMuYmxlbmRNb2Rlc1tDT05TVC5ibGVuZE1vZGVzLlNBVFVSQVRJT05dICAgID0gJ3NhdHVyYXRpb24nO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JdICAgICAgICAgPSAnY29sb3InO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTFVNSU5PU0lUWV0gICAgPSAnbHVtaW5vc2l0eSc7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyB0aGlzIG1lYW5zIHRoYXQgdGhlIGJyb3dzZXIgZG9lcyBub3Qgc3VwcG9ydCB0aGUgY29vbCBuZXcgYmxlbmQgbW9kZXMgaW4gY2FudmFzICdjb3VnaCcgaWUgJ2NvdWdoJ1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTk9STUFMXSAgICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQUREXSAgICAgICAgICAgPSAnbGlnaHRlcic7IC8vSVMgVEhJUyBPSz8/P1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTVVMVElQTFldICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuU0NSRUVOXSAgICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuT1ZFUkxBWV0gICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuREFSS0VOXSAgICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTElHSFRFTl0gICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JfRE9ER0VdICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JfQlVSTl0gICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuSEFSRF9MSUdIVF0gICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuU09GVF9MSUdIVF0gICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuRElGRkVSRU5DRV0gICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuRVhDTFVTSU9OXSAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuSFVFXSAgICAgICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuU0FUVVJBVElPTl0gICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JdICAgICAgICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTFVNSU5PU0lUWV0gICAgPSAnc291cmNlLW92ZXInO1xuICAgICAgICB9XG4gICAgfVxufTtcbiIsIi8qKlxuICogQ3JlYXRlcyBhIENhbnZhcyBlbGVtZW50IG9mIHRoZSBnaXZlbiBzaXplLlxuICpcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gdGhlIHdpZHRoIGZvciB0aGUgbmV3bHkgY3JlYXRlZCBjYW52YXNcbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gdGhlIGhlaWdodCBmb3IgdGhlIG5ld2x5IGNyZWF0ZWQgY2FudmFzXG4gKi9cbmZ1bmN0aW9uIENhbnZhc0J1ZmZlcih3aWR0aCwgaGVpZ2h0KSB7XG4gICAgLyoqXG4gICAgICogVGhlIENhbnZhcyBvYmplY3QgdGhhdCBiZWxvbmdzIHRvIHRoaXMgQ2FudmFzQnVmZmVyLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7SFRNTENhbnZhc0VsZW1lbnR9XG4gICAgICovXG4gICAgdGhpcy5jYW52YXMgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcblxuICAgIC8qKlxuICAgICAqIEEgQ2FudmFzUmVuZGVyaW5nQ29udGV4dDJEIG9iamVjdCByZXByZXNlbnRpbmcgYSB0d28tZGltZW5zaW9uYWwgcmVuZGVyaW5nIGNvbnRleHQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtDYW52YXNSZW5kZXJpbmdDb250ZXh0MkR9XG4gICAgICovXG4gICAgdGhpcy5jb250ZXh0ID0gdGhpcy5jYW52YXMuZ2V0Q29udGV4dCgnMmQnKTtcblxuICAgIHRoaXMuY2FudmFzLndpZHRoID0gd2lkdGg7XG4gICAgdGhpcy5jYW52YXMuaGVpZ2h0ID0gaGVpZ2h0O1xufVxuXG5DYW52YXNCdWZmZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQ2FudmFzQnVmZmVyO1xubW9kdWxlLmV4cG9ydHMgPSBDYW52YXNCdWZmZXI7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKENhbnZhc0J1ZmZlci5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBUaGUgd2lkdGggb2YgdGhlIGNhbnZhcyBidWZmZXIgaW4gcGl4ZWxzLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBDYW52YXNCdWZmZXIjXG4gICAgICovXG4gICAgd2lkdGg6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jYW52YXMud2lkdGg7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbCkge1xuICAgICAgICAgICAgdGhpcy5jYW52YXMud2lkdGggPSB2YWw7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIC8qKlxuICAgICAqIFRoZSBoZWlnaHQgb2YgdGhlIGNhbnZhcyBidWZmZXIgaW4gcGl4ZWxzLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBDYW52YXNCdWZmZXIjXG4gICAgICovXG4gICAgaGVpZ2h0OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY2FudmFzLmhlaWdodDtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsKSB7XG4gICAgICAgICAgICB0aGlzLmNhbnZhcy5oZWlnaHQgPSB2YWw7XG4gICAgICAgIH1cbiAgICB9XG59KTtcblxuLyoqXG4gKiBDbGVhcnMgdGhlIGNhbnZhcyB0aGF0IHdhcyBjcmVhdGVkIGJ5IHRoZSBDYW52YXNCdWZmZXIgY2xhc3MuXG4gKlxuICogQHByaXZhdGVcbiAqL1xuQ2FudmFzQnVmZmVyLnByb3RvdHlwZS5jbGVhciA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmNvbnRleHQuc2V0VHJhbnNmb3JtKDEsIDAsIDAsIDEsIDAsIDApO1xuICAgIHRoaXMuY29udGV4dC5jbGVhclJlY3QoMCwwLCB0aGlzLmNhbnZhcy53aWR0aCwgdGhpcy5jYW52YXMuaGVpZ2h0KTtcbn07XG5cbi8qKlxuICogUmVzaXplcyB0aGUgY2FudmFzIHRvIHRoZSBzcGVjaWZpZWQgd2lkdGggYW5kIGhlaWdodC5cbiAqXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gdGhlIG5ldyB3aWR0aCBvZiB0aGUgY2FudmFzXG4gKiBAcGFyYW0gaGVpZ2h0IHtudW1iZXJ9IHRoZSBuZXcgaGVpZ2h0IG9mIHRoZSBjYW52YXNcbiAqL1xuQ2FudmFzQnVmZmVyLnByb3RvdHlwZS5yZXNpemUgPSBmdW5jdGlvbiAod2lkdGgsIGhlaWdodCkge1xuICAgIHRoaXMuY2FudmFzLndpZHRoID0gd2lkdGg7XG4gICAgdGhpcy5jYW52YXMuaGVpZ2h0ID0gaGVpZ2h0O1xufTtcbiIsInZhciBDT05TVCA9IHJlcXVpcmUoJy4uLy4uLy4uL2NvbnN0Jyk7XG5cbi8qKlxuICogQSBzZXQgb2YgZnVuY3Rpb25zIHVzZWQgYnkgdGhlIGNhbnZhcyByZW5kZXJlciB0byBkcmF3IHRoZSBwcmltaXRpdmUgZ3JhcGhpY3MgZGF0YS5cbiAqXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xudmFyIENhbnZhc0dyYXBoaWNzID0gbW9kdWxlLmV4cG9ydHMgPSB7fTtcblxuLypcbiAqIFJlbmRlcnMgYSBHcmFwaGljcyBvYmplY3QgdG8gYSBjYW52YXMuXG4gKlxuICogQHBhcmFtIGdyYXBoaWNzIHtHcmFwaGljc30gdGhlIGFjdHVhbCBncmFwaGljcyBvYmplY3QgdG8gcmVuZGVyXG4gKiBAcGFyYW0gY29udGV4dCB7Q2FudmFzUmVuZGVyaW5nQ29udGV4dDJEfSB0aGUgMmQgZHJhd2luZyBtZXRob2Qgb2YgdGhlIGNhbnZhc1xuICovXG5DYW52YXNHcmFwaGljcy5yZW5kZXJHcmFwaGljcyA9IGZ1bmN0aW9uIChncmFwaGljcywgY29udGV4dCkge1xuICAgIHZhciB3b3JsZEFscGhhID0gZ3JhcGhpY3Mud29ybGRBbHBoYTtcblxuICAgIGlmIChncmFwaGljcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnVwZGF0ZUdyYXBoaWNzVGludChncmFwaGljcyk7XG4gICAgICAgIGdyYXBoaWNzLmRpcnR5ID0gZmFsc2U7XG4gICAgfVxuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBncmFwaGljcy5ncmFwaGljc0RhdGEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGRhdGEgPSBncmFwaGljcy5ncmFwaGljc0RhdGFbaV07XG4gICAgICAgIHZhciBzaGFwZSA9IGRhdGEuc2hhcGU7XG5cbiAgICAgICAgdmFyIGZpbGxDb2xvciA9IGRhdGEuX2ZpbGxUaW50O1xuICAgICAgICB2YXIgbGluZUNvbG9yID0gZGF0YS5fbGluZVRpbnQ7XG5cbiAgICAgICAgY29udGV4dC5saW5lV2lkdGggPSBkYXRhLmxpbmVXaWR0aDtcblxuICAgICAgICBpZiAoZGF0YS50eXBlID09PSBDT05TVC5TSEFQRVMuUE9MWSkge1xuICAgICAgICAgICAgY29udGV4dC5iZWdpblBhdGgoKTtcblxuICAgICAgICAgICAgdmFyIHBvaW50cyA9IHNoYXBlLnBvaW50cztcblxuICAgICAgICAgICAgY29udGV4dC5tb3ZlVG8ocG9pbnRzWzBdLCBwb2ludHNbMV0pO1xuXG4gICAgICAgICAgICBmb3IgKHZhciBqPTE7IGogPCBwb2ludHMubGVuZ3RoLzI7IGorKykge1xuICAgICAgICAgICAgICAgIGNvbnRleHQubGluZVRvKHBvaW50c1tqICogMl0sIHBvaW50c1tqICogMiArIDFdKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHNoYXBlLmNsb3NlZCkge1xuICAgICAgICAgICAgICAgIGNvbnRleHQubGluZVRvKHBvaW50c1swXSwgcG9pbnRzWzFdKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gaWYgdGhlIGZpcnN0IGFuZCBsYXN0IHBvaW50IGFyZSB0aGUgc2FtZSBjbG9zZSB0aGUgcGF0aCAtIG11Y2ggbmVhdGVyIDopXG4gICAgICAgICAgICBpZiAocG9pbnRzWzBdID09PSBwb2ludHNbcG9pbnRzLmxlbmd0aC0yXSAmJiBwb2ludHNbMV0gPT09IHBvaW50c1twb2ludHMubGVuZ3RoLTFdKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5jbG9zZVBhdGgoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGRhdGEuZmlsbCkge1xuICAgICAgICAgICAgICAgIGNvbnRleHQuZ2xvYmFsQWxwaGEgPSBkYXRhLmZpbGxBbHBoYSAqIHdvcmxkQWxwaGE7XG4gICAgICAgICAgICAgICAgY29udGV4dC5maWxsU3R5bGUgPSAnIycgKyAoJzAwMDAwJyArICggZmlsbENvbG9yIHwgMCkudG9TdHJpbmcoMTYpKS5zdWJzdHIoLTYpO1xuICAgICAgICAgICAgICAgIGNvbnRleHQuZmlsbCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRhdGEubGluZVdpZHRoKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IGRhdGEubGluZUFscGhhICogd29ybGRBbHBoYTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZVN0eWxlID0gJyMnICsgKCcwMDAwMCcgKyAoIGxpbmVDb2xvciB8IDApLnRvU3RyaW5nKDE2KSkuc3Vic3RyKC02KTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLlJFQ1QpIHtcblxuICAgICAgICAgICAgaWYgKGRhdGEuZmlsbENvbG9yIHx8IGRhdGEuZmlsbENvbG9yID09PSAwKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IGRhdGEuZmlsbEFscGhhICogd29ybGRBbHBoYTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LmZpbGxTdHlsZSA9ICcjJyArICgnMDAwMDAnICsgKCBmaWxsQ29sb3IgfCAwKS50b1N0cmluZygxNikpLnN1YnN0cigtNik7XG4gICAgICAgICAgICAgICAgY29udGV4dC5maWxsUmVjdChzaGFwZS54LCBzaGFwZS55LCBzaGFwZS53aWR0aCwgc2hhcGUuaGVpZ2h0KTtcblxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRhdGEubGluZVdpZHRoKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IGRhdGEubGluZUFscGhhICogd29ybGRBbHBoYTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZVN0eWxlID0gJyMnICsgKCcwMDAwMCcgKyAoIGxpbmVDb2xvciB8IDApLnRvU3RyaW5nKDE2KSkuc3Vic3RyKC02KTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZVJlY3Qoc2hhcGUueCwgc2hhcGUueSwgc2hhcGUud2lkdGgsIHNoYXBlLmhlaWdodCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZGF0YS50eXBlID09PSBDT05TVC5TSEFQRVMuQ0lSQykge1xuICAgICAgICAgICAgLy8gVE9ETyAtIG5lZWQgdG8gYmUgVW5kZWZpbmVkIVxuICAgICAgICAgICAgY29udGV4dC5iZWdpblBhdGgoKTtcbiAgICAgICAgICAgIGNvbnRleHQuYXJjKHNoYXBlLngsIHNoYXBlLnksIHNoYXBlLnJhZGl1cywwLDIqTWF0aC5QSSk7XG4gICAgICAgICAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuXG4gICAgICAgICAgICBpZiAoZGF0YS5maWxsKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IGRhdGEuZmlsbEFscGhhICogd29ybGRBbHBoYTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LmZpbGxTdHlsZSA9ICcjJyArICgnMDAwMDAnICsgKCBmaWxsQ29sb3IgfCAwKS50b1N0cmluZygxNikpLnN1YnN0cigtNik7XG4gICAgICAgICAgICAgICAgY29udGV4dC5maWxsKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZGF0YS5saW5lV2lkdGgpIHtcbiAgICAgICAgICAgICAgICBjb250ZXh0Lmdsb2JhbEFscGhhID0gZGF0YS5saW5lQWxwaGEgKiB3b3JsZEFscGhhO1xuICAgICAgICAgICAgICAgIGNvbnRleHQuc3Ryb2tlU3R5bGUgPSAnIycgKyAoJzAwMDAwJyArICggbGluZUNvbG9yIHwgMCkudG9TdHJpbmcoMTYpKS5zdWJzdHIoLTYpO1xuICAgICAgICAgICAgICAgIGNvbnRleHQuc3Ryb2tlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoZGF0YS50eXBlID09PSBDT05TVC5TSEFQRVMuRUxJUCkge1xuICAgICAgICAgICAgLy8gZWxsaXBzZSBjb2RlIHRha2VuIGZyb206IGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMjE3Mjc5OC9ob3ctdG8tZHJhdy1hbi1vdmFsLWluLWh0bWw1LWNhbnZhc1xuXG4gICAgICAgICAgICB2YXIgdyA9IHNoYXBlLndpZHRoICogMjtcbiAgICAgICAgICAgIHZhciBoID0gc2hhcGUuaGVpZ2h0ICogMjtcblxuICAgICAgICAgICAgdmFyIHggPSBzaGFwZS54IC0gdy8yO1xuICAgICAgICAgICAgdmFyIHkgPSBzaGFwZS55IC0gaC8yO1xuXG4gICAgICAgICAgICBjb250ZXh0LmJlZ2luUGF0aCgpO1xuXG4gICAgICAgICAgICB2YXIga2FwcGEgPSAwLjU1MjI4NDgsXG4gICAgICAgICAgICAgICAgb3ggPSAodyAvIDIpICoga2FwcGEsIC8vIGNvbnRyb2wgcG9pbnQgb2Zmc2V0IGhvcml6b250YWxcbiAgICAgICAgICAgICAgICBveSA9IChoIC8gMikgKiBrYXBwYSwgLy8gY29udHJvbCBwb2ludCBvZmZzZXQgdmVydGljYWxcbiAgICAgICAgICAgICAgICB4ZSA9IHggKyB3LCAgICAgICAgICAgLy8geC1lbmRcbiAgICAgICAgICAgICAgICB5ZSA9IHkgKyBoLCAgICAgICAgICAgLy8geS1lbmRcbiAgICAgICAgICAgICAgICB4bSA9IHggKyB3IC8gMiwgICAgICAgLy8geC1taWRkbGVcbiAgICAgICAgICAgICAgICB5bSA9IHkgKyBoIC8gMjsgICAgICAgLy8geS1taWRkbGVcblxuICAgICAgICAgICAgY29udGV4dC5tb3ZlVG8oeCwgeW0pO1xuICAgICAgICAgICAgY29udGV4dC5iZXppZXJDdXJ2ZVRvKHgsIHltIC0gb3ksIHhtIC0gb3gsIHksIHhtLCB5KTtcbiAgICAgICAgICAgIGNvbnRleHQuYmV6aWVyQ3VydmVUbyh4bSArIG94LCB5LCB4ZSwgeW0gLSBveSwgeGUsIHltKTtcbiAgICAgICAgICAgIGNvbnRleHQuYmV6aWVyQ3VydmVUbyh4ZSwgeW0gKyBveSwgeG0gKyBveCwgeWUsIHhtLCB5ZSk7XG4gICAgICAgICAgICBjb250ZXh0LmJlemllckN1cnZlVG8oeG0gLSBveCwgeWUsIHgsIHltICsgb3ksIHgsIHltKTtcblxuICAgICAgICAgICAgY29udGV4dC5jbG9zZVBhdGgoKTtcblxuICAgICAgICAgICAgaWYgKGRhdGEuZmlsbCkge1xuICAgICAgICAgICAgICAgIGNvbnRleHQuZ2xvYmFsQWxwaGEgPSBkYXRhLmZpbGxBbHBoYSAqIHdvcmxkQWxwaGE7XG4gICAgICAgICAgICAgICAgY29udGV4dC5maWxsU3R5bGUgPSAnIycgKyAoJzAwMDAwJyArICggZmlsbENvbG9yIHwgMCkudG9TdHJpbmcoMTYpKS5zdWJzdHIoLTYpO1xuICAgICAgICAgICAgICAgIGNvbnRleHQuZmlsbCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRhdGEubGluZVdpZHRoKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IGRhdGEubGluZUFscGhhICogd29ybGRBbHBoYTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZVN0eWxlID0gJyMnICsgKCcwMDAwMCcgKyAoIGxpbmVDb2xvciB8IDApLnRvU3RyaW5nKDE2KSkuc3Vic3RyKC02KTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLlJSRUMpIHtcbiAgICAgICAgICAgIHZhciByeCA9IHNoYXBlLng7XG4gICAgICAgICAgICB2YXIgcnkgPSBzaGFwZS55O1xuICAgICAgICAgICAgdmFyIHdpZHRoID0gc2hhcGUud2lkdGg7XG4gICAgICAgICAgICB2YXIgaGVpZ2h0ID0gc2hhcGUuaGVpZ2h0O1xuICAgICAgICAgICAgdmFyIHJhZGl1cyA9IHNoYXBlLnJhZGl1cztcblxuICAgICAgICAgICAgdmFyIG1heFJhZGl1cyA9IE1hdGgubWluKHdpZHRoLCBoZWlnaHQpIC8gMiB8IDA7XG4gICAgICAgICAgICByYWRpdXMgPSByYWRpdXMgPiBtYXhSYWRpdXMgPyBtYXhSYWRpdXMgOiByYWRpdXM7XG5cbiAgICAgICAgICAgIGNvbnRleHQuYmVnaW5QYXRoKCk7XG4gICAgICAgICAgICBjb250ZXh0Lm1vdmVUbyhyeCwgcnkgKyByYWRpdXMpO1xuICAgICAgICAgICAgY29udGV4dC5saW5lVG8ocngsIHJ5ICsgaGVpZ2h0IC0gcmFkaXVzKTtcbiAgICAgICAgICAgIGNvbnRleHQucXVhZHJhdGljQ3VydmVUbyhyeCwgcnkgKyBoZWlnaHQsIHJ4ICsgcmFkaXVzLCByeSArIGhlaWdodCk7XG4gICAgICAgICAgICBjb250ZXh0LmxpbmVUbyhyeCArIHdpZHRoIC0gcmFkaXVzLCByeSArIGhlaWdodCk7XG4gICAgICAgICAgICBjb250ZXh0LnF1YWRyYXRpY0N1cnZlVG8ocnggKyB3aWR0aCwgcnkgKyBoZWlnaHQsIHJ4ICsgd2lkdGgsIHJ5ICsgaGVpZ2h0IC0gcmFkaXVzKTtcbiAgICAgICAgICAgIGNvbnRleHQubGluZVRvKHJ4ICsgd2lkdGgsIHJ5ICsgcmFkaXVzKTtcbiAgICAgICAgICAgIGNvbnRleHQucXVhZHJhdGljQ3VydmVUbyhyeCArIHdpZHRoLCByeSwgcnggKyB3aWR0aCAtIHJhZGl1cywgcnkpO1xuICAgICAgICAgICAgY29udGV4dC5saW5lVG8ocnggKyByYWRpdXMsIHJ5KTtcbiAgICAgICAgICAgIGNvbnRleHQucXVhZHJhdGljQ3VydmVUbyhyeCwgcnksIHJ4LCByeSArIHJhZGl1cyk7XG4gICAgICAgICAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuXG4gICAgICAgICAgICBpZiAoZGF0YS5maWxsQ29sb3IgfHwgZGF0YS5maWxsQ29sb3IgPT09IDApIHtcbiAgICAgICAgICAgICAgICBjb250ZXh0Lmdsb2JhbEFscGhhID0gZGF0YS5maWxsQWxwaGEgKiB3b3JsZEFscGhhO1xuICAgICAgICAgICAgICAgIGNvbnRleHQuZmlsbFN0eWxlID0gJyMnICsgKCcwMDAwMCcgKyAoIGZpbGxDb2xvciB8IDApLnRvU3RyaW5nKDE2KSkuc3Vic3RyKC02KTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LmZpbGwoKTtcblxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRhdGEubGluZVdpZHRoKSB7XG4gICAgICAgICAgICAgICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IGRhdGEubGluZUFscGhhICogd29ybGRBbHBoYTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZVN0eWxlID0gJyMnICsgKCcwMDAwMCcgKyAoIGxpbmVDb2xvciB8IDApLnRvU3RyaW5nKDE2KSkuc3Vic3RyKC02KTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN0cm9rZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxufTtcblxuLypcbiAqIFJlbmRlcnMgYSBncmFwaGljcyBtYXNrXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSBncmFwaGljcyB7R3JhcGhpY3N9IHRoZSBncmFwaGljcyB3aGljaCB3aWxsIGJlIHVzZWQgYXMgYSBtYXNrXG4gKiBAcGFyYW0gY29udGV4dCB7Q2FudmFzUmVuZGVyaW5nQ29udGV4dDJEfSB0aGUgY29udGV4dCAyZCBtZXRob2Qgb2YgdGhlIGNhbnZhc1xuICovXG5DYW52YXNHcmFwaGljcy5yZW5kZXJHcmFwaGljc01hc2sgPSBmdW5jdGlvbiAoZ3JhcGhpY3MsIGNvbnRleHQpIHtcbiAgICB2YXIgbGVuID0gZ3JhcGhpY3MuZ3JhcGhpY3NEYXRhLmxlbmd0aDtcblxuICAgIGlmIChsZW4gPT09IDApIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnRleHQuYmVnaW5QYXRoKCk7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgIHZhciBkYXRhID0gZ3JhcGhpY3MuZ3JhcGhpY3NEYXRhW2ldO1xuICAgICAgICB2YXIgc2hhcGUgPSBkYXRhLnNoYXBlO1xuXG4gICAgICAgIGlmIChkYXRhLnR5cGUgPT09IENPTlNULlNIQVBFUy5QT0xZKSB7XG5cbiAgICAgICAgICAgIHZhciBwb2ludHMgPSBzaGFwZS5wb2ludHM7XG5cbiAgICAgICAgICAgIGNvbnRleHQubW92ZVRvKHBvaW50c1swXSwgcG9pbnRzWzFdKTtcblxuICAgICAgICAgICAgZm9yICh2YXIgaj0xOyBqIDwgcG9pbnRzLmxlbmd0aC8yOyBqKyspIHtcbiAgICAgICAgICAgICAgICBjb250ZXh0LmxpbmVUbyhwb2ludHNbaiAqIDJdLCBwb2ludHNbaiAqIDIgKyAxXSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIGlmIHRoZSBmaXJzdCBhbmQgbGFzdCBwb2ludCBhcmUgdGhlIHNhbWUgY2xvc2UgdGhlIHBhdGggLSBtdWNoIG5lYXRlciA6KVxuICAgICAgICAgICAgaWYgKHBvaW50c1swXSA9PT0gcG9pbnRzW3BvaW50cy5sZW5ndGgtMl0gJiYgcG9pbnRzWzFdID09PSBwb2ludHNbcG9pbnRzLmxlbmd0aC0xXSkge1xuICAgICAgICAgICAgICAgIGNvbnRleHQuY2xvc2VQYXRoKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChkYXRhLnR5cGUgPT09IENPTlNULlNIQVBFUy5SRUNUKSB7XG4gICAgICAgICAgICBjb250ZXh0LnJlY3Qoc2hhcGUueCwgc2hhcGUueSwgc2hhcGUud2lkdGgsIHNoYXBlLmhlaWdodCk7XG4gICAgICAgICAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLkNJUkMpIHtcbiAgICAgICAgICAgIC8vIFRPRE8gLSBuZWVkIHRvIGJlIFVuZGVmaW5lZCFcbiAgICAgICAgICAgIGNvbnRleHQuYXJjKHNoYXBlLngsIHNoYXBlLnksIHNoYXBlLnJhZGl1cywgMCwgMiAqIE1hdGguUEkpO1xuICAgICAgICAgICAgY29udGV4dC5jbG9zZVBhdGgoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChkYXRhLnR5cGUgPT09IENPTlNULlNIQVBFUy5FTElQKSB7XG5cbiAgICAgICAgICAgIC8vIGVsbGlwc2UgY29kZSB0YWtlbiBmcm9tOiBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzIxNzI3OTgvaG93LXRvLWRyYXctYW4tb3ZhbC1pbi1odG1sNS1jYW52YXNcblxuICAgICAgICAgICAgdmFyIHcgPSBzaGFwZS53aWR0aCAqIDI7XG4gICAgICAgICAgICB2YXIgaCA9IHNoYXBlLmhlaWdodCAqIDI7XG5cbiAgICAgICAgICAgIHZhciB4ID0gc2hhcGUueCAtIHcvMjtcbiAgICAgICAgICAgIHZhciB5ID0gc2hhcGUueSAtIGgvMjtcblxuICAgICAgICAgICAgdmFyIGthcHBhID0gMC41NTIyODQ4LFxuICAgICAgICAgICAgICAgIG94ID0gKHcgLyAyKSAqIGthcHBhLCAvLyBjb250cm9sIHBvaW50IG9mZnNldCBob3Jpem9udGFsXG4gICAgICAgICAgICAgICAgb3kgPSAoaCAvIDIpICoga2FwcGEsIC8vIGNvbnRyb2wgcG9pbnQgb2Zmc2V0IHZlcnRpY2FsXG4gICAgICAgICAgICAgICAgeGUgPSB4ICsgdywgICAgICAgICAgIC8vIHgtZW5kXG4gICAgICAgICAgICAgICAgeWUgPSB5ICsgaCwgICAgICAgICAgIC8vIHktZW5kXG4gICAgICAgICAgICAgICAgeG0gPSB4ICsgdyAvIDIsICAgICAgIC8vIHgtbWlkZGxlXG4gICAgICAgICAgICAgICAgeW0gPSB5ICsgaCAvIDI7ICAgICAgIC8vIHktbWlkZGxlXG5cbiAgICAgICAgICAgIGNvbnRleHQubW92ZVRvKHgsIHltKTtcbiAgICAgICAgICAgIGNvbnRleHQuYmV6aWVyQ3VydmVUbyh4LCB5bSAtIG95LCB4bSAtIG94LCB5LCB4bSwgeSk7XG4gICAgICAgICAgICBjb250ZXh0LmJlemllckN1cnZlVG8oeG0gKyBveCwgeSwgeGUsIHltIC0gb3ksIHhlLCB5bSk7XG4gICAgICAgICAgICBjb250ZXh0LmJlemllckN1cnZlVG8oeGUsIHltICsgb3ksIHhtICsgb3gsIHllLCB4bSwgeWUpO1xuICAgICAgICAgICAgY29udGV4dC5iZXppZXJDdXJ2ZVRvKHhtIC0gb3gsIHllLCB4LCB5bSArIG95LCB4LCB5bSk7XG4gICAgICAgICAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLlJSRUMpIHtcblxuICAgICAgICAgICAgdmFyIHJ4ID0gc2hhcGUueDtcbiAgICAgICAgICAgIHZhciByeSA9IHNoYXBlLnk7XG4gICAgICAgICAgICB2YXIgd2lkdGggPSBzaGFwZS53aWR0aDtcbiAgICAgICAgICAgIHZhciBoZWlnaHQgPSBzaGFwZS5oZWlnaHQ7XG4gICAgICAgICAgICB2YXIgcmFkaXVzID0gc2hhcGUucmFkaXVzO1xuXG4gICAgICAgICAgICB2YXIgbWF4UmFkaXVzID0gTWF0aC5taW4od2lkdGgsIGhlaWdodCkgLyAyIHwgMDtcbiAgICAgICAgICAgIHJhZGl1cyA9IHJhZGl1cyA+IG1heFJhZGl1cyA/IG1heFJhZGl1cyA6IHJhZGl1cztcblxuICAgICAgICAgICAgY29udGV4dC5tb3ZlVG8ocngsIHJ5ICsgcmFkaXVzKTtcbiAgICAgICAgICAgIGNvbnRleHQubGluZVRvKHJ4LCByeSArIGhlaWdodCAtIHJhZGl1cyk7XG4gICAgICAgICAgICBjb250ZXh0LnF1YWRyYXRpY0N1cnZlVG8ocngsIHJ5ICsgaGVpZ2h0LCByeCArIHJhZGl1cywgcnkgKyBoZWlnaHQpO1xuICAgICAgICAgICAgY29udGV4dC5saW5lVG8ocnggKyB3aWR0aCAtIHJhZGl1cywgcnkgKyBoZWlnaHQpO1xuICAgICAgICAgICAgY29udGV4dC5xdWFkcmF0aWNDdXJ2ZVRvKHJ4ICsgd2lkdGgsIHJ5ICsgaGVpZ2h0LCByeCArIHdpZHRoLCByeSArIGhlaWdodCAtIHJhZGl1cyk7XG4gICAgICAgICAgICBjb250ZXh0LmxpbmVUbyhyeCArIHdpZHRoLCByeSArIHJhZGl1cyk7XG4gICAgICAgICAgICBjb250ZXh0LnF1YWRyYXRpY0N1cnZlVG8ocnggKyB3aWR0aCwgcnksIHJ4ICsgd2lkdGggLSByYWRpdXMsIHJ5KTtcbiAgICAgICAgICAgIGNvbnRleHQubGluZVRvKHJ4ICsgcmFkaXVzLCByeSk7XG4gICAgICAgICAgICBjb250ZXh0LnF1YWRyYXRpY0N1cnZlVG8ocngsIHJ5LCByeCwgcnkgKyByYWRpdXMpO1xuICAgICAgICAgICAgY29udGV4dC5jbG9zZVBhdGgoKTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cbkNhbnZhc0dyYXBoaWNzLnVwZGF0ZUdyYXBoaWNzVGludCA9IGZ1bmN0aW9uIChncmFwaGljcykge1xuICAgIGlmIChncmFwaGljcy50aW50ID09PSAweEZGRkZGRikge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIHRpbnRSID0gKGdyYXBoaWNzLnRpbnQgPj4gMTYgJiAweEZGKSAvIDI1NTtcbiAgICB2YXIgdGludEcgPSAoZ3JhcGhpY3MudGludCA+PiA4ICYgMHhGRikgLyAyNTU7XG4gICAgdmFyIHRpbnRCID0gKGdyYXBoaWNzLnRpbnQgJiAweEZGKS8gMjU1O1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBncmFwaGljcy5ncmFwaGljc0RhdGEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGRhdGEgPSBncmFwaGljcy5ncmFwaGljc0RhdGFbaV07XG5cbiAgICAgICAgdmFyIGZpbGxDb2xvciA9IGRhdGEuZmlsbENvbG9yIHwgMDtcbiAgICAgICAgdmFyIGxpbmVDb2xvciA9IGRhdGEubGluZUNvbG9yIHwgMDtcblxuICAgICAgICAvKlxuICAgICAgICB2YXIgY29sb3JSID0gKGZpbGxDb2xvciA+PiAxNiAmIDB4RkYpIC8gMjU1O1xuICAgICAgICB2YXIgY29sb3JHID0gKGZpbGxDb2xvciA+PiA4ICYgMHhGRikgLyAyNTU7XG4gICAgICAgIHZhciBjb2xvckIgPSAoZmlsbENvbG9yICYgMHhGRikgLyAyNTU7XG5cbiAgICAgICAgY29sb3JSICo9IHRpbnRSO1xuICAgICAgICBjb2xvckcgKj0gdGludEc7XG4gICAgICAgIGNvbG9yQiAqPSB0aW50QjtcblxuICAgICAgICBmaWxsQ29sb3IgPSAoKGNvbG9yUioyNTUgPDwgMTYpICsgKGNvbG9yRyoyNTUgPDwgOCkgKyBjb2xvckIqMjU1KTtcblxuICAgICAgICBjb2xvclIgPSAobGluZUNvbG9yID4+IDE2ICYgMHhGRikgLyAyNTU7XG4gICAgICAgIGNvbG9yRyA9IChsaW5lQ29sb3IgPj4gOCAmIDB4RkYpIC8gMjU1O1xuICAgICAgICBjb2xvckIgPSAobGluZUNvbG9yICYgMHhGRikgLyAyNTU7XG5cbiAgICAgICAgY29sb3JSICo9IHRpbnRSO1xuICAgICAgICBjb2xvckcgKj0gdGludEc7XG4gICAgICAgIGNvbG9yQiAqPSB0aW50QjtcblxuICAgICAgICBsaW5lQ29sb3IgPSAoKGNvbG9yUioyNTUgPDwgMTYpICsgKGNvbG9yRyoyNTUgPDwgOCkgKyBjb2xvckIqMjU1KTtcbiAgICAgICAgKi9cblxuICAgICAgICAvLyBzdXBlciBpbmxpbmUgY29zIGltIGFuIG9wdGltaXphdGlvbiBOQVpJIDopXG4gICAgICAgIGRhdGEuX2ZpbGxUaW50ID0gKCgoZmlsbENvbG9yID4+IDE2ICYgMHhGRikgLyAyNTUgKiB0aW50UioyNTUgPDwgMTYpICsgKChmaWxsQ29sb3IgPj4gOCAmIDB4RkYpIC8gMjU1ICogdGludEcqMjU1IDw8IDgpICsgIChmaWxsQ29sb3IgJiAweEZGKSAvIDI1NSAqIHRpbnRCKjI1NSk7XG4gICAgICAgIGRhdGEuX2xpbmVUaW50ID0gKCgobGluZUNvbG9yID4+IDE2ICYgMHhGRikgLyAyNTUgKiB0aW50UioyNTUgPDwgMTYpICsgKChsaW5lQ29sb3IgPj4gOCAmIDB4RkYpIC8gMjU1ICogdGludEcqMjU1IDw8IDgpICsgIChsaW5lQ29sb3IgJiAweEZGKSAvIDI1NSAqIHRpbnRCKjI1NSk7XG5cbiAgICB9XG59O1xuXG4iLCJ2YXIgQ2FudmFzR3JhcGhpY3MgPSByZXF1aXJlKCcuL0NhbnZhc0dyYXBoaWNzJyk7XG5cbi8qKlxuICogQSBzZXQgb2YgZnVuY3Rpb25zIHVzZWQgdG8gaGFuZGxlIG1hc2tpbmcuXG4gKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gQ2FudmFzTWFza01hbmFnZXIoKSB7fVxuXG5DYW52YXNNYXNrTWFuYWdlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDYW52YXNNYXNrTWFuYWdlcjtcbm1vZHVsZS5leHBvcnRzID0gQ2FudmFzTWFza01hbmFnZXI7XG5cbi8qKlxuICogVGhpcyBtZXRob2QgYWRkcyBpdCB0byB0aGUgY3VycmVudCBzdGFjayBvZiBtYXNrcy5cbiAqXG4gKiBAcGFyYW0gbWFza0RhdGEge29iamVjdH0gdGhlIG1hc2tEYXRhIHRoYXQgd2lsbCBiZSBwdXNoZWRcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcnxDYW52YXNSZW5kZXJlcn0gVGhlIHJlbmRlcmVyIGNvbnRleHQgdG8gdXNlLlxuICovXG5DYW52YXNNYXNrTWFuYWdlci5wcm90b3R5cGUucHVzaE1hc2sgPSBmdW5jdGlvbiAobWFza0RhdGEsIHJlbmRlcmVyKSB7XG4gICAgcmVuZGVyZXIuY29udGV4dC5zYXZlKCk7XG5cbiAgICB2YXIgY2FjaGVBbHBoYSA9IG1hc2tEYXRhLmFscGhhO1xuICAgIHZhciB0cmFuc2Zvcm0gPSBtYXNrRGF0YS53b3JsZFRyYW5zZm9ybTtcbiAgICB2YXIgcmVzb2x1dGlvbiA9IHJlbmRlcmVyLnJlc29sdXRpb247XG5cbiAgICByZW5kZXJlci5jb250ZXh0LnNldFRyYW5zZm9ybShcbiAgICAgICAgdHJhbnNmb3JtLmEgKiByZXNvbHV0aW9uLFxuICAgICAgICB0cmFuc2Zvcm0uYiAqIHJlc29sdXRpb24sXG4gICAgICAgIHRyYW5zZm9ybS5jICogcmVzb2x1dGlvbixcbiAgICAgICAgdHJhbnNmb3JtLmQgKiByZXNvbHV0aW9uLFxuICAgICAgICB0cmFuc2Zvcm0udHggKiByZXNvbHV0aW9uLFxuICAgICAgICB0cmFuc2Zvcm0udHkgKiByZXNvbHV0aW9uXG4gICAgKTtcblxuICAgIENhbnZhc0dyYXBoaWNzLnJlbmRlckdyYXBoaWNzTWFzayhtYXNrRGF0YSwgcmVuZGVyZXIuY29udGV4dCk7XG5cbiAgICByZW5kZXJlci5jb250ZXh0LmNsaXAoKTtcblxuICAgIG1hc2tEYXRhLndvcmxkQWxwaGEgPSBjYWNoZUFscGhhO1xufTtcblxuLyoqXG4gKiBSZXN0b3JlcyB0aGUgY3VycmVudCBkcmF3aW5nIGNvbnRleHQgdG8gdGhlIHN0YXRlIGl0IHdhcyBiZWZvcmUgdGhlIG1hc2sgd2FzIGFwcGxpZWQuXG4gKlxuICogQHBhcmFtIHJlbmRlcmVyIHtXZWJHTFJlbmRlcmVyfENhbnZhc1JlbmRlcmVyfSBUaGUgcmVuZGVyZXIgY29udGV4dCB0byB1c2UuXG4gKi9cbkNhbnZhc01hc2tNYW5hZ2VyLnByb3RvdHlwZS5wb3BNYXNrID0gZnVuY3Rpb24gKHJlbmRlcmVyKSB7XG4gICAgcmVuZGVyZXIuY29udGV4dC5yZXN0b3JlKCk7XG59O1xuIiwidmFyIHV0aWxzID0gcmVxdWlyZSgnLi4vLi4vLi4vdXRpbHMnKTtcblxuLyoqXG4gKiBVdGlsaXR5IG1ldGhvZHMgZm9yIFNwcml0ZS9UZXh0dXJlIHRpbnRpbmcuXG4gKlxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbnZhciBDYW52YXNUaW50ZXIgPSBtb2R1bGUuZXhwb3J0cyA9IHt9O1xuXG4vKipcbiAqIEJhc2ljYWxseSB0aGlzIG1ldGhvZCBqdXN0IG5lZWRzIGEgc3ByaXRlIGFuZCBhIGNvbG9yIGFuZCB0aW50cyB0aGUgc3ByaXRlIHdpdGggdGhlIGdpdmVuIGNvbG9yLlxuICpcbiAqIEBwYXJhbSBzcHJpdGUge1Nwcml0ZX0gdGhlIHNwcml0ZSB0byB0aW50XG4gKiBAcGFyYW0gY29sb3Ige251bWJlcn0gdGhlIGNvbG9yIHRvIHVzZSB0byB0aW50IHRoZSBzcHJpdGUgd2l0aFxuICogQHJldHVybiB7SFRNTENhbnZhc0VsZW1lbnR9IFRoZSB0aW50ZWQgY2FudmFzXG4gKi9cbkNhbnZhc1RpbnRlci5nZXRUaW50ZWRUZXh0dXJlID0gZnVuY3Rpb24gKHNwcml0ZSwgY29sb3IpIHtcbiAgICB2YXIgdGV4dHVyZSA9IHNwcml0ZS50ZXh0dXJlO1xuXG4gICAgY29sb3IgPSBDYW52YXNUaW50ZXIucm91bmRDb2xvcihjb2xvcik7XG5cbiAgICB2YXIgc3RyaW5nQ29sb3IgPSAnIycgKyAoJzAwMDAwJyArICggY29sb3IgfCAwKS50b1N0cmluZygxNikpLnN1YnN0cigtNik7XG5cbiAgICB0ZXh0dXJlLnRpbnRDYWNoZSA9IHRleHR1cmUudGludENhY2hlIHx8IHt9O1xuXG4gICAgaWYgKHRleHR1cmUudGludENhY2hlW3N0cmluZ0NvbG9yXSkge1xuICAgICAgICByZXR1cm4gdGV4dHVyZS50aW50Q2FjaGVbc3RyaW5nQ29sb3JdO1xuICAgIH1cblxuICAgICAvLyBjbG9uZSB0ZXh0dXJlLi5cbiAgICB2YXIgY2FudmFzID0gQ2FudmFzVGludGVyLmNhbnZhcyB8fCBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcblxuICAgIC8vQ2FudmFzVGludGVyLnRpbnRXaXRoUGVyUGl4ZWwodGV4dHVyZSwgc3RyaW5nQ29sb3IsIGNhbnZhcyk7XG4gICAgQ2FudmFzVGludGVyLnRpbnRNZXRob2QodGV4dHVyZSwgY29sb3IsIGNhbnZhcyk7XG5cbiAgICBpZiAoQ2FudmFzVGludGVyLmNvbnZlcnRUaW50VG9JbWFnZSkge1xuICAgICAgICAvLyBpcyB0aGlzIGJldHRlcj9cbiAgICAgICAgdmFyIHRpbnRJbWFnZSA9IG5ldyBJbWFnZSgpO1xuICAgICAgICB0aW50SW1hZ2Uuc3JjID0gY2FudmFzLnRvRGF0YVVSTCgpO1xuXG4gICAgICAgIHRleHR1cmUudGludENhY2hlW3N0cmluZ0NvbG9yXSA9IHRpbnRJbWFnZTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHRleHR1cmUudGludENhY2hlW3N0cmluZ0NvbG9yXSA9IGNhbnZhcztcbiAgICAgICAgLy8gaWYgd2UgYXJlIG5vdCBjb252ZXJ0aW5nIHRoZSB0ZXh0dXJlIHRvIGFuIGltYWdlIHRoZW4gd2UgbmVlZCB0byBsb3NlIHRoZSByZWZlcmVuY2UgdG8gdGhlIGNhbnZhc1xuICAgICAgICBDYW52YXNUaW50ZXIuY2FudmFzID0gbnVsbDtcbiAgICB9XG5cbiAgICByZXR1cm4gY2FudmFzO1xufTtcblxuLyoqXG4gKiBUaW50IGEgdGV4dHVyZSB1c2luZyB0aGUgJ211bHRpcGx5JyBvcGVyYXRpb24uXG4gKlxuICogQHBhcmFtIHRleHR1cmUge1RleHR1cmV9IHRoZSB0ZXh0dXJlIHRvIHRpbnRcbiAqIEBwYXJhbSBjb2xvciB7bnVtYmVyfSB0aGUgY29sb3IgdG8gdXNlIHRvIHRpbnQgdGhlIHNwcml0ZSB3aXRoXG4gKiBAcGFyYW0gY2FudmFzIHtIVE1MQ2FudmFzRWxlbWVudH0gdGhlIGN1cnJlbnQgY2FudmFzXG4gKi9cbkNhbnZhc1RpbnRlci50aW50V2l0aE11bHRpcGx5ID0gZnVuY3Rpb24gKHRleHR1cmUsIGNvbG9yLCBjYW52YXMpIHtcbiAgICB2YXIgY29udGV4dCA9IGNhbnZhcy5nZXRDb250ZXh0KCAnMmQnICk7XG5cbiAgICB2YXIgY3JvcCA9IHRleHR1cmUuY3JvcDtcblxuICAgIGNhbnZhcy53aWR0aCA9IGNyb3Aud2lkdGg7XG4gICAgY2FudmFzLmhlaWdodCA9IGNyb3AuaGVpZ2h0O1xuXG4gICAgY29udGV4dC5maWxsU3R5bGUgPSAnIycgKyAoJzAwMDAwJyArICggY29sb3IgfCAwKS50b1N0cmluZygxNikpLnN1YnN0cigtNik7XG5cbiAgICBjb250ZXh0LmZpbGxSZWN0KDAsIDAsIGNyb3Aud2lkdGgsIGNyb3AuaGVpZ2h0KTtcblxuICAgIGNvbnRleHQuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uID0gJ211bHRpcGx5JztcblxuICAgIGNvbnRleHQuZHJhd0ltYWdlKFxuICAgICAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLnNvdXJjZSxcbiAgICAgICAgY3JvcC54LFxuICAgICAgICBjcm9wLnksXG4gICAgICAgIGNyb3Aud2lkdGgsXG4gICAgICAgIGNyb3AuaGVpZ2h0LFxuICAgICAgICAwLFxuICAgICAgICAwLFxuICAgICAgICBjcm9wLndpZHRoLFxuICAgICAgICBjcm9wLmhlaWdodFxuICAgICk7XG5cbiAgICBjb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9ICdkZXN0aW5hdGlvbi1hdG9wJztcblxuICAgIGNvbnRleHQuZHJhd0ltYWdlKFxuICAgICAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLnNvdXJjZSxcbiAgICAgICAgY3JvcC54LFxuICAgICAgICBjcm9wLnksXG4gICAgICAgIGNyb3Aud2lkdGgsXG4gICAgICAgIGNyb3AuaGVpZ2h0LFxuICAgICAgICAwLFxuICAgICAgICAwLFxuICAgICAgICBjcm9wLndpZHRoLFxuICAgICAgICBjcm9wLmhlaWdodFxuICAgICk7XG59O1xuXG4vKipcbiAqIFRpbnQgYSB0ZXh0dXJlIHVzaW5nIHRoZSAnb3ZlcmxheScgb3BlcmF0aW9uLlxuICpcbiAqIEBwYXJhbSB0ZXh0dXJlIHtUZXh0dXJlfSB0aGUgdGV4dHVyZSB0byB0aW50XG4gKiBAcGFyYW0gY29sb3Ige251bWJlcn0gdGhlIGNvbG9yIHRvIHVzZSB0byB0aW50IHRoZSBzcHJpdGUgd2l0aFxuICogQHBhcmFtIGNhbnZhcyB7SFRNTENhbnZhc0VsZW1lbnR9IHRoZSBjdXJyZW50IGNhbnZhc1xuICovXG5DYW52YXNUaW50ZXIudGludFdpdGhPdmVybGF5ID0gZnVuY3Rpb24gKHRleHR1cmUsIGNvbG9yLCBjYW52YXMpIHtcbiAgICB2YXIgY29udGV4dCA9IGNhbnZhcy5nZXRDb250ZXh0KCAnMmQnICk7XG5cbiAgICB2YXIgY3JvcCA9IHRleHR1cmUuY3JvcDtcblxuICAgIGNhbnZhcy53aWR0aCA9IGNyb3Aud2lkdGg7XG4gICAgY2FudmFzLmhlaWdodCA9IGNyb3AuaGVpZ2h0O1xuXG4gICAgY29udGV4dC5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb24gPSAnY29weSc7XG4gICAgY29udGV4dC5maWxsU3R5bGUgPSAnIycgKyAoJzAwMDAwJyArICggY29sb3IgfCAwKS50b1N0cmluZygxNikpLnN1YnN0cigtNik7XG4gICAgY29udGV4dC5maWxsUmVjdCgwLCAwLCBjcm9wLndpZHRoLCBjcm9wLmhlaWdodCk7XG5cbiAgICBjb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9ICdkZXN0aW5hdGlvbi1hdG9wJztcbiAgICBjb250ZXh0LmRyYXdJbWFnZShcbiAgICAgICAgdGV4dHVyZS5iYXNlVGV4dHVyZS5zb3VyY2UsXG4gICAgICAgIGNyb3AueCxcbiAgICAgICAgY3JvcC55LFxuICAgICAgICBjcm9wLndpZHRoLFxuICAgICAgICBjcm9wLmhlaWdodCxcbiAgICAgICAgMCxcbiAgICAgICAgMCxcbiAgICAgICAgY3JvcC53aWR0aCxcbiAgICAgICAgY3JvcC5oZWlnaHRcbiAgICApO1xuXG4gICAgLy8gY29udGV4dC5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb24gPSAnY29weSc7XG59O1xuXG4vKipcbiAqIFRpbnQgYSB0ZXh0dXJlIHBpeGVsIHBlciBwaXhlbC5cbiAqXG4gKiBAcGFyYW0gdGV4dHVyZSB7VGV4dHVyZX0gdGhlIHRleHR1cmUgdG8gdGludFxuICogQHBhcmFtIGNvbG9yIHtudW1iZXJ9IHRoZSBjb2xvciB0byB1c2UgdG8gdGludCB0aGUgc3ByaXRlIHdpdGhcbiAqIEBwYXJhbSBjYW52YXMge0hUTUxDYW52YXNFbGVtZW50fSB0aGUgY3VycmVudCBjYW52YXNcbiAqL1xuQ2FudmFzVGludGVyLnRpbnRXaXRoUGVyUGl4ZWwgPSBmdW5jdGlvbiAodGV4dHVyZSwgY29sb3IsIGNhbnZhcykge1xuICAgIHZhciBjb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoICcyZCcgKTtcblxuICAgIHZhciBjcm9wID0gdGV4dHVyZS5jcm9wO1xuXG4gICAgY2FudmFzLndpZHRoID0gY3JvcC53aWR0aDtcbiAgICBjYW52YXMuaGVpZ2h0ID0gY3JvcC5oZWlnaHQ7XG5cbiAgICBjb250ZXh0Lmdsb2JhbENvbXBvc2l0ZU9wZXJhdGlvbiA9ICdjb3B5JztcbiAgICBjb250ZXh0LmRyYXdJbWFnZShcbiAgICAgICAgdGV4dHVyZS5iYXNlVGV4dHVyZS5zb3VyY2UsXG4gICAgICAgIGNyb3AueCxcbiAgICAgICAgY3JvcC55LFxuICAgICAgICBjcm9wLndpZHRoLFxuICAgICAgICBjcm9wLmhlaWdodCxcbiAgICAgICAgMCxcbiAgICAgICAgMCxcbiAgICAgICAgY3JvcC53aWR0aCxcbiAgICAgICAgY3JvcC5oZWlnaHRcbiAgICApO1xuXG4gICAgdmFyIHJnYlZhbHVlcyA9IHV0aWxzLmhleDJyZ2IoY29sb3IpO1xuICAgIHZhciByID0gcmdiVmFsdWVzWzBdLCBnID0gcmdiVmFsdWVzWzFdLCBiID0gcmdiVmFsdWVzWzJdO1xuXG4gICAgdmFyIHBpeGVsRGF0YSA9IGNvbnRleHQuZ2V0SW1hZ2VEYXRhKDAsIDAsIGNyb3Aud2lkdGgsIGNyb3AuaGVpZ2h0KTtcblxuICAgIHZhciBwaXhlbHMgPSBwaXhlbERhdGEuZGF0YTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcGl4ZWxzLmxlbmd0aDsgaSArPSA0KSB7XG4gICAgICAgIHBpeGVsc1tpKzBdICo9IHI7XG4gICAgICAgIHBpeGVsc1tpKzFdICo9IGc7XG4gICAgICAgIHBpeGVsc1tpKzJdICo9IGI7XG4gICAgfVxuXG4gICAgY29udGV4dC5wdXRJbWFnZURhdGEocGl4ZWxEYXRhLCAwLCAwKTtcbn07XG5cbi8qKlxuICogUm91bmRzIHRoZSBzcGVjaWZpZWQgY29sb3IgYWNjb3JkaW5nIHRvIHRoZSBDYW52YXNUaW50ZXIuY2FjaGVTdGVwc1BlckNvbG9yQ2hhbm5lbC5cbiAqXG4gKiBAcGFyYW0gY29sb3Ige251bWJlcn0gdGhlIGNvbG9yIHRvIHJvdW5kLCBzaG91bGQgYmUgYSBoZXggY29sb3JcbiAqL1xuQ2FudmFzVGludGVyLnJvdW5kQ29sb3IgPSBmdW5jdGlvbiAoY29sb3IpIHtcbiAgICB2YXIgc3RlcCA9IENhbnZhc1RpbnRlci5jYWNoZVN0ZXBzUGVyQ29sb3JDaGFubmVsO1xuXG4gICAgdmFyIHJnYlZhbHVlcyA9IHV0aWxzLmhleDJyZ2IoY29sb3IpO1xuXG4gICAgcmdiVmFsdWVzWzBdID0gTWF0aC5taW4oMjU1LCAocmdiVmFsdWVzWzBdIC8gc3RlcCkgKiBzdGVwKTtcbiAgICByZ2JWYWx1ZXNbMV0gPSBNYXRoLm1pbigyNTUsIChyZ2JWYWx1ZXNbMV0gLyBzdGVwKSAqIHN0ZXApO1xuICAgIHJnYlZhbHVlc1syXSA9IE1hdGgubWluKDI1NSwgKHJnYlZhbHVlc1syXSAvIHN0ZXApICogc3RlcCk7XG5cbiAgICByZXR1cm4gdXRpbHMucmdiMmhleChyZ2JWYWx1ZXMpO1xufTtcblxuLyoqXG4gKiBOdW1iZXIgb2Ygc3RlcHMgd2hpY2ggd2lsbCBiZSB1c2VkIGFzIGEgY2FwIHdoZW4gcm91bmRpbmcgY29sb3JzLlxuICpcbiAqIEBtZW1iZXJcbiAqL1xuQ2FudmFzVGludGVyLmNhY2hlU3RlcHNQZXJDb2xvckNoYW5uZWwgPSA4O1xuXG4vKipcbiAqIFRpbnQgY2FjaGUgYm9vbGVhbiBmbGFnLlxuICpcbiAqIEBtZW1iZXJcbiAqL1xuQ2FudmFzVGludGVyLmNvbnZlcnRUaW50VG9JbWFnZSA9IGZhbHNlO1xuXG4vKipcbiAqIFdoZXRoZXIgb3Igbm90IHRoZSBDYW52YXMgQmxlbmRNb2RlcyBhcmUgc3VwcG9ydGVkLCBjb25zZXF1ZW50bHkgdGhlIGFiaWxpdHkgdG8gdGludCB1c2luZyB0aGUgbXVsdGlwbHkgbWV0aG9kLlxuICpcbiAqIEBtZW1iZXJcbiAqL1xuQ2FudmFzVGludGVyLmNhblVzZU11bHRpcGx5ID0gdXRpbHMuY2FuVXNlTmV3Q2FudmFzQmxlbmRNb2RlcygpO1xuXG4vKipcbiAqIFRoZSB0aW50aW5nIG1ldGhvZCB0aGF0IHdpbGwgYmUgdXNlZC5cbiAqXG4gKi9cbkNhbnZhc1RpbnRlci50aW50TWV0aG9kID0gQ2FudmFzVGludGVyLmNhblVzZU11bHRpcGx5ID8gQ2FudmFzVGludGVyLnRpbnRXaXRoTXVsdGlwbHkgOiAgQ2FudmFzVGludGVyLnRpbnRXaXRoUGVyUGl4ZWw7XG4iLCJ2YXIgV2ViR0xTcHJpdGVCYXRjaCA9IHJlcXVpcmUoJy4vdXRpbHMvV2ViR0xTcHJpdGVCYXRjaCcpLFxuICAgIFdlYkdMRmFzdFNwcml0ZUJhdGNoID0gcmVxdWlyZSgnLi91dGlscy9XZWJHTEZhc3RTcHJpdGVCYXRjaCcpLFxuICAgIFdlYkdMU2hhZGVyTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvV2ViR0xTaGFkZXJNYW5hZ2VyJyksXG4gICAgV2ViR0xNYXNrTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvV2ViR0xNYXNrTWFuYWdlcicpLFxuICAgIFdlYkdMRmlsdGVyTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvV2ViR0xGaWx0ZXJNYW5hZ2VyJyksXG4gICAgV2ViR0xTdGVuY2lsTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvV2ViR0xTdGVuY2lsTWFuYWdlcicpLFxuICAgIFdlYkdMQmxlbmRNb2RlTWFuYWdlciA9IHJlcXVpcmUoJy4vbWFuYWdlcnMvV2ViR0xCbGVuZE1vZGVNYW5hZ2VyJyksXG4gICAgbWF0aCA9IHJlcXVpcmUoJy4uLy4uL21hdGgnKSxcbiAgICB1dGlscyA9IHJlcXVpcmUoJy4uLy4uL3V0aWxzJyksXG4gICAgQ09OU1QgPSByZXF1aXJlKCcuLi8uLi9jb25zdCcpO1xuXG4vKipcbiAqIFRoZSBXZWJHTFJlbmRlcmVyIGRyYXdzIHRoZSBzY2VuZSBhbmQgYWxsIGl0cyBjb250ZW50IG9udG8gYSB3ZWJHTCBlbmFibGVkIGNhbnZhcy4gVGhpcyByZW5kZXJlclxuICogc2hvdWxkIGJlIHVzZWQgZm9yIGJyb3dzZXJzIHRoYXQgc3VwcG9ydCB3ZWJHTC4gVGhpcyBSZW5kZXIgd29ya3MgYnkgYXV0b21hdGljYWxseSBtYW5hZ2luZyB3ZWJHTEJhdGNocy5cbiAqIFNvIG5vIG5lZWQgZm9yIFNwcml0ZSBCYXRjaGVzIG9yIFNwcml0ZSBDbG91ZHMuXG4gKiBEb24ndCBmb3JnZXQgdG8gYWRkIHRoZSB2aWV3IHRvIHlvdXIgRE9NIG9yIHlvdSB3aWxsIG5vdCBzZWUgYW55dGhpbmcgOilcbiAqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIFt3aWR0aD0wXSB7bnVtYmVyfSB0aGUgd2lkdGggb2YgdGhlIGNhbnZhcyB2aWV3XG4gKiBAcGFyYW0gW2hlaWdodD0wXSB7bnVtYmVyfSB0aGUgaGVpZ2h0IG9mIHRoZSBjYW52YXMgdmlld1xuICogQHBhcmFtIFtvcHRpb25zXSB7b2JqZWN0fSBUaGUgb3B0aW9uYWwgcmVuZGVyZXIgcGFyYW1ldGVyc1xuICogQHBhcmFtIFtvcHRpb25zLnZpZXddIHtIVE1MQ2FudmFzRWxlbWVudH0gdGhlIGNhbnZhcyB0byB1c2UgYXMgYSB2aWV3LCBvcHRpb25hbFxuICogQHBhcmFtIFtvcHRpb25zLnRyYW5zcGFyZW50PWZhbHNlXSB7Ym9vbGVhbn0gSWYgdGhlIHJlbmRlciB2aWV3IGlzIHRyYW5zcGFyZW50LCBkZWZhdWx0IGZhbHNlXG4gKiBAcGFyYW0gW29wdGlvbnMuYXV0b1Jlc2l6ZT1mYWxzZV0ge2Jvb2xlYW59IElmIHRoZSByZW5kZXIgdmlldyBpcyBhdXRvbWF0aWNhbGx5IHJlc2l6ZWQsIGRlZmF1bHQgZmFsc2VcbiAqIEBwYXJhbSBbb3B0aW9ucy5hbnRpYWxpYXM9ZmFsc2VdIHtib29sZWFufSBzZXRzIGFudGlhbGlhcyAob25seSBhcHBsaWNhYmxlIGluIGNocm9tZSBhdCB0aGUgbW9tZW50KVxuICogQHBhcmFtIFtvcHRpb25zLnByZXNlcnZlRHJhd2luZ0J1ZmZlcj1mYWxzZV0ge2Jvb2xlYW59IGVuYWJsZXMgZHJhd2luZyBidWZmZXIgcHJlc2VydmF0aW9uLCBlbmFibGUgdGhpcyBpZiB5b3UgbmVlZCB0byBjYWxsIHRvRGF0YVVybCBvbiB0aGUgd2ViZ2wgY29udGV4dFxuICogQHBhcmFtIFtvcHRpb25zLnJlc29sdXRpb249MV0ge251bWJlcn0gdGhlIHJlc29sdXRpb24gb2YgdGhlIHJlbmRlcmVyIHJldGluYSB3b3VsZCBiZSAyXG4gKi9cbmZ1bmN0aW9uIFdlYkdMUmVuZGVyZXIod2lkdGgsIGhlaWdodCwgb3B0aW9ucykge1xuICAgIHV0aWxzLnNheUhlbGxvKCd3ZWJHTCcpO1xuXG4gICAgaWYgKG9wdGlvbnMpIHtcbiAgICAgICAgZm9yICh2YXIgaSBpbiBDT05TVC5kZWZhdWx0UmVuZGVyT3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBvcHRpb25zW2ldID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgIG9wdGlvbnNbaV0gPSBDT05TVC5kZWZhdWx0UmVuZGVyT3B0aW9uc1tpXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgb3B0aW9ucyA9IENPTlNULmRlZmF1bHRSZW5kZXJPcHRpb25zO1xuICAgIH1cblxuICAgIHRoaXMudXVpZCA9IHV0aWxzLnV1aWQoKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLnR5cGUgPSBDT05TVC5XRUJHTF9SRU5ERVJFUjtcblxuICAgIC8qKlxuICAgICAqIFRoZSByZXNvbHV0aW9uIG9mIHRoZSByZW5kZXJlclxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDFcbiAgICAgKi9cbiAgICB0aGlzLnJlc29sdXRpb24gPSBvcHRpb25zLnJlc29sdXRpb247XG5cbiAgICAvLyBkbyBhIGNhdGNoLi4gb25seSAxIHdlYkdMIHJlbmRlcmVyLi5cblxuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgdGhlIHJlbmRlciB2aWV3IGlzIHRyYW5zcGFyZW50XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMudHJhbnNwYXJlbnQgPSBvcHRpb25zLnRyYW5zcGFyZW50O1xuXG4gICAgLyoqXG4gICAgICogVGhlIGJhY2tncm91bmQgY29sb3IgYXMgYSBudW1iZXIuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl9iYWNrZ3JvdW5kQ29sb3IgPSAweDAwMDAwMDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBiYWNrZ3JvdW5kIGNvbG9yIGFzIGFuIFtSLCBHLCBCXSBhcnJheS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcltdfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fYmFja2dyb3VuZENvbG9yUmdiID0gWzAsIDAsIDBdO1xuXG4gICAgdGhpcy5iYWNrZ3JvdW5kQ29sb3IgPSBvcHRpb25zLmJhY2tncm91bmRDb2xvciB8fCB0aGlzLl9iYWNrZ3JvdW5kQ29sb3I7IC8vIHJ1biBiZyBjb2xvciBzZXR0ZXJcblxuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgdGhlIHJlbmRlciB2aWV3IHNob3VsZCBiZSByZXNpemVkIGF1dG9tYXRpY2FsbHlcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5hdXRvUmVzaXplID0gb3B0aW9ucy5hdXRvUmVzaXplIHx8IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHZhbHVlIG9mIHRoZSBwcmVzZXJ2ZURyYXdpbmdCdWZmZXIgZmxhZyBhZmZlY3RzIHdoZXRoZXIgb3Igbm90IHRoZSBjb250ZW50cyBvZiB0aGUgc3RlbmNpbCBidWZmZXIgaXMgcmV0YWluZWQgYWZ0ZXIgcmVuZGVyaW5nLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLnByZXNlcnZlRHJhd2luZ0J1ZmZlciA9IG9wdGlvbnMucHJlc2VydmVEcmF3aW5nQnVmZmVyO1xuXG4gICAgLyoqXG4gICAgICogVGhpcyBzZXRzIGlmIHRoZSBXZWJHTFJlbmRlcmVyIHdpbGwgY2xlYXIgdGhlIGNvbnRleHQgdGV4dHVyZSBvciBub3QgYmVmb3JlIHRoZSBuZXcgcmVuZGVyIHBhc3MuIElmIHRydWU6XG4gICAgICogSWYgdGhlIHJlbmRlcmVyIGlzIE5PVCB0cmFuc3BhcmVudCwgUGl4aSB3aWxsIGNsZWFyIHRvIGFscGhhICgwLCAwLCAwLCAwKS5cbiAgICAgKiBJZiB0aGUgcmVuZGVyZXIgaXMgdHJhbnNwYXJlbnQsIFBpeGkgd2lsbCBjbGVhciB0byB0aGUgdGFyZ2V0IFN0YWdlJ3MgYmFja2dyb3VuZCBjb2xvci5cbiAgICAgKiBEaXNhYmxlIHRoaXMgYnkgc2V0dGluZyB0aGlzIHRvIGZhbHNlLiBGb3IgZXhhbXBsZTogaWYgeW91ciBnYW1lIGhhcyBhIGNhbnZhcyBmaWxsaW5nIGJhY2tncm91bmQgaW1hZ2UsIHlvdSBvZnRlbiBkb24ndCBuZWVkIHRoaXMgc2V0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAZGVmYXVsdFxuICAgICAqL1xuICAgIHRoaXMuY2xlYXJCZWZvcmVSZW5kZXIgPSBvcHRpb25zLmNsZWFyQmVmb3JlUmVuZGVyO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHdpZHRoIG9mIHRoZSBjYW52YXMgdmlld1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDgwMFxuICAgICAqL1xuICAgIHRoaXMud2lkdGggPSB3aWR0aCB8fCA4MDA7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgaGVpZ2h0IG9mIHRoZSBjYW52YXMgdmlld1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IDYwMFxuICAgICAqL1xuICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0IHx8IDYwMDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBjYW52YXMgZWxlbWVudCB0aGF0IGV2ZXJ5dGhpbmcgaXMgZHJhd24gdG9cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0hUTUxDYW52YXNFbGVtZW50fVxuICAgICAqL1xuICAgIHRoaXMudmlldyA9IG9wdGlvbnMudmlldyB8fCBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnY2FudmFzJyApO1xuXG4gICAgLy8gZGVhbCB3aXRoIGxvc2luZyBjb250ZXh0Li5cblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge0Z1bmN0aW9ufVxuICAgICAqL1xuICAgIHRoaXMuY29udGV4dExvc3RCb3VuZCA9IHRoaXMuaGFuZGxlQ29udGV4dExvc3QuYmluZCh0aGlzKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge0Z1bmN0aW9ufVxuICAgICAqL1xuICAgIHRoaXMuY29udGV4dFJlc3RvcmVkQm91bmQgPSB0aGlzLmhhbmRsZUNvbnRleHRSZXN0b3JlZC5iaW5kKHRoaXMpO1xuXG4gICAgdGhpcy52aWV3LmFkZEV2ZW50TGlzdGVuZXIoJ3dlYmdsY29udGV4dGxvc3QnLCB0aGlzLmNvbnRleHRMb3N0Qm91bmQsIGZhbHNlKTtcbiAgICB0aGlzLnZpZXcuYWRkRXZlbnRMaXN0ZW5lcignd2ViZ2xjb250ZXh0cmVzdG9yZWQnLCB0aGlzLmNvbnRleHRSZXN0b3JlZEJvdW5kLCBmYWxzZSk7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtvYmplY3R9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl9jb250ZXh0T3B0aW9ucyA9IHtcbiAgICAgICAgYWxwaGE6IHRoaXMudHJhbnNwYXJlbnQsXG4gICAgICAgIGFudGlhbGlhczogb3B0aW9ucy5hbnRpYWxpYXMsIC8vIFNQRUVEIFVQPz9cbiAgICAgICAgcHJlbXVsdGlwbGllZEFscGhhOnRoaXMudHJhbnNwYXJlbnQgJiYgdGhpcy50cmFuc3BhcmVudCAhPT0gJ25vdE11bHRpcGxpZWQnLFxuICAgICAgICBzdGVuY2lsOnRydWUsXG4gICAgICAgIHByZXNlcnZlRHJhd2luZ0J1ZmZlcjogb3B0aW9ucy5wcmVzZXJ2ZURyYXdpbmdCdWZmZXJcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICovXG4gICAgdGhpcy5wcm9qZWN0aW9uID0gbmV3IG1hdGguUG9pbnQoKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge1BvaW50fVxuICAgICAqL1xuICAgIHRoaXMub2Zmc2V0ID0gbmV3IG1hdGguUG9pbnQoMCwgMCk7XG5cbiAgICAvKipcbiAgICAgKiBDb3VudGVyIGZvciB0aGUgbnVtYmVyIG9mIGRyYXdzIG1hZGUgZWFjaCBmcmFtZVxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMuZHJhd0NvdW50ID0gMDtcblxuICAgIC8vIHRpbWUgdG8gY3JlYXRlIHRoZSByZW5kZXIgbWFuYWdlcnMhIGVhY2ggb25lIGZvY3VzZXMgb24gbWFuYWdpbmcgYSBzdGF0ZSBpbiB3ZWJHTFxuXG4gICAgLyoqXG4gICAgICogRGVhbHMgd2l0aCBtYW5hZ2luZyB0aGUgc2hhZGVyIHByb2dyYW1zIGFuZCB0aGVpciBhdHRyaWJzXG4gICAgICogQG1lbWJlciB7V2ViR0xTaGFkZXJNYW5hZ2VyfVxuICAgICAqL1xuICAgIHRoaXMuc2hhZGVyTWFuYWdlciA9IG5ldyBXZWJHTFNoYWRlck1hbmFnZXIodGhpcyk7XG5cbiAgICAvKipcbiAgICAgKiBNYW5hZ2VzIHRoZSByZW5kZXJpbmcgb2Ygc3ByaXRlc1xuICAgICAqIEBtZW1iZXIge1dlYkdMU3ByaXRlQmF0Y2h9XG4gICAgICovXG4gICAgdGhpcy5zcHJpdGVCYXRjaCA9IG5ldyBXZWJHTFNwcml0ZUJhdGNoKHRoaXMpO1xuXG4gICAgLyoqXG4gICAgICogTWFuYWdlcyB0aGUgcmVuZGVyaW5nIG9mIHNwcml0ZXNcbiAgICAgKiBAbWVtYmVyIHtXZWJHTEZhc3RTcHJpdGVCYXRjaH1cbiAgICAgKi9cbiAgICB0aGlzLmZhc3RTcHJpdGVCYXRjaCA9IG5ldyBXZWJHTEZhc3RTcHJpdGVCYXRjaCh0aGlzKTtcblxuICAgIC8qKlxuICAgICAqIE1hbmFnZXMgdGhlIG1hc2tzIHVzaW5nIHRoZSBzdGVuY2lsIGJ1ZmZlclxuICAgICAqIEBtZW1iZXIge1dlYkdMTWFza01hbmFnZXJ9XG4gICAgICovXG4gICAgdGhpcy5tYXNrTWFuYWdlciA9IG5ldyBXZWJHTE1hc2tNYW5hZ2VyKHRoaXMpO1xuXG4gICAgLyoqXG4gICAgICogTWFuYWdlcyB0aGUgZmlsdGVyc1xuICAgICAqIEBtZW1iZXIge1dlYkdMRmlsdGVyTWFuYWdlcn1cbiAgICAgKi9cbiAgICB0aGlzLmZpbHRlck1hbmFnZXIgPSBuZXcgV2ViR0xGaWx0ZXJNYW5hZ2VyKHRoaXMpO1xuXG4gICAgLyoqXG4gICAgICogTWFuYWdlcyB0aGUgc3RlbmNpbCBidWZmZXJcbiAgICAgKiBAbWVtYmVyIHtXZWJHTFN0ZW5jaWxNYW5hZ2VyfVxuICAgICAqL1xuICAgIHRoaXMuc3RlbmNpbE1hbmFnZXIgPSBuZXcgV2ViR0xTdGVuY2lsTWFuYWdlcih0aGlzKTtcblxuICAgIC8qKlxuICAgICAqIE1hbmFnZXMgdGhlIGJsZW5kTW9kZXNcbiAgICAgKiBAbWVtYmVyIHtXZWJHTEJsZW5kTW9kZU1hbmFnZXJ9XG4gICAgICovXG4gICAgdGhpcy5ibGVuZE1vZGVNYW5hZ2VyID0gbmV3IFdlYkdMQmxlbmRNb2RlTWFuYWdlcih0aGlzKTtcblxuICAgIHRoaXMuYmxlbmRNb2RlcyA9IG51bGw7XG5cbiAgICB0aGlzLl9ib3VuZFVwZGF0ZVRleHR1cmUgPSB0aGlzLnVwZGF0ZVRleHR1cmUuYmluZCh0aGlzKTtcbiAgICB0aGlzLl9ib3VuZERlc3Ryb3lUZXh0dXJlID0gdGhpcy5kZXN0cm95VGV4dHVyZS5iaW5kKHRoaXMpO1xuXG4gICAgLy8gdGltZSBpbml0IHRoZSBjb250ZXh0Li5cbiAgICB0aGlzLl9pbml0Q29udGV4dCgpO1xuXG4gICAgLy8gbWFwIHNvbWUgd2ViR0wgYmxlbmQgbW9kZXMuLlxuICAgIHRoaXMuX21hcEJsZW5kTW9kZXMoKTtcbn1cblxuLy8gY29uc3RydWN0b3JcbldlYkdMUmVuZGVyZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gV2ViR0xSZW5kZXJlcjtcbm1vZHVsZS5leHBvcnRzID0gV2ViR0xSZW5kZXJlcjtcblxudXRpbHMuZXZlbnRUYXJnZXQubWl4aW4oV2ViR0xSZW5kZXJlci5wcm90b3R5cGUpO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhXZWJHTFJlbmRlcmVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSBiYWNrZ3JvdW5kIGNvbG9yIHRvIGZpbGwgaWYgbm90IHRyYW5zcGFyZW50XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIFdlYkdMUmVuZGVyZXIjXG4gICAgICovXG4gICAgYmFja2dyb3VuZENvbG9yOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2JhY2tncm91bmRDb2xvcjtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsKSB7XG4gICAgICAgICAgICB0aGlzLl9iYWNrZ3JvdW5kQ29sb3IgPSB2YWw7XG4gICAgICAgICAgICB1dGlscy5oZXgycmdiKHZhbCwgdGhpcy5fYmFja2dyb3VuZENvbG9yUmdiKTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG4vKipcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5XZWJHTFJlbmRlcmVyLnByb3RvdHlwZS5faW5pdENvbnRleHQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGdsID0gdGhpcy52aWV3LmdldENvbnRleHQoJ3dlYmdsJywgdGhpcy5fY29udGV4dE9wdGlvbnMpIHx8IHRoaXMudmlldy5nZXRDb250ZXh0KCdleHBlcmltZW50YWwtd2ViZ2wnLCB0aGlzLl9jb250ZXh0T3B0aW9ucyk7XG4gICAgdGhpcy5nbCA9IGdsO1xuXG4gICAgaWYgKCFnbCkge1xuICAgICAgICAvLyBmYWlsLCBub3QgYWJsZSB0byBnZXQgYSBjb250ZXh0XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVGhpcyBicm93c2VyIGRvZXMgbm90IHN1cHBvcnQgd2ViR0wuIFRyeSB1c2luZyB0aGUgY2FudmFzIHJlbmRlcmVyJyk7XG4gICAgfVxuXG4gICAgdGhpcy5nbENvbnRleHRJZCA9IFdlYkdMUmVuZGVyZXIuZ2xDb250ZXh0SWQrKztcbiAgICBnbC5pZCA9IHRoaXMuZ2xDb250ZXh0SWQ7XG4gICAgZ2wucmVuZGVyZXIgPSB0aGlzO1xuXG4gICAgLy8gc2V0IHVwIHRoZSBkZWZhdWx0IHBpeGkgc2V0dGluZ3MuLlxuICAgIGdsLmRpc2FibGUoZ2wuREVQVEhfVEVTVCk7XG4gICAgZ2wuZGlzYWJsZShnbC5DVUxMX0ZBQ0UpO1xuICAgIGdsLmVuYWJsZShnbC5CTEVORCk7XG5cbiAgICB0aGlzLmVtaXQoJ2NvbnRleHQnLCBnbCk7XG5cbiAgICAvLyBub3cgcmVzaXplIGFuZCB3ZSBhcmUgZ29vZCB0byBnbyFcbiAgICB0aGlzLnJlc2l6ZSh0aGlzLndpZHRoLCB0aGlzLmhlaWdodCk7XG59O1xuXG4vKipcbiAqIFJlbmRlcnMgdGhlIG9iamVjdCB0byBpdHMgd2ViR0wgdmlld1xuICpcbiAqIEBwYXJhbSBvYmplY3Qge0Rpc3BsYXlPYmplY3R9IHRoZSBvYmplY3QgdG8gYmUgcmVuZGVyZWRcbiAqL1xuV2ViR0xSZW5kZXJlci5wcm90b3R5cGUucmVuZGVyID0gZnVuY3Rpb24gKG9iamVjdCkge1xuICAgIC8vIG5vIHBvaW50IHJlbmRlcmluZyBpZiBvdXIgY29udGV4dCBoYXMgYmVlbiBibG93biB1cCFcbiAgICBpZiAodGhpcy5nbC5pc0NvbnRleHRMb3N0KCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIHVwZGF0ZSB0aGUgc2NlbmUgZ3JhcGhcbiAgICBvYmplY3QudXBkYXRlVHJhbnNmb3JtKCk7XG5cbiAgICB2YXIgZ2wgPSB0aGlzLmdsO1xuXG4gICAgLy8gLS0gRG9lcyB0aGlzIG5lZWQgdG8gYmUgc2V0IGV2ZXJ5IGZyYW1lPyAtLSAvL1xuICAgIGdsLnZpZXdwb3J0KDAsIDAsIHRoaXMud2lkdGgsIHRoaXMuaGVpZ2h0KTtcblxuICAgIC8vIG1ha2Ugc3VyZSB3ZSBhcmUgYm91bmQgdG8gdGhlIG1haW4gZnJhbWUgYnVmZmVyXG4gICAgZ2wuYmluZEZyYW1lYnVmZmVyKGdsLkZSQU1FQlVGRkVSLCBudWxsKTtcblxuICAgIGlmICh0aGlzLmNsZWFyQmVmb3JlUmVuZGVyKSB7XG4gICAgICAgIGlmICh0aGlzLnRyYW5zcGFyZW50KSB7XG4gICAgICAgICAgICBnbC5jbGVhckNvbG9yKDAsIDAsIDAsIDApO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZ2wuY2xlYXJDb2xvcih0aGlzLl9iYWNrZ3JvdW5kQ29sb3JSZ2JbMF0sIHRoaXMuX2JhY2tncm91bmRDb2xvclJnYlsxXSwgdGhpcy5fYmFja2dyb3VuZENvbG9yUmdiWzJdLCAxKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGdsLmNsZWFyKGdsLkNPTE9SX0JVRkZFUl9CSVQpO1xuICAgIH1cblxuICAgIHRoaXMucmVuZGVyRGlzcGxheU9iamVjdChvYmplY3QsIHRoaXMucHJvamVjdGlvbik7XG59O1xuXG4vKipcbiAqIFJlbmRlcnMgYSBEaXNwbGF5IE9iamVjdC5cbiAqXG4gKiBAcGFyYW0gZGlzcGxheU9iamVjdCB7RGlzcGxheU9iamVjdH0gVGhlIERpc3BsYXlPYmplY3QgdG8gcmVuZGVyXG4gKiBAcGFyYW0gcHJvamVjdGlvbiB7UG9pbnR9IFRoZSBwcm9qZWN0aW9uXG4gKiBAcGFyYW0gYnVmZmVyIHtBcnJheX0gYSBzdGFuZGFyZCBXZWJHTCBidWZmZXJcbiAqL1xuV2ViR0xSZW5kZXJlci5wcm90b3R5cGUucmVuZGVyRGlzcGxheU9iamVjdCA9IGZ1bmN0aW9uIChkaXNwbGF5T2JqZWN0LCBwcm9qZWN0aW9uLCBidWZmZXIpIHtcbiAgICB0aGlzLmJsZW5kTW9kZU1hbmFnZXIuc2V0QmxlbmRNb2RlKENPTlNULmJsZW5kTW9kZXMuTk9STUFMKTtcblxuICAgIC8vIHJlc2V0IHRoZSByZW5kZXIgc2Vzc2lvbiBkYXRhLi5cbiAgICB0aGlzLmRyYXdDb3VudCA9IDA7XG5cbiAgICAvLyBtYWtlIHN1cmUgdG8gZmxpcCB0aGUgWSBpZiB1c2luZyBhIHJlbmRlciB0ZXh0dXJlLi5cbiAgICB0aGlzLmZsaXBZID0gYnVmZmVyID8gLTEgOiAxO1xuXG4gICAgLy8gc2V0IHRoZSBkZWZhdWx0IHByb2plY3Rpb25cbiAgICB0aGlzLnByb2plY3Rpb24gPSBwcm9qZWN0aW9uO1xuXG4gICAgLy9zZXQgdGhlIGRlZmF1bHQgb2Zmc2V0XG4gICAgdGhpcy5vZmZzZXQgPSB0aGlzLm9mZnNldDtcblxuICAgIC8vIHN0YXJ0IHRoZSBzcHJpdGUgYmF0Y2hcbiAgICB0aGlzLnNwcml0ZUJhdGNoLmJlZ2luKCk7XG5cbiAgICAvLyBzdGFydCB0aGUgZmlsdGVyIG1hbmFnZXJcbiAgICB0aGlzLmZpbHRlck1hbmFnZXIuYmVnaW4oYnVmZmVyKTtcblxuICAgIC8vIHJlbmRlciB0aGUgc2NlbmUhXG4gICAgZGlzcGxheU9iamVjdC5yZW5kZXJXZWJHTCh0aGlzKTtcblxuICAgIC8vIGZpbmlzaCB0aGUgc3ByaXRlIGJhdGNoXG4gICAgdGhpcy5zcHJpdGVCYXRjaC5lbmQoKTtcbn07XG5cbi8qKlxuICogUmVzaXplcyB0aGUgd2ViR0wgdmlldyB0byB0aGUgc3BlY2lmaWVkIHdpZHRoIGFuZCBoZWlnaHQuXG4gKlxuICogQHBhcmFtIHdpZHRoIHtudW1iZXJ9IHRoZSBuZXcgd2lkdGggb2YgdGhlIHdlYkdMIHZpZXdcbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gdGhlIG5ldyBoZWlnaHQgb2YgdGhlIHdlYkdMIHZpZXdcbiAqL1xuV2ViR0xSZW5kZXJlci5wcm90b3R5cGUucmVzaXplID0gZnVuY3Rpb24gKHdpZHRoLCBoZWlnaHQpIHtcbiAgICB0aGlzLndpZHRoID0gd2lkdGggKiB0aGlzLnJlc29sdXRpb247XG4gICAgdGhpcy5oZWlnaHQgPSBoZWlnaHQgKiB0aGlzLnJlc29sdXRpb247XG5cbiAgICB0aGlzLnZpZXcud2lkdGggPSB0aGlzLndpZHRoO1xuICAgIHRoaXMudmlldy5oZWlnaHQgPSB0aGlzLmhlaWdodDtcblxuICAgIGlmICh0aGlzLmF1dG9SZXNpemUpIHtcbiAgICAgICAgdGhpcy52aWV3LnN0eWxlLndpZHRoID0gdGhpcy53aWR0aCAvIHRoaXMucmVzb2x1dGlvbiArICdweCc7XG4gICAgICAgIHRoaXMudmlldy5zdHlsZS5oZWlnaHQgPSB0aGlzLmhlaWdodCAvIHRoaXMucmVzb2x1dGlvbiArICdweCc7XG4gICAgfVxuXG4gICAgdGhpcy5nbC52aWV3cG9ydCgwLCAwLCB0aGlzLndpZHRoLCB0aGlzLmhlaWdodCk7XG5cbiAgICB0aGlzLnByb2plY3Rpb24ueCA9ICB0aGlzLndpZHRoIC8gMiAvIHRoaXMucmVzb2x1dGlvbjtcbiAgICB0aGlzLnByb2plY3Rpb24ueSA9ICAtdGhpcy5oZWlnaHQgLyAyIC8gdGhpcy5yZXNvbHV0aW9uO1xufTtcblxuLyoqXG4gKiBVcGRhdGVzIGFuZC9vciBDcmVhdGVzIGEgV2ViR0wgdGV4dHVyZSBmb3IgdGhlIHJlbmRlcmVyJ3MgY29udGV4dC5cbiAqXG4gKiBAcGFyYW0gdGV4dHVyZSB7QmFzZVRleHR1cmV8VGV4dHVyZX0gdGhlIHRleHR1cmUgdG8gdXBkYXRlXG4gKi9cbldlYkdMUmVuZGVyZXIucHJvdG90eXBlLnVwZGF0ZVRleHR1cmUgPSBmdW5jdGlvbiAodGV4dHVyZSkge1xuICAgIHRleHR1cmUgPSB0ZXh0dXJlLmJhc2VUZXh0dXJlIHx8IHRleHR1cmU7XG5cbiAgICBpZiAoIXRleHR1cmUuaGFzTG9hZGVkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgZ2wgPSB0aGlzLmdsO1xuXG4gICAgaWYgKCF0ZXh0dXJlLl9nbFRleHR1cmVzW2dsLmlkXSkge1xuICAgICAgICB0ZXh0dXJlLl9nbFRleHR1cmVzW2dsLmlkXSA9IGdsLmNyZWF0ZVRleHR1cmUoKTtcbiAgICAgICAgdGV4dHVyZS5vbigndXBkYXRlJywgdGhpcy5fYm91bmRVcGRhdGVUZXh0dXJlKTtcbiAgICAgICAgdGV4dHVyZS5vbignZGlzcG9zZScsIHRoaXMuX2JvdW5kRGVzdHJveVRleHR1cmUpO1xuICAgIH1cblxuICAgIGdsLmJpbmRUZXh0dXJlKGdsLlRFWFRVUkVfMkQsIHRleHR1cmUuX2dsVGV4dHVyZXNbZ2wuaWRdKTtcblxuICAgIGdsLnBpeGVsU3RvcmVpKGdsLlVOUEFDS19QUkVNVUxUSVBMWV9BTFBIQV9XRUJHTCwgdGV4dHVyZS5wcmVtdWx0aXBsaWVkQWxwaGEpO1xuICAgIGdsLnRleEltYWdlMkQoZ2wuVEVYVFVSRV8yRCwgMCwgZ2wuUkdCQSwgZ2wuUkdCQSwgZ2wuVU5TSUdORURfQllURSwgdGV4dHVyZS5zb3VyY2UpO1xuXG4gICAgZ2wudGV4UGFyYW1ldGVyaShnbC5URVhUVVJFXzJELCBnbC5URVhUVVJFX01BR19GSUxURVIsIHRleHR1cmUuc2NhbGVNb2RlID09PSBDT05TVC5zY2FsZU1vZGVzLkxJTkVBUiA/IGdsLkxJTkVBUiA6IGdsLk5FQVJFU1QpO1xuXG5cbiAgICBpZiAodGV4dHVyZS5taXBtYXAgJiYgdXRpbHMuaXNQb3dlck9mVHdvKHRleHR1cmUud2lkdGgsIHRleHR1cmUuaGVpZ2h0KSkge1xuICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfTUlOX0ZJTFRFUiwgdGV4dHVyZS5zY2FsZU1vZGUgPT09IENPTlNULnNjYWxlTW9kZXMuTElORUFSID8gZ2wuTElORUFSX01JUE1BUF9MSU5FQVIgOiBnbC5ORUFSRVNUX01JUE1BUF9ORUFSRVNUKTtcbiAgICAgICAgZ2wuZ2VuZXJhdGVNaXBtYXAoZ2wuVEVYVFVSRV8yRCk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfTUlOX0ZJTFRFUiwgdGV4dHVyZS5zY2FsZU1vZGUgPT09IENPTlNULnNjYWxlTW9kZXMuTElORUFSID8gZ2wuTElORUFSIDogZ2wuTkVBUkVTVCk7XG4gICAgfVxuXG4gICAgaWYgKCF0ZXh0dXJlLl9wb3dlck9mMikge1xuICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfV1JBUF9TLCBnbC5DTEFNUF9UT19FREdFKTtcbiAgICAgICAgZ2wudGV4UGFyYW1ldGVyaShnbC5URVhUVVJFXzJELCBnbC5URVhUVVJFX1dSQVBfVCwgZ2wuQ0xBTVBfVE9fRURHRSk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfV1JBUF9TLCBnbC5SRVBFQVQpO1xuICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfV1JBUF9ULCBnbC5SRVBFQVQpO1xuICAgIH1cblxuICAgIHJldHVybiAgdGV4dHVyZS5fZ2xUZXh0dXJlc1tnbC5pZF07XG59O1xuXG5XZWJHTFJlbmRlcmVyLnByb3RvdHlwZS5kZXN0cm95VGV4dHVyZSA9IGZ1bmN0aW9uICh0ZXh0dXJlKSB7XG4gICAgdGV4dHVyZSA9IHRleHR1cmUuYmFzZVRleHR1cmUgfHwgdGV4dHVyZTtcblxuICAgIGlmICghdGV4dHVyZS5oYXNMb2FkZWQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0ZXh0dXJlLl9nbFRleHR1cmVzW3RoaXMuZ2wuaWRdKSB7XG4gICAgICAgIHRoaXMuZ2wuZGVsZXRlVGV4dHVyZSh0ZXh0dXJlLl9nbFRleHR1cmVzW3RoaXMuZ2wuaWRdKTtcbiAgICB9XG59O1xuXG4vKipcbiAqIEhhbmRsZXMgYSBsb3N0IHdlYmdsIGNvbnRleHRcbiAqXG4gKiBAcGFyYW0gZXZlbnQge0V2ZW50fVxuICogQHByaXZhdGVcbiAqL1xuV2ViR0xSZW5kZXJlci5wcm90b3R5cGUuaGFuZGxlQ29udGV4dExvc3QgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xufTtcblxuLyoqXG4gKiBIYW5kbGVzIGEgcmVzdG9yZWQgd2ViZ2wgY29udGV4dFxuICpcbiAqIEBwYXJhbSBldmVudCB7RXZlbnR9XG4gKiBAcHJpdmF0ZVxuICovXG5XZWJHTFJlbmRlcmVyLnByb3RvdHlwZS5oYW5kbGVDb250ZXh0UmVzdG9yZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5faW5pdENvbnRleHQoKTtcblxuICAgIC8vIGVtcHR5IGFsbCB0aGUgb2wgZ2wgdGV4dHVyZXMgYXMgdGhleSBhcmUgdXNlbGVzcyBub3dcbiAgICBmb3IgKHZhciBrZXkgaW4gdXRpbHMuVGV4dHVyZUNhY2hlKSB7XG4gICAgICAgIHZhciB0ZXh0dXJlID0gdXRpbHMuVGV4dHVyZUNhY2hlW2tleV0uYmFzZVRleHR1cmU7XG4gICAgICAgIHRleHR1cmUuX2dsVGV4dHVyZXMgPSBbXTtcbiAgICB9XG59O1xuXG4vKipcbiAqIFJlbW92ZXMgZXZlcnl0aGluZyBmcm9tIHRoZSByZW5kZXJlciAoZXZlbnQgbGlzdGVuZXJzLCBzcHJpdGViYXRjaCwgZXRjLi4uKVxuICpcbiAqIEBwYXJhbSBbcmVtb3ZlVmlldz1mYWxzZV0ge2Jvb2xlYW59IFJlbW92ZXMgdGhlIENhbnZhcyBlbGVtZW50IGZyb20gdGhlIERPTS5cbiAqL1xuV2ViR0xSZW5kZXJlci5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uIChyZW1vdmVWaWV3KSB7XG4gICAgaWYgKHJlbW92ZVZpZXcgJiYgdGhpcy52aWV3LnBhcmVudCkge1xuICAgICAgICB0aGlzLnZpZXcucGFyZW50LnJlbW92ZUNoaWxkKHRoaXMudmlldyk7XG4gICAgfVxuXG4gICAgLy8gcmVtb3ZlIGxpc3RlbmVyc1xuICAgIHRoaXMudmlldy5yZW1vdmVFdmVudExpc3RlbmVyKCd3ZWJnbGNvbnRleHRsb3N0JywgdGhpcy5jb250ZXh0TG9zdEJvdW5kKTtcbiAgICB0aGlzLnZpZXcucmVtb3ZlRXZlbnRMaXN0ZW5lcignd2ViZ2xjb250ZXh0cmVzdG9yZWQnLCB0aGlzLmNvbnRleHRSZXN0b3JlZEJvdW5kKTtcblxuICAgIC8vIHRpbWUgdG8gY3JlYXRlIHRoZSByZW5kZXIgbWFuYWdlcnMhIGVhY2ggb25lIGZvY3VzZXMgb24gbWFuYWdpbmUgYSBzdGF0ZSBpbiB3ZWJHTFxuICAgIHRoaXMuc2hhZGVyTWFuYWdlci5kZXN0cm95KCk7XG4gICAgdGhpcy5zcHJpdGVCYXRjaC5kZXN0cm95KCk7XG4gICAgdGhpcy5tYXNrTWFuYWdlci5kZXN0cm95KCk7XG4gICAgdGhpcy5maWx0ZXJNYW5hZ2VyLmRlc3Ryb3koKTtcblxuXG4gICAgLy8gdGhpcy51dWlkID0gdXRpbHMudXVpZCgpO1xuICAgIC8vIHRoaXMudHlwZSA9IENPTlNULldFQkdMX1JFTkRFUkVSO1xuXG4gICAgLy8gdGhpcy5yZXNvbHV0aW9uID0gb3B0aW9ucy5yZXNvbHV0aW9uO1xuICAgIC8vIHRoaXMudHJhbnNwYXJlbnQgPSBvcHRpb25zLnRyYW5zcGFyZW50O1xuXG4gICAgdGhpcy5fYmFja2dyb3VuZENvbG9yID0gMHgwMDAwMDA7XG4gICAgdGhpcy5fYmFja2dyb3VuZENvbG9yUmdiID0gbnVsbDtcblxuICAgIC8vIHRoaXMuYmFja2dyb3VuZENvbG9yID0gbnVsbDtcbiAgICAvLyB0aGlzLmF1dG9SZXNpemUgPSBvcHRpb25zLmF1dG9SZXNpemUgfHwgZmFsc2U7XG4gICAgLy8gdGhpcy5wcmVzZXJ2ZURyYXdpbmdCdWZmZXIgPSBvcHRpb25zLnByZXNlcnZlRHJhd2luZ0J1ZmZlcjtcbiAgICAvLyB0aGlzLmNsZWFyQmVmb3JlUmVuZGVyID0gb3B0aW9ucy5jbGVhckJlZm9yZVJlbmRlcjtcbiAgICAvLyB0aGlzLndpZHRoID0gd2lkdGggfHwgODAwO1xuICAgIC8vIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0IHx8IDYwMDtcblxuICAgIHRoaXMudmlldyA9IG51bGw7XG5cbiAgICB0aGlzLmNvbnRleHRMb3N0Qm91bmQgPSBudWxsO1xuICAgIHRoaXMuY29udGV4dFJlc3RvcmVkQm91bmQgPSBudWxsO1xuXG4gICAgdGhpcy5fY29udGV4dE9wdGlvbnMgPSBudWxsO1xuXG4gICAgdGhpcy5wcm9qZWN0aW9uID0gbnVsbDtcbiAgICB0aGlzLm9mZnNldCA9IG51bGw7XG4gICAgdGhpcy5kcmF3Q291bnQgPSAwO1xuXG4gICAgdGhpcy5zaGFkZXJNYW5hZ2VyID0gbnVsbDtcbiAgICB0aGlzLnNwcml0ZUJhdGNoID0gbnVsbDtcbiAgICB0aGlzLm1hc2tNYW5hZ2VyID0gbnVsbDtcbiAgICB0aGlzLmZpbHRlck1hbmFnZXIgPSBudWxsO1xuICAgIHRoaXMuc3RlbmNpbE1hbmFnZXIgPSBudWxsO1xuICAgIHRoaXMuYmxlbmRNb2RlTWFuYWdlciA9IG51bGw7XG5cbiAgICB0aGlzLmJsZW5kTW9kZXMgPSBudWxsO1xuXG4gICAgdGhpcy5nbCA9IG51bGw7XG4gICAgdGhpcy5ibGVuZE1vZGVzID0gbnVsbDtcbn07XG5cbi8qKlxuICogTWFwcyBQaXhpIGJsZW5kIG1vZGVzIHRvIFdlYkdMIGJsZW5kIG1vZGVzLlxuICpcbiAqIEBwcml2YXRlXG4gKi9cbldlYkdMUmVuZGVyZXIucHJvdG90eXBlLl9tYXBCbGVuZE1vZGVzID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBnbCA9IHRoaXMuZ2w7XG5cbiAgICBpZiAoIXRoaXMuYmxlbmRNb2Rlcykge1xuICAgICAgICB0aGlzLmJsZW5kTW9kZXMgPSB7fTtcblxuICAgICAgICB0aGlzLmJsZW5kTW9kZXNbQ09OU1QuYmxlbmRNb2Rlcy5OT1JNQUxdICAgICAgICA9IFtnbC5PTkUsICAgICAgIGdsLk9ORV9NSU5VU19TUkNfQUxQSEFdO1xuICAgICAgICB0aGlzLmJsZW5kTW9kZXNbQ09OU1QuYmxlbmRNb2Rlcy5BRERdICAgICAgICAgICA9IFtnbC5TUkNfQUxQSEEsIGdsLkRTVF9BTFBIQV07XG4gICAgICAgIHRoaXMuYmxlbmRNb2Rlc1tDT05TVC5ibGVuZE1vZGVzLk1VTFRJUExZXSAgICAgID0gW2dsLkRTVF9DT0xPUiwgZ2wuT05FX01JTlVTX1NSQ19BTFBIQV07XG4gICAgICAgIHRoaXMuYmxlbmRNb2Rlc1tDT05TVC5ibGVuZE1vZGVzLlNDUkVFTl0gICAgICAgID0gW2dsLlNSQ19BTFBIQSwgZ2wuT05FXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuT1ZFUkxBWV0gICAgICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuREFSS0VOXSAgICAgICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTElHSFRFTl0gICAgICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JfRE9ER0VdICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JfQlVSTl0gICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuSEFSRF9MSUdIVF0gICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuU09GVF9MSUdIVF0gICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuRElGRkVSRU5DRV0gICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuRVhDTFVTSU9OXSAgICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuSFVFXSAgICAgICAgICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuU0FUVVJBVElPTl0gICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuQ09MT1JdICAgICAgICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICAgICAgdGhpcy5ibGVuZE1vZGVzW0NPTlNULmJsZW5kTW9kZXMuTFVNSU5PU0lUWV0gICAgPSBbZ2wuT05FLCAgICAgICBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBXTtcbiAgICB9XG59O1xuXG5XZWJHTFJlbmRlcmVyLmdsQ29udGV4dElkID0gMDtcbiIsInZhciBXZWJHTE1hbmFnZXIgPSByZXF1aXJlKCcuL1dlYkdMTWFuYWdlcicpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9IFRoZSByZW5kZXJlciB0aGlzIG1hbmFnZXIgd29ya3MgZm9yLlxuICovXG5mdW5jdGlvbiBXZWJHTEJsZW5kTW9kZU1hbmFnZXIocmVuZGVyZXIpIHtcbiAgICBXZWJHTE1hbmFnZXIuY2FsbCh0aGlzLCByZW5kZXJlcik7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5jdXJyZW50QmxlbmRNb2RlID0gOTk5OTk7XG59XG5cbldlYkdMQmxlbmRNb2RlTWFuYWdlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKFdlYkdMTWFuYWdlci5wcm90b3R5cGUpO1xuV2ViR0xCbGVuZE1vZGVNYW5hZ2VyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFdlYkdMQmxlbmRNb2RlTWFuYWdlcjtcbm1vZHVsZS5leHBvcnRzID0gV2ViR0xCbGVuZE1vZGVNYW5hZ2VyO1xuXG4vKipcbiAqIFNldHMtdXAgdGhlIGdpdmVuIGJsZW5kTW9kZSBmcm9tIFdlYkdMJ3MgcG9pbnQgb2Ygdmlldy5cbiAqXG4gKiBAcGFyYW0gYmxlbmRNb2RlIHtudW1iZXJ9IHRoZSBibGVuZE1vZGUsIHNob3VsZCBiZSBhIFBpeGkgY29uc3QsIHN1Y2ggYXMgQmxlbmRNb2Rlcy5BRERcbiAqL1xuV2ViR0xCbGVuZE1vZGVNYW5hZ2VyLnByb3RvdHlwZS5zZXRCbGVuZE1vZGUgPSBmdW5jdGlvbiAoYmxlbmRNb2RlKSB7XG4gICAgaWYgKHRoaXMuY3VycmVudEJsZW5kTW9kZSA9PT0gYmxlbmRNb2RlKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICB0aGlzLmN1cnJlbnRCbGVuZE1vZGUgPSBibGVuZE1vZGU7XG5cbiAgICB2YXIgbW9kZSA9IHRoaXMucmVuZGVyZXIuYmxlbmRNb2Rlc1t0aGlzLmN1cnJlbnRCbGVuZE1vZGVdO1xuICAgIHRoaXMucmVuZGVyZXIuZ2wuYmxlbmRGdW5jKG1vZGVbMF0sIG1vZGVbMV0pO1xuXG4gICAgcmV0dXJuIHRydWU7XG59O1xuIiwidmFyIFdlYkdMTWFuYWdlciA9IHJlcXVpcmUoJy4vV2ViR0xNYW5hZ2VyJyksXG4gICAgRmlsdGVyVGV4dHVyZSA9IHJlcXVpcmUoJy4uL3V0aWxzL0ZpbHRlclRleHR1cmUnKSxcbiAgICBTaGFkZXIgPSByZXF1aXJlKCcuLi9zaGFkZXJzL1NoYWRlcicpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9IFRoZSByZW5kZXJlciB0aGlzIG1hbmFnZXIgd29ya3MgZm9yLlxuICovXG5mdW5jdGlvbiBXZWJHTEZpbHRlck1hbmFnZXIocmVuZGVyZXIpIHtcbiAgICBXZWJHTE1hbmFnZXIuY2FsbCh0aGlzLCByZW5kZXJlcik7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHthbnlbXX1cbiAgICAgKi9cbiAgICB0aGlzLmZpbHRlclN0YWNrID0gW107XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHthbnlbXV19XG4gICAgICovXG4gICAgdGhpcy50ZXh0dXJlUG9vbCA9IFtdO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMub2Zmc2V0WCA9IDA7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5vZmZzZXRZID0gMDtcblxuICAgIC8vIGxpc3RlbiBmb3IgY29udGV4dCBhbmQgdXBkYXRlIG5lY2Vzc2FyeSBidWZmZXJzXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHRoaXMucmVuZGVyZXIub24oJ2NvbnRleHQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHNlbGYudGV4dHVyZVBvb2wubGVuZ3RoID0gMDtcbiAgICAgICAgc2VsZi5pbml0U2hhZGVyQnVmZmVycygpO1xuICAgIH0pO1xufVxuXG5XZWJHTEZpbHRlck1hbmFnZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShXZWJHTE1hbmFnZXIucHJvdG90eXBlKTtcbldlYkdMRmlsdGVyTWFuYWdlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBXZWJHTEZpbHRlck1hbmFnZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFdlYkdMRmlsdGVyTWFuYWdlcjtcblxuLyoqXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9XG4gKiBAcGFyYW0gYnVmZmVyIHtBcnJheUJ1ZmZlcn1cbiAqL1xuV2ViR0xGaWx0ZXJNYW5hZ2VyLnByb3RvdHlwZS5iZWdpbiA9IGZ1bmN0aW9uIChidWZmZXIpIHtcbiAgICB0aGlzLmRlZmF1bHRTaGFkZXIgPSB0aGlzLnJlbmRlcmVyLnNoYWRlck1hbmFnZXIuZGVmYXVsdFNoYWRlcjtcblxuICAgIHRoaXMud2lkdGggPSB0aGlzLnJlbmRlcmVyLnByb2plY3Rpb24ueCAqIDI7XG4gICAgdGhpcy5oZWlnaHQgPSAtdGhpcy5yZW5kZXJlci5wcm9qZWN0aW9uLnkgKiAyO1xuXG4gICAgdGhpcy5idWZmZXIgPSBidWZmZXI7XG59O1xuXG4vKipcbiAqIEFwcGxpZXMgdGhlIGZpbHRlciBhbmQgYWRkcyBpdCB0byB0aGUgY3VycmVudCBmaWx0ZXIgc3RhY2suXG4gKlxuICogQHBhcmFtIGZpbHRlckJsb2NrIHtvYmplY3R9IHRoZSBmaWx0ZXIgdGhhdCB3aWxsIGJlIHB1c2hlZCB0byB0aGUgY3VycmVudCBmaWx0ZXIgc3RhY2tcbiAqL1xuV2ViR0xGaWx0ZXJNYW5hZ2VyLnByb3RvdHlwZS5wdXNoRmlsdGVyID0gZnVuY3Rpb24gKGZpbHRlckJsb2NrKSB7XG4gICAgdmFyIGdsID0gdGhpcy5yZW5kZXJlci5nbDtcblxuICAgIHZhciBwcm9qZWN0aW9uID0gdGhpcy5yZW5kZXJlci5wcm9qZWN0aW9uO1xuICAgIHZhciBvZmZzZXQgPSB0aGlzLnJlbmRlcmVyLm9mZnNldDtcblxuICAgIGZpbHRlckJsb2NrLl9maWx0ZXJBcmVhID0gZmlsdGVyQmxvY2sudGFyZ2V0LmZpbHRlckFyZWEgfHwgZmlsdGVyQmxvY2sudGFyZ2V0LmdldEJvdW5kcygpO1xuXG4gICAgLy8gZmlsdGVyIHByb2dyYW1cbiAgICAvLyBPUFRJTUlTQVRJT04gLSB0aGUgZmlyc3QgZmlsdGVyIGlzIGZyZWUgaWYgaXRzIGEgc2ltcGxlIGNvbG9yIGNoYW5nZT9cbiAgICB0aGlzLmZpbHRlclN0YWNrLnB1c2goZmlsdGVyQmxvY2spO1xuXG4gICAgdmFyIGZpbHRlciA9IGZpbHRlckJsb2NrLmZpbHRlclBhc3Nlc1swXTtcblxuICAgIHRoaXMub2Zmc2V0WCArPSBmaWx0ZXJCbG9jay5fZmlsdGVyQXJlYS54O1xuICAgIHRoaXMub2Zmc2V0WSArPSBmaWx0ZXJCbG9jay5fZmlsdGVyQXJlYS55O1xuXG4gICAgdmFyIHRleHR1cmUgPSB0aGlzLnRleHR1cmVQb29sLnBvcCgpO1xuICAgIGlmICghdGV4dHVyZSkge1xuICAgICAgICB0ZXh0dXJlID0gbmV3IEZpbHRlclRleHR1cmUodGhpcy5yZW5kZXJlci5nbCwgdGhpcy53aWR0aCwgdGhpcy5oZWlnaHQpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdGV4dHVyZS5yZXNpemUodGhpcy53aWR0aCwgdGhpcy5oZWlnaHQpO1xuICAgIH1cblxuICAgIGdsLmJpbmRUZXh0dXJlKGdsLlRFWFRVUkVfMkQsICB0ZXh0dXJlLnRleHR1cmUpO1xuXG4gICAgdmFyIGZpbHRlckFyZWEgPSBmaWx0ZXJCbG9jay5fZmlsdGVyQXJlYTsvLyBmaWx0ZXJCbG9jay50YXJnZXQuZ2V0Qm91bmRzKCk7Ly8vZmlsdGVyQmxvY2sudGFyZ2V0LmZpbHRlckFyZWE7XG5cbiAgICB2YXIgcGFkZGluZyA9IGZpbHRlci5wYWRkaW5nO1xuICAgIGZpbHRlckFyZWEueCAtPSBwYWRkaW5nO1xuICAgIGZpbHRlckFyZWEueSAtPSBwYWRkaW5nO1xuICAgIGZpbHRlckFyZWEud2lkdGggKz0gcGFkZGluZyAqIDI7XG4gICAgZmlsdGVyQXJlYS5oZWlnaHQgKz0gcGFkZGluZyAqIDI7XG5cbiAgICB2YXIgbG9jYWxYID0gZmlsdGVyQXJlYS54LFxuICAgICAgICBsb2NhbFkgPSBmaWx0ZXJBcmVhLnk7XG5cbiAgICBpZiAoZmlsdGVyQXJlYS54IDwgMCkge1xuICAgICAgICBmaWx0ZXJBcmVhLndpZHRoICs9IGZpbHRlckFyZWEueDtcbiAgICAgICAgZmlsdGVyQXJlYS54ID0gMDtcbiAgICB9XG5cbiAgICBpZiAoZmlsdGVyQXJlYS55IDwgMCkge1xuICAgICAgICBmaWx0ZXJBcmVhLmhlaWdodCArPSBmaWx0ZXJBcmVhLnk7XG4gICAgICAgIGZpbHRlckFyZWEueSA9IDA7XG4gICAgfVxuXG4gICAgaWYgKGxvY2FsWCArIGZpbHRlckFyZWEud2lkdGggPiB0aGlzLndpZHRoKSB7XG4gICAgICAgIGZpbHRlckFyZWEud2lkdGggPSB0aGlzLndpZHRoIC0gbG9jYWxYO1xuICAgIH1cblxuICAgIGlmIChsb2NhbFkgKyBmaWx0ZXJBcmVhLmhlaWdodCA+IHRoaXMuaGVpZ2h0KSB7XG4gICAgICAgIGZpbHRlckFyZWEuaGVpZ2h0ID0gdGhpcy5oZWlnaHQgLSBsb2NhbFk7XG4gICAgfVxuXG4gICAgaWYgKGZpbHRlckFyZWEud2lkdGggPCAwKSB7XG4gICAgICAgIGZpbHRlckFyZWEud2lkdGggPSAwO1xuICAgIH1cblxuICAgIGlmIChmaWx0ZXJBcmVhLmhlaWdodCA8IDApIHtcbiAgICAgICAgZmlsdGVyQXJlYS5oZWlnaHQgPSAwO1xuICAgIH1cblxuICAgIC8vZ2wudGV4SW1hZ2UyRChnbC5URVhUVVJFXzJELCAwLCBnbC5SR0JBLCAgZmlsdGVyQXJlYS53aWR0aCwgZmlsdGVyQXJlYS5oZWlnaHQsIDAsIGdsLlJHQkEsIGdsLlVOU0lHTkVEX0JZVEUsIG51bGwpO1xuICAgIGdsLmJpbmRGcmFtZWJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgdGV4dHVyZS5mcmFtZUJ1ZmZlcik7XG5cbiAgICAvLyBzZXQgdmlldyBwb3J0XG4gICAgZ2wudmlld3BvcnQoMCwgMCwgZmlsdGVyQXJlYS53aWR0aCwgZmlsdGVyQXJlYS5oZWlnaHQpO1xuXG4gICAgcHJvamVjdGlvbi54ID0gZmlsdGVyQXJlYS53aWR0aC8yO1xuICAgIHByb2plY3Rpb24ueSA9IC1maWx0ZXJBcmVhLmhlaWdodC8yO1xuXG4gICAgb2Zmc2V0LnggPSAtZmlsdGVyQXJlYS54O1xuICAgIG9mZnNldC55ID0gLWZpbHRlckFyZWEueTtcblxuICAgIC8vIHVwZGF0ZSBwcm9qZWN0aW9uXG4gICAgLy8gbm93IHJlc3RvcmUgdGhlIHJlZ3VsYXIgc2hhZGVyLi5cbiAgICAvLyB0aGlzLnJlbmRlcmVyLnNoYWRlck1hbmFnZXIuc2V0U2hhZGVyKHRoaXMuZGVmYXVsdFNoYWRlcik7XG4gICAgLy9nbC51bmlmb3JtMmYodGhpcy5kZWZhdWx0U2hhZGVyLnByb2plY3Rpb25WZWN0b3IsIGZpbHRlckFyZWEud2lkdGgvMiwgLWZpbHRlckFyZWEuaGVpZ2h0LzIpO1xuICAgIC8vZ2wudW5pZm9ybTJmKHRoaXMuZGVmYXVsdFNoYWRlci5vZmZzZXRWZWN0b3IsIC1maWx0ZXJBcmVhLngsIC1maWx0ZXJBcmVhLnkpO1xuXG4gICAgZ2wuY29sb3JNYXNrKHRydWUsIHRydWUsIHRydWUsIHRydWUpO1xuICAgIGdsLmNsZWFyQ29sb3IoMCwwLDAsIDApO1xuICAgIGdsLmNsZWFyKGdsLkNPTE9SX0JVRkZFUl9CSVQpO1xuXG4gICAgZmlsdGVyQmxvY2suX2dsRmlsdGVyVGV4dHVyZSA9IHRleHR1cmU7XG5cbn07XG5cbi8qKlxuICogUmVtb3ZlcyB0aGUgbGFzdCBmaWx0ZXIgZnJvbSB0aGUgZmlsdGVyIHN0YWNrIGFuZCBkb2Vzbid0IHJldHVybiBpdC5cbiAqXG4gKi9cbldlYkdMRmlsdGVyTWFuYWdlci5wcm90b3R5cGUucG9wRmlsdGVyID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBnbCA9IHRoaXMucmVuZGVyZXIuZ2w7XG5cbiAgICB2YXIgZmlsdGVyQmxvY2sgPSB0aGlzLmZpbHRlclN0YWNrLnBvcCgpO1xuICAgIHZhciBmaWx0ZXJBcmVhID0gZmlsdGVyQmxvY2suX2ZpbHRlckFyZWE7XG4gICAgdmFyIHRleHR1cmUgPSBmaWx0ZXJCbG9jay5fZ2xGaWx0ZXJUZXh0dXJlO1xuICAgIHZhciBwcm9qZWN0aW9uID0gdGhpcy5yZW5kZXJlci5wcm9qZWN0aW9uO1xuICAgIHZhciBvZmZzZXQgPSB0aGlzLnJlbmRlcmVyLm9mZnNldDtcblxuICAgIGlmIChmaWx0ZXJCbG9jay5maWx0ZXJQYXNzZXMubGVuZ3RoID4gMSkge1xuICAgICAgICBnbC52aWV3cG9ydCgwLCAwLCBmaWx0ZXJBcmVhLndpZHRoLCBmaWx0ZXJBcmVhLmhlaWdodCk7XG5cbiAgICAgICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMudmVydGV4QnVmZmVyKTtcblxuICAgICAgICB0aGlzLnZlcnRleEFycmF5WzBdID0gMDtcbiAgICAgICAgdGhpcy52ZXJ0ZXhBcnJheVsxXSA9IGZpbHRlckFyZWEuaGVpZ2h0O1xuXG4gICAgICAgIHRoaXMudmVydGV4QXJyYXlbMl0gPSBmaWx0ZXJBcmVhLndpZHRoO1xuICAgICAgICB0aGlzLnZlcnRleEFycmF5WzNdID0gZmlsdGVyQXJlYS5oZWlnaHQ7XG5cbiAgICAgICAgdGhpcy52ZXJ0ZXhBcnJheVs0XSA9IDA7XG4gICAgICAgIHRoaXMudmVydGV4QXJyYXlbNV0gPSAwO1xuXG4gICAgICAgIHRoaXMudmVydGV4QXJyYXlbNl0gPSBmaWx0ZXJBcmVhLndpZHRoO1xuICAgICAgICB0aGlzLnZlcnRleEFycmF5WzddID0gMDtcblxuICAgICAgICBnbC5idWZmZXJTdWJEYXRhKGdsLkFSUkFZX0JVRkZFUiwgMCwgdGhpcy52ZXJ0ZXhBcnJheSk7XG5cbiAgICAgICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMudXZCdWZmZXIpO1xuICAgICAgICAvLyBub3cgc2V0IHRoZSB1dnMuLlxuICAgICAgICB0aGlzLnV2QXJyYXlbMl0gPSBmaWx0ZXJBcmVhLndpZHRoL3RoaXMud2lkdGg7XG4gICAgICAgIHRoaXMudXZBcnJheVs1XSA9IGZpbHRlckFyZWEuaGVpZ2h0L3RoaXMuaGVpZ2h0O1xuICAgICAgICB0aGlzLnV2QXJyYXlbNl0gPSBmaWx0ZXJBcmVhLndpZHRoL3RoaXMud2lkdGg7XG4gICAgICAgIHRoaXMudXZBcnJheVs3XSA9IGZpbHRlckFyZWEuaGVpZ2h0L3RoaXMuaGVpZ2h0O1xuXG4gICAgICAgIGdsLmJ1ZmZlclN1YkRhdGEoZ2wuQVJSQVlfQlVGRkVSLCAwLCB0aGlzLnV2QXJyYXkpO1xuXG4gICAgICAgIHZhciBpbnB1dFRleHR1cmUgPSB0ZXh0dXJlO1xuICAgICAgICB2YXIgb3V0cHV0VGV4dHVyZSA9IHRoaXMudGV4dHVyZVBvb2wucG9wKCk7XG4gICAgICAgIGlmICghb3V0cHV0VGV4dHVyZSkge1xuICAgICAgICAgICAgb3V0cHV0VGV4dHVyZSA9IG5ldyBGaWx0ZXJUZXh0dXJlKHRoaXMucmVuZGVyZXIuZ2wsIHRoaXMud2lkdGgsIHRoaXMuaGVpZ2h0KTtcbiAgICAgICAgfVxuICAgICAgICBvdXRwdXRUZXh0dXJlLnJlc2l6ZSh0aGlzLndpZHRoLCB0aGlzLmhlaWdodCk7XG5cbiAgICAgICAgLy8gbmVlZCB0byBjbGVhciB0aGlzIEZCTyBhcyBpdCBtYXkgaGF2ZSBzb21lIGxlZnQgb3ZlciBlbGVtZW50cyBmcm9tIGEgcHJldmlvdXMgZmlsdGVyLlxuICAgICAgICBnbC5iaW5kRnJhbWVidWZmZXIoZ2wuRlJBTUVCVUZGRVIsIG91dHB1dFRleHR1cmUuZnJhbWVCdWZmZXIgKTtcbiAgICAgICAgZ2wuY2xlYXIoZ2wuQ09MT1JfQlVGRkVSX0JJVCk7XG5cbiAgICAgICAgZ2wuZGlzYWJsZShnbC5CTEVORCk7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBmaWx0ZXJCbG9jay5maWx0ZXJQYXNzZXMubGVuZ3RoLTE7IGkrKykge1xuICAgICAgICAgICAgdmFyIGZpbHRlclBhc3MgPSBmaWx0ZXJCbG9jay5maWx0ZXJQYXNzZXNbaV07XG5cbiAgICAgICAgICAgIGdsLmJpbmRGcmFtZWJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgb3V0cHV0VGV4dHVyZS5mcmFtZUJ1ZmZlciApO1xuXG4gICAgICAgICAgICAvLyBzZXQgdGV4dHVyZVxuICAgICAgICAgICAgZ2wuYWN0aXZlVGV4dHVyZShnbC5URVhUVVJFMCk7XG4gICAgICAgICAgICBnbC5iaW5kVGV4dHVyZShnbC5URVhUVVJFXzJELCBpbnB1dFRleHR1cmUudGV4dHVyZSk7XG5cbiAgICAgICAgICAgIC8vIGRyYXcgdGV4dHVyZS4uXG4gICAgICAgICAgICAvL2ZpbHRlclBhc3MuYXBwbHlGaWx0ZXJQYXNzKGZpbHRlckFyZWEud2lkdGgsIGZpbHRlckFyZWEuaGVpZ2h0KTtcbiAgICAgICAgICAgIHRoaXMuYXBwbHlGaWx0ZXJQYXNzKGZpbHRlclBhc3MsIGZpbHRlckFyZWEsIGZpbHRlckFyZWEud2lkdGgsIGZpbHRlckFyZWEuaGVpZ2h0KTtcblxuICAgICAgICAgICAgLy8gc3dhcCB0aGUgdGV4dHVyZXMuLlxuICAgICAgICAgICAgdmFyIHRlbXAgPSBpbnB1dFRleHR1cmU7XG4gICAgICAgICAgICBpbnB1dFRleHR1cmUgPSBvdXRwdXRUZXh0dXJlO1xuICAgICAgICAgICAgb3V0cHV0VGV4dHVyZSA9IHRlbXA7XG4gICAgICAgIH1cblxuICAgICAgICBnbC5lbmFibGUoZ2wuQkxFTkQpO1xuXG4gICAgICAgIHRleHR1cmUgPSBpbnB1dFRleHR1cmU7XG4gICAgICAgIHRoaXMudGV4dHVyZVBvb2wucHVzaChvdXRwdXRUZXh0dXJlKTtcbiAgICB9XG5cbiAgICB2YXIgZmlsdGVyID0gZmlsdGVyQmxvY2suZmlsdGVyUGFzc2VzW2ZpbHRlckJsb2NrLmZpbHRlclBhc3Nlcy5sZW5ndGgtMV07XG5cbiAgICB0aGlzLm9mZnNldFggLT0gZmlsdGVyQXJlYS54O1xuICAgIHRoaXMub2Zmc2V0WSAtPSBmaWx0ZXJBcmVhLnk7XG5cbiAgICB2YXIgc2l6ZVggPSB0aGlzLndpZHRoO1xuICAgIHZhciBzaXplWSA9IHRoaXMuaGVpZ2h0O1xuXG4gICAgdmFyIG9mZnNldFggPSAwO1xuICAgIHZhciBvZmZzZXRZID0gMDtcblxuICAgIHZhciBidWZmZXIgPSB0aGlzLmJ1ZmZlcjtcblxuICAgIC8vIHRpbWUgdG8gcmVuZGVyIHRoZSBmaWx0ZXJzIHRleHR1cmUgdG8gdGhlIHByZXZpb3VzIHNjZW5lXG4gICAgaWYgKHRoaXMuZmlsdGVyU3RhY2subGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGdsLmNvbG9yTWFzayh0cnVlLCB0cnVlLCB0cnVlLCB0cnVlKTsvL3RoaXMudHJhbnNwYXJlbnQpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdmFyIGN1cnJlbnRGaWx0ZXIgPSB0aGlzLmZpbHRlclN0YWNrW3RoaXMuZmlsdGVyU3RhY2subGVuZ3RoLTFdO1xuICAgICAgICBmaWx0ZXJBcmVhID0gY3VycmVudEZpbHRlci5fZmlsdGVyQXJlYTtcblxuICAgICAgICBzaXplWCA9IGZpbHRlckFyZWEud2lkdGg7XG4gICAgICAgIHNpemVZID0gZmlsdGVyQXJlYS5oZWlnaHQ7XG5cbiAgICAgICAgb2Zmc2V0WCA9IGZpbHRlckFyZWEueDtcbiAgICAgICAgb2Zmc2V0WSA9IGZpbHRlckFyZWEueTtcblxuICAgICAgICBidWZmZXIgPSAgY3VycmVudEZpbHRlci5fZ2xGaWx0ZXJUZXh0dXJlLmZyYW1lQnVmZmVyO1xuICAgIH1cblxuICAgIC8vIFRPRE8gbmVlZCB0byByZW1vdmUgdGhlc2UgZ2xvYmFsIGVsZW1lbnRzLi5cbiAgICBwcm9qZWN0aW9uLnggPSBzaXplWC8yO1xuICAgIHByb2plY3Rpb24ueSA9IC1zaXplWS8yO1xuXG4gICAgb2Zmc2V0LnggPSBvZmZzZXRYO1xuICAgIG9mZnNldC55ID0gb2Zmc2V0WTtcblxuICAgIGZpbHRlckFyZWEgPSBmaWx0ZXJCbG9jay5fZmlsdGVyQXJlYTtcblxuICAgIHZhciB4ID0gZmlsdGVyQXJlYS54LW9mZnNldFg7XG4gICAgdmFyIHkgPSBmaWx0ZXJBcmVhLnktb2Zmc2V0WTtcblxuICAgIC8vIHVwZGF0ZSB0aGUgYnVmZmVycy4uXG4gICAgLy8gbWFrZSBzdXJlIHRvIGZsaXAgdGhlIHkhXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMudmVydGV4QnVmZmVyKTtcblxuICAgIHRoaXMudmVydGV4QXJyYXlbMF0gPSB4O1xuICAgIHRoaXMudmVydGV4QXJyYXlbMV0gPSB5ICsgZmlsdGVyQXJlYS5oZWlnaHQ7XG5cbiAgICB0aGlzLnZlcnRleEFycmF5WzJdID0geCArIGZpbHRlckFyZWEud2lkdGg7XG4gICAgdGhpcy52ZXJ0ZXhBcnJheVszXSA9IHkgKyBmaWx0ZXJBcmVhLmhlaWdodDtcblxuICAgIHRoaXMudmVydGV4QXJyYXlbNF0gPSB4O1xuICAgIHRoaXMudmVydGV4QXJyYXlbNV0gPSB5O1xuXG4gICAgdGhpcy52ZXJ0ZXhBcnJheVs2XSA9IHggKyBmaWx0ZXJBcmVhLndpZHRoO1xuICAgIHRoaXMudmVydGV4QXJyYXlbN10gPSB5O1xuXG4gICAgZ2wuYnVmZmVyU3ViRGF0YShnbC5BUlJBWV9CVUZGRVIsIDAsIHRoaXMudmVydGV4QXJyYXkpO1xuXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMudXZCdWZmZXIpO1xuXG4gICAgdGhpcy51dkFycmF5WzJdID0gZmlsdGVyQXJlYS53aWR0aC90aGlzLndpZHRoO1xuICAgIHRoaXMudXZBcnJheVs1XSA9IGZpbHRlckFyZWEuaGVpZ2h0L3RoaXMuaGVpZ2h0O1xuICAgIHRoaXMudXZBcnJheVs2XSA9IGZpbHRlckFyZWEud2lkdGgvdGhpcy53aWR0aDtcbiAgICB0aGlzLnV2QXJyYXlbN10gPSBmaWx0ZXJBcmVhLmhlaWdodC90aGlzLmhlaWdodDtcblxuICAgIGdsLmJ1ZmZlclN1YkRhdGEoZ2wuQVJSQVlfQlVGRkVSLCAwLCB0aGlzLnV2QXJyYXkpO1xuXG4gICAgZ2wudmlld3BvcnQoMCwgMCwgc2l6ZVgsIHNpemVZKTtcblxuICAgIC8vIGJpbmQgdGhlIGJ1ZmZlclxuICAgIGdsLmJpbmRGcmFtZWJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgYnVmZmVyICk7XG5cbiAgICAvLyBzZXQgdGhlIGJsZW5kIG1vZGUhXG4gICAgLy9nbC5ibGVuZEZ1bmMoZ2wuT05FLCBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBKVxuXG4gICAgLy8gc2V0IHRleHR1cmVcbiAgICBnbC5hY3RpdmVUZXh0dXJlKGdsLlRFWFRVUkUwKTtcbiAgICBnbC5iaW5kVGV4dHVyZShnbC5URVhUVVJFXzJELCB0ZXh0dXJlLnRleHR1cmUpO1xuXG4gICAgLy8gYXBwbHkhXG4gICAgdGhpcy5hcHBseUZpbHRlclBhc3MoZmlsdGVyLCBmaWx0ZXJBcmVhLCBzaXplWCwgc2l6ZVkpO1xuXG4gICAgLy8gbm93IHJlc3RvcmUgdGhlIHJlZ3VsYXIgc2hhZGVyLi4gc2hvdWxkIGhhcHBlbiBhdXRvbWF0aWNhbGx5IG5vdy4uXG4gICAgLy8gdGhpcy5yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLnNldFNoYWRlcih0aGlzLmRlZmF1bHRTaGFkZXIpO1xuICAgIC8vIGdsLnVuaWZvcm0yZih0aGlzLmRlZmF1bHRTaGFkZXIucHJvamVjdGlvblZlY3Rvciwgc2l6ZVgvMiwgLXNpemVZLzIpO1xuICAgIC8vIGdsLnVuaWZvcm0yZih0aGlzLmRlZmF1bHRTaGFkZXIub2Zmc2V0VmVjdG9yLCAtb2Zmc2V0WCwgLW9mZnNldFkpO1xuXG4gICAgLy8gcmV0dXJuIHRoZSB0ZXh0dXJlIHRvIHRoZSBwb29sXG4gICAgdGhpcy50ZXh0dXJlUG9vbC5wdXNoKHRleHR1cmUpO1xuICAgIGZpbHRlckJsb2NrLl9nbEZpbHRlclRleHR1cmUgPSBudWxsO1xufTtcblxuXG4vKipcbiAqIEFwcGxpZXMgdGhlIGZpbHRlciB0byB0aGUgc3BlY2lmaWVkIGFyZWEuXG4gKlxuICogQHBhcmFtIGZpbHRlciB7QWJzdHJhY3RGaWx0ZXJ9IHRoZSBmaWx0ZXIgdGhhdCBuZWVkcyB0byBiZSBhcHBsaWVkXG4gKiBAcGFyYW0gZmlsdGVyQXJlYSB7VGV4dHVyZX0gVE9ETyAtIG1pZ2h0IG5lZWQgYW4gdXBkYXRlXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gdGhlIGhvcml6b250YWwgcmFuZ2Ugb2YgdGhlIGZpbHRlclxuICogQHBhcmFtIGhlaWdodCB7bnVtYmVyfSB0aGUgdmVydGljYWwgcmFuZ2Ugb2YgdGhlIGZpbHRlclxuICovXG5XZWJHTEZpbHRlck1hbmFnZXIucHJvdG90eXBlLmFwcGx5RmlsdGVyUGFzcyA9IGZ1bmN0aW9uIChmaWx0ZXIsIGZpbHRlckFyZWEsIHdpZHRoLCBoZWlnaHQpIHtcbiAgICAvLyB1c2UgcHJvZ3JhbVxuICAgIHZhciBnbCA9IHRoaXMucmVuZGVyZXIuZ2w7XG5cbiAgICB2YXIgc2hhZGVyID0gZmlsdGVyLnNoYWRlcnNbZ2wuaWRdO1xuXG4gICAgaWYgKCFzaGFkZXIpIHtcbiAgICAgICAgc2hhZGVyID0gbmV3IFNoYWRlcihnbCk7XG5cbiAgICAgICAgc2hhZGVyLmZyYWdtZW50U3JjID0gZmlsdGVyLmZyYWdtZW50U3JjO1xuICAgICAgICBzaGFkZXIudW5pZm9ybXMgPSBmaWx0ZXIudW5pZm9ybXM7XG4gICAgICAgIHNoYWRlci5pbml0KCk7XG5cbiAgICAgICAgZmlsdGVyLnNoYWRlcnNbZ2wuaWRdID0gc2hhZGVyO1xuICAgIH1cblxuICAgIC8vIHNldCB0aGUgc2hhZGVyXG4gICAgdGhpcy5yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLnNldFNoYWRlcihzaGFkZXIpO1xuXG4vLyAgICBnbC51c2VQcm9ncmFtKHNoYWRlci5wcm9ncmFtKTtcblxuICAgIGdsLnVuaWZvcm0yZihzaGFkZXIucHJvamVjdGlvblZlY3Rvciwgd2lkdGgvMiwgLWhlaWdodC8yKTtcbiAgICBnbC51bmlmb3JtMmYoc2hhZGVyLm9mZnNldFZlY3RvciwgMCwwKTtcblxuICAgIGlmIChmaWx0ZXIudW5pZm9ybXMuZGltZW5zaW9ucykge1xuICAgICAgICBmaWx0ZXIudW5pZm9ybXMuZGltZW5zaW9ucy52YWx1ZVswXSA9IHRoaXMud2lkdGg7Ly93aWR0aDtcbiAgICAgICAgZmlsdGVyLnVuaWZvcm1zLmRpbWVuc2lvbnMudmFsdWVbMV0gPSB0aGlzLmhlaWdodDsvL2hlaWdodDtcbiAgICAgICAgZmlsdGVyLnVuaWZvcm1zLmRpbWVuc2lvbnMudmFsdWVbMl0gPSB0aGlzLnZlcnRleEFycmF5WzBdO1xuICAgICAgICBmaWx0ZXIudW5pZm9ybXMuZGltZW5zaW9ucy52YWx1ZVszXSA9IHRoaXMudmVydGV4QXJyYXlbNV07Ly9maWx0ZXJBcmVhLmhlaWdodDtcbiAgICB9XG5cbiAgICBzaGFkZXIuc3luY1VuaWZvcm1zKCk7XG5cbiAgICBnbC5iaW5kQnVmZmVyKGdsLkFSUkFZX0JVRkZFUiwgdGhpcy52ZXJ0ZXhCdWZmZXIpO1xuICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIoc2hhZGVyLmFWZXJ0ZXhQb3NpdGlvbiwgMiwgZ2wuRkxPQVQsIGZhbHNlLCAwLCAwKTtcblxuICAgIGdsLmJpbmRCdWZmZXIoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLnV2QnVmZmVyKTtcbiAgICBnbC52ZXJ0ZXhBdHRyaWJQb2ludGVyKHNoYWRlci5hVGV4dHVyZUNvb3JkLCAyLCBnbC5GTE9BVCwgZmFsc2UsIDAsIDApO1xuXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMuY29sb3JCdWZmZXIpO1xuICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIoc2hhZGVyLmFDb2xvciwgMiwgZ2wuRkxPQVQsIGZhbHNlLCAwLCAwKTtcblxuICAgIGdsLmJpbmRCdWZmZXIoZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIsIHRoaXMuaW5kZXhCdWZmZXIpO1xuXG4gICAgLy8gZHJhdyB0aGUgZmlsdGVyLi4uXG4gICAgZ2wuZHJhd0VsZW1lbnRzKGdsLlRSSUFOR0xFUywgNiwgZ2wuVU5TSUdORURfU0hPUlQsIDAgKTtcblxuICAgIHRoaXMucmVuZGVyZXIuZHJhd0NvdW50Kys7XG59O1xuXG4vKipcbiAqIEluaXRpYWxpc2VzIHRoZSBzaGFkZXIgYnVmZmVycy5cbiAqXG4gKi9cbldlYkdMRmlsdGVyTWFuYWdlci5wcm90b3R5cGUuaW5pdFNoYWRlckJ1ZmZlcnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGdsID0gdGhpcy5yZW5kZXJlci5nbDtcblxuICAgIC8vIGNyZWF0ZSBzb21lIGJ1ZmZlcnNcbiAgICB0aGlzLnZlcnRleEJ1ZmZlciA9IGdsLmNyZWF0ZUJ1ZmZlcigpO1xuICAgIHRoaXMudXZCdWZmZXIgPSBnbC5jcmVhdGVCdWZmZXIoKTtcbiAgICB0aGlzLmNvbG9yQnVmZmVyID0gZ2wuY3JlYXRlQnVmZmVyKCk7XG4gICAgdGhpcy5pbmRleEJ1ZmZlciA9IGdsLmNyZWF0ZUJ1ZmZlcigpO1xuXG4gICAgLy8gYmluZCBhbmQgdXBsb2FkIHRoZSB2ZXJ0ZXhzLi5cbiAgICAvLyBrZWVwIGEgcmVmZXJlbmNlIHRvIHRoZSB2ZXJ0ZXhGbG9hdERhdGEuLlxuICAgIHRoaXMudmVydGV4QXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KFswLjAsIDAuMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMS4wLCAwLjAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAuMCwgMS4wLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLjAsIDEuMF0pO1xuXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMudmVydGV4QnVmZmVyKTtcbiAgICBnbC5idWZmZXJEYXRhKGdsLkFSUkFZX0JVRkZFUiwgdGhpcy52ZXJ0ZXhBcnJheSwgZ2wuU1RBVElDX0RSQVcpO1xuXG4gICAgLy8gYmluZCBhbmQgdXBsb2FkIHRoZSB1diBidWZmZXJcbiAgICB0aGlzLnV2QXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KFswLjAsIDAuMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLjAsIDAuMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLjAsIDEuMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLjAsIDEuMF0pO1xuXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMudXZCdWZmZXIpO1xuICAgIGdsLmJ1ZmZlckRhdGEoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLnV2QXJyYXksIGdsLlNUQVRJQ19EUkFXKTtcblxuICAgIHRoaXMuY29sb3JBcnJheSA9IG5ldyBGbG9hdDMyQXJyYXkoWzEuMCwgMHhGRkZGRkYsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMS4wLCAweEZGRkZGRixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLjAsIDB4RkZGRkZGLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEuMCwgMHhGRkZGRkZdKTtcblxuICAgIGdsLmJpbmRCdWZmZXIoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLmNvbG9yQnVmZmVyKTtcbiAgICBnbC5idWZmZXJEYXRhKGdsLkFSUkFZX0JVRkZFUiwgdGhpcy5jb2xvckFycmF5LCBnbC5TVEFUSUNfRFJBVyk7XG5cbiAgICAvLyBiaW5kIGFuZCB1cGxvYWQgdGhlIGluZGV4XG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5FTEVNRU5UX0FSUkFZX0JVRkZFUiwgdGhpcy5pbmRleEJ1ZmZlcik7XG4gICAgZ2wuYnVmZmVyRGF0YShnbC5FTEVNRU5UX0FSUkFZX0JVRkZFUiwgbmV3IFVpbnQxNkFycmF5KFswLCAxLCAyLCAxLCAzLCAyXSksIGdsLlNUQVRJQ19EUkFXKTtcblxufTtcblxuLyoqXG4gKiBEZXN0cm95cyB0aGUgZmlsdGVyIGFuZCByZW1vdmVzIGl0IGZyb20gdGhlIGZpbHRlciBzdGFjay5cbiAqXG4gKi9cbldlYkdMRmlsdGVyTWFuYWdlci5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuXG4gICAgdGhpcy5maWx0ZXJTdGFjayA9IG51bGw7XG5cbiAgICB0aGlzLm9mZnNldFggPSAwO1xuICAgIHRoaXMub2Zmc2V0WSA9IDA7XG5cbiAgICAvLyBkZXN0cm95IHRleHR1cmVzXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnRleHR1cmVQb29sLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHRoaXMudGV4dHVyZVBvb2xbaV0uZGVzdHJveSgpO1xuICAgIH1cblxuICAgIHRoaXMudGV4dHVyZVBvb2wgPSBudWxsO1xuXG4gICAgLy9kZXN0cm95IGJ1ZmZlcnMuLlxuICAgIGdsLmRlbGV0ZUJ1ZmZlcih0aGlzLnZlcnRleEJ1ZmZlcik7XG4gICAgZ2wuZGVsZXRlQnVmZmVyKHRoaXMudXZCdWZmZXIpO1xuICAgIGdsLmRlbGV0ZUJ1ZmZlcih0aGlzLmNvbG9yQnVmZmVyKTtcbiAgICBnbC5kZWxldGVCdWZmZXIodGhpcy5pbmRleEJ1ZmZlcik7XG5cbiAgICB0aGlzLnJlbmRlcmVyID0gbnVsbDtcbn07XG4iLCIvKipcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9IFRoZSByZW5kZXJlciB0aGlzIG1hbmFnZXIgd29ya3MgZm9yLlxuICovXG5mdW5jdGlvbiBXZWJHTE1hbmFnZXIocmVuZGVyZXIpIHtcbiAgICAvKipcbiAgICAgKiBUaGUgcmVuZGVyZXIgdGhpcyBtYW5hZ2VyIHdvcmtzIGZvci5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1dlYkdMUmVuZGVyZXJ9XG4gICAgICovXG4gICAgdGhpcy5yZW5kZXJlciA9IHJlbmRlcmVyO1xufVxuXG5XZWJHTE1hbmFnZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gV2ViR0xNYW5hZ2VyO1xubW9kdWxlLmV4cG9ydHMgPSBXZWJHTE1hbmFnZXI7XG5cbldlYkdMTWFuYWdlci5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnJlbmRlcmVyID0gbnVsbDtcbn07XG4iLCJ2YXIgV2ViR0xNYW5hZ2VyID0gcmVxdWlyZSgnLi9XZWJHTE1hbmFnZXInKSxcbiAgICBXZWJHTEdyYXBoaWNzID0gcmVxdWlyZSgnLi4vdXRpbHMvV2ViR0xHcmFwaGljcycpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9IFRoZSByZW5kZXJlciB0aGlzIG1hbmFnZXIgd29ya3MgZm9yLlxuICovXG5mdW5jdGlvbiBXZWJHTE1hc2tNYW5hZ2VyKHJlbmRlcmVyKSB7XG4gICAgV2ViR0xNYW5hZ2VyLmNhbGwodGhpcywgcmVuZGVyZXIpO1xufVxuXG5XZWJHTE1hc2tNYW5hZ2VyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoV2ViR0xNYW5hZ2VyLnByb3RvdHlwZSk7XG5XZWJHTE1hc2tNYW5hZ2VyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFdlYkdMTWFza01hbmFnZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFdlYkdMTWFza01hbmFnZXI7XG5cbi8qKlxuICogQXBwbGllcyB0aGUgTWFzayBhbmQgYWRkcyBpdCB0byB0aGUgY3VycmVudCBmaWx0ZXIgc3RhY2suXG4gKlxuICogQHBhcmFtIG1hc2tEYXRhIHthbnlbXX1cbiAqL1xuV2ViR0xNYXNrTWFuYWdlci5wcm90b3R5cGUucHVzaE1hc2sgPSBmdW5jdGlvbiAobWFza0RhdGEpIHtcbiAgICBpZiAobWFza0RhdGEuZGlydHkpIHtcbiAgICAgICAgV2ViR0xHcmFwaGljcy51cGRhdGVHcmFwaGljcyhtYXNrRGF0YSwgdGhpcy5yZW5kZXJlci5nbCk7XG4gICAgfVxuXG4gICAgaWYgKCFtYXNrRGF0YS5fd2ViR0xbdGhpcy5yZW5kZXJlci5nbC5pZF0uZGF0YS5sZW5ndGgpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMucmVuZGVyZXIuc3RlbmNpbE1hbmFnZXIucHVzaFN0ZW5jaWwobWFza0RhdGEsIG1hc2tEYXRhLl93ZWJHTFt0aGlzLnJlbmRlcmVyLmdsLmlkXS5kYXRhWzBdLCB0aGlzLnJlbmRlcmVyKTtcbn07XG5cbi8qKlxuICogUmVtb3ZlcyB0aGUgbGFzdCBmaWx0ZXIgZnJvbSB0aGUgZmlsdGVyIHN0YWNrIGFuZCBkb2Vzbid0IHJldHVybiBpdC5cbiAqXG4gKiBAcGFyYW0gbWFza0RhdGEge2FueVtdfVxuICovXG5XZWJHTE1hc2tNYW5hZ2VyLnByb3RvdHlwZS5wb3BNYXNrID0gZnVuY3Rpb24gKG1hc2tEYXRhKSB7XG4gICAgdGhpcy5yZW5kZXJlci5zdGVuY2lsTWFuYWdlci5wb3BTdGVuY2lsKG1hc2tEYXRhLCBtYXNrRGF0YS5fd2ViR0xbdGhpcy5yZW5kZXJlci5nbC5pZF0uZGF0YVswXSwgdGhpcy5yZW5kZXJlcik7XG59O1xuIiwidmFyIFdlYkdMTWFuYWdlciA9IHJlcXVpcmUoJy4vV2ViR0xNYW5hZ2VyJyksXG4gICAgUHJpbWl0aXZlU2hhZGVyID0gcmVxdWlyZSgnLi4vc2hhZGVycy9QcmltaXRpdmVTaGFkZXInKSxcbiAgICBDb21wbGV4UHJpbWl0aXZlU2hhZGVyID0gcmVxdWlyZSgnLi4vc2hhZGVycy9Db21wbGV4UHJpbWl0aXZlU2hhZGVyJyksXG4gICAgU2hhZGVyID0gcmVxdWlyZSgnLi4vc2hhZGVycy9TaGFkZXInKSxcbiAgICBGYXN0U2hhZGVyID0gcmVxdWlyZSgnLi4vc2hhZGVycy9GYXN0U2hhZGVyJyksXG4gICAgU3RyaXBTaGFkZXIgPSByZXF1aXJlKCcuLi9zaGFkZXJzL1N0cmlwU2hhZGVyJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcn0gVGhlIHJlbmRlcmVyIHRoaXMgbWFuYWdlciB3b3JrcyBmb3IuXG4gKi9cbmZ1bmN0aW9uIFdlYkdMU2hhZGVyTWFuYWdlcihyZW5kZXJlcikge1xuICAgIFdlYkdMTWFuYWdlci5jYWxsKHRoaXMsIHJlbmRlcmVyKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLm1heEF0dGlicyA9IDEwO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7YW55W119XG4gICAgICovXG4gICAgdGhpcy5hdHRyaWJTdGF0ZSA9IFtdO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7YW55W119XG4gICAgICovXG4gICAgdGhpcy50ZW1wQXR0cmliU3RhdGUgPSBbXTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5tYXhBdHRpYnM7IGkrKykge1xuICAgICAgICB0aGlzLmF0dHJpYlN0YXRlW2ldID0gZmFsc2U7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7YW55W119XG4gICAgICovXG4gICAgdGhpcy5zdGFjayA9IFtdO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fY3VycmVudElkID0gLTE7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtTaGFkZXJ9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLmN1cnJlbnRTaGFkZXIgPSBudWxsO1xuXG4gICAgLy8gdGhpcyBzaGFkZXIgaXMgdXNlZCBmb3IgcmVuZGVyaW5nIHByaW1pdGl2ZXNcbiAgICB0aGlzLnByaW1pdGl2ZVNoYWRlciA9IG51bGw7XG5cbiAgICAvLyB0aGlzIHNoYWRlciBpcyB1c2VkIGZvciByZW5kZXJpbmcgdHJpYW5nbGUgc3RyaXBzXG4gICAgdGhpcy5jb21wbGV4UHJpbWl0aXZlU2hhZGVyID0gbnVsbDtcblxuICAgIC8vIHRoaXMgc2hhZGVyIGlzIHVzZWQgZm9yIHRoZSBkZWZhdWx0IHNwcml0ZSByZW5kZXJpbmdcbiAgICB0aGlzLmRlZmF1bHRTaGFkZXIgPSBudWxsO1xuXG4gICAgLy8gdGhpcyBzaGFkZXIgaXMgdXNlZCBmb3IgdGhlIGZhc3Qgc3ByaXRlIHJlbmRlcmluZ1xuICAgIHRoaXMuZmFzdFNoYWRlciA9IG51bGw7XG5cbiAgICAvLyB0aGUgbmV4dCBvbmUgaXMgdXNlZCBmb3IgcmVuZGVyaW5nIHRyaWFuZ2xlIHN0cmlwc1xuICAgIHRoaXMuc3RyaXBTaGFkZXIgPSBudWxsO1xuXG4gICAgLy8gbGlzdGVuIGZvciBjb250ZXh0IGFuZCB1cGRhdGUgbmVjZXNzYXJ5IHNoYWRlcnNcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy5yZW5kZXJlci5vbignY29udGV4dCcsIGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICB2YXIgZ2wgPSBldmVudC5kYXRhO1xuXG4gICAgICAgIC8vIHRoaXMgc2hhZGVyIGlzIHVzZWQgZm9yIHJlbmRlcmluZyBwcmltaXRpdmVzXG4gICAgICAgIHNlbGYucHJpbWl0aXZlU2hhZGVyID0gbmV3IFByaW1pdGl2ZVNoYWRlcihnbCk7XG5cbiAgICAgICAgLy8gdGhpcyBzaGFkZXIgaXMgdXNlZCBmb3IgcmVuZGVyaW5nIHRyaWFuZ2xlIHN0cmlwc1xuICAgICAgICBzZWxmLmNvbXBsZXhQcmltaXRpdmVTaGFkZXIgPSBuZXcgQ29tcGxleFByaW1pdGl2ZVNoYWRlcihnbCk7XG5cbiAgICAgICAgLy8gdGhpcyBzaGFkZXIgaXMgdXNlZCBmb3IgdGhlIGRlZmF1bHQgc3ByaXRlIHJlbmRlcmluZ1xuICAgICAgICBzZWxmLmRlZmF1bHRTaGFkZXIgPSBuZXcgU2hhZGVyKGdsKTtcblxuICAgICAgICAvLyB0aGlzIHNoYWRlciBpcyB1c2VkIGZvciB0aGUgZmFzdCBzcHJpdGUgcmVuZGVyaW5nXG4gICAgICAgIHNlbGYuZmFzdFNoYWRlciA9IG5ldyBGYXN0U2hhZGVyKGdsKTtcblxuICAgICAgICAvLyB0aGUgbmV4dCBvbmUgaXMgdXNlZCBmb3IgcmVuZGVyaW5nIHRyaWFuZ2xlIHN0cmlwc1xuICAgICAgICBzZWxmLnN0cmlwU2hhZGVyID0gbmV3IFN0cmlwU2hhZGVyKGdsKTtcblxuICAgICAgICBzZWxmLnNldFNoYWRlcihzZWxmLmRlZmF1bHRTaGFkZXIpO1xuICAgIH0pO1xufVxuXG5XZWJHTFNoYWRlck1hbmFnZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShXZWJHTE1hbmFnZXIucHJvdG90eXBlKTtcbldlYkdMU2hhZGVyTWFuYWdlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBXZWJHTFNoYWRlck1hbmFnZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFdlYkdMU2hhZGVyTWFuYWdlcjtcblxuLyoqXG4gKiBUYWtlcyB0aGUgYXR0cmlidXRlcyBnaXZlbiBpbiBwYXJhbWV0ZXJzLlxuICpcbiAqIEBwYXJhbSBhdHRyaWJzIHtBcnJheX0gYXR0cmlic1xuICovXG5XZWJHTFNoYWRlck1hbmFnZXIucHJvdG90eXBlLnNldEF0dHJpYnMgPSBmdW5jdGlvbiAoYXR0cmlicykge1xuICAgIC8vIHJlc2V0IHRlbXAgc3RhdGVcbiAgICB2YXIgaTtcblxuICAgIGZvciAoaSA9IDA7IGkgPCB0aGlzLnRlbXBBdHRyaWJTdGF0ZS5sZW5ndGg7IGkrKykge1xuICAgICAgICB0aGlzLnRlbXBBdHRyaWJTdGF0ZVtpXSA9IGZhbHNlO1xuICAgIH1cblxuICAgIC8vIHNldCB0aGUgbmV3IGF0dHJpYnNcbiAgICBmb3IgKHZhciBhIGluIGF0dHJpYnMpIHtcbiAgICAgICAgdGhpcy50ZW1wQXR0cmliU3RhdGVbYXR0cmlic1thXV0gPSB0cnVlO1xuICAgIH1cblxuICAgIHZhciBnbCA9IHRoaXMucmVuZGVyZXIuZ2w7XG5cbiAgICBmb3IgKGkgPSAwOyBpIDwgdGhpcy5hdHRyaWJTdGF0ZS5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAodGhpcy5hdHRyaWJTdGF0ZVtpXSAhPT0gdGhpcy50ZW1wQXR0cmliU3RhdGVbaV0pIHtcbiAgICAgICAgICAgIHRoaXMuYXR0cmliU3RhdGVbaV0gPSB0aGlzLnRlbXBBdHRyaWJTdGF0ZVtpXTtcblxuICAgICAgICAgICAgaWYgKHRoaXMuYXR0cmliU3RhdGVbaV0pIHtcbiAgICAgICAgICAgICAgICBnbC5lbmFibGVWZXJ0ZXhBdHRyaWJBcnJheShpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGdsLmRpc2FibGVWZXJ0ZXhBdHRyaWJBcnJheShpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn07XG5cbi8qKlxuICogU2V0cyB0aGUgY3VycmVudCBzaGFkZXIuXG4gKlxuICogQHBhcmFtIHNoYWRlciB7QW55fVxuICovXG5XZWJHTFNoYWRlck1hbmFnZXIucHJvdG90eXBlLnNldFNoYWRlciA9IGZ1bmN0aW9uIChzaGFkZXIpIHtcbiAgICBpZiAodGhpcy5fY3VycmVudElkID09PSBzaGFkZXIudXVpZCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgdGhpcy5fY3VycmVudElkID0gc2hhZGVyLnV1aWQ7XG5cbiAgICB0aGlzLmN1cnJlbnRTaGFkZXIgPSBzaGFkZXI7XG5cbiAgICB0aGlzLnJlbmRlcmVyLmdsLnVzZVByb2dyYW0oc2hhZGVyLnByb2dyYW0pO1xuICAgIHRoaXMuc2V0QXR0cmlicyhzaGFkZXIuYXR0cmlidXRlcyk7XG5cbiAgICByZXR1cm4gdHJ1ZTtcbn07XG5cbi8qKlxuICogRGVzdHJveXMgdGhpcyBvYmplY3QuXG4gKlxuICovXG5XZWJHTFNoYWRlck1hbmFnZXIucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5hdHRyaWJTdGF0ZSA9IG51bGw7XG5cbiAgICB0aGlzLnRlbXBBdHRyaWJTdGF0ZSA9IG51bGw7XG5cbiAgICB0aGlzLnByaW1pdGl2ZVNoYWRlci5kZXN0cm95KCk7XG4gICAgdGhpcy5wcmltaXRpdmVTaGFkZXIgPSBudWxsO1xuXG4gICAgdGhpcy5jb21wbGV4UHJpbWl0aXZlU2hhZGVyLmRlc3Ryb3koKTtcbiAgICB0aGlzLmNvbXBsZXhQcmltaXRpdmVTaGFkZXIgPSBudWxsO1xuXG4gICAgdGhpcy5kZWZhdWx0U2hhZGVyLmRlc3Ryb3koKTtcbiAgICB0aGlzLmRlZmF1bHRTaGFkZXIgPSBudWxsO1xuXG4gICAgdGhpcy5mYXN0U2hhZGVyLmRlc3Ryb3koKTtcbiAgICB0aGlzLmZhc3RTaGFkZXIgPSBudWxsO1xuXG4gICAgdGhpcy5zdHJpcFNoYWRlci5kZXN0cm95KCk7XG4gICAgdGhpcy5zdHJpcFNoYWRlciA9IG51bGw7XG5cbiAgICB0aGlzLnJlbmRlcmVyID0gbnVsbDtcbn07XG4iLCJ2YXIgV2ViR0xNYW5hZ2VyID0gcmVxdWlyZSgnLi9XZWJHTE1hbmFnZXInKSxcbiAgICB1dGlscyA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWxzJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcn0gVGhlIHJlbmRlcmVyIHRoaXMgbWFuYWdlciB3b3JrcyBmb3IuXG4gKi9cbmZ1bmN0aW9uIFdlYkdMU3RlbmNpbE1hbmFnZXIocmVuZGVyZXIpIHtcbiAgICBXZWJHTE1hbmFnZXIuY2FsbCh0aGlzLCByZW5kZXJlcik7XG5cbiAgICB0aGlzLnN0ZW5jaWxTdGFjayA9IFtdO1xuICAgIHRoaXMucmV2ZXJzZSA9IHRydWU7XG4gICAgdGhpcy5jb3VudCA9IDA7XG59XG5cbldlYkdMU3RlbmNpbE1hbmFnZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShXZWJHTE1hbmFnZXIucHJvdG90eXBlKTtcbldlYkdMU3RlbmNpbE1hbmFnZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gV2ViR0xTdGVuY2lsTWFuYWdlcjtcbm1vZHVsZS5leHBvcnRzID0gV2ViR0xTdGVuY2lsTWFuYWdlcjtcblxuLyoqXG4gKiBBcHBsaWVzIHRoZSBNYXNrIGFuZCBhZGRzIGl0IHRvIHRoZSBjdXJyZW50IGZpbHRlciBzdGFjay5cbiAqXG4gKiBAcGFyYW0gZ3JhcGhpY3Mge0dyYXBoaWNzfVxuICogQHBhcmFtIHdlYkdMRGF0YSB7YW55W119XG4gKi9cbldlYkdMU3RlbmNpbE1hbmFnZXIucHJvdG90eXBlLnB1c2hTdGVuY2lsID0gZnVuY3Rpb24gKGdyYXBoaWNzLCB3ZWJHTERhdGEpIHtcbiAgICB2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuXG4gICAgdGhpcy5iaW5kR3JhcGhpY3MoZ3JhcGhpY3MsIHdlYkdMRGF0YSwgdGhpcy5yZW5kZXJlcik7XG5cbiAgICBpZiAodGhpcy5zdGVuY2lsU3RhY2subGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGdsLmVuYWJsZShnbC5TVEVOQ0lMX1RFU1QpO1xuICAgICAgICBnbC5jbGVhcihnbC5TVEVOQ0lMX0JVRkZFUl9CSVQpO1xuICAgICAgICB0aGlzLnJldmVyc2UgPSB0cnVlO1xuICAgICAgICB0aGlzLmNvdW50ID0gMDtcbiAgICB9XG5cbiAgICB0aGlzLnN0ZW5jaWxTdGFjay5wdXNoKHdlYkdMRGF0YSk7XG5cbiAgICB2YXIgbGV2ZWwgPSB0aGlzLmNvdW50O1xuXG4gICAgZ2wuY29sb3JNYXNrKGZhbHNlLCBmYWxzZSwgZmFsc2UsIGZhbHNlKTtcblxuICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkFMV0FZUywwLDB4RkYpO1xuICAgIGdsLnN0ZW5jaWxPcChnbC5LRUVQLGdsLktFRVAsZ2wuSU5WRVJUKTtcblxuICAgIC8vIGRyYXcgdGhlIHRyaWFuZ2xlIHN0cmlwIVxuXG4gICAgaWYgKHdlYkdMRGF0YS5tb2RlID09PSAxKSB7XG4gICAgICAgIGdsLmRyYXdFbGVtZW50cyhnbC5UUklBTkdMRV9GQU4sICB3ZWJHTERhdGEuaW5kaWNlcy5sZW5ndGggLSA0LCBnbC5VTlNJR05FRF9TSE9SVCwgMCApO1xuXG4gICAgICAgIGlmICh0aGlzLnJldmVyc2UpIHtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLCAweEZGIC0gbGV2ZWwsIDB4RkYpO1xuICAgICAgICAgICAgZ2wuc3RlbmNpbE9wKGdsLktFRVAsZ2wuS0VFUCxnbC5ERUNSKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLGxldmVsLCAweEZGKTtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxPcChnbC5LRUVQLGdsLktFRVAsZ2wuSU5DUik7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkcmF3IGEgcXVhZCB0byBpbmNyZW1lbnQuLlxuICAgICAgICBnbC5kcmF3RWxlbWVudHMoZ2wuVFJJQU5HTEVfRkFOLCA0LCBnbC5VTlNJR05FRF9TSE9SVCwgKCB3ZWJHTERhdGEuaW5kaWNlcy5sZW5ndGggLSA0ICkgKiAyICk7XG5cbiAgICAgICAgaWYgKHRoaXMucmV2ZXJzZSkge1xuICAgICAgICAgICAgZ2wuc3RlbmNpbEZ1bmMoZ2wuRVFVQUwsMHhGRi0obGV2ZWwrMSksIDB4RkYpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZ2wuc3RlbmNpbEZ1bmMoZ2wuRVFVQUwsbGV2ZWwrMSwgMHhGRik7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnJldmVyc2UgPSAhdGhpcy5yZXZlcnNlO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgaWYgKCF0aGlzLnJldmVyc2UpIHtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLCAweEZGIC0gbGV2ZWwsIDB4RkYpO1xuICAgICAgICAgICAgZ2wuc3RlbmNpbE9wKGdsLktFRVAsZ2wuS0VFUCxnbC5ERUNSKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLGxldmVsLCAweEZGKTtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxPcChnbC5LRUVQLGdsLktFRVAsZ2wuSU5DUik7XG4gICAgICAgIH1cblxuICAgICAgICBnbC5kcmF3RWxlbWVudHMoZ2wuVFJJQU5HTEVfU1RSSVAsICB3ZWJHTERhdGEuaW5kaWNlcy5sZW5ndGgsIGdsLlVOU0lHTkVEX1NIT1JULCAwICk7XG5cbiAgICAgICAgaWYgKCF0aGlzLnJldmVyc2UpIHtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLDB4RkYtKGxldmVsKzEpLCAweEZGKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLGxldmVsKzEsIDB4RkYpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZ2wuY29sb3JNYXNrKHRydWUsIHRydWUsIHRydWUsIHRydWUpO1xuICAgIGdsLnN0ZW5jaWxPcChnbC5LRUVQLGdsLktFRVAsZ2wuS0VFUCk7XG5cbiAgICB0aGlzLmNvdW50Kys7XG59O1xuXG4vKipcbiAqIFRPRE8gdGhpcyBkb2VzIG5vdCBiZWxvbmcgaGVyZSFcbiAqXG4gKiBAcGFyYW0gZ3JhcGhpY3Mge0dyYXBoaWNzfVxuICogQHBhcmFtIHdlYkdMRGF0YSB7QXJyYXl9XG4gKi9cbldlYkdMU3RlbmNpbE1hbmFnZXIucHJvdG90eXBlLmJpbmRHcmFwaGljcyA9IGZ1bmN0aW9uIChncmFwaGljcywgd2ViR0xEYXRhKSB7XG4gICAgLy9pZiAodGhpcy5fY3VycmVudEdyYXBoaWNzID09PSBncmFwaGljcylyZXR1cm47XG4gICAgdGhpcy5fY3VycmVudEdyYXBoaWNzID0gZ3JhcGhpY3M7XG5cbiAgICB2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuXG4gICAgIC8vIGJpbmQgdGhlIGdyYXBoaWNzIG9iamVjdC4uXG4gICAgdmFyIHByb2plY3Rpb24gPSB0aGlzLnJlbmRlcmVyLnByb2plY3Rpb24sXG4gICAgICAgIG9mZnNldCA9IHRoaXMucmVuZGVyZXIub2Zmc2V0LFxuICAgICAgICBzaGFkZXI7Ly8gPSB0aGlzLnJlbmRlcmVyLnNoYWRlck1hbmFnZXIucHJpbWl0aXZlU2hhZGVyO1xuXG4gICAgaWYgKHdlYkdMRGF0YS5tb2RlID09PSAxKSB7XG4gICAgICAgIHNoYWRlciA9IHRoaXMucmVuZGVyZXIuc2hhZGVyTWFuYWdlci5jb21wbGV4UHJpbWl0aXZlU2hhZGVyO1xuXG4gICAgICAgIHRoaXMucmVuZGVyZXIuc2hhZGVyTWFuYWdlci5zZXRTaGFkZXIoc2hhZGVyKTtcblxuICAgICAgICBnbC51bmlmb3JtMWYoc2hhZGVyLmZsaXBZLCB0aGlzLnJlbmRlcmVyLmZsaXBZKTtcblxuICAgICAgICBnbC51bmlmb3JtTWF0cml4M2Z2KHNoYWRlci50cmFuc2xhdGlvbk1hdHJpeCwgZmFsc2UsIGdyYXBoaWNzLndvcmxkVHJhbnNmb3JtLnRvQXJyYXkodHJ1ZSkpO1xuXG4gICAgICAgIGdsLnVuaWZvcm0yZihzaGFkZXIucHJvamVjdGlvblZlY3RvciwgcHJvamVjdGlvbi54LCAtcHJvamVjdGlvbi55KTtcbiAgICAgICAgZ2wudW5pZm9ybTJmKHNoYWRlci5vZmZzZXRWZWN0b3IsIC1vZmZzZXQueCwgLW9mZnNldC55KTtcblxuICAgICAgICBnbC51bmlmb3JtM2Z2KHNoYWRlci50aW50Q29sb3IsIHV0aWxzLmhleDJyZ2IoZ3JhcGhpY3MudGludCkpO1xuICAgICAgICBnbC51bmlmb3JtM2Z2KHNoYWRlci5jb2xvciwgd2ViR0xEYXRhLmNvbG9yKTtcblxuICAgICAgICBnbC51bmlmb3JtMWYoc2hhZGVyLmFscGhhLCBncmFwaGljcy53b3JsZEFscGhhICogd2ViR0xEYXRhLmFscGhhKTtcblxuICAgICAgICBnbC5iaW5kQnVmZmVyKGdsLkFSUkFZX0JVRkZFUiwgd2ViR0xEYXRhLmJ1ZmZlcik7XG5cbiAgICAgICAgZ2wudmVydGV4QXR0cmliUG9pbnRlcihzaGFkZXIuYVZlcnRleFBvc2l0aW9uLCAyLCBnbC5GTE9BVCwgZmFsc2UsIDQgKiAyLCAwKTtcblxuXG4gICAgICAgIC8vIG5vdyBkbyB0aGUgcmVzdC4uXG4gICAgICAgIC8vIHNldCB0aGUgaW5kZXggYnVmZmVyIVxuICAgICAgICBnbC5iaW5kQnVmZmVyKGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCB3ZWJHTERhdGEuaW5kZXhCdWZmZXIpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgLy90aGlzLnJlbmRlcmVyLnNoYWRlck1hbmFnZXIuYWN0aXZhdGVQcmltaXRpdmVTaGFkZXIoKTtcbiAgICAgICAgc2hhZGVyID0gdGhpcy5yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLnByaW1pdGl2ZVNoYWRlcjtcbiAgICAgICAgdGhpcy5yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLnNldFNoYWRlciggc2hhZGVyICk7XG5cbiAgICAgICAgZ2wudW5pZm9ybU1hdHJpeDNmdihzaGFkZXIudHJhbnNsYXRpb25NYXRyaXgsIGZhbHNlLCBncmFwaGljcy53b3JsZFRyYW5zZm9ybS50b0FycmF5KHRydWUpKTtcblxuICAgICAgICBnbC51bmlmb3JtMWYoc2hhZGVyLmZsaXBZLCB0aGlzLnJlbmRlcmVyLmZsaXBZKTtcbiAgICAgICAgZ2wudW5pZm9ybTJmKHNoYWRlci5wcm9qZWN0aW9uVmVjdG9yLCBwcm9qZWN0aW9uLngsIC1wcm9qZWN0aW9uLnkpO1xuICAgICAgICBnbC51bmlmb3JtMmYoc2hhZGVyLm9mZnNldFZlY3RvciwgLW9mZnNldC54LCAtb2Zmc2V0LnkpO1xuXG4gICAgICAgIGdsLnVuaWZvcm0zZnYoc2hhZGVyLnRpbnRDb2xvciwgdXRpbHMuaGV4MnJnYihncmFwaGljcy50aW50KSk7XG5cbiAgICAgICAgZ2wudW5pZm9ybTFmKHNoYWRlci5hbHBoYSwgZ3JhcGhpY3Mud29ybGRBbHBoYSk7XG5cbiAgICAgICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHdlYkdMRGF0YS5idWZmZXIpO1xuXG4gICAgICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIoc2hhZGVyLmFWZXJ0ZXhQb3NpdGlvbiwgMiwgZ2wuRkxPQVQsIGZhbHNlLCA0ICogNiwgMCk7XG4gICAgICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIoc2hhZGVyLmFDb2xvciwgNCwgZ2wuRkxPQVQsIGZhbHNlLDQgKiA2LCAyICogNCk7XG5cbiAgICAgICAgLy8gc2V0IHRoZSBpbmRleCBidWZmZXIhXG4gICAgICAgIGdsLmJpbmRCdWZmZXIoZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIsIHdlYkdMRGF0YS5pbmRleEJ1ZmZlcik7XG4gICAgfVxufTtcblxuLyoqXG4gKiBAcGFyYW0gZ3JhcGhpY3Mge0dyYXBoaWNzfVxuICogQHBhcmFtIHdlYkdMRGF0YSB7QXJyYXl9XG4gKi9cbldlYkdMU3RlbmNpbE1hbmFnZXIucHJvdG90eXBlLnBvcFN0ZW5jaWwgPSBmdW5jdGlvbiAoZ3JhcGhpY3MsIHdlYkdMRGF0YSkge1xuXHR2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuXG4gICAgdGhpcy5zdGVuY2lsU3RhY2sucG9wKCk7XG5cbiAgICB0aGlzLmNvdW50LS07XG5cbiAgICBpZiAodGhpcy5zdGVuY2lsU3RhY2subGVuZ3RoID09PSAwKSB7XG4gICAgICAgIC8vIHRoZSBzdGFjayBpcyBlbXB0eSFcbiAgICAgICAgZ2wuZGlzYWJsZShnbC5TVEVOQ0lMX1RFU1QpO1xuXG4gICAgfVxuICAgIGVsc2Uge1xuXG4gICAgICAgIHZhciBsZXZlbCA9IHRoaXMuY291bnQ7XG5cbiAgICAgICAgdGhpcy5iaW5kR3JhcGhpY3MoZ3JhcGhpY3MsIHdlYkdMRGF0YSwgdGhpcy5yZW5kZXJlcik7XG5cbiAgICAgICAgZ2wuY29sb3JNYXNrKGZhbHNlLCBmYWxzZSwgZmFsc2UsIGZhbHNlKTtcblxuICAgICAgICBpZiAod2ViR0xEYXRhLm1vZGUgPT09IDEpIHtcbiAgICAgICAgICAgIHRoaXMucmV2ZXJzZSA9ICF0aGlzLnJldmVyc2U7XG5cbiAgICAgICAgICAgIGlmICh0aGlzLnJldmVyc2UpIHtcbiAgICAgICAgICAgICAgICBnbC5zdGVuY2lsRnVuYyhnbC5FUVVBTCwgMHhGRiAtIChsZXZlbCsxKSwgMHhGRik7XG4gICAgICAgICAgICAgICAgZ2wuc3RlbmNpbE9wKGdsLktFRVAsZ2wuS0VFUCxnbC5JTkNSKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLGxldmVsKzEsIDB4RkYpO1xuICAgICAgICAgICAgICAgIGdsLnN0ZW5jaWxPcChnbC5LRUVQLGdsLktFRVAsZ2wuREVDUik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIGRyYXcgYSBxdWFkIHRvIGluY3JlbWVudC4uXG4gICAgICAgICAgICBnbC5kcmF3RWxlbWVudHMoZ2wuVFJJQU5HTEVfRkFOLCA0LCBnbC5VTlNJR05FRF9TSE9SVCwgKCB3ZWJHTERhdGEuaW5kaWNlcy5sZW5ndGggLSA0ICkgKiAyICk7XG5cbiAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkFMV0FZUywwLDB4RkYpO1xuICAgICAgICAgICAgZ2wuc3RlbmNpbE9wKGdsLktFRVAsZ2wuS0VFUCxnbC5JTlZFUlQpO1xuXG4gICAgICAgICAgICAvLyBkcmF3IHRoZSB0cmlhbmdsZSBzdHJpcCFcbiAgICAgICAgICAgIGdsLmRyYXdFbGVtZW50cyhnbC5UUklBTkdMRV9GQU4sICB3ZWJHTERhdGEuaW5kaWNlcy5sZW5ndGggLSA0LCBnbC5VTlNJR05FRF9TSE9SVCwgMCApO1xuXG4gICAgICAgICAgICBpZiAoIXRoaXMucmV2ZXJzZSkge1xuICAgICAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLDB4RkYtKGxldmVsKSwgMHhGRik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBnbC5zdGVuY2lsRnVuYyhnbC5FUVVBTCxsZXZlbCwgMHhGRik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAvLyAgY29uc29sZS5sb2coXCI8PD4+XCIpXG4gICAgICAgICAgICBpZiAoIXRoaXMucmV2ZXJzZSkge1xuICAgICAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLCAweEZGIC0gKGxldmVsKzEpLCAweEZGKTtcbiAgICAgICAgICAgICAgICBnbC5zdGVuY2lsT3AoZ2wuS0VFUCxnbC5LRUVQLGdsLklOQ1IpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgZ2wuc3RlbmNpbEZ1bmMoZ2wuRVFVQUwsbGV2ZWwrMSwgMHhGRik7XG4gICAgICAgICAgICAgICAgZ2wuc3RlbmNpbE9wKGdsLktFRVAsZ2wuS0VFUCxnbC5ERUNSKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZ2wuZHJhd0VsZW1lbnRzKGdsLlRSSUFOR0xFX1NUUklQLCAgd2ViR0xEYXRhLmluZGljZXMubGVuZ3RoLCBnbC5VTlNJR05FRF9TSE9SVCwgMCApO1xuXG4gICAgICAgICAgICBpZiAoIXRoaXMucmV2ZXJzZSkge1xuICAgICAgICAgICAgICAgIGdsLnN0ZW5jaWxGdW5jKGdsLkVRVUFMLDB4RkYtKGxldmVsKSwgMHhGRik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBnbC5zdGVuY2lsRnVuYyhnbC5FUVVBTCxsZXZlbCwgMHhGRik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBnbC5jb2xvck1hc2sodHJ1ZSwgdHJ1ZSwgdHJ1ZSwgdHJ1ZSk7XG4gICAgICAgIGdsLnN0ZW5jaWxPcChnbC5LRUVQLGdsLktFRVAsZ2wuS0VFUCk7XG5cblxuICAgIH1cbn07XG5cbi8qKlxuICogRGVzdHJveXMgdGhlIG1hc2sgc3RhY2suXG4gKlxuICovXG5XZWJHTFN0ZW5jaWxNYW5hZ2VyLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMucmVuZGVyZXIgPSBudWxsO1xuICAgIHRoaXMuc3RlbmNpbFN0YWNrID0gbnVsbDtcbn07XG4iLCJ2YXIgU2hhZGVyID0gcmVxdWlyZSgnLi9TaGFkZXInKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIGdsIHtXZWJHTENvbnRleHR9IHRoZSBjdXJyZW50IFdlYkdMIGRyYXdpbmcgY29udGV4dFxuICovXG5mdW5jdGlvbiBDb21wbGV4UHJpbWl0aXZlU2hhZGVyKGdsKSB7XG4gICAgU2hhZGVyLmNhbGwodGhpcyxcbiAgICAgICAgZ2wsXG4gICAgICAgIC8vIHZlcnRleCBzaGFkZXJcbiAgICAgICAgW1xuICAgICAgICAgICAgJ2F0dHJpYnV0ZSB2ZWMyIGFWZXJ0ZXhQb3NpdGlvbjsnLFxuICAgICAgICAgICAgLy8gJ2F0dHJpYnV0ZSB2ZWMyIGFUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgICAgIC8vICdhdHRyaWJ1dGUgdmVjNCBhQ29sb3I7JyxcblxuICAgICAgICAgICAgJ3VuaWZvcm0gbWF0MyB0cmFuc2xhdGlvbk1hdHJpeDsnLFxuICAgICAgICAgICAgJ3VuaWZvcm0gdmVjMiBwcm9qZWN0aW9uVmVjdG9yOycsXG4gICAgICAgICAgICAndW5pZm9ybSB2ZWMyIG9mZnNldFZlY3RvcjsnLFxuXG4gICAgICAgICAgICAndW5pZm9ybSB2ZWMzIHRpbnQ7JyxcbiAgICAgICAgICAgICd1bmlmb3JtIGZsb2F0IGFscGhhOycsXG4gICAgICAgICAgICAndW5pZm9ybSB2ZWMzIGNvbG9yOycsXG4gICAgICAgICAgICAndW5pZm9ybSBmbG9hdCBmbGlwWTsnLFxuICAgICAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAgICAgJ3ZvaWQgbWFpbih2b2lkKSB7JyxcbiAgICAgICAgICAgICcgICB2ZWMzIHYgPSB0cmFuc2xhdGlvbk1hdHJpeCAqIHZlYzMoYVZlcnRleFBvc2l0aW9uICwgMS4wKTsnLFxuICAgICAgICAgICAgJyAgIHYgLT0gb2Zmc2V0VmVjdG9yLnh5eDsnLFxuICAgICAgICAgICAgJyAgIGdsX1Bvc2l0aW9uID0gdmVjNCggdi54IC8gcHJvamVjdGlvblZlY3Rvci54IC0xLjAsICh2LnkgLyBwcm9qZWN0aW9uVmVjdG9yLnkgKiAtZmxpcFkpICsgZmxpcFkgLCAwLjAsIDEuMCk7JyxcbiAgICAgICAgICAgICcgICB2Q29sb3IgPSB2ZWM0KGNvbG9yICogYWxwaGEgKiB0aW50LCBhbHBoYSk7JywvL1wiICogdmVjNCh0aW50ICogYWxwaGEsIGFscGhhKTsnLFxuICAgICAgICAgICAgJ30nXG4gICAgICAgIF0uam9pbignXFxuJyksXG4gICAgICAgIC8vIGZyYWdtZW50IHNoYWRlclxuICAgICAgICBbXG4gICAgICAgICAgICAncHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7JyxcblxuICAgICAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAgICAgJ3ZvaWQgbWFpbih2b2lkKSB7JyxcbiAgICAgICAgICAgICcgICBnbF9GcmFnQ29sb3IgPSB2Q29sb3I7JyxcbiAgICAgICAgICAgICd9J1xuICAgICAgICBdLmpvaW4oJ1xcbicpLFxuICAgICAgICAvLyBjdXN0b20gdW5pZm9ybXNcbiAgICAgICAge1xuICAgICAgICAgICAgdGludDogICB7IHR5cGU6ICczZicsIHZhbHVlOiBbMCwgMCwgMF0gfSxcbiAgICAgICAgICAgIGZsaXBZOiAgeyB0eXBlOiAnMWYnLCB2YWx1ZTogMCB9LFxuICAgICAgICAgICAgYWxwaGE6ICB7IHR5cGU6ICcxZicsIHZhbHVlOiAwIH0sXG4gICAgICAgICAgICB0cmFuc2xhdGlvbk1hdHJpeDogeyB0eXBlOiAnbWF0MycsIHZhbHVlOiBuZXcgRmxvYXQzMkFycmF5KDkpIH1cbiAgICAgICAgfVxuICAgICk7XG59XG5cbkNvbXBsZXhQcmltaXRpdmVTaGFkZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShTaGFkZXIucHJvdG90eXBlKTtcbkNvbXBsZXhQcmltaXRpdmVTaGFkZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQ29tcGxleFByaW1pdGl2ZVNoYWRlcjtcbm1vZHVsZS5leHBvcnRzID0gQ29tcGxleFByaW1pdGl2ZVNoYWRlcjtcbiIsInZhciBTaGFkZXIgPSByZXF1aXJlKCcuL1NoYWRlcicpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgU2hhZGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSBnbCB7V2ViR0xDb250ZXh0fSB0aGUgY3VycmVudCBXZWJHTCBkcmF3aW5nIGNvbnRleHRcbiAqL1xuZnVuY3Rpb24gRmFzdFNoYWRlcihnbCkge1xuICAgIFNoYWRlci5jYWxsKHRoaXMsXG4gICAgICAgIGdsLFxuICAgICAgICAvLyB2ZXJ0ZXggc2hhZGVyXG4gICAgICAgIFtcbiAgICAgICAgICAgICdhdHRyaWJ1dGUgdmVjMiBhVmVydGV4UG9zaXRpb247JyxcbiAgICAgICAgICAgICdhdHRyaWJ1dGUgdmVjMiBhVGV4dHVyZUNvb3JkOycsXG4gICAgICAgICAgICAnYXR0cmlidXRlIHZlYzQgYUNvbG9yOycsXG5cbiAgICAgICAgICAgICdhdHRyaWJ1dGUgdmVjMiBhUG9zaXRpb25Db29yZDsnLFxuICAgICAgICAgICAgJ2F0dHJpYnV0ZSB2ZWMyIGFTY2FsZTsnLFxuICAgICAgICAgICAgJ2F0dHJpYnV0ZSBmbG9hdCBhUm90YXRpb247JyxcblxuICAgICAgICAgICAgJ3VuaWZvcm0gdmVjMiBwcm9qZWN0aW9uVmVjdG9yOycsXG4gICAgICAgICAgICAndW5pZm9ybSB2ZWMyIG9mZnNldFZlY3RvcjsnLFxuICAgICAgICAgICAgJ3VuaWZvcm0gbWF0MyB1TWF0cml4OycsXG5cbiAgICAgICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAgICAgJ2NvbnN0IHZlYzIgY2VudGVyID0gdmVjMigtMS4wLCAxLjApOycsXG5cbiAgICAgICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICAgICAnICAgdmVjMiB2OycsXG4gICAgICAgICAgICAnICAgdmVjMiBzdiA9IGFWZXJ0ZXhQb3NpdGlvbiAqIGFTY2FsZTsnLFxuICAgICAgICAgICAgJyAgIHYueCA9IChzdi54KSAqIGNvcyhhUm90YXRpb24pIC0gKHN2LnkpICogc2luKGFSb3RhdGlvbik7JyxcbiAgICAgICAgICAgICcgICB2LnkgPSAoc3YueCkgKiBzaW4oYVJvdGF0aW9uKSArIChzdi55KSAqIGNvcyhhUm90YXRpb24pOycsXG4gICAgICAgICAgICAnICAgdiA9ICggdU1hdHJpeCAqIHZlYzModiArIGFQb3NpdGlvbkNvb3JkICwgMS4wKSApLnh5IDsnLFxuICAgICAgICAgICAgJyAgIGdsX1Bvc2l0aW9uID0gdmVjNCggKCB2IC8gcHJvamVjdGlvblZlY3RvcikgKyBjZW50ZXIgLCAwLjAsIDEuMCk7JyxcbiAgICAgICAgICAgICcgICB2VGV4dHVyZUNvb3JkID0gYVRleHR1cmVDb29yZDsnLFxuICAgICAgICAgIC8vICAnICAgdmVjMyBjb2xvciA9IG1vZCh2ZWMzKGFDb2xvci55LzY1NTM2LjAsIGFDb2xvci55LzI1Ni4wLCBhQ29sb3IueSksIDI1Ni4wKSAvIDI1Ni4wOycsXG4gICAgICAgICAgICAnICAgdkNvbG9yID0gYUNvbG9yOycsXG4gICAgICAgICAgICAnfSdcbiAgICAgICAgXS5qb2luKCdcXG4nKSxcbiAgICAgICAgLy8gZnJhZ21lbnQgc2hhZGVyLCB1c2UgZGVmYXVsdFxuICAgICAgICBudWxsLFxuICAgICAgICAvLyBjdXN0b20gdW5pZm9ybXNcbiAgICAgICAge1xuICAgICAgICAgICAgdU1hdHJpeDogeyB0eXBlOiAnbWF0MycsIHZhbHVlOiBuZXcgRmxvYXQzMkFycmF5KDkpIH1cbiAgICAgICAgfSxcbiAgICAgICAgLy8gY3VzdG9tIGF0dHJpYnV0ZXNcbiAgICAgICAge1xuICAgICAgICAgICAgYVBvc2l0aW9uQ29vcmQ6IDAsXG4gICAgICAgICAgICBhUm90YXRpb246ICAgICAgMCxcbiAgICAgICAgICAgIGFTY2FsZTogICAgICAgICAwXG4gICAgICAgIH1cbiAgICApO1xufVxuXG5GYXN0U2hhZGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoU2hhZGVyLnByb3RvdHlwZSk7XG5GYXN0U2hhZGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEZhc3RTaGFkZXI7XG5tb2R1bGUuZXhwb3J0cyA9IEZhc3RTaGFkZXI7XG4iLCJ2YXIgU2hhZGVyID0gcmVxdWlyZSgnLi9TaGFkZXInKTtcblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIGdsIHtXZWJHTENvbnRleHR9IHRoZSBjdXJyZW50IFdlYkdMIGRyYXdpbmcgY29udGV4dFxuICovXG5mdW5jdGlvbiBQcmltaXRpdmVTaGFkZXIoZ2wpIHtcbiAgICBTaGFkZXIuY2FsbCh0aGlzLFxuICAgICAgICBnbCxcbiAgICAgICAgLy8gdmVydGV4IHNoYWRlclxuICAgICAgICBbXG4gICAgICAgICAgICAnYXR0cmlidXRlIHZlYzIgYVZlcnRleFBvc2l0aW9uOycsXG4gICAgICAgICAgICAvLyAnYXR0cmlidXRlIHZlYzIgYVRleHR1cmVDb29yZDsnLFxuICAgICAgICAgICAgJ2F0dHJpYnV0ZSB2ZWM0IGFDb2xvcjsnLFxuXG4gICAgICAgICAgICAndW5pZm9ybSBtYXQzIHRyYW5zbGF0aW9uTWF0cml4OycsXG4gICAgICAgICAgICAndW5pZm9ybSB2ZWMyIHByb2plY3Rpb25WZWN0b3I7JyxcbiAgICAgICAgICAgICd1bmlmb3JtIHZlYzIgb2Zmc2V0VmVjdG9yOycsXG4gICAgICAgICAgICAndW5pZm9ybSBmbG9hdCBhbHBoYTsnLFxuICAgICAgICAgICAgJ3VuaWZvcm0gZmxvYXQgZmxpcFk7JyxcbiAgICAgICAgICAgICd1bmlmb3JtIHZlYzMgdGludDsnLFxuXG4gICAgICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAgICAgJyAgIHZlYzMgdiA9IHRyYW5zbGF0aW9uTWF0cml4ICogdmVjMyhhVmVydGV4UG9zaXRpb24gLCAxLjApOycsXG4gICAgICAgICAgICAnICAgdiAtPSBvZmZzZXRWZWN0b3IueHl4OycsXG4gICAgICAgICAgICAnICAgZ2xfUG9zaXRpb24gPSB2ZWM0KCB2LnggLyBwcm9qZWN0aW9uVmVjdG9yLnggLTEuMCwgKHYueSAvIHByb2plY3Rpb25WZWN0b3IueSAqIC1mbGlwWSkgKyBmbGlwWSAsIDAuMCwgMS4wKTsnLFxuICAgICAgICAgICAgJyAgIHZDb2xvciA9IGFDb2xvciAqIHZlYzQodGludCAqIGFscGhhLCBhbHBoYSk7JyxcbiAgICAgICAgICAgICd9J1xuICAgICAgICBdLmpvaW4oJ1xcbicpLFxuICAgICAgICAvLyBmcmFnbWVudCBzaGFkZXJcbiAgICAgICAgW1xuICAgICAgICAgICAgJ3ByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OycsXG5cbiAgICAgICAgICAgICd2YXJ5aW5nIHZlYzQgdkNvbG9yOycsXG5cbiAgICAgICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gdkNvbG9yOycsXG4gICAgICAgICAgICAnfSdcbiAgICAgICAgXS5qb2luKCdcXG4nKSxcbiAgICAgICAgLy8gY3VzdG9tIHVuaWZvcm1zXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRpbnQ6ICAgeyB0eXBlOiAnM2YnLCB2YWx1ZTogWzAsIDAsIDBdIH0sXG4gICAgICAgICAgICBmbGlwWTogIHsgdHlwZTogJzFmJywgdmFsdWU6IDAgfSxcbiAgICAgICAgICAgIGFscGhhOiAgeyB0eXBlOiAnMWYnLCB2YWx1ZTogMCB9LFxuICAgICAgICAgICAgdHJhbnNsYXRpb25NYXRyaXg6IHsgdHlwZTogJ21hdDMnLCB2YWx1ZTogbmV3IEZsb2F0MzJBcnJheSg5KSB9XG4gICAgICAgIH1cbiAgICApO1xufVxuXG5QcmltaXRpdmVTaGFkZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShTaGFkZXIucHJvdG90eXBlKTtcblByaW1pdGl2ZVNoYWRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBQcmltaXRpdmVTaGFkZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFByaW1pdGl2ZVNoYWRlcjtcbiIsInZhciB1dGlscyA9IHJlcXVpcmUoJy4uLy4uLy4uL3V0aWxzJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSBbZnJhZ21lbnRTcmNdIHtzdHJpbmd9IFRoZSBzb3VyY2Ugb2YgdGhlIGZyYWdtZW50IHNoYWRlci5cbiAqIEBwYXJhbSBbdmVydGV4U3JjXSB7c3RyaW5nfSBUaGUgc291cmNlIG9mIHRoZSB2ZXJ0ZXggc2hhZGVyLlxuICovXG5mdW5jdGlvbiBTaGFkZXIoZ2wsIHZlcnRleFNyYywgZnJhZ21lbnRTcmMsIGN1c3RvbVVuaWZvcm1zLCBjdXN0b21BdHRyaWJ1dGVzKSB7XG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEByZWFkb25seVxuICAgICAqL1xuICAgIHRoaXMudXVpZCA9IHV0aWxzLnV1aWQoKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge1dlYkdMQ29udGV4dH1cbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKi9cbiAgICB0aGlzLmdsID0gZ2w7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgV2ViR0wgcHJvZ3JhbS5cbiAgICAgKiBAbWVtYmVyIHtXZWJHTFByb2dyYW19XG4gICAgICogQHJlYWRvbmx5XG4gICAgICovXG4gICAgdGhpcy5wcm9ncmFtID0gbnVsbDtcblxuICAgIHRoaXMudW5pZm9ybXMgPSB7XG4gICAgICAgIHVTYW1wbGVyOiAgICAgICAgICAgeyB0eXBlOiAnc2FtcGxlcjJEJywgdmFsdWU6IDAgfSxcbiAgICAgICAgcHJvamVjdGlvblZlY3RvcjogICB7IHR5cGU6ICcyZicsIHZhbHVlOiB7IHg6IDAsIHk6IDAgfSB9LFxuICAgICAgICBvZmZzZXRWZWN0b3I6ICAgICAgIHsgdHlwZTogJzJmJywgdmFsdWU6IHsgeDogMCwgeTogMCB9IH0sXG4gICAgICAgIGRpbWVuc2lvbnM6ICAgICAgICAgeyB0eXBlOiAnNGYnLCB2YWx1ZTogbmV3IEZsb2F0MzJBcnJheSg0KSB9XG4gICAgfTtcblxuICAgIGZvciAodmFyIHUgaW4gY3VzdG9tVW5pZm9ybXMpIHtcbiAgICAgICAgdGhpcy51bmlmb3Jtc1t1XSA9IGN1c3RvbVVuaWZvcm1zW3VdO1xuICAgIH1cblxuICAgIHRoaXMuYXR0cmlidXRlcyA9IHtcbiAgICAgICAgYVZlcnRleFBvc2l0aW9uOiAgICAwLFxuICAgICAgICBhVGV4dHVyZUNvb3JkOiAgICAgIDAsXG4gICAgICAgIGFDb2xvcjogICAgICAgICAgICAgMFxuICAgIH07XG5cbiAgICBmb3IgKHZhciBhIGluIGN1c3RvbUF0dHJpYnV0ZXMpIHtcbiAgICAgICAgdGhpcy5hdHRyaWJ1dGVzW2FdID0gY3VzdG9tQXR0cmlidXRlc1thXTtcbiAgICB9XG5cbiAgICB0aGlzLnRleHR1cmVDb3VudCA9IDA7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdmVydGV4IHNoYWRlci5cbiAgICAgKiBAbWVtYmVyIHtBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLnZlcnRleFNyYyA9IHZlcnRleFNyYyB8fCBbXG4gICAgICAgICdhdHRyaWJ1dGUgdmVjMiBhVmVydGV4UG9zaXRpb247JyxcbiAgICAgICAgJ2F0dHJpYnV0ZSB2ZWMyIGFUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgJ2F0dHJpYnV0ZSB2ZWM0IGFDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIHZlYzIgcHJvamVjdGlvblZlY3RvcjsnLFxuICAgICAgICAndW5pZm9ybSB2ZWMyIG9mZnNldFZlY3RvcjsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICdjb25zdCB2ZWMyIGNlbnRlciA9IHZlYzIoLTEuMCwgMS4wKTsnLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICBnbF9Qb3NpdGlvbiA9IHZlYzQoICgoYVZlcnRleFBvc2l0aW9uICsgb2Zmc2V0VmVjdG9yKSAvIHByb2plY3Rpb25WZWN0b3IpICsgY2VudGVyICwgMC4wLCAxLjApOycsXG4gICAgICAgICcgICB2VGV4dHVyZUNvb3JkID0gYVRleHR1cmVDb29yZDsnLFxuICAgICAgICAnICAgdkNvbG9yID0gdmVjNChhQ29sb3IucmdiICogYUNvbG9yLmEsIGFDb2xvci5hKTsnLFxuICAgICAgICAnfSdcbiAgICBdLmpvaW4oJ1xcbicpO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGZyYWdtZW50IHNoYWRlci5cbiAgICAgKiBAbWVtYmVyIHtBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLmZyYWdtZW50U3JjID0gZnJhZ21lbnRTcmMgfHwgW1xuICAgICAgICAncHJlY2lzaW9uIGxvd3AgZmxvYXQ7JyxcblxuICAgICAgICAndmFyeWluZyB2ZWMyIHZUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAndW5pZm9ybSBzYW1wbGVyMkQgdVNhbXBsZXI7JyxcblxuICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkKSAqIHZDb2xvciA7JyxcbiAgICAgICAgJ30nXG4gICAgXS5qb2luKCdcXG4nKTtcblxuICAgIHRoaXMuaW5pdCgpO1xufVxuXG5TaGFkZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gU2hhZGVyO1xubW9kdWxlLmV4cG9ydHMgPSBTaGFkZXI7XG5cblNoYWRlci5wcm90b3R5cGUuaW5pdCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmNvbXBpbGUoKTtcblxuICAgIHRoaXMuZ2wudXNlUHJvZ3JhbSh0aGlzLnByb2dyYW0pO1xuXG4gICAgdGhpcy5jYWNoZVVuaWZvcm1Mb2NhdGlvbnMoT2JqZWN0LmtleXModGhpcy51bmlmb3JtcykpO1xuICAgIHRoaXMuY2FjaGVBdHRyaWJ1dGVMb2NhdGlvbnMoT2JqZWN0LmtleXModGhpcy5hdHRyaWJ1dGVzKSk7XG59O1xuXG5TaGFkZXIucHJvdG90eXBlLmNhY2hlVW5pZm9ybUxvY2F0aW9ucyA9IGZ1bmN0aW9uIChrZXlzKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBrZXlzLmxlbmd0aDsgKytpKSB7XG4gICAgICAgIHRoaXMudW5pZm9ybXNba2V5c1tpXV0uX2xvY2F0aW9uID0gdGhpcy5nbC5nZXRVbmlmb3JtTG9jYXRpb24odGhpcy5wcm9ncmFtLCBrZXlzW2ldKTtcbiAgICB9XG59O1xuXG5TaGFkZXIucHJvdG90eXBlLmNhY2hlQXR0cmlidXRlTG9jYXRpb25zID0gZnVuY3Rpb24gKGtleXMpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGtleXMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgdGhpcy5hdHRyaWJ1dGVzW2tleXNbaV1dID0gdGhpcy5nbC5nZXRBdHRyaWJMb2NhdGlvbih0aGlzLnByb2dyYW0sIGtleXNbaV0pO1xuICAgIH1cblxuICAgIC8vIFRPRE86IENoZWNrIGlmIHRoaXMgaXMgbmVlZGVkIGFueW1vcmUuLi5cblxuICAgIC8vIEJlZ2luIHdvcnN0IGhhY2sgZXZhIC8vXG5cbiAgICAvLyBXSFk/Pz8gT05MWSBvbiBteSBjaHJvbWUgcGl4ZWwgdGhlIGxpbmUgYWJvdmUgcmV0dXJucyAtMSB3aGVuIHVzaW5nIGZpbHRlcnM/XG4gICAgLy8gbWF5YmUgaXRzIHNvbWV0aGluZyB0byBkbyB3aXRoIHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBnbCBjb250ZXh0LlxuICAgIC8vIEknbSBjb252aW5jZWQgdGhpcyBpcyBhIGJ1ZyBpbiB0aGUgY2hyb21lIGJyb3dzZXIgYXMgdGhlcmUgaXMgTk8gcmVhc29uIHdoeSB0aGlzIHNob3VsZCBiZSByZXR1cm5pbmcgLTEgZXNwZWNpYWxseSBhcyBpdCBvbmx5IG1hbmlmZXN0cyBvbiBteSBjaHJvbWUgcGl4ZWxcbiAgICAvLyBJZiB0aGVyZXMgYW55IHdlYkdMIHBlb3BsZSB0aGF0IGtub3cgd2h5IGNvdWxkIGhhcHBlbiBwbGVhc2UgaGVscCA6KVxuICAgIC8vIGlmICh0aGlzLmF0dHJpYnV0ZXMuYUNvbG9yID09PSAtMSkge1xuICAgIC8vICAgICB0aGlzLmF0dHJpYnV0ZXMuYUNvbG9yID0gMjtcbiAgICAvLyB9XG5cbiAgICAvLyBFbmQgd29yc3QgaGFjayBldmEgLy9cbn07XG5cblNoYWRlci5wcm90b3R5cGUuY29tcGlsZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZ2wgPSB0aGlzLmdsO1xuXG4gICAgdmFyIGdsVmVydFNoYWRlciA9IHRoaXMuX2dsQ29tcGlsZShnbC5WRVJURVhfU0hBREVSLCB0aGlzLnZlcnRleFNyYyk7XG4gICAgdmFyIGdsRnJhZ1NoYWRlciA9IHRoaXMuX2dsQ29tcGlsZShnbC5GUkFHTUVOVF9TSEFERVIsIHRoaXMuZnJhZ21lbnRTcmMpO1xuXG4gICAgdmFyIHByb2dyYW0gPSBnbC5jcmVhdGVQcm9ncmFtKCk7XG5cbiAgICBnbC5hdHRhY2hTaGFkZXIocHJvZ3JhbSwgZ2xWZXJ0U2hhZGVyKTtcbiAgICBnbC5hdHRhY2hTaGFkZXIocHJvZ3JhbSwgZ2xGcmFnU2hhZGVyKTtcbiAgICBnbC5saW5rUHJvZ3JhbShwcm9ncmFtKTtcblxuICAgIC8vIGlmIGxpbmtpbmcgZmFpbHMsIHRoZW4gbG9nIGFuZCBjbGVhbnVwXG4gICAgaWYgKCFnbC5nZXRQcm9ncmFtUGFyYW1ldGVyKHByb2dyYW0sIGdsLkxJTktfU1RBVFVTKSkge1xuICAgICAgICB3aW5kb3cuY29uc29sZS5lcnJvcignUGl4aS5qcyBFcnJvcjogQ291bGQgbm90IGluaXRpYWxpemUgc2hhZGVyLicpO1xuICAgICAgICB3aW5kb3cuY29uc29sZS5lcnJvcignZ2wuVkFMSURBVEVfU1RBVFVTJywgZ2wuZ2V0UHJvZ3JhbVBhcmFtZXRlcihwcm9ncmFtLCBnbC5WQUxJREFURV9TVEFUVVMpKTtcbiAgICAgICAgd2luZG93LmNvbnNvbGUuZXJyb3IoJ2dsLmdldEVycm9yKCknLCBnbC5nZXRFcnJvcigpKTtcblxuICAgICAgICAvLyBpZiB0aGVyZSBpcyBhIHByb2dyYW0gaW5mbyBsb2csIGxvZyBpdFxuICAgICAgICBpZiAoZ2wuZ2V0UHJvZ3JhbUluZm9Mb2cocHJvZ3JhbSkgIT09ICcnKSB7XG4gICAgICAgICAgICB3aW5kb3cuY29uc29sZS53YXJuKCdQaXhpLmpzIFdhcm5pbmc6IGdsLmdldFByb2dyYW1JbmZvTG9nKCknLCBnbC5nZXRQcm9ncmFtSW5mb0xvZyhwcm9ncmFtKSk7XG4gICAgICAgIH1cblxuICAgICAgICBnbC5kZWxldGVQcm9ncmFtKHByb2dyYW0pO1xuICAgICAgICBwcm9ncmFtID0gbnVsbDtcbiAgICB9XG5cbiAgICAvLyBjbGVhbiB1cCBzb21lIHNoYWRlcnNcbiAgICBnbC5kZWxldGVTaGFkZXIoZ2xWZXJ0U2hhZGVyKTtcbiAgICBnbC5kZWxldGVTaGFkZXIoZ2xGcmFnU2hhZGVyKTtcblxuICAgIHJldHVybiAodGhpcy5wcm9ncmFtID0gcHJvZ3JhbSk7XG59O1xuXG5TaGFkZXIucHJvdG90eXBlLnN5bmNVbmlmb3JtcyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZ2wgPSB0aGlzLmdsO1xuXG4gICAgdGhpcy50ZXh0dXJlQ291bnQgPSAxO1xuXG4gICAgZm9yICh2YXIga2V5IGluIHRoaXMudW5pZm9ybXMpIHtcbiAgICAgICAgdmFyIHVuaWZvcm0gPSB0aGlzLnVuaWZvcm1zW2tleV0sXG4gICAgICAgICAgICBsb2NhdGlvbiA9IHVuaWZvcm0uX2xvY2F0aW9uLFxuICAgICAgICAgICAgdmFsdWUgPSB1bmlmb3JtLnZhbHVlLFxuICAgICAgICAgICAgaSwgaWw7XG5cbiAgICAgICAgc3dpdGNoICh1bmlmb3JtLnR5cGUpIHtcbiAgICAgICAgICAgIGNhc2UgJ2knOlxuICAgICAgICAgICAgY2FzZSAnMWknOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0xaShsb2NhdGlvbiwgdmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICBjYXNlICdmJzpcbiAgICAgICAgICAgIGNhc2UgJzFmJzpcbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtMWYobG9jYXRpb24sIHZhbHVlKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSAnMmYnOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0yZihsb2NhdGlvbiwgdmFsdWVbMF0sIHZhbHVlWzFdKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSAnM2YnOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0zZihsb2NhdGlvbiwgdmFsdWVbMF0sIHZhbHVlWzFdLCB2YWx1ZVsyXSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIGNhc2UgJzRmJzpcbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtNGYobG9jYXRpb24sIHZhbHVlWzBdLCB2YWx1ZVsxXSwgdmFsdWVbMl0sIHZhbHVlWzNdKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgLy8gYSAyRCBQb2ludCBvYmplY3RcbiAgICAgICAgICAgIGNhc2UgJ3YyJzpcbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtMmYobG9jYXRpb24sIHZhbHVlLngsIHZhbHVlLnkpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAvLyBhIDNEIFBvaW50IG9iamVjdFxuICAgICAgICAgICAgY2FzZSAndjMnOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0zZihsb2NhdGlvbiwgdmFsdWUueCwgdmFsdWUueSwgdmFsdWUueik7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIC8vIGEgNEQgUG9pbnQgb2JqZWN0XG4gICAgICAgICAgICBjYXNlICd2NCc6XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTRmKGxvY2F0aW9uLCB2YWx1ZS54LCB2YWx1ZS55LCB2YWx1ZS56LCB2YWx1ZS53KTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSAnMWl2JzpcbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtMWl2KGxvY2F0aW9uLCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIGNhc2UgJzNpdic6XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTNpdihsb2NhdGlvbiwgdmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICBjYXNlICcxZnYnOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0xZnYobG9jYXRpb24sIHZhbHVlKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSAnMmZ2JzpcbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtMmZ2KGxvY2F0aW9uLCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIGNhc2UgJzNmdic6XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTNmdihsb2NhdGlvbiwgdmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICBjYXNlICc0ZnYnOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm00ZnYobG9jYXRpb24sIHZhbHVlKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgY2FzZSAnbTInOlxuICAgICAgICAgICAgY2FzZSAnbWF0Mic6XG4gICAgICAgICAgICBjYXNlICdNYXRyaXgyZnYnOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm1NYXRyaXgyZnYobG9jYXRpb24sIHVuaWZvcm0udHJhbnNwb3NlLCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIGNhc2UgJ20zJzpcbiAgICAgICAgICAgIGNhc2UgJ21hdDMnOlxuICAgICAgICAgICAgY2FzZSAnTWF0cml4M2Z2JzpcbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtTWF0cml4M2Z2KGxvY2F0aW9uLCB1bmlmb3JtLnRyYW5zcG9zZSwgdmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICBjYXNlICdtNCc6XG4gICAgICAgICAgICBjYXNlICdtYXQ0JzpcbiAgICAgICAgICAgIGNhc2UgJ01hdHJpeDRmdic6XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybU1hdHJpeDRmdihsb2NhdGlvbiwgdW5pZm9ybS50cmFuc3Bvc2UsIHZhbHVlKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgLy8gYSBDb2xvciBWYWx1ZVxuICAgICAgICAgICAgY2FzZSAnYyc6XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB1dGlscy5oZXgycmdiKHZhbHVlKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtM2YobG9jYXRpb24sIHZhbHVlWzBdLCB2YWx1ZVsxXSwgdmFsdWVbMl0pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAvLyBmbGF0IGFycmF5IG9mIGludGVnZXJzIChKUyBvciB0eXBlZCBhcnJheSlcbiAgICAgICAgICAgIGNhc2UgJ2l2MSc6XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTFpdihsb2NhdGlvbiwgdmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAvLyBmbGF0IGFycmF5IG9mIGludGVnZXJzIHdpdGggMyB4IE4gc2l6ZSAoSlMgb3IgdHlwZWQgYXJyYXkpXG4gICAgICAgICAgICBjYXNlICdpdic6XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTNpdihsb2NhdGlvbiwgdmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAvLyBmbGF0IGFycmF5IG9mIGZsb2F0cyAoSlMgb3IgdHlwZWQgYXJyYXkpXG4gICAgICAgICAgICBjYXNlICdmdjEnOlxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0xZnYobG9jYXRpb24sIHZhbHVlKTtcbiAgICAgICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgICAgLy8gZmxhdCBhcnJheSBvZiBmbG9hdHMgd2l0aCAzIHggTiBzaXplIChKUyBvciB0eXBlZCBhcnJheSlcbiAgICAgICAgICAgIGNhc2UgJ2Z2JzpcbiAgICAgICAgICAgICAgICBnbC51bmlmb3JtM2Z2KGxvY2F0aW9uLCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIC8vIGFycmF5IG9mIDJEIFBvaW50IG9iamVjdHNcbiAgICAgICAgICAgIGNhc2UgJ3Yydic6XG4gICAgICAgICAgICAgICAgaWYgKCF1bmlmb3JtLl9hcnJheSkge1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheSA9IG5ldyBGbG9hdDMyQXJyYXkoMiAqIHZhbHVlLmxlbmd0aCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgZm9yIChpID0gMCwgaWwgPSB2YWx1ZS5sZW5ndGg7IGkgPCBpbDsgKytpKSB7XG4gICAgICAgICAgICAgICAgICAgIHVuaWZvcm0uX2FycmF5W2kgKiAyXSAgICAgICA9IHZhbHVlW2ldLng7XG4gICAgICAgICAgICAgICAgICAgIHVuaWZvcm0uX2FycmF5W2kgKiAyICsgMV0gICA9IHZhbHVlW2ldLnk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTJmdihsb2NhdGlvbiwgdW5pZm9ybS5fYXJyYXkpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAvLyBhcnJheSBvZiAzRCBQb2ludCBvYmplY3RzXG4gICAgICAgICAgICBjYXNlICd2M3YnOlxuICAgICAgICAgICAgICAgIGlmICghdW5pZm9ybS5fYXJyYXkpIHtcbiAgICAgICAgICAgICAgICAgICAgdW5pZm9ybS5fYXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KDMgKiB2YWx1ZS5sZW5ndGgpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGZvciAoaSA9IDAsIGlsID0gdmFsdWUubGVuZ3RoOyBpIDwgaWw7ICsraSkge1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheVtpICogM10gICAgICAgPSB2YWx1ZVtpXS54O1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheVtpICogMyArIDFdICAgPSB2YWx1ZVtpXS55O1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheVtpICogMyArIDJdICAgPSB2YWx1ZVtpXS56O1xuXG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTNmdihsb2NhdGlvbiwgdW5pZm9ybS5fYXJyYXkpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICAvLyBhcnJheSBvZiA0RCBQb2ludCBvYmplY3RzXG4gICAgICAgICAgICBjYXNlICd2NHYnOlxuICAgICAgICAgICAgICAgIGlmICghdW5pZm9ybS5fYXJyYXkpIHtcbiAgICAgICAgICAgICAgICAgICAgdW5pZm9ybS5fYXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KDQgKiB2YWx1ZS5sZW5ndGgpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGZvciAoaSA9IDAsIGlsID0gdmFsdWUubGVuZ3RoOyBpIDwgaWw7ICsraSkge1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheVtpICogNF0gICAgICAgPSB2YWx1ZVtpXS54O1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheVtpICogNCArIDFdICAgPSB2YWx1ZVtpXS55O1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheVtpICogNCArIDJdICAgPSB2YWx1ZVtpXS56O1xuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9hcnJheVtpICogNCArIDNdICAgPSB2YWx1ZVtpXS53O1xuXG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTRmdihsb2NhdGlvbiwgdW5pZm9ybS5fYXJyYXkpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgICAgICBjYXNlICd0JzpcbiAgICAgICAgICAgIGNhc2UgJ3NhbXBsZXIyRCc6XG4gICAgICAgICAgICAgICAgaWYgKCF1bmlmb3JtLnZhbHVlIHx8ICF1bmlmb3JtLnZhbHVlLmJhc2VUZXh0dXJlIHx8ICF1bmlmb3JtLnZhbHVlLmJhc2VUZXh0dXJlLmhhc0xvYWRlZCkge1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBhY3RpdmF0ZSB0aGlzIHRleHR1cmVcbiAgICAgICAgICAgICAgICBnbC5hY3RpdmVUZXh0dXJlKGdsWydURVhUVVJFJyArIHRoaXMudGV4dHVyZUNvdW50XSk7XG5cbiAgICAgICAgICAgICAgICAvLyBiaW5kIHRoZSB0ZXh0dXJlXG4gICAgICAgICAgICAgICAgZ2wuYmluZFRleHR1cmUoZ2wuVEVYVFVSRV8yRCwgdW5pZm9ybS52YWx1ZS5iYXNlVGV4dHVyZS5fZ2xUZXh0dXJlc1tnbC5pZF0pO1xuXG4gICAgICAgICAgICAgICAgLy8gc2V0IHVuaWZvcm0gdG8gdGV4dHVyZSBpbmRleFxuICAgICAgICAgICAgICAgIGdsLnVuaWZvcm0xaSh1bmlmb3JtLl9sb2NhdGlvbiwgdGhpcy50ZXh0dXJlQ291bnQpO1xuXG4gICAgICAgICAgICAgICAgLy8gaW5jcmVtZW50IG5leHQgdGV4dHVyZSBpZFxuICAgICAgICAgICAgICAgIHRoaXMudGV4dHVyZUNvdW50Kys7XG5cbiAgICAgICAgICAgICAgICAvLyBpbml0aWFsaXplIHRoZSB0ZXh0dXJlIGlmIHdlIGhhdmVuJ3QgeWV0XG4gICAgICAgICAgICAgICAgaWYgKCF1bmlmb3JtLl9pbml0KSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaW5pdFNhbXBsZXIyRCh1bmlmb3JtKTtcblxuICAgICAgICAgICAgICAgICAgICB1bmlmb3JtLl9pbml0ID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgd2luZG93LmNvbnNvbGUud2FybignUGl4aS5qcyBTaGFkZXIgV2FybmluZzogVW5rbm93biB1bmlmb3JtIHR5cGU6ICcgKyB1bmlmb3JtLnR5cGUpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuXG4vKipcbiAqIEluaXRpYWxpc2VzIGEgU2FtcGxlcjJEIHVuaWZvcm0gKHdoaWNoIG1heSBvbmx5IGJlIGF2YWlsYWJsZSBsYXRlciBvbiBhZnRlciBpbml0VW5pZm9ybXMgb25jZSB0aGUgdGV4dHVyZSBoYXMgbG9hZGVkKVxuICpcbiAqL1xuU2hhZGVyLnByb3RvdHlwZS5pbml0U2FtcGxlcjJEID0gZnVuY3Rpb24gKHVuaWZvcm0pIHtcbiAgICB2YXIgZ2wgPSB0aGlzLmdsO1xuXG4gICAgLy8gIEV4dGVuZGVkIHRleHR1cmUgZGF0YVxuICAgIGlmICh1bmlmb3JtLnRleHR1cmVEYXRhKSB7XG4gICAgICAgIHZhciBkYXRhID0gdW5pZm9ybS50ZXh0dXJlRGF0YTtcblxuICAgICAgICAvLyBHTFRleHR1cmUgPSBtYWcgbGluZWFyLCBtaW4gbGluZWFyX21pcG1hcF9saW5lYXIsIHdyYXAgcmVwZWF0ICsgZ2wuZ2VuZXJhdGVNaXBtYXAoZ2wuVEVYVFVSRV8yRCk7XG4gICAgICAgIC8vIEdMVGV4dHVyZUxpbmVhciA9IG1hZy9taW4gbGluZWFyLCB3cmFwIGNsYW1wXG4gICAgICAgIC8vIEdMVGV4dHVyZU5lYXJlc3RSZXBlYXQgPSBtYWcvbWluIE5FQVJFU1QsIHdyYXAgcmVwZWF0XG4gICAgICAgIC8vIEdMVGV4dHVyZU5lYXJlc3QgPSBtYWcvbWluIG5lYXJlc3QsIHdyYXAgY2xhbXBcbiAgICAgICAgLy8gQXVkaW9UZXh0dXJlID0gd2hhdGV2ZXIgKyBsdW1pbmFuY2UgKyB3aWR0aCA1MTIsIGhlaWdodCAyLCBib3JkZXIgMFxuICAgICAgICAvLyBLZXlUZXh0dXJlID0gd2hhdGV2ZXIgKyBsdW1pbmFuY2UgKyB3aWR0aCAyNTYsIGhlaWdodCAyLCBib3JkZXIgMFxuXG4gICAgICAgIC8vICBtYWdGaWx0ZXIgY2FuIGJlOiBnbC5MSU5FQVIsIGdsLkxJTkVBUl9NSVBNQVBfTElORUFSIG9yIGdsLk5FQVJFU1RcbiAgICAgICAgLy8gIHdyYXBTL1QgY2FuIGJlOiBnbC5DTEFNUF9UT19FREdFIG9yIGdsLlJFUEVBVFxuXG4gICAgICAgIHZhciBtYWdGaWx0ZXIgPSAoZGF0YS5tYWdGaWx0ZXIpID8gZGF0YS5tYWdGaWx0ZXIgOiBnbC5MSU5FQVI7XG4gICAgICAgIHZhciBtaW5GaWx0ZXIgPSAoZGF0YS5taW5GaWx0ZXIpID8gZGF0YS5taW5GaWx0ZXIgOiBnbC5MSU5FQVI7XG4gICAgICAgIHZhciB3cmFwUyA9IChkYXRhLndyYXBTKSA/IGRhdGEud3JhcFMgOiBnbC5DTEFNUF9UT19FREdFO1xuICAgICAgICB2YXIgd3JhcFQgPSAoZGF0YS53cmFwVCkgPyBkYXRhLndyYXBUIDogZ2wuQ0xBTVBfVE9fRURHRTtcbiAgICAgICAgdmFyIGZvcm1hdCA9IChkYXRhLmx1bWluYW5jZSkgPyBnbC5MVU1JTkFOQ0UgOiBnbC5SR0JBO1xuXG4gICAgICAgIGlmIChkYXRhLnJlcGVhdCkge1xuICAgICAgICAgICAgd3JhcFMgPSBnbC5SRVBFQVQ7XG4gICAgICAgICAgICB3cmFwVCA9IGdsLlJFUEVBVDtcbiAgICAgICAgfVxuXG4gICAgICAgIGdsLnBpeGVsU3RvcmVpKGdsLlVOUEFDS19GTElQX1lfV0VCR0wsICEhZGF0YS5mbGlwWSk7XG5cbiAgICAgICAgaWYgKGRhdGEud2lkdGgpIHtcbiAgICAgICAgICAgIHZhciB3aWR0aCA9IChkYXRhLndpZHRoKSA/IGRhdGEud2lkdGggOiA1MTI7XG4gICAgICAgICAgICB2YXIgaGVpZ2h0ID0gKGRhdGEuaGVpZ2h0KSA/IGRhdGEuaGVpZ2h0IDogMjtcbiAgICAgICAgICAgIHZhciBib3JkZXIgPSAoZGF0YS5ib3JkZXIpID8gZGF0YS5ib3JkZXIgOiAwO1xuXG4gICAgICAgICAgICAvLyB2b2lkIHRleEltYWdlMkQoR0xlbnVtIHRhcmdldCwgR0xpbnQgbGV2ZWwsIEdMZW51bSBpbnRlcm5hbGZvcm1hdCwgR0xzaXplaSB3aWR0aCwgR0xzaXplaSBoZWlnaHQsIEdMaW50IGJvcmRlciwgR0xlbnVtIGZvcm1hdCwgR0xlbnVtIHR5cGUsIEFycmF5QnVmZmVyVmlldz8gcGl4ZWxzKTtcbiAgICAgICAgICAgIGdsLnRleEltYWdlMkQoZ2wuVEVYVFVSRV8yRCwgMCwgZm9ybWF0LCB3aWR0aCwgaGVpZ2h0LCBib3JkZXIsIGZvcm1hdCwgZ2wuVU5TSUdORURfQllURSwgbnVsbCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyAgdm9pZCB0ZXhJbWFnZTJEKEdMZW51bSB0YXJnZXQsIEdMaW50IGxldmVsLCBHTGVudW0gaW50ZXJuYWxmb3JtYXQsIEdMZW51bSBmb3JtYXQsIEdMZW51bSB0eXBlLCBJbWFnZURhdGE/IHBpeGVscyk7XG4gICAgICAgICAgICBnbC50ZXhJbWFnZTJEKGdsLlRFWFRVUkVfMkQsIDAsIGZvcm1hdCwgZ2wuUkdCQSwgZ2wuVU5TSUdORURfQllURSwgdW5pZm9ybS52YWx1ZS5iYXNlVGV4dHVyZS5zb3VyY2UpO1xuICAgICAgICB9XG5cbiAgICAgICAgZ2wudGV4UGFyYW1ldGVyaShnbC5URVhUVVJFXzJELCBnbC5URVhUVVJFX01BR19GSUxURVIsIG1hZ0ZpbHRlcik7XG4gICAgICAgIGdsLnRleFBhcmFtZXRlcmkoZ2wuVEVYVFVSRV8yRCwgZ2wuVEVYVFVSRV9NSU5fRklMVEVSLCBtaW5GaWx0ZXIpO1xuICAgICAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfV1JBUF9TLCB3cmFwUyk7XG4gICAgICAgIGdsLnRleFBhcmFtZXRlcmkoZ2wuVEVYVFVSRV8yRCwgZ2wuVEVYVFVSRV9XUkFQX1QsIHdyYXBUKTtcbiAgICB9XG59O1xuXG4vKipcbiAqIERlc3Ryb3lzIHRoZSBzaGFkZXIuXG4gKlxuICovXG5TaGFkZXIucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5nbC5kZWxldGVQcm9ncmFtKHRoaXMucHJvZ3JhbSk7XG5cbiAgICB0aGlzLmdsID0gbnVsbDtcbiAgICB0aGlzLnVuaWZvcm1zID0gbnVsbDtcbiAgICB0aGlzLmF0dHJpYnV0ZXMgPSBudWxsO1xuXG4gICAgdGhpcy52ZXJ0ZXhTcmMgPSBudWxsO1xuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBudWxsO1xufTtcblxuU2hhZGVyLnByb3RvdHlwZS5fZ2xDb21waWxlID0gZnVuY3Rpb24gKHR5cGUsIHNyYykge1xuICAgIHZhciBzaGFkZXIgPSB0aGlzLmdsLmNyZWF0ZVNoYWRlcih0eXBlKTtcblxuICAgIGlmIChBcnJheS5pc0FycmF5KHNyYykpIHtcbiAgICAgICAgZGVidWdnZXI7XG4gICAgfVxuXG4gICAgdGhpcy5nbC5zaGFkZXJTb3VyY2Uoc2hhZGVyLCBzcmMpO1xuICAgIHRoaXMuZ2wuY29tcGlsZVNoYWRlcihzaGFkZXIpO1xuXG4gICAgaWYgKCF0aGlzLmdsLmdldFNoYWRlclBhcmFtZXRlcihzaGFkZXIsIHRoaXMuZ2wuQ09NUElMRV9TVEFUVVMpKSB7XG4gICAgICAgIHdpbmRvdy5jb25zb2xlLmxvZyh0aGlzLmdsLmdldFNoYWRlckluZm9Mb2coc2hhZGVyKSk7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHJldHVybiBzaGFkZXI7XG59O1xuIiwidmFyIFNoYWRlciA9IHJlcXVpcmUoJy4vU2hhZGVyJyk7XG5cbi8qKlxuICogQGNsYXNzXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSBnbCB7V2ViR0xDb250ZXh0fSB0aGUgY3VycmVudCBXZWJHTCBkcmF3aW5nIGNvbnRleHRcbiAqL1xuZnVuY3Rpb24gU3RyaXBTaGFkZXIoZ2wpIHtcbiAgICBTaGFkZXIuY2FsbCh0aGlzLFxuICAgICAgICBnbCxcbiAgICAgICAgLy8gdmVydGV4IHNoYWRlclxuICAgICAgICBbXG4gICAgICAgICAgICAnYXR0cmlidXRlIHZlYzIgYVZlcnRleFBvc2l0aW9uOycsXG4gICAgICAgICAgICAnYXR0cmlidXRlIHZlYzIgYVRleHR1cmVDb29yZDsnLFxuICAgICAgICAgICAgLy8gJ2F0dHJpYnV0ZSB2ZWM0IGFDb2xvcjsnLFxuXG4gICAgICAgICAgICAndW5pZm9ybSBtYXQzIHRyYW5zbGF0aW9uTWF0cml4OycsXG4gICAgICAgICAgICAndW5pZm9ybSB2ZWMyIHByb2plY3Rpb25WZWN0b3I7JyxcbiAgICAgICAgICAgICd1bmlmb3JtIHZlYzIgb2Zmc2V0VmVjdG9yOycsXG5cbiAgICAgICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuXG4gICAgICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAgICAgJyAgIHZlYzMgdiA9IHRyYW5zbGF0aW9uTWF0cml4ICogdmVjMyhhVmVydGV4UG9zaXRpb24gLCAxLjApOycsXG4gICAgICAgICAgICAnICAgdiAtPSBvZmZzZXRWZWN0b3IueHl4OycsXG4gICAgICAgICAgICAnICAgZ2xfUG9zaXRpb24gPSB2ZWM0KCB2LnggLyBwcm9qZWN0aW9uVmVjdG9yLnggLTEuMCwgdi55IC8gLXByb2plY3Rpb25WZWN0b3IueSArIDEuMCAsIDAuMCwgMS4wKTsnLFxuICAgICAgICAgICAgJyAgIHZUZXh0dXJlQ29vcmQgPSBhVGV4dHVyZUNvb3JkOycsXG4gICAgICAgICAgICAnfSdcbiAgICAgICAgXS5qb2luKCdcXG4nKSxcbiAgICAgICAgLy8gZnJhZ21lbnQgc2hhZGVyXG4gICAgICAgIFtcbiAgICAgICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICAgICAndW5pZm9ybSBmbG9hdCBhbHBoYTsnLFxuICAgICAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG5cbiAgICAgICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuXG4gICAgICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAgICAgJyAgIGdsX0ZyYWdDb2xvciA9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLngsIHZUZXh0dXJlQ29vcmQueSkpICogYWxwaGE7JyxcbiAgICAgICAgICAgICd9J1xuICAgICAgICBdLmpvaW4oJ1xcbicpLFxuICAgICAgICAvLyBjdXN0b20gdW5pZm9ybXNcbiAgICAgICAge1xuICAgICAgICAgICAgYWxwaGE6ICB7IHR5cGU6ICcxZicsIHZhbHVlOiAwIH0sXG4gICAgICAgICAgICB0cmFuc2xhdGlvbk1hdHJpeDogeyB0eXBlOiAnbWF0MycsIHZhbHVlOiBuZXcgRmxvYXQzMkFycmF5KDkpIH1cbiAgICAgICAgfVxuICAgICk7XG59XG5cblN0cmlwU2hhZGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoU2hhZGVyLnByb3RvdHlwZSk7XG5TdHJpcFNoYWRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBTdHJpcFNoYWRlcjtcbm1vZHVsZS5leHBvcnRzID0gU3RyaXBTaGFkZXI7XG4iLCJ2YXIgQ09OU1QgPSByZXF1aXJlKCcuLi8uLi8uLi9jb25zdCcpO1xuXG4vKipcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gZ2wge1dlYkdMQ29udGV4dH0gdGhlIGN1cnJlbnQgV2ViR0wgZHJhd2luZyBjb250ZXh0XG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gdGhlIGhvcml6b250YWwgcmFuZ2Ugb2YgdGhlIGZpbHRlclxuICogQHBhcmFtIGhlaWdodCB7bnVtYmVyfSB0aGUgdmVydGljYWwgcmFuZ2Ugb2YgdGhlIGZpbHRlclxuICogQHBhcmFtIHNjYWxlTW9kZSB7bnVtYmVyfSBTZWUge3sjY3Jvc3NMaW5rIFwiUElYSS9zY2FsZU1vZGVzOnByb3BlcnR5XCJ9fXNjYWxlTW9kZXN7ey9jcm9zc0xpbmt9fSBmb3IgcG9zc2libGUgdmFsdWVzXG4gKi9cbmZ1bmN0aW9uIEZpbHRlclRleHR1cmUoZ2wsIHdpZHRoLCBoZWlnaHQsIHNjYWxlTW9kZSkge1xuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge1dlYkdMQ29udGV4dH1cbiAgICAgKi9cbiAgICB0aGlzLmdsID0gZ2w7XG5cbiAgICAvLyBuZXh0IHRpbWUgdG8gY3JlYXRlIGEgZnJhbWUgYnVmZmVyIGFuZCB0ZXh0dXJlXG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtBbnl9XG4gICAgICovXG4gICAgdGhpcy5mcmFtZUJ1ZmZlciA9IGdsLmNyZWF0ZUZyYW1lYnVmZmVyKCk7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtBbnl9XG4gICAgICovXG4gICAgdGhpcy50ZXh0dXJlID0gZ2wuY3JlYXRlVGV4dHVyZSgpO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHNjYWxlTW9kZSA9IHNjYWxlTW9kZSB8fCBDT05TVC5zY2FsZU1vZGVzLkRFRkFVTFQ7XG5cbiAgICBnbC5iaW5kVGV4dHVyZShnbC5URVhUVVJFXzJELCAgdGhpcy50ZXh0dXJlKTtcbiAgICBnbC50ZXhQYXJhbWV0ZXJpKGdsLlRFWFRVUkVfMkQsIGdsLlRFWFRVUkVfTUFHX0ZJTFRFUiwgc2NhbGVNb2RlID09PSBDT05TVC5zY2FsZU1vZGVzLkxJTkVBUiA/IGdsLkxJTkVBUiA6IGdsLk5FQVJFU1QpO1xuICAgIGdsLnRleFBhcmFtZXRlcmkoZ2wuVEVYVFVSRV8yRCwgZ2wuVEVYVFVSRV9NSU5fRklMVEVSLCBzY2FsZU1vZGUgPT09IENPTlNULnNjYWxlTW9kZXMuTElORUFSID8gZ2wuTElORUFSIDogZ2wuTkVBUkVTVCk7XG4gICAgZ2wudGV4UGFyYW1ldGVyaShnbC5URVhUVVJFXzJELCBnbC5URVhUVVJFX1dSQVBfUywgZ2wuQ0xBTVBfVE9fRURHRSk7XG4gICAgZ2wudGV4UGFyYW1ldGVyaShnbC5URVhUVVJFXzJELCBnbC5URVhUVVJFX1dSQVBfVCwgZ2wuQ0xBTVBfVE9fRURHRSk7XG4gICAgZ2wuYmluZEZyYW1lYnVmZmVyKGdsLkZSQU1FQlVGRkVSLCB0aGlzLmZyYW1lQnVmZmVyICk7XG5cbiAgICBnbC5iaW5kRnJhbWVidWZmZXIoZ2wuRlJBTUVCVUZGRVIsIHRoaXMuZnJhbWVCdWZmZXIgKTtcbiAgICBnbC5mcmFtZWJ1ZmZlclRleHR1cmUyRChnbC5GUkFNRUJVRkZFUiwgZ2wuQ09MT1JfQVRUQUNITUVOVDAsIGdsLlRFWFRVUkVfMkQsIHRoaXMudGV4dHVyZSwgMCk7XG5cbiAgICAvLyByZXF1aXJlZCBmb3IgbWFza2luZyBhIG1hc2s/P1xuICAgIHRoaXMucmVuZGVyQnVmZmVyID0gZ2wuY3JlYXRlUmVuZGVyYnVmZmVyKCk7XG4gICAgZ2wuYmluZFJlbmRlcmJ1ZmZlcihnbC5SRU5ERVJCVUZGRVIsIHRoaXMucmVuZGVyQnVmZmVyKTtcbiAgICBnbC5mcmFtZWJ1ZmZlclJlbmRlcmJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgZ2wuREVQVEhfU1RFTkNJTF9BVFRBQ0hNRU5ULCBnbC5SRU5ERVJCVUZGRVIsIHRoaXMucmVuZGVyQnVmZmVyKTtcblxuICAgIC8vIHJlc2V0IHJlbmRlciBidWZmZXJcbiAgICBnbC5iaW5kUmVuZGVyYnVmZmVyKGdsLlJFTkRFUkJVRkZFUiwgbnVsbCk7XG5cbiAgICB0aGlzLnJlc2l6ZSh3aWR0aCwgaGVpZ2h0KTtcbn1cblxuRmlsdGVyVGV4dHVyZS5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBGaWx0ZXJUZXh0dXJlO1xubW9kdWxlLmV4cG9ydHMgPSBGaWx0ZXJUZXh0dXJlO1xuXG4vKipcbiAqIENsZWFycyB0aGUgZmlsdGVyIHRleHR1cmUuXG4gKlxuICovXG5GaWx0ZXJUZXh0dXJlLnByb3RvdHlwZS5jbGVhciA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZ2wgPSB0aGlzLmdsO1xuXG4gICAgZ2wuY2xlYXJDb2xvcigwLDAsMCwgMCk7XG4gICAgZ2wuY2xlYXIoZ2wuQ09MT1JfQlVGRkVSX0JJVCk7XG59O1xuXG4vKipcbiAqIFJlc2l6ZXMgdGhlIHRleHR1cmUgdG8gdGhlIHNwZWNpZmllZCB3aWR0aCBhbmQgaGVpZ2h0XG4gKlxuICogQHBhcmFtIHdpZHRoIHtudW1iZXJ9IHRoZSBuZXcgd2lkdGggb2YgdGhlIHRleHR1cmVcbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gdGhlIG5ldyBoZWlnaHQgb2YgdGhlIHRleHR1cmVcbiAqL1xuRmlsdGVyVGV4dHVyZS5wcm90b3R5cGUucmVzaXplID0gZnVuY3Rpb24gKHdpZHRoLCBoZWlnaHQpIHtcbiAgICBpZiAodGhpcy53aWR0aCA9PT0gd2lkdGggJiYgdGhpcy5oZWlnaHQgPT09IGhlaWdodCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy53aWR0aCA9IHdpZHRoO1xuICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xuXG4gICAgdmFyIGdsID0gdGhpcy5nbDtcblxuICAgIGdsLmJpbmRUZXh0dXJlKGdsLlRFWFRVUkVfMkQsICB0aGlzLnRleHR1cmUpO1xuICAgIGdsLnRleEltYWdlMkQoZ2wuVEVYVFVSRV8yRCwgMCwgZ2wuUkdCQSwgIHdpZHRoICwgaGVpZ2h0ICwgMCwgZ2wuUkdCQSwgZ2wuVU5TSUdORURfQllURSwgbnVsbCk7XG4gICAgLy8gdXBkYXRlIHRoZSBzdGVuY2lsIGJ1ZmZlciB3aWR0aCBhbmQgaGVpZ2h0XG4gICAgZ2wuYmluZFJlbmRlcmJ1ZmZlcihnbC5SRU5ERVJCVUZGRVIsIHRoaXMucmVuZGVyQnVmZmVyKTtcbiAgICBnbC5yZW5kZXJidWZmZXJTdG9yYWdlKGdsLlJFTkRFUkJVRkZFUiwgZ2wuREVQVEhfU1RFTkNJTCwgd2lkdGggLCBoZWlnaHQpO1xuXG4gICAgLy8gcmVzZXQgcmVuZGVyIGJ1ZmZlclxuICAgIGdsLmJpbmRSZW5kZXJidWZmZXIoZ2wuUkVOREVSQlVGRkVSLCBudWxsKTtcbn07XG5cbi8qKlxuICogRGVzdHJveXMgdGhlIGZpbHRlciB0ZXh0dXJlLlxuICpcbiAqL1xuRmlsdGVyVGV4dHVyZS5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZ2wgPSB0aGlzLmdsO1xuICAgIGdsLmRlbGV0ZUZyYW1lYnVmZmVyKCB0aGlzLmZyYW1lQnVmZmVyICk7XG4gICAgZ2wuZGVsZXRlVGV4dHVyZSggdGhpcy50ZXh0dXJlICk7XG5cbiAgICB0aGlzLmZyYW1lQnVmZmVyID0gbnVsbDtcbiAgICB0aGlzLnRleHR1cmUgPSBudWxsO1xufTtcbiIsIi8qKlxuICogQGF1dGhvciBNYXQgR3JvdmVzXG4gKlxuICogQmlnIHRoYW5rcyB0byB0aGUgdmVyeSBjbGV2ZXIgTWF0dCBEZXNMYXVyaWVycyA8bWF0dGRlc2w+IGh0dHBzOi8vZ2l0aHViLmNvbS9tYXR0ZGVzbC9cbiAqIGZvciBjcmVhdGluZyB0aGUgb3JpZ2luYWwgcGl4aSB2ZXJzaW9uIVxuICpcbiAqIEhlYXZpbHkgaW5zcGlyZWQgYnkgTGliR0RYJ3MgV2ViR0xTcHJpdGVCYXRjaDpcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9saWJnZHgvbGliZ2R4L2Jsb2IvbWFzdGVyL2dkeC9zcmMvY29tL2JhZGxvZ2ljL2dkeC9ncmFwaGljcy9nMmQvV2ViR0xTcHJpdGVCYXRjaC5qYXZhXG4gKi9cblxuLyoqXG4gKiBAY2xhc3NcbiAqIEBwcml2YXRlXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcn0gVGhlIHJlbmRlcmVyIHRoaXMgc3ByaXRlIGJhdGNoIHdvcmtzIGZvci5cbiAqL1xuZnVuY3Rpb24gV2ViR0xGYXN0U3ByaXRlQmF0Y2gocmVuZGVyZXIpIHtcbiAgICAvKipcbiAgICAgKiBUaGUgcmVuZGVyZXIgaW5zdGFuY2UgdGhpcyBzcHJpdGUgYmF0Y2ggb3BlcmF0ZXMgb24uXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtXZWJHTFJlbmRlcmVyfVxuICAgICAqL1xuICAgIHRoaXMucmVuZGVyZXIgPSByZW5kZXJlcjtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy52ZXJ0U2l6ZSA9IDEwO1xuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLm1heFNpemUgPSA2MDAwOy8vTWF0aC5wb3coMiwgMTYpIC8gIHRoaXMudmVydFNpemU7XG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMuc2l6ZSA9IHRoaXMubWF4U2l6ZTtcblxuICAgIC8vdGhlIHRvdGFsIG51bWJlciBvZiBmbG9hdHMgaW4gb3VyIGJhdGNoXG4gICAgdmFyIG51bVZlcnRzID0gdGhpcy5zaXplICogNCAqICB0aGlzLnZlcnRTaXplO1xuXG4gICAgLy90aGUgdG90YWwgbnVtYmVyIG9mIGluZGljZXMgaW4gb3VyIGJhdGNoXG4gICAgdmFyIG51bUluZGljZXMgPSB0aGlzLm1heFNpemUgKiA2O1xuXG4gICAgLyoqXG4gICAgICogVmVydGV4IGRhdGFcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0Zsb2F0MzJBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLnZlcnRpY2VzID0gbmV3IEZsb2F0MzJBcnJheShudW1WZXJ0cyk7XG5cbiAgICAvKipcbiAgICAgKiBJbmRleCBkYXRhXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtVaW50MTZBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLmluZGljZXMgPSBuZXcgVWludDE2QXJyYXkobnVtSW5kaWNlcyk7XG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqXG4gICAgICogQG1lbWJlciB7b2JqZWN0fVxuICAgICAqL1xuICAgIHRoaXMudmVydGV4QnVmZmVyID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtvYmplY3R9XG4gICAgICovXG4gICAgdGhpcy5pbmRleEJ1ZmZlciA9IG51bGw7XG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMubGFzdEluZGV4Q291bnQgPSAwO1xuXG4gICAgZm9yICh2YXIgaT0wLCBqPTA7IGkgPCBudW1JbmRpY2VzOyBpICs9IDYsIGogKz0gNCkge1xuICAgICAgICB0aGlzLmluZGljZXNbaSArIDBdID0gaiArIDA7XG4gICAgICAgIHRoaXMuaW5kaWNlc1tpICsgMV0gPSBqICsgMTtcbiAgICAgICAgdGhpcy5pbmRpY2VzW2kgKyAyXSA9IGogKyAyO1xuICAgICAgICB0aGlzLmluZGljZXNbaSArIDNdID0gaiArIDA7XG4gICAgICAgIHRoaXMuaW5kaWNlc1tpICsgNF0gPSBqICsgMjtcbiAgICAgICAgdGhpcy5pbmRpY2VzW2kgKyA1XSA9IGogKyAzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMuZHJhd2luZyA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLmN1cnJlbnRCYXRjaFNpemUgPSAwO1xuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0Jhc2VUZXh0dXJlfVxuICAgICAqL1xuICAgIHRoaXMuY3VycmVudEJhc2VUZXh0dXJlID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5jdXJyZW50QmxlbmRNb2RlID0gMDtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtvYmplY3R9XG4gICAgICovXG4gICAgdGhpcy5zaGFkZXIgPSBudWxsO1xuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge01hdHJpeH1cbiAgICAgKi9cbiAgICB0aGlzLm1hdHJpeCA9IG51bGw7XG5cbiAgICAvLyBsaXN0ZW4gZm9yIGNvbnRleHQgYW5kIHVwZGF0ZSBuZWNlc3NhcnkgYnVmZmVyc1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB0aGlzLnJlbmRlcmVyLm9uKCdjb250ZXh0JywgZnVuY3Rpb24gKCkge1xuICAgICAgICBzZWxmLnNldHVwQ29udGV4dCgpO1xuICAgIH0pO1xufVxuXG5XZWJHTEZhc3RTcHJpdGVCYXRjaC5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBXZWJHTEZhc3RTcHJpdGVCYXRjaDtcbm1vZHVsZS5leHBvcnRzID0gV2ViR0xGYXN0U3ByaXRlQmF0Y2g7XG5cbi8qKlxuICogU2V0cyB0aGUgV2ViR0wgQ29udGV4dC5cbiAqXG4gKiBAcGFyYW0gZ2wge1dlYkdMQ29udGV4dH0gdGhlIGN1cnJlbnQgV2ViR0wgZHJhd2luZyBjb250ZXh0XG4gKi9cbldlYkdMRmFzdFNwcml0ZUJhdGNoLnByb3RvdHlwZS5zZXR1cENvbnRleHQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGdsID0gdGhpcy5yZW5kZXJlci5nbDtcblxuICAgIC8vIGNyZWF0ZSBhIGNvdXBsZSBvZiBidWZmZXJzXG4gICAgdGhpcy52ZXJ0ZXhCdWZmZXIgPSBnbC5jcmVhdGVCdWZmZXIoKTtcbiAgICB0aGlzLmluZGV4QnVmZmVyID0gZ2wuY3JlYXRlQnVmZmVyKCk7XG5cbiAgICAvLyA2NTUzNSBpcyBtYXggaW5kZXgsIHNvIDY1NTM1IC8gNiA9IDEwOTIyLlxuXG4gICAgLy91cGxvYWQgdGhlIGluZGV4IGRhdGFcbiAgICBnbC5iaW5kQnVmZmVyKGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCB0aGlzLmluZGV4QnVmZmVyKTtcbiAgICBnbC5idWZmZXJEYXRhKGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCB0aGlzLmluZGljZXMsIGdsLlNUQVRJQ19EUkFXKTtcblxuICAgIGdsLmJpbmRCdWZmZXIoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLnZlcnRleEJ1ZmZlcik7XG4gICAgZ2wuYnVmZmVyRGF0YShnbC5BUlJBWV9CVUZGRVIsIHRoaXMudmVydGljZXMsIGdsLkRZTkFNSUNfRFJBVyk7XG59O1xuXG4vKipcbiAqIEBwYXJhbSBzcHJpdGVCYXRjaCB7U3ByaXRlQmF0Y2h9IFRoZSBTcHJpdGVCYXRjaCBjb250YWluZXIgdG8gcHJlcGFyZSBmb3IuXG4gKi9cbldlYkdMRmFzdFNwcml0ZUJhdGNoLnByb3RvdHlwZS5iZWdpbiA9IGZ1bmN0aW9uIChzcHJpdGVCYXRjaCkge1xuICAgIHRoaXMuc2hhZGVyID0gdGhpcy5yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLmZhc3RTaGFkZXI7XG5cbiAgICB0aGlzLm1hdHJpeCA9IHNwcml0ZUJhdGNoLndvcmxkVHJhbnNmb3JtLnRvQXJyYXkodHJ1ZSk7XG5cbiAgICB0aGlzLnN0YXJ0KCk7XG59O1xuXG4vKipcbiAqL1xuV2ViR0xGYXN0U3ByaXRlQmF0Y2gucHJvdG90eXBlLmVuZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmZsdXNoKCk7XG59O1xuXG4vKipcbiAqIEBwYXJhbSBzcHJpdGVCYXRjaCB7U3ByaXRlQmF0Y2h9IFRoZSBTcHJpdGVCYXRjaCBjb250YWluZXIgdG8gcmVuZGVyLlxuICovXG5XZWJHTEZhc3RTcHJpdGVCYXRjaC5wcm90b3R5cGUucmVuZGVyID0gZnVuY3Rpb24gKHNwcml0ZUJhdGNoKSB7XG4gICAgdmFyIGNoaWxkcmVuID0gc3ByaXRlQmF0Y2guY2hpbGRyZW47XG4gICAgdmFyIHNwcml0ZSA9IGNoaWxkcmVuWzBdO1xuXG4gICAgLy8gaWYgdGhlIHV2cyBoYXZlIG5vdCB1cGRhdGVkIHRoZW4gbm8gcG9pbnQgcmVuZGVyaW5nIGp1c3QgeWV0IVxuXG4gICAgLy8gY2hlY2sgdGV4dHVyZS5cbiAgICBpZiAoIXNwcml0ZS50ZXh0dXJlLl91dnMpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuY3VycmVudEJhc2VUZXh0dXJlID0gc3ByaXRlLnRleHR1cmUuYmFzZVRleHR1cmU7XG5cbiAgICAvLyBjaGVjayBibGVuZCBtb2RlXG4gICAgaWYgKHNwcml0ZS5ibGVuZE1vZGUgIT09IHRoaXMucmVuZGVyZXIuYmxlbmRNb2RlTWFuYWdlci5jdXJyZW50QmxlbmRNb2RlKSB7XG4gICAgICAgIHRoaXMuZmx1c2goKTtcbiAgICAgICAgdGhpcy5yZW5kZXJlci5ibGVuZE1vZGVNYW5hZ2VyLnNldEJsZW5kTW9kZShzcHJpdGUuYmxlbmRNb2RlKTtcbiAgICB9XG5cbiAgICBmb3IgKHZhciBpPTAsaj0gY2hpbGRyZW4ubGVuZ3RoOyBpPGo7IGkrKykge1xuICAgICAgICB0aGlzLnJlbmRlclNwcml0ZShjaGlsZHJlbltpXSk7XG4gICAgfVxuXG4gICAgdGhpcy5mbHVzaCgpO1xufTtcblxuLyoqXG4gKiBAcGFyYW0gc3ByaXRlIHtTcHJpdGV9IFRoZSBTcHJpdGUgdG8gcmVuZGVyLlxuICovXG5XZWJHTEZhc3RTcHJpdGVCYXRjaC5wcm90b3R5cGUucmVuZGVyU3ByaXRlID0gZnVuY3Rpb24gKHNwcml0ZSkge1xuICAgIC8vc3ByaXRlID0gY2hpbGRyZW5baV07XG4gICAgaWYgKCFzcHJpdGUudmlzaWJsZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gVE9ETyB0cmltPz9cbiAgICBpZiAoc3ByaXRlLnRleHR1cmUuYmFzZVRleHR1cmUgIT09IHRoaXMuY3VycmVudEJhc2VUZXh0dXJlKSB7XG4gICAgICAgIHRoaXMuZmx1c2goKTtcbiAgICAgICAgdGhpcy5jdXJyZW50QmFzZVRleHR1cmUgPSBzcHJpdGUudGV4dHVyZS5iYXNlVGV4dHVyZTtcblxuICAgICAgICBpZiAoIXNwcml0ZS50ZXh0dXJlLl91dnMpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHZhciB1dnMsIHZlcnRpY2VzID0gdGhpcy52ZXJ0aWNlcywgd2lkdGgsIGhlaWdodCwgdzAsIHcxLCBoMCwgaDEsIGluZGV4O1xuXG4gICAgdXZzID0gc3ByaXRlLnRleHR1cmUuX3V2cztcblxuICAgIHdpZHRoID0gc3ByaXRlLnRleHR1cmUuZnJhbWUud2lkdGg7XG4gICAgaGVpZ2h0ID0gc3ByaXRlLnRleHR1cmUuZnJhbWUuaGVpZ2h0O1xuXG4gICAgaWYgKHNwcml0ZS50ZXh0dXJlLnRyaW0pIHtcbiAgICAgICAgLy8gaWYgdGhlIHNwcml0ZSBpcyB0cmltbWVkIHRoZW4gd2UgbmVlZCB0byBhZGQgdGhlIGV4dHJhIHNwYWNlIGJlZm9yZSB0cmFuc2Zvcm1pbmcgdGhlIHNwcml0ZSBjb29yZHMuLlxuICAgICAgICB2YXIgdHJpbSA9IHNwcml0ZS50ZXh0dXJlLnRyaW07XG5cbiAgICAgICAgdzEgPSB0cmltLnggLSBzcHJpdGUuYW5jaG9yLnggKiB0cmltLndpZHRoO1xuICAgICAgICB3MCA9IHcxICsgc3ByaXRlLnRleHR1cmUuY3JvcC53aWR0aDtcblxuICAgICAgICBoMSA9IHRyaW0ueSAtIHNwcml0ZS5hbmNob3IueSAqIHRyaW0uaGVpZ2h0O1xuICAgICAgICBoMCA9IGgxICsgc3ByaXRlLnRleHR1cmUuY3JvcC5oZWlnaHQ7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB3MCA9IChzcHJpdGUudGV4dHVyZS5mcmFtZS53aWR0aCApICogKDEtc3ByaXRlLmFuY2hvci54KTtcbiAgICAgICAgdzEgPSAoc3ByaXRlLnRleHR1cmUuZnJhbWUud2lkdGggKSAqIC1zcHJpdGUuYW5jaG9yLng7XG5cbiAgICAgICAgaDAgPSBzcHJpdGUudGV4dHVyZS5mcmFtZS5oZWlnaHQgKiAoMS1zcHJpdGUuYW5jaG9yLnkpO1xuICAgICAgICBoMSA9IHNwcml0ZS50ZXh0dXJlLmZyYW1lLmhlaWdodCAqIC1zcHJpdGUuYW5jaG9yLnk7XG4gICAgfVxuXG4gICAgaW5kZXggPSB0aGlzLmN1cnJlbnRCYXRjaFNpemUgKiA0ICogdGhpcy52ZXJ0U2l6ZTtcblxuICAgIC8vIHh5XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB3MTtcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IGgxO1xuXG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUucG9zaXRpb24ueDtcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5wb3NpdGlvbi55O1xuXG4gICAgLy9zY2FsZVxuICAgIHZlcnRpY2VzW2luZGV4KytdID0gc3ByaXRlLnNjYWxlLng7XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUuc2NhbGUueTtcblxuICAgIC8vcm90YXRpb25cbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5yb3RhdGlvbjtcblxuICAgIC8vIHV2XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB1dnMueDA7XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB1dnMueTE7XG4gICAgLy8gY29sb3JcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5hbHBoYTtcblxuXG4gICAgLy8geHlcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHcwO1xuICAgIHZlcnRpY2VzW2luZGV4KytdID0gaDE7XG5cbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5wb3NpdGlvbi54O1xuICAgIHZlcnRpY2VzW2luZGV4KytdID0gc3ByaXRlLnBvc2l0aW9uLnk7XG5cbiAgICAvL3NjYWxlXG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUuc2NhbGUueDtcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5zY2FsZS55O1xuXG4gICAgIC8vcm90YXRpb25cbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5yb3RhdGlvbjtcblxuICAgIC8vIHV2XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB1dnMueDE7XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB1dnMueTE7XG4gICAgLy8gY29sb3JcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5hbHBoYTtcblxuXG4gICAgLy8geHlcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHcwO1xuICAgIHZlcnRpY2VzW2luZGV4KytdID0gaDA7XG5cbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5wb3NpdGlvbi54O1xuICAgIHZlcnRpY2VzW2luZGV4KytdID0gc3ByaXRlLnBvc2l0aW9uLnk7XG5cbiAgICAvL3NjYWxlXG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUuc2NhbGUueDtcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5zY2FsZS55O1xuXG4gICAgIC8vcm90YXRpb25cbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5yb3RhdGlvbjtcblxuICAgIC8vIHV2XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB1dnMueDI7XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB1dnMueTI7XG4gICAgLy8gY29sb3JcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5hbHBoYTtcblxuXG5cblxuICAgIC8vIHh5XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSB3MTtcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IGgwO1xuXG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUucG9zaXRpb24ueDtcbiAgICB2ZXJ0aWNlc1tpbmRleCsrXSA9IHNwcml0ZS5wb3NpdGlvbi55O1xuXG4gICAgLy9zY2FsZVxuICAgIHZlcnRpY2VzW2luZGV4KytdID0gc3ByaXRlLnNjYWxlLng7XG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUuc2NhbGUueTtcblxuICAgICAvL3JvdGF0aW9uXG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUucm90YXRpb247XG5cbiAgICAvLyB1dlxuICAgIHZlcnRpY2VzW2luZGV4KytdID0gdXZzLngzO1xuICAgIHZlcnRpY2VzW2luZGV4KytdID0gdXZzLnkzO1xuICAgIC8vIGNvbG9yXG4gICAgdmVydGljZXNbaW5kZXgrK10gPSBzcHJpdGUuYWxwaGE7XG5cbiAgICAvLyBpbmNyZW1lbnQgdGhlIGJhdGNoc1xuICAgIHRoaXMuY3VycmVudEJhdGNoU2l6ZSsrO1xuXG4gICAgaWYgKHRoaXMuY3VycmVudEJhdGNoU2l6ZSA+PSB0aGlzLnNpemUpIHtcbiAgICAgICAgdGhpcy5mbHVzaCgpO1xuICAgIH1cbn07XG5cbi8qKlxuICpcbiAqL1xuV2ViR0xGYXN0U3ByaXRlQmF0Y2gucHJvdG90eXBlLmZsdXNoID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIElmIHRoZSBiYXRjaCBpcyBsZW5ndGggMCB0aGVuIHJldHVybiBhcyB0aGVyZSBpcyBub3RoaW5nIHRvIGRyYXdcbiAgICBpZiAodGhpcy5jdXJyZW50QmF0Y2hTaXplID09PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuXG4gICAgLy8gYmluZCB0aGUgY3VycmVudCB0ZXh0dXJlXG4gICAgaWYgKCF0aGlzLmN1cnJlbnRCYXNlVGV4dHVyZS5fZ2xUZXh0dXJlc1tnbC5pZF0pIHtcbiAgICAgICAgdGhpcy5yZW5kZXJlci51cGRhdGVUZXh0dXJlKHRoaXMuY3VycmVudEJhc2VUZXh0dXJlLCBnbCk7XG4gICAgfVxuICAgIC8vVE9ETy1TSE9VRCBUSElTIEJFIEVMU0U/PyE/IT8hXG4gICAgZWxzZSB7XG4gICAgICAgIGdsLmJpbmRUZXh0dXJlKGdsLlRFWFRVUkVfMkQsIHRoaXMuY3VycmVudEJhc2VUZXh0dXJlLl9nbFRleHR1cmVzW2dsLmlkXSk7XG4gICAgfVxuXG4gICAgLy8gdXBsb2FkIHRoZSB2ZXJ0cyB0byB0aGUgYnVmZmVyXG5cbiAgICBpZiAodGhpcy5jdXJyZW50QmF0Y2hTaXplID4gKCB0aGlzLnNpemUgKiAwLjUgKSApIHtcbiAgICAgICAgZ2wuYnVmZmVyU3ViRGF0YShnbC5BUlJBWV9CVUZGRVIsIDAsIHRoaXMudmVydGljZXMpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdmFyIHZpZXcgPSB0aGlzLnZlcnRpY2VzLnN1YmFycmF5KDAsIHRoaXMuY3VycmVudEJhdGNoU2l6ZSAqIDQgKiB0aGlzLnZlcnRTaXplKTtcblxuICAgICAgICBnbC5idWZmZXJTdWJEYXRhKGdsLkFSUkFZX0JVRkZFUiwgMCwgdmlldyk7XG4gICAgfVxuXG4gICAgLy8gbm93IGRyYXcgdGhvc2Ugc3Vja2FzIVxuICAgIGdsLmRyYXdFbGVtZW50cyhnbC5UUklBTkdMRVMsIHRoaXMuY3VycmVudEJhdGNoU2l6ZSAqIDYsIGdsLlVOU0lHTkVEX1NIT1JULCAwKTtcblxuICAgIC8vIHRoZW4gcmVzZXQgdGhlIGJhdGNoIVxuICAgIHRoaXMuY3VycmVudEJhdGNoU2l6ZSA9IDA7XG5cbiAgICAvLyBpbmNyZW1lbnQgdGhlIGRyYXcgY291bnRcbiAgICB0aGlzLnJlbmRlcmVyLmRyYXdDb3VudCsrO1xufTtcblxuXG4vKipcbiAqIEVuZHMgdGhlIGJhdGNoIGFuZCBmbHVzaGVzXG4gKlxuICovXG5XZWJHTEZhc3RTcHJpdGVCYXRjaC5wcm90b3R5cGUuc3RvcCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmZsdXNoKCk7XG59O1xuXG4vKipcbiAqXG4gKi9cbldlYkdMRmFzdFNwcml0ZUJhdGNoLnByb3RvdHlwZS5zdGFydCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuXG4gICAgLy8gYmluZCB0aGUgbWFpbiB0ZXh0dXJlXG4gICAgZ2wuYWN0aXZlVGV4dHVyZShnbC5URVhUVVJFMCk7XG5cbiAgICAvLyBiaW5kIHRoZSBidWZmZXJzXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMudmVydGV4QnVmZmVyKTtcbiAgICBnbC5iaW5kQnVmZmVyKGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCB0aGlzLmluZGV4QnVmZmVyKTtcblxuICAgIC8vIHNldCB0aGUgcHJvamVjdGlvblxuICAgIHZhciBwcm9qZWN0aW9uID0gdGhpcy5yZW5kZXJlci5wcm9qZWN0aW9uO1xuICAgIGdsLnVuaWZvcm0yZih0aGlzLnNoYWRlci5wcm9qZWN0aW9uVmVjdG9yLCBwcm9qZWN0aW9uLngsIHByb2plY3Rpb24ueSk7XG5cbiAgICAvLyBzZXQgdGhlIG1hdHJpeFxuICAgIGdsLnVuaWZvcm1NYXRyaXgzZnYodGhpcy5zaGFkZXIudU1hdHJpeCwgZmFsc2UsIHRoaXMubWF0cml4KTtcblxuICAgIC8vIHNldCB0aGUgcG9pbnRlcnNcbiAgICB2YXIgc3RyaWRlID0gIHRoaXMudmVydFNpemUgKiA0O1xuXG4gICAgZ2wudmVydGV4QXR0cmliUG9pbnRlcih0aGlzLnNoYWRlci5hdHRyaWJ1dGVzLmFWZXJ0ZXhQb3NpdGlvbiwgMiwgZ2wuRkxPQVQsIGZhbHNlLCBzdHJpZGUsIDApO1xuICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIodGhpcy5zaGFkZXIuYXR0cmlidXRlcy5hUG9zaXRpb25Db29yZCwgMiwgZ2wuRkxPQVQsIGZhbHNlLCBzdHJpZGUsIDIgKiA0KTtcbiAgICBnbC52ZXJ0ZXhBdHRyaWJQb2ludGVyKHRoaXMuc2hhZGVyLmF0dHJpYnV0ZXMuYVNjYWxlLCAyLCBnbC5GTE9BVCwgZmFsc2UsIHN0cmlkZSwgNCAqIDQpO1xuICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIodGhpcy5zaGFkZXIuYXR0cmlidXRlcy5hUm90YXRpb24sIDEsIGdsLkZMT0FULCBmYWxzZSwgc3RyaWRlLCA2ICogNCk7XG4gICAgZ2wudmVydGV4QXR0cmliUG9pbnRlcih0aGlzLnNoYWRlci5hdHRyaWJ1dGVzLmFUZXh0dXJlQ29vcmQsIDIsIGdsLkZMT0FULCBmYWxzZSwgc3RyaWRlLCA3ICogNCk7XG4gICAgZ2wudmVydGV4QXR0cmliUG9pbnRlcih0aGlzLnNoYWRlci5hdHRyaWJ1dGVzLmFDb2xvciwgMSwgZ2wuRkxPQVQsIGZhbHNlLCBzdHJpZGUsIDkgKiA0KTtcbn07XG4iLCJ2YXIgdXRpbHMgPSByZXF1aXJlKCcuLi8uLi8uLi91dGlscycpLFxuICAgIG1hdGggPSByZXF1aXJlKCcuLi8uLi8uLi9tYXRoJyksXG4gICAgQ09OU1QgPSByZXF1aXJlKCcuLi8uLi8uLi9jb25zdCcpLFxuICAgIFdlYkdMR3JhcGhpY3NEYXRhID0gcmVxdWlyZSgnLi9XZWJHTEdyYXBoaWNzRGF0YScpO1xuXG4vKipcbiAqIEEgc2V0IG9mIGZ1bmN0aW9ucyB1c2VkIGJ5IHRoZSB3ZWJHTCByZW5kZXJlciB0byBkcmF3IHRoZSBwcmltaXRpdmUgZ3JhcGhpY3MgZGF0YVxuICpcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHByaXZhdGVcbiAqL1xudmFyIFdlYkdMR3JhcGhpY3MgPSBtb2R1bGUuZXhwb3J0cyA9IHt9O1xuXG4vKipcbiAqIFJlbmRlcnMgdGhlIGdyYXBoaWNzIG9iamVjdFxuICpcbiAqIEBzdGF0aWNcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0gZ3JhcGhpY3Mge0dyYXBoaWNzfVxuICogQHBhcmFtIHJlbmRlcmVyIHtXZWJHTFJlbmRlcmVyfVxuICovXG5XZWJHTEdyYXBoaWNzLnJlbmRlckdyYXBoaWNzID0gZnVuY3Rpb24gKGdyYXBoaWNzLCByZW5kZXJlcikgey8vcHJvamVjdGlvbiwgb2Zmc2V0KSB7XG4gICAgdmFyIGdsID0gcmVuZGVyZXIuZ2w7XG5cbiAgICB2YXIgcHJvamVjdGlvbiA9IHJlbmRlcmVyLnByb2plY3Rpb24sXG4gICAgICAgIG9mZnNldCA9IHJlbmRlcmVyLm9mZnNldCxcbiAgICAgICAgc2hhZGVyID0gcmVuZGVyZXIuc2hhZGVyTWFuYWdlci5wcmltaXRpdmVTaGFkZXIsXG4gICAgICAgIHdlYkdMRGF0YTtcblxuICAgIGlmIChncmFwaGljcy5kaXJ0eSkge1xuICAgICAgICBXZWJHTEdyYXBoaWNzLnVwZGF0ZUdyYXBoaWNzKGdyYXBoaWNzLCBnbCk7XG4gICAgfVxuXG4gICAgdmFyIHdlYkdMID0gZ3JhcGhpY3MuX3dlYkdMW2dsLmlkXTtcblxuICAgIC8vIFRoaXMgIGNvdWxkIGJlIHNwZWVkZWQgdXAgZm9yIHN1cmUhXG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHdlYkdMLmRhdGEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaWYgKHdlYkdMLmRhdGFbaV0ubW9kZSA9PT0gMSkge1xuICAgICAgICAgICAgd2ViR0xEYXRhID0gd2ViR0wuZGF0YVtpXTtcblxuICAgICAgICAgICAgcmVuZGVyZXIuc3RlbmNpbE1hbmFnZXIucHVzaFN0ZW5jaWwoZ3JhcGhpY3MsIHdlYkdMRGF0YSwgcmVuZGVyZXIpO1xuXG4gICAgICAgICAgICAvLyByZW5kZXIgcXVhZC4uXG4gICAgICAgICAgICBnbC5kcmF3RWxlbWVudHMoZ2wuVFJJQU5HTEVfRkFOLCA0LCBnbC5VTlNJR05FRF9TSE9SVCwgKCB3ZWJHTERhdGEuaW5kaWNlcy5sZW5ndGggLSA0ICkgKiAyICk7XG5cbiAgICAgICAgICAgIHJlbmRlcmVyLnN0ZW5jaWxNYW5hZ2VyLnBvcFN0ZW5jaWwoZ3JhcGhpY3MsIHdlYkdMRGF0YSwgcmVuZGVyZXIpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgd2ViR0xEYXRhID0gd2ViR0wuZGF0YVtpXTtcblxuXG4gICAgICAgICAgICByZW5kZXJlci5zaGFkZXJNYW5hZ2VyLnNldFNoYWRlciggc2hhZGVyICk7Ly9hY3RpdmF0ZVByaW1pdGl2ZVNoYWRlcigpO1xuICAgICAgICAgICAgc2hhZGVyID0gcmVuZGVyZXIuc2hhZGVyTWFuYWdlci5wcmltaXRpdmVTaGFkZXI7XG4gICAgICAgICAgICBnbC51bmlmb3JtTWF0cml4M2Z2KHNoYWRlci50cmFuc2xhdGlvbk1hdHJpeCwgZmFsc2UsIGdyYXBoaWNzLndvcmxkVHJhbnNmb3JtLnRvQXJyYXkodHJ1ZSkpO1xuXG4gICAgICAgICAgICBnbC51bmlmb3JtMWYoc2hhZGVyLmZsaXBZLCAxKTtcblxuICAgICAgICAgICAgZ2wudW5pZm9ybTJmKHNoYWRlci5wcm9qZWN0aW9uVmVjdG9yLCBwcm9qZWN0aW9uLngsIC1wcm9qZWN0aW9uLnkpO1xuICAgICAgICAgICAgZ2wudW5pZm9ybTJmKHNoYWRlci5vZmZzZXRWZWN0b3IsIC1vZmZzZXQueCwgLW9mZnNldC55KTtcblxuICAgICAgICAgICAgZ2wudW5pZm9ybTNmdihzaGFkZXIudGludENvbG9yLCB1dGlscy5oZXgycmdiKGdyYXBoaWNzLnRpbnQpKTtcblxuICAgICAgICAgICAgZ2wudW5pZm9ybTFmKHNoYWRlci5hbHBoYSwgZ3JhcGhpY3Mud29ybGRBbHBoYSk7XG5cblxuICAgICAgICAgICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHdlYkdMRGF0YS5idWZmZXIpO1xuXG4gICAgICAgICAgICBnbC52ZXJ0ZXhBdHRyaWJQb2ludGVyKHNoYWRlci5hVmVydGV4UG9zaXRpb24sIDIsIGdsLkZMT0FULCBmYWxzZSwgNCAqIDYsIDApO1xuICAgICAgICAgICAgZ2wudmVydGV4QXR0cmliUG9pbnRlcihzaGFkZXIuYUNvbG9yLCA0LCBnbC5GTE9BVCwgZmFsc2UsNCAqIDYsIDIgKiA0KTtcblxuICAgICAgICAgICAgLy8gc2V0IHRoZSBpbmRleCBidWZmZXIhXG4gICAgICAgICAgICBnbC5iaW5kQnVmZmVyKGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCB3ZWJHTERhdGEuaW5kZXhCdWZmZXIpO1xuICAgICAgICAgICAgZ2wuZHJhd0VsZW1lbnRzKGdsLlRSSUFOR0xFX1NUUklQLCAgd2ViR0xEYXRhLmluZGljZXMubGVuZ3RoLCBnbC5VTlNJR05FRF9TSE9SVCwgMCApO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuLyoqXG4gKiBVcGRhdGVzIHRoZSBncmFwaGljcyBvYmplY3RcbiAqXG4gKiBAc3RhdGljXG4gKiBAcHJpdmF0ZVxuICogQHBhcmFtIGdyYXBoaWNzRGF0YSB7R3JhcGhpY3N9IFRoZSBncmFwaGljcyBvYmplY3QgdG8gdXBkYXRlXG4gKiBAcGFyYW0gZ2wge1dlYkdMQ29udGV4dH0gdGhlIGN1cnJlbnQgV2ViR0wgZHJhd2luZyBjb250ZXh0XG4gKi9cbldlYkdMR3JhcGhpY3MudXBkYXRlR3JhcGhpY3MgPSBmdW5jdGlvbiAoZ3JhcGhpY3MsIGdsKSB7XG4gICAgLy8gZ2V0IHRoZSBjb250ZXh0cyBncmFwaGljcyBvYmplY3RcbiAgICB2YXIgd2ViR0wgPSBncmFwaGljcy5fd2ViR0xbZ2wuaWRdO1xuXG4gICAgLy8gaWYgdGhlIGdyYXBoaWNzIG9iamVjdCBkb2VzIG5vdCBleGlzdCBpbiB0aGUgd2ViR0wgY29udGV4dCB0aW1lIHRvIGNyZWF0ZSBpdCFcbiAgICBpZiAoIXdlYkdMKSB7XG4gICAgICAgIHdlYkdMID0gZ3JhcGhpY3MuX3dlYkdMW2dsLmlkXSA9IHtsYXN0SW5kZXg6MCwgZGF0YTpbXSwgZ2w6Z2x9O1xuICAgIH1cblxuICAgIC8vIGZsYWcgdGhlIGdyYXBoaWNzIGFzIG5vdCBkaXJ0eSBhcyB3ZSBhcmUgYWJvdXQgdG8gdXBkYXRlIGl0Li4uXG4gICAgZ3JhcGhpY3MuZGlydHkgPSBmYWxzZTtcblxuICAgIHZhciBpO1xuXG4gICAgLy8gaWYgdGhlIHVzZXIgY2xlYXJlZCB0aGUgZ3JhcGhpY3Mgb2JqZWN0IHdlIHdpbGwgbmVlZCB0byBjbGVhciBldmVyeSBvYmplY3RcbiAgICBpZiAoZ3JhcGhpY3MuY2xlYXJEaXJ0eSkge1xuICAgICAgICBncmFwaGljcy5jbGVhckRpcnR5ID0gZmFsc2U7XG5cbiAgICAgICAgLy8gbG9wIHRocm91Z2ggYW5kIHJldHVybiBhbGwgdGhlIHdlYkdMRGF0YXMgdG8gdGhlIG9iamVjdCBwb29sIHNvIHRoYW4gY2FuIGJlIHJldXNlZCBsYXRlciBvblxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgd2ViR0wuZGF0YS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIGdyYXBoaWNzRGF0YSA9IHdlYkdMLmRhdGFbaV07XG4gICAgICAgICAgICBncmFwaGljc0RhdGEucmVzZXQoKTtcbiAgICAgICAgICAgIFdlYkdMR3JhcGhpY3MuZ3JhcGhpY3NEYXRhUG9vbC5wdXNoKCBncmFwaGljc0RhdGEgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGNsZWFyIHRoZSBhcnJheSBhbmQgcmVzZXQgdGhlIGluZGV4Li5cbiAgICAgICAgd2ViR0wuZGF0YSA9IFtdO1xuICAgICAgICB3ZWJHTC5sYXN0SW5kZXggPSAwO1xuICAgIH1cblxuICAgIHZhciB3ZWJHTERhdGE7XG5cbiAgICAvLyBsb29wIHRocm91Z2ggdGhlIGdyYXBoaWNzIGRhdGFzIGFuZCBjb25zdHJ1Y3QgZWFjaCBvbmUuLlxuICAgIC8vIGlmIHRoZSBvYmplY3QgaXMgYSBjb21wbGV4IGZpbGwgdGhlbiB0aGUgbmV3IHN0ZW5jaWwgYnVmZmVyIHRlY2huaXF1ZSB3aWxsIGJlIHVzZWRcbiAgICAvLyBvdGhlciB3aXNlIGdyYXBoaWNzIG9iamVjdHMgd2lsbCBiZSBwdXNoZWQgaW50byBhIGJhdGNoLi5cbiAgICBmb3IgKGkgPSB3ZWJHTC5sYXN0SW5kZXg7IGkgPCBncmFwaGljcy5ncmFwaGljc0RhdGEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGRhdGEgPSBncmFwaGljcy5ncmFwaGljc0RhdGFbaV07XG5cbiAgICAgICAgaWYgKGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLlBPTFkpIHtcbiAgICAgICAgICAgIC8vIG5lZWQgdG8gYWRkIHRoZSBwb2ludHMgdGhlIHRoZSBncmFwaGljcyBvYmplY3QuLlxuICAgICAgICAgICAgZGF0YS5wb2ludHMgPSBkYXRhLnNoYXBlLnBvaW50cy5zbGljZSgpO1xuICAgICAgICAgICAgaWYgKGRhdGEuc2hhcGUuY2xvc2VkKSB7XG4gICAgICAgICAgICAgICAgLy8gY2xvc2UgdGhlIHBvbHkgaWYgdGhlIHZhbHVlIGlzIHRydWUhXG4gICAgICAgICAgICAgICAgaWYgKGRhdGEucG9pbnRzWzBdICE9PSBkYXRhLnBvaW50c1tkYXRhLnBvaW50cy5sZW5ndGgtMl0gfHwgZGF0YS5wb2ludHNbMV0gIT09IGRhdGEucG9pbnRzW2RhdGEucG9pbnRzLmxlbmd0aC0xXSkge1xuICAgICAgICAgICAgICAgICAgICBkYXRhLnBvaW50cy5wdXNoKGRhdGEucG9pbnRzWzBdLCBkYXRhLnBvaW50c1sxXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBNQUtFIFNVUkUgV0UgSEFWRSBUSEUgQ09SUkVDVCBUWVBFLi5cbiAgICAgICAgICAgIGlmIChkYXRhLmZpbGwpIHtcbiAgICAgICAgICAgICAgICBpZiAoZGF0YS5wb2ludHMubGVuZ3RoID49IDYpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGRhdGEucG9pbnRzLmxlbmd0aCA8IDYgKiAyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB3ZWJHTERhdGEgPSBXZWJHTEdyYXBoaWNzLnN3aXRjaE1vZGUod2ViR0wsIDApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgY2FuRHJhd1VzaW5nU2ltcGxlID0gV2ViR0xHcmFwaGljcy5idWlsZFBvbHkoZGF0YSwgd2ViR0xEYXRhKTtcbiAgICAgICAgICAgICAgICAgICAvLyAgICAgY29uc29sZS5sb2coY2FuRHJhd1VzaW5nU2ltcGxlKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFjYW5EcmF3VXNpbmdTaW1wbGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgIGNvbnNvbGUubG9nKFwiPD4+PlwiKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdlYkdMRGF0YSA9IFdlYkdMR3JhcGhpY3Muc3dpdGNoTW9kZSh3ZWJHTCwgMSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgV2ViR0xHcmFwaGljcy5idWlsZENvbXBsZXhQb2x5KGRhdGEsIHdlYkdMRGF0YSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdlYkdMRGF0YSA9IFdlYkdMR3JhcGhpY3Muc3dpdGNoTW9kZSh3ZWJHTCwgMSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBXZWJHTEdyYXBoaWNzLmJ1aWxkQ29tcGxleFBvbHkoZGF0YSwgd2ViR0xEYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGRhdGEubGluZVdpZHRoID4gMCkge1xuICAgICAgICAgICAgICAgIHdlYkdMRGF0YSA9IFdlYkdMR3JhcGhpY3Muc3dpdGNoTW9kZSh3ZWJHTCwgMCk7XG4gICAgICAgICAgICAgICAgV2ViR0xHcmFwaGljcy5idWlsZExpbmUoZGF0YSwgd2ViR0xEYXRhKTtcblxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgd2ViR0xEYXRhID0gV2ViR0xHcmFwaGljcy5zd2l0Y2hNb2RlKHdlYkdMLCAwKTtcblxuICAgICAgICAgICAgaWYgKGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLlJFQ1QpIHtcbiAgICAgICAgICAgICAgICBXZWJHTEdyYXBoaWNzLmJ1aWxkUmVjdGFuZ2xlKGRhdGEsIHdlYkdMRGF0YSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChkYXRhLnR5cGUgPT09IENPTlNULlNIQVBFUy5DSVJDIHx8IGRhdGEudHlwZSA9PT0gQ09OU1QuU0hBUEVTLkVMSVApIHtcbiAgICAgICAgICAgICAgICBXZWJHTEdyYXBoaWNzLmJ1aWxkQ2lyY2xlKGRhdGEsIHdlYkdMRGF0YSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChkYXRhLnR5cGUgPT09IENPTlNULlNIQVBFUy5SUkVDKSB7XG4gICAgICAgICAgICAgICAgV2ViR0xHcmFwaGljcy5idWlsZFJvdW5kZWRSZWN0YW5nbGUoZGF0YSwgd2ViR0xEYXRhKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHdlYkdMLmxhc3RJbmRleCsrO1xuICAgIH1cblxuICAgIC8vIHVwbG9hZCBhbGwgdGhlIGRpcnR5IGRhdGEuLi5cbiAgICBmb3IgKGkgPSAwOyBpIDwgd2ViR0wuZGF0YS5sZW5ndGg7IGkrKykge1xuICAgICAgICB3ZWJHTERhdGEgPSB3ZWJHTC5kYXRhW2ldO1xuXG4gICAgICAgIGlmICh3ZWJHTERhdGEuZGlydHkpIHtcbiAgICAgICAgICAgIHdlYkdMRGF0YS51cGxvYWQoKTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cbi8qKlxuICogQHN0YXRpY1xuICogQHByaXZhdGVcbiAqIEBwYXJhbSB3ZWJHTCB7V2ViR0xDb250ZXh0fVxuICogQHBhcmFtIHR5cGUge251bWJlcn1cbiAqL1xuV2ViR0xHcmFwaGljcy5zd2l0Y2hNb2RlID0gZnVuY3Rpb24gKHdlYkdMLCB0eXBlKSB7XG4gICAgdmFyIHdlYkdMRGF0YTtcblxuICAgIGlmICghd2ViR0wuZGF0YS5sZW5ndGgpIHtcbiAgICAgICAgd2ViR0xEYXRhID0gV2ViR0xHcmFwaGljcy5ncmFwaGljc0RhdGFQb29sLnBvcCgpIHx8IG5ldyBXZWJHTEdyYXBoaWNzRGF0YSh3ZWJHTC5nbCk7XG4gICAgICAgIHdlYkdMRGF0YS5tb2RlID0gdHlwZTtcbiAgICAgICAgd2ViR0wuZGF0YS5wdXNoKHdlYkdMRGF0YSk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB3ZWJHTERhdGEgPSB3ZWJHTC5kYXRhW3dlYkdMLmRhdGEubGVuZ3RoLTFdO1xuXG4gICAgICAgIGlmICh3ZWJHTERhdGEubW9kZSAhPT0gdHlwZSB8fCB0eXBlID09PSAxKSB7XG4gICAgICAgICAgICB3ZWJHTERhdGEgPSBXZWJHTEdyYXBoaWNzLmdyYXBoaWNzRGF0YVBvb2wucG9wKCkgfHwgbmV3IFdlYkdMR3JhcGhpY3NEYXRhKHdlYkdMLmdsKTtcbiAgICAgICAgICAgIHdlYkdMRGF0YS5tb2RlID0gdHlwZTtcbiAgICAgICAgICAgIHdlYkdMLmRhdGEucHVzaCh3ZWJHTERhdGEpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgd2ViR0xEYXRhLmRpcnR5ID0gdHJ1ZTtcblxuICAgIHJldHVybiB3ZWJHTERhdGE7XG59O1xuXG4vKipcbiAqIEJ1aWxkcyBhIHJlY3RhbmdsZSB0byBkcmF3XG4gKlxuICogQHN0YXRpY1xuICogQHByaXZhdGVcbiAqIEBwYXJhbSBncmFwaGljc0RhdGEge0dyYXBoaWNzfSBUaGUgZ3JhcGhpY3Mgb2JqZWN0IGNvbnRhaW5pbmcgYWxsIHRoZSBuZWNlc3NhcnkgcHJvcGVydGllc1xuICogQHBhcmFtIHdlYkdMRGF0YSB7b2JqZWN0fVxuICovXG5XZWJHTEdyYXBoaWNzLmJ1aWxkUmVjdGFuZ2xlID0gZnVuY3Rpb24gKGdyYXBoaWNzRGF0YSwgd2ViR0xEYXRhKSB7XG4gICAgLy8gLS0tIC8vXG4gICAgLy8gbmVlZCB0byBjb252ZXJ0IHBvaW50cyB0byBhIG5pY2UgcmVndWxhciBkYXRhXG4gICAgLy9cbiAgICB2YXIgcmVjdERhdGEgPSBncmFwaGljc0RhdGEuc2hhcGU7XG4gICAgdmFyIHggPSByZWN0RGF0YS54O1xuICAgIHZhciB5ID0gcmVjdERhdGEueTtcbiAgICB2YXIgd2lkdGggPSByZWN0RGF0YS53aWR0aDtcbiAgICB2YXIgaGVpZ2h0ID0gcmVjdERhdGEuaGVpZ2h0O1xuXG4gICAgaWYgKGdyYXBoaWNzRGF0YS5maWxsKSB7XG4gICAgICAgIHZhciBjb2xvciA9IHV0aWxzLmhleDJyZ2IoZ3JhcGhpY3NEYXRhLmZpbGxDb2xvcik7XG4gICAgICAgIHZhciBhbHBoYSA9IGdyYXBoaWNzRGF0YS5maWxsQWxwaGE7XG5cbiAgICAgICAgdmFyIHIgPSBjb2xvclswXSAqIGFscGhhO1xuICAgICAgICB2YXIgZyA9IGNvbG9yWzFdICogYWxwaGE7XG4gICAgICAgIHZhciBiID0gY29sb3JbMl0gKiBhbHBoYTtcblxuICAgICAgICB2YXIgdmVydHMgPSB3ZWJHTERhdGEucG9pbnRzO1xuICAgICAgICB2YXIgaW5kaWNlcyA9IHdlYkdMRGF0YS5pbmRpY2VzO1xuXG4gICAgICAgIHZhciB2ZXJ0UG9zID0gdmVydHMubGVuZ3RoLzY7XG5cbiAgICAgICAgLy8gc3RhcnRcbiAgICAgICAgdmVydHMucHVzaCh4LCB5KTtcbiAgICAgICAgdmVydHMucHVzaChyLCBnLCBiLCBhbHBoYSk7XG5cbiAgICAgICAgdmVydHMucHVzaCh4ICsgd2lkdGgsIHkpO1xuICAgICAgICB2ZXJ0cy5wdXNoKHIsIGcsIGIsIGFscGhhKTtcblxuICAgICAgICB2ZXJ0cy5wdXNoKHggLCB5ICsgaGVpZ2h0KTtcbiAgICAgICAgdmVydHMucHVzaChyLCBnLCBiLCBhbHBoYSk7XG5cbiAgICAgICAgdmVydHMucHVzaCh4ICsgd2lkdGgsIHkgKyBoZWlnaHQpO1xuICAgICAgICB2ZXJ0cy5wdXNoKHIsIGcsIGIsIGFscGhhKTtcblxuICAgICAgICAvLyBpbnNlcnQgMiBkZWFkIHRyaWFuZ2xlcy4uXG4gICAgICAgIGluZGljZXMucHVzaCh2ZXJ0UG9zLCB2ZXJ0UG9zLCB2ZXJ0UG9zKzEsIHZlcnRQb3MrMiwgdmVydFBvcyszLCB2ZXJ0UG9zKzMpO1xuICAgIH1cblxuICAgIGlmIChncmFwaGljc0RhdGEubGluZVdpZHRoKSB7XG4gICAgICAgIHZhciB0ZW1wUG9pbnRzID0gZ3JhcGhpY3NEYXRhLnBvaW50cztcblxuICAgICAgICBncmFwaGljc0RhdGEucG9pbnRzID0gW3gsIHksXG4gICAgICAgICAgICAgICAgICB4ICsgd2lkdGgsIHksXG4gICAgICAgICAgICAgICAgICB4ICsgd2lkdGgsIHkgKyBoZWlnaHQsXG4gICAgICAgICAgICAgICAgICB4LCB5ICsgaGVpZ2h0LFxuICAgICAgICAgICAgICAgICAgeCwgeV07XG5cblxuICAgICAgICBXZWJHTEdyYXBoaWNzLmJ1aWxkTGluZShncmFwaGljc0RhdGEsIHdlYkdMRGF0YSk7XG5cbiAgICAgICAgZ3JhcGhpY3NEYXRhLnBvaW50cyA9IHRlbXBQb2ludHM7XG4gICAgfVxufTtcblxuLyoqXG4gKiBCdWlsZHMgYSByb3VuZGVkIHJlY3RhbmdsZSB0byBkcmF3XG4gKlxuICogQHN0YXRpY1xuICogQHByaXZhdGVcbiAqIEBwYXJhbSBncmFwaGljc0RhdGEge0dyYXBoaWNzfSBUaGUgZ3JhcGhpY3Mgb2JqZWN0IGNvbnRhaW5pbmcgYWxsIHRoZSBuZWNlc3NhcnkgcHJvcGVydGllc1xuICogQHBhcmFtIHdlYkdMRGF0YSB7b2JqZWN0fVxuICovXG5XZWJHTEdyYXBoaWNzLmJ1aWxkUm91bmRlZFJlY3RhbmdsZSA9IGZ1bmN0aW9uIChncmFwaGljc0RhdGEsIHdlYkdMRGF0YSkge1xuICAgIHZhciBycmVjdERhdGEgPSBncmFwaGljc0RhdGEuc2hhcGU7XG4gICAgdmFyIHggPSBycmVjdERhdGEueDtcbiAgICB2YXIgeSA9IHJyZWN0RGF0YS55O1xuICAgIHZhciB3aWR0aCA9IHJyZWN0RGF0YS53aWR0aDtcbiAgICB2YXIgaGVpZ2h0ID0gcnJlY3REYXRhLmhlaWdodDtcblxuICAgIHZhciByYWRpdXMgPSBycmVjdERhdGEucmFkaXVzO1xuXG4gICAgdmFyIHJlY1BvaW50cyA9IFtdO1xuICAgIHJlY1BvaW50cy5wdXNoKHgsIHkgKyByYWRpdXMpO1xuICAgIHJlY1BvaW50cyA9IHJlY1BvaW50cy5jb25jYXQoV2ViR0xHcmFwaGljcy5xdWFkcmF0aWNCZXppZXJDdXJ2ZSh4LCB5ICsgaGVpZ2h0IC0gcmFkaXVzLCB4LCB5ICsgaGVpZ2h0LCB4ICsgcmFkaXVzLCB5ICsgaGVpZ2h0KSk7XG4gICAgcmVjUG9pbnRzID0gcmVjUG9pbnRzLmNvbmNhdChXZWJHTEdyYXBoaWNzLnF1YWRyYXRpY0JlemllckN1cnZlKHggKyB3aWR0aCAtIHJhZGl1cywgeSArIGhlaWdodCwgeCArIHdpZHRoLCB5ICsgaGVpZ2h0LCB4ICsgd2lkdGgsIHkgKyBoZWlnaHQgLSByYWRpdXMpKTtcbiAgICByZWNQb2ludHMgPSByZWNQb2ludHMuY29uY2F0KFdlYkdMR3JhcGhpY3MucXVhZHJhdGljQmV6aWVyQ3VydmUoeCArIHdpZHRoLCB5ICsgcmFkaXVzLCB4ICsgd2lkdGgsIHksIHggKyB3aWR0aCAtIHJhZGl1cywgeSkpO1xuICAgIHJlY1BvaW50cyA9IHJlY1BvaW50cy5jb25jYXQoV2ViR0xHcmFwaGljcy5xdWFkcmF0aWNCZXppZXJDdXJ2ZSh4ICsgcmFkaXVzLCB5LCB4LCB5LCB4LCB5ICsgcmFkaXVzKSk7XG5cbiAgICBpZiAoZ3JhcGhpY3NEYXRhLmZpbGwpIHtcbiAgICAgICAgdmFyIGNvbG9yID0gdXRpbHMuaGV4MnJnYihncmFwaGljc0RhdGEuZmlsbENvbG9yKTtcbiAgICAgICAgdmFyIGFscGhhID0gZ3JhcGhpY3NEYXRhLmZpbGxBbHBoYTtcblxuICAgICAgICB2YXIgciA9IGNvbG9yWzBdICogYWxwaGE7XG4gICAgICAgIHZhciBnID0gY29sb3JbMV0gKiBhbHBoYTtcbiAgICAgICAgdmFyIGIgPSBjb2xvclsyXSAqIGFscGhhO1xuXG4gICAgICAgIHZhciB2ZXJ0cyA9IHdlYkdMRGF0YS5wb2ludHM7XG4gICAgICAgIHZhciBpbmRpY2VzID0gd2ViR0xEYXRhLmluZGljZXM7XG5cbiAgICAgICAgdmFyIHZlY1BvcyA9IHZlcnRzLmxlbmd0aC82O1xuXG4gICAgICAgIHZhciB0cmlhbmdsZXMgPSB1dGlscy5Qb2x5Sy5Ucmlhbmd1bGF0ZShyZWNQb2ludHMpO1xuXG4gICAgICAgIC8vXG5cbiAgICAgICAgdmFyIGkgPSAwO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdHJpYW5nbGVzLmxlbmd0aDsgaSs9Mykge1xuICAgICAgICAgICAgaW5kaWNlcy5wdXNoKHRyaWFuZ2xlc1tpXSArIHZlY1Bvcyk7XG4gICAgICAgICAgICBpbmRpY2VzLnB1c2godHJpYW5nbGVzW2ldICsgdmVjUG9zKTtcbiAgICAgICAgICAgIGluZGljZXMucHVzaCh0cmlhbmdsZXNbaSsxXSArIHZlY1Bvcyk7XG4gICAgICAgICAgICBpbmRpY2VzLnB1c2godHJpYW5nbGVzW2krMl0gKyB2ZWNQb3MpO1xuICAgICAgICAgICAgaW5kaWNlcy5wdXNoKHRyaWFuZ2xlc1tpKzJdICsgdmVjUG9zKTtcbiAgICAgICAgfVxuXG5cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHJlY1BvaW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmVydHMucHVzaChyZWNQb2ludHNbaV0sIHJlY1BvaW50c1srK2ldLCByLCBnLCBiLCBhbHBoYSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoZ3JhcGhpY3NEYXRhLmxpbmVXaWR0aCkge1xuICAgICAgICB2YXIgdGVtcFBvaW50cyA9IGdyYXBoaWNzRGF0YS5wb2ludHM7XG5cbiAgICAgICAgZ3JhcGhpY3NEYXRhLnBvaW50cyA9IHJlY1BvaW50cztcblxuICAgICAgICBXZWJHTEdyYXBoaWNzLmJ1aWxkTGluZShncmFwaGljc0RhdGEsIHdlYkdMRGF0YSk7XG5cbiAgICAgICAgZ3JhcGhpY3NEYXRhLnBvaW50cyA9IHRlbXBQb2ludHM7XG4gICAgfVxufTtcblxuLyoqXG4gKiBDYWxjdWxhdGUgdGhlIHBvaW50cyBmb3IgYSBxdWFkcmF0aWMgYmV6aWVyIGN1cnZlLiAoaGVscGVyIGZ1bmN0aW9uLi4pXG4gKiBCYXNlZCBvbjogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNzg1MDk3L2hvdy1kby1pLWltcGxlbWVudC1hLWJlemllci1jdXJ2ZS1pbi1jXG4gKlxuICogQHN0YXRpY1xuICogQHByaXZhdGVcbiAqIEBwYXJhbSBmcm9tWCB7bnVtYmVyfSBPcmlnaW4gcG9pbnQgeFxuICogQHBhcmFtIGZyb21ZIHtudW1iZXJ9IE9yaWdpbiBwb2ludCB4XG4gKiBAcGFyYW0gY3BYIHtudW1iZXJ9IENvbnRyb2wgcG9pbnQgeFxuICogQHBhcmFtIGNwWSB7bnVtYmVyfSBDb250cm9sIHBvaW50IHlcbiAqIEBwYXJhbSB0b1gge251bWJlcn0gRGVzdGluYXRpb24gcG9pbnQgeFxuICogQHBhcmFtIHRvWSB7bnVtYmVyfSBEZXN0aW5hdGlvbiBwb2ludCB5XG4gKiBAcmV0dXJuIHtudW1iZXJbXX1cbiAqL1xuV2ViR0xHcmFwaGljcy5xdWFkcmF0aWNCZXppZXJDdXJ2ZSA9IGZ1bmN0aW9uIChmcm9tWCwgZnJvbVksIGNwWCwgY3BZLCB0b1gsIHRvWSkge1xuXG4gICAgdmFyIHhhLFxuICAgICAgICB5YSxcbiAgICAgICAgeGIsXG4gICAgICAgIHliLFxuICAgICAgICB4LFxuICAgICAgICB5LFxuICAgICAgICBuID0gMjAsXG4gICAgICAgIHBvaW50cyA9IFtdO1xuXG4gICAgZnVuY3Rpb24gZ2V0UHQobjEgLCBuMiwgcGVyYykge1xuICAgICAgICB2YXIgZGlmZiA9IG4yIC0gbjE7XG5cbiAgICAgICAgcmV0dXJuIG4xICsgKCBkaWZmICogcGVyYyApO1xuICAgIH1cblxuICAgIHZhciBqID0gMDtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8PSBuOyBpKysgKSB7XG4gICAgICAgIGogPSBpIC8gbjtcblxuICAgICAgICAvLyBUaGUgR3JlZW4gTGluZVxuICAgICAgICB4YSA9IGdldFB0KCBmcm9tWCAsIGNwWCAsIGogKTtcbiAgICAgICAgeWEgPSBnZXRQdCggZnJvbVkgLCBjcFkgLCBqICk7XG4gICAgICAgIHhiID0gZ2V0UHQoIGNwWCAsIHRvWCAsIGogKTtcbiAgICAgICAgeWIgPSBnZXRQdCggY3BZICwgdG9ZICwgaiApO1xuXG4gICAgICAgIC8vIFRoZSBCbGFjayBEb3RcbiAgICAgICAgeCA9IGdldFB0KCB4YSAsIHhiICwgaiApO1xuICAgICAgICB5ID0gZ2V0UHQoIHlhICwgeWIgLCBqICk7XG5cbiAgICAgICAgcG9pbnRzLnB1c2goeCwgeSk7XG4gICAgfVxuICAgIHJldHVybiBwb2ludHM7XG59O1xuXG4vKipcbiAqIEJ1aWxkcyBhIGNpcmNsZSB0byBkcmF3XG4gKlxuICogQHN0YXRpY1xuICogQHByaXZhdGVcbiAqIEBwYXJhbSBncmFwaGljc0RhdGEge0dyYXBoaWNzfSBUaGUgZ3JhcGhpY3Mgb2JqZWN0IHRvIGRyYXdcbiAqIEBwYXJhbSB3ZWJHTERhdGEge29iamVjdH1cbiAqL1xuV2ViR0xHcmFwaGljcy5idWlsZENpcmNsZSA9IGZ1bmN0aW9uIChncmFwaGljc0RhdGEsIHdlYkdMRGF0YSkge1xuICAgIC8vIG5lZWQgdG8gY29udmVydCBwb2ludHMgdG8gYSBuaWNlIHJlZ3VsYXIgZGF0YVxuICAgIHZhciBjaXJjbGVEYXRhID0gZ3JhcGhpY3NEYXRhLnNoYXBlO1xuICAgIHZhciB4ID0gY2lyY2xlRGF0YS54O1xuICAgIHZhciB5ID0gY2lyY2xlRGF0YS55O1xuICAgIHZhciB3aWR0aDtcbiAgICB2YXIgaGVpZ2h0O1xuXG4gICAgLy8gVE9ETyAtIGJpdCBoYWNreT8/XG4gICAgaWYgKGdyYXBoaWNzRGF0YS50eXBlID09PSBDT05TVC5TSEFQRVMuQ0lSQykge1xuICAgICAgICB3aWR0aCA9IGNpcmNsZURhdGEucmFkaXVzO1xuICAgICAgICBoZWlnaHQgPSBjaXJjbGVEYXRhLnJhZGl1cztcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHdpZHRoID0gY2lyY2xlRGF0YS53aWR0aDtcbiAgICAgICAgaGVpZ2h0ID0gY2lyY2xlRGF0YS5oZWlnaHQ7XG4gICAgfVxuXG4gICAgdmFyIHRvdGFsU2VncyA9IDQwO1xuICAgIHZhciBzZWcgPSAoTWF0aC5QSSAqIDIpIC8gdG90YWxTZWdzIDtcblxuICAgIHZhciBpID0gMDtcblxuICAgIGlmIChncmFwaGljc0RhdGEuZmlsbCkge1xuICAgICAgICB2YXIgY29sb3IgPSB1dGlscy5oZXgycmdiKGdyYXBoaWNzRGF0YS5maWxsQ29sb3IpO1xuICAgICAgICB2YXIgYWxwaGEgPSBncmFwaGljc0RhdGEuZmlsbEFscGhhO1xuXG4gICAgICAgIHZhciByID0gY29sb3JbMF0gKiBhbHBoYTtcbiAgICAgICAgdmFyIGcgPSBjb2xvclsxXSAqIGFscGhhO1xuICAgICAgICB2YXIgYiA9IGNvbG9yWzJdICogYWxwaGE7XG5cbiAgICAgICAgdmFyIHZlcnRzID0gd2ViR0xEYXRhLnBvaW50cztcbiAgICAgICAgdmFyIGluZGljZXMgPSB3ZWJHTERhdGEuaW5kaWNlcztcblxuICAgICAgICB2YXIgdmVjUG9zID0gdmVydHMubGVuZ3RoLzY7XG5cbiAgICAgICAgaW5kaWNlcy5wdXNoKHZlY1Bvcyk7XG5cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHRvdGFsU2VncyArIDEgOyBpKyspIHtcbiAgICAgICAgICAgIHZlcnRzLnB1c2goeCx5LCByLCBnLCBiLCBhbHBoYSk7XG5cbiAgICAgICAgICAgIHZlcnRzLnB1c2goeCArIE1hdGguc2luKHNlZyAqIGkpICogd2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgIHkgKyBNYXRoLmNvcyhzZWcgKiBpKSAqIGhlaWdodCxcbiAgICAgICAgICAgICAgICAgICAgICAgciwgZywgYiwgYWxwaGEpO1xuXG4gICAgICAgICAgICBpbmRpY2VzLnB1c2godmVjUG9zKyssIHZlY1BvcysrKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGluZGljZXMucHVzaCh2ZWNQb3MtMSk7XG4gICAgfVxuXG4gICAgaWYgKGdyYXBoaWNzRGF0YS5saW5lV2lkdGgpIHtcbiAgICAgICAgdmFyIHRlbXBQb2ludHMgPSBncmFwaGljc0RhdGEucG9pbnRzO1xuXG4gICAgICAgIGdyYXBoaWNzRGF0YS5wb2ludHMgPSBbXTtcblxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdG90YWxTZWdzICsgMTsgaSsrKSB7XG4gICAgICAgICAgICBncmFwaGljc0RhdGEucG9pbnRzLnB1c2goeCArIE1hdGguc2luKHNlZyAqIGkpICogd2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSArIE1hdGguY29zKHNlZyAqIGkpICogaGVpZ2h0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIFdlYkdMR3JhcGhpY3MuYnVpbGRMaW5lKGdyYXBoaWNzRGF0YSwgd2ViR0xEYXRhKTtcblxuICAgICAgICBncmFwaGljc0RhdGEucG9pbnRzID0gdGVtcFBvaW50cztcbiAgICB9XG59O1xuXG4vKipcbiAqIEJ1aWxkcyBhIGxpbmUgdG8gZHJhd1xuICpcbiAqIEBzdGF0aWNcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0gZ3JhcGhpY3NEYXRhIHtHcmFwaGljc30gVGhlIGdyYXBoaWNzIG9iamVjdCBjb250YWluaW5nIGFsbCB0aGUgbmVjZXNzYXJ5IHByb3BlcnRpZXNcbiAqIEBwYXJhbSB3ZWJHTERhdGEge29iamVjdH1cbiAqL1xuV2ViR0xHcmFwaGljcy5idWlsZExpbmUgPSBmdW5jdGlvbiAoZ3JhcGhpY3NEYXRhLCB3ZWJHTERhdGEpIHtcbiAgICAvLyBUT0RPIE9QVElNSVNFIVxuICAgIHZhciBpID0gMDtcbiAgICB2YXIgcG9pbnRzID0gZ3JhcGhpY3NEYXRhLnBvaW50cztcblxuICAgIGlmIChwb2ludHMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBpZiB0aGUgbGluZSB3aWR0aCBpcyBhbiBvZGQgbnVtYmVyIGFkZCAwLjUgdG8gYWxpZ24gdG8gYSB3aG9sZSBwaXhlbFxuICAgIGlmIChncmFwaGljc0RhdGEubGluZVdpZHRoJTIpIHtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHBvaW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgcG9pbnRzW2ldICs9IDAuNTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIGdldCBmaXJzdCBhbmQgbGFzdCBwb2ludC4uIGZpZ3VyZSBvdXQgdGhlIG1pZGRsZSFcbiAgICB2YXIgZmlyc3RQb2ludCA9IG5ldyBtYXRoLlBvaW50KHBvaW50c1swXSwgcG9pbnRzWzFdKTtcbiAgICB2YXIgbGFzdFBvaW50ID0gbmV3IG1hdGguUG9pbnQocG9pbnRzW3BvaW50cy5sZW5ndGggLSAyXSwgcG9pbnRzW3BvaW50cy5sZW5ndGggLSAxXSk7XG5cbiAgICAvLyBpZiB0aGUgZmlyc3QgcG9pbnQgaXMgdGhlIGxhc3QgcG9pbnQgLSBnb25uYSBoYXZlIGlzc3VlcyA6KVxuICAgIGlmIChmaXJzdFBvaW50LnggPT09IGxhc3RQb2ludC54ICYmIGZpcnN0UG9pbnQueSA9PT0gbGFzdFBvaW50LnkpIHtcbiAgICAgICAgLy8gbmVlZCB0byBjbG9uZSBhcyB3ZSBhcmUgZ29pbmcgdG8gc2xpZ2h0bHkgbW9kaWZ5IHRoZSBzaGFwZS4uXG4gICAgICAgIHBvaW50cyA9IHBvaW50cy5zbGljZSgpO1xuXG4gICAgICAgIHBvaW50cy5wb3AoKTtcbiAgICAgICAgcG9pbnRzLnBvcCgpO1xuXG4gICAgICAgIGxhc3RQb2ludCA9IG5ldyBtYXRoLlBvaW50KHBvaW50c1twb2ludHMubGVuZ3RoIC0gMl0sIHBvaW50c1twb2ludHMubGVuZ3RoIC0gMV0pO1xuXG4gICAgICAgIHZhciBtaWRQb2ludFggPSBsYXN0UG9pbnQueCArIChmaXJzdFBvaW50LnggLSBsYXN0UG9pbnQueCkgKjAuNTtcbiAgICAgICAgdmFyIG1pZFBvaW50WSA9IGxhc3RQb2ludC55ICsgKGZpcnN0UG9pbnQueSAtIGxhc3RQb2ludC55KSAqMC41O1xuXG4gICAgICAgIHBvaW50cy51bnNoaWZ0KG1pZFBvaW50WCwgbWlkUG9pbnRZKTtcbiAgICAgICAgcG9pbnRzLnB1c2gobWlkUG9pbnRYLCBtaWRQb2ludFkpO1xuICAgIH1cblxuICAgIHZhciB2ZXJ0cyA9IHdlYkdMRGF0YS5wb2ludHM7XG4gICAgdmFyIGluZGljZXMgPSB3ZWJHTERhdGEuaW5kaWNlcztcbiAgICB2YXIgbGVuZ3RoID0gcG9pbnRzLmxlbmd0aCAvIDI7XG4gICAgdmFyIGluZGV4Q291bnQgPSBwb2ludHMubGVuZ3RoO1xuICAgIHZhciBpbmRleFN0YXJ0ID0gdmVydHMubGVuZ3RoLzY7XG5cbiAgICAvLyBEUkFXIHRoZSBMaW5lXG4gICAgdmFyIHdpZHRoID0gZ3JhcGhpY3NEYXRhLmxpbmVXaWR0aCAvIDI7XG5cbiAgICAvLyBzb3J0IGNvbG9yXG4gICAgdmFyIGNvbG9yID0gdXRpbHMuaGV4MnJnYihncmFwaGljc0RhdGEubGluZUNvbG9yKTtcbiAgICB2YXIgYWxwaGEgPSBncmFwaGljc0RhdGEubGluZUFscGhhO1xuICAgIHZhciByID0gY29sb3JbMF0gKiBhbHBoYTtcbiAgICB2YXIgZyA9IGNvbG9yWzFdICogYWxwaGE7XG4gICAgdmFyIGIgPSBjb2xvclsyXSAqIGFscGhhO1xuXG4gICAgdmFyIHB4LCBweSwgcDF4LCBwMXksIHAyeCwgcDJ5LCBwM3gsIHAzeTtcbiAgICB2YXIgcGVycHgsIHBlcnB5LCBwZXJwMngsIHBlcnAyeSwgcGVycDN4LCBwZXJwM3k7XG4gICAgdmFyIGExLCBiMSwgYzEsIGEyLCBiMiwgYzI7XG4gICAgdmFyIGRlbm9tLCBwZGlzdCwgZGlzdDtcblxuICAgIHAxeCA9IHBvaW50c1swXTtcbiAgICBwMXkgPSBwb2ludHNbMV07XG5cbiAgICBwMnggPSBwb2ludHNbMl07XG4gICAgcDJ5ID0gcG9pbnRzWzNdO1xuXG4gICAgcGVycHggPSAtKHAxeSAtIHAyeSk7XG4gICAgcGVycHkgPSAgcDF4IC0gcDJ4O1xuXG4gICAgZGlzdCA9IE1hdGguc3FydChwZXJweCpwZXJweCArIHBlcnB5KnBlcnB5KTtcblxuICAgIHBlcnB4IC89IGRpc3Q7XG4gICAgcGVycHkgLz0gZGlzdDtcbiAgICBwZXJweCAqPSB3aWR0aDtcbiAgICBwZXJweSAqPSB3aWR0aDtcblxuICAgIC8vIHN0YXJ0XG4gICAgdmVydHMucHVzaChwMXggLSBwZXJweCAsIHAxeSAtIHBlcnB5LFxuICAgICAgICAgICAgICAgIHIsIGcsIGIsIGFscGhhKTtcblxuICAgIHZlcnRzLnB1c2gocDF4ICsgcGVycHggLCBwMXkgKyBwZXJweSxcbiAgICAgICAgICAgICAgICByLCBnLCBiLCBhbHBoYSk7XG5cbiAgICBmb3IgKGkgPSAxOyBpIDwgbGVuZ3RoLTE7IGkrKykge1xuICAgICAgICBwMXggPSBwb2ludHNbKGktMSkqMl07XG4gICAgICAgIHAxeSA9IHBvaW50c1soaS0xKSoyICsgMV07XG5cbiAgICAgICAgcDJ4ID0gcG9pbnRzWyhpKSoyXTtcbiAgICAgICAgcDJ5ID0gcG9pbnRzWyhpKSoyICsgMV07XG5cbiAgICAgICAgcDN4ID0gcG9pbnRzWyhpKzEpKjJdO1xuICAgICAgICBwM3kgPSBwb2ludHNbKGkrMSkqMiArIDFdO1xuXG4gICAgICAgIHBlcnB4ID0gLShwMXkgLSBwMnkpO1xuICAgICAgICBwZXJweSA9IHAxeCAtIHAyeDtcblxuICAgICAgICBkaXN0ID0gTWF0aC5zcXJ0KHBlcnB4KnBlcnB4ICsgcGVycHkqcGVycHkpO1xuICAgICAgICBwZXJweCAvPSBkaXN0O1xuICAgICAgICBwZXJweSAvPSBkaXN0O1xuICAgICAgICBwZXJweCAqPSB3aWR0aDtcbiAgICAgICAgcGVycHkgKj0gd2lkdGg7XG5cbiAgICAgICAgcGVycDJ4ID0gLShwMnkgLSBwM3kpO1xuICAgICAgICBwZXJwMnkgPSBwMnggLSBwM3g7XG5cbiAgICAgICAgZGlzdCA9IE1hdGguc3FydChwZXJwMngqcGVycDJ4ICsgcGVycDJ5KnBlcnAyeSk7XG4gICAgICAgIHBlcnAyeCAvPSBkaXN0O1xuICAgICAgICBwZXJwMnkgLz0gZGlzdDtcbiAgICAgICAgcGVycDJ4ICo9IHdpZHRoO1xuICAgICAgICBwZXJwMnkgKj0gd2lkdGg7XG5cbiAgICAgICAgYTEgPSAoLXBlcnB5ICsgcDF5KSAtICgtcGVycHkgKyBwMnkpO1xuICAgICAgICBiMSA9ICgtcGVycHggKyBwMngpIC0gKC1wZXJweCArIHAxeCk7XG4gICAgICAgIGMxID0gKC1wZXJweCArIHAxeCkgKiAoLXBlcnB5ICsgcDJ5KSAtICgtcGVycHggKyBwMngpICogKC1wZXJweSArIHAxeSk7XG4gICAgICAgIGEyID0gKC1wZXJwMnkgKyBwM3kpIC0gKC1wZXJwMnkgKyBwMnkpO1xuICAgICAgICBiMiA9ICgtcGVycDJ4ICsgcDJ4KSAtICgtcGVycDJ4ICsgcDN4KTtcbiAgICAgICAgYzIgPSAoLXBlcnAyeCArIHAzeCkgKiAoLXBlcnAyeSArIHAyeSkgLSAoLXBlcnAyeCArIHAyeCkgKiAoLXBlcnAyeSArIHAzeSk7XG5cbiAgICAgICAgZGVub20gPSBhMSpiMiAtIGEyKmIxO1xuXG4gICAgICAgIGlmIChNYXRoLmFicyhkZW5vbSkgPCAwLjEgKSB7XG5cbiAgICAgICAgICAgIGRlbm9tKz0xMC4xO1xuICAgICAgICAgICAgdmVydHMucHVzaChwMnggLSBwZXJweCAsIHAyeSAtIHBlcnB5LFxuICAgICAgICAgICAgICAgIHIsIGcsIGIsIGFscGhhKTtcblxuICAgICAgICAgICAgdmVydHMucHVzaChwMnggKyBwZXJweCAsIHAyeSArIHBlcnB5LFxuICAgICAgICAgICAgICAgIHIsIGcsIGIsIGFscGhhKTtcblxuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBweCA9IChiMSpjMiAtIGIyKmMxKS9kZW5vbTtcbiAgICAgICAgcHkgPSAoYTIqYzEgLSBhMSpjMikvZGVub207XG5cblxuICAgICAgICBwZGlzdCA9IChweCAtcDJ4KSAqIChweCAtcDJ4KSArIChweSAtcDJ5KSArIChweSAtcDJ5KTtcblxuXG4gICAgICAgIGlmIChwZGlzdCA+IDE0MCAqIDE0MCkge1xuICAgICAgICAgICAgcGVycDN4ID0gcGVycHggLSBwZXJwMng7XG4gICAgICAgICAgICBwZXJwM3kgPSBwZXJweSAtIHBlcnAyeTtcblxuICAgICAgICAgICAgZGlzdCA9IE1hdGguc3FydChwZXJwM3gqcGVycDN4ICsgcGVycDN5KnBlcnAzeSk7XG4gICAgICAgICAgICBwZXJwM3ggLz0gZGlzdDtcbiAgICAgICAgICAgIHBlcnAzeSAvPSBkaXN0O1xuICAgICAgICAgICAgcGVycDN4ICo9IHdpZHRoO1xuICAgICAgICAgICAgcGVycDN5ICo9IHdpZHRoO1xuXG4gICAgICAgICAgICB2ZXJ0cy5wdXNoKHAyeCAtIHBlcnAzeCwgcDJ5IC1wZXJwM3kpO1xuICAgICAgICAgICAgdmVydHMucHVzaChyLCBnLCBiLCBhbHBoYSk7XG5cbiAgICAgICAgICAgIHZlcnRzLnB1c2gocDJ4ICsgcGVycDN4LCBwMnkgK3BlcnAzeSk7XG4gICAgICAgICAgICB2ZXJ0cy5wdXNoKHIsIGcsIGIsIGFscGhhKTtcblxuICAgICAgICAgICAgdmVydHMucHVzaChwMnggLSBwZXJwM3gsIHAyeSAtcGVycDN5KTtcbiAgICAgICAgICAgIHZlcnRzLnB1c2gociwgZywgYiwgYWxwaGEpO1xuXG4gICAgICAgICAgICBpbmRleENvdW50Kys7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG5cbiAgICAgICAgICAgIHZlcnRzLnB1c2gocHggLCBweSk7XG4gICAgICAgICAgICB2ZXJ0cy5wdXNoKHIsIGcsIGIsIGFscGhhKTtcblxuICAgICAgICAgICAgdmVydHMucHVzaChwMnggLSAocHgtcDJ4KSwgcDJ5IC0gKHB5IC0gcDJ5KSk7XG4gICAgICAgICAgICB2ZXJ0cy5wdXNoKHIsIGcsIGIsIGFscGhhKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHAxeCA9IHBvaW50c1sobGVuZ3RoLTIpKjJdO1xuICAgIHAxeSA9IHBvaW50c1sobGVuZ3RoLTIpKjIgKyAxXTtcblxuICAgIHAyeCA9IHBvaW50c1sobGVuZ3RoLTEpKjJdO1xuICAgIHAyeSA9IHBvaW50c1sobGVuZ3RoLTEpKjIgKyAxXTtcblxuICAgIHBlcnB4ID0gLShwMXkgLSBwMnkpO1xuICAgIHBlcnB5ID0gcDF4IC0gcDJ4O1xuXG4gICAgZGlzdCA9IE1hdGguc3FydChwZXJweCpwZXJweCArIHBlcnB5KnBlcnB5KTtcbiAgICBwZXJweCAvPSBkaXN0O1xuICAgIHBlcnB5IC89IGRpc3Q7XG4gICAgcGVycHggKj0gd2lkdGg7XG4gICAgcGVycHkgKj0gd2lkdGg7XG5cbiAgICB2ZXJ0cy5wdXNoKHAyeCAtIHBlcnB4ICwgcDJ5IC0gcGVycHkpO1xuICAgIHZlcnRzLnB1c2gociwgZywgYiwgYWxwaGEpO1xuXG4gICAgdmVydHMucHVzaChwMnggKyBwZXJweCAsIHAyeSArIHBlcnB5KTtcbiAgICB2ZXJ0cy5wdXNoKHIsIGcsIGIsIGFscGhhKTtcblxuICAgIGluZGljZXMucHVzaChpbmRleFN0YXJ0KTtcblxuICAgIGZvciAoaSA9IDA7IGkgPCBpbmRleENvdW50OyBpKyspIHtcbiAgICAgICAgaW5kaWNlcy5wdXNoKGluZGV4U3RhcnQrKyk7XG4gICAgfVxuXG4gICAgaW5kaWNlcy5wdXNoKGluZGV4U3RhcnQtMSk7XG59O1xuXG4vKipcbiAqIEJ1aWxkcyBhIGNvbXBsZXggcG9seWdvbiB0byBkcmF3XG4gKlxuICogQHN0YXRpY1xuICogQHByaXZhdGVcbiAqIEBwYXJhbSBncmFwaGljc0RhdGEge0dyYXBoaWNzfSBUaGUgZ3JhcGhpY3Mgb2JqZWN0IGNvbnRhaW5pbmcgYWxsIHRoZSBuZWNlc3NhcnkgcHJvcGVydGllc1xuICogQHBhcmFtIHdlYkdMRGF0YSB7b2JqZWN0fVxuICovXG5XZWJHTEdyYXBoaWNzLmJ1aWxkQ29tcGxleFBvbHkgPSBmdW5jdGlvbiAoZ3JhcGhpY3NEYXRhLCB3ZWJHTERhdGEpIHtcbiAgICAvL1RPRE8gLSBubyBuZWVkIHRvIGNvcHkgdGhpcyBhcyBpdCBnZXRzIHR1cm5lZCBpbnRvIGEgRkxvYXQzMkFycmF5IGFueXdheXMuLlxuICAgIHZhciBwb2ludHMgPSBncmFwaGljc0RhdGEucG9pbnRzLnNsaWNlKCk7XG5cbiAgICBpZiAocG9pbnRzLmxlbmd0aCA8IDYpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIGdldCBmaXJzdCBhbmQgbGFzdCBwb2ludC4uIGZpZ3VyZSBvdXQgdGhlIG1pZGRsZSFcbiAgICB2YXIgaW5kaWNlcyA9IHdlYkdMRGF0YS5pbmRpY2VzO1xuICAgIHdlYkdMRGF0YS5wb2ludHMgPSBwb2ludHM7XG4gICAgd2ViR0xEYXRhLmFscGhhID0gZ3JhcGhpY3NEYXRhLmZpbGxBbHBoYTtcbiAgICB3ZWJHTERhdGEuY29sb3IgPSB1dGlscy5oZXgycmdiKGdyYXBoaWNzRGF0YS5maWxsQ29sb3IpO1xuXG4gICAgLy8gY2FsY2xhdGUgdGhlIGJvdW5kcy4uXG4gICAgdmFyIG1pblggPSBJbmZpbml0eTtcbiAgICB2YXIgbWF4WCA9IC1JbmZpbml0eTtcblxuICAgIHZhciBtaW5ZID0gSW5maW5pdHk7XG4gICAgdmFyIG1heFkgPSAtSW5maW5pdHk7XG5cbiAgICB2YXIgeCx5O1xuXG4gICAgLy8gZ2V0IHNpemUuLlxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSs9Mikge1xuICAgICAgICB4ID0gcG9pbnRzW2ldO1xuICAgICAgICB5ID0gcG9pbnRzW2krMV07XG5cbiAgICAgICAgbWluWCA9IHggPCBtaW5YID8geCA6IG1pblg7XG4gICAgICAgIG1heFggPSB4ID4gbWF4WCA/IHggOiBtYXhYO1xuXG4gICAgICAgIG1pblkgPSB5IDwgbWluWSA/IHkgOiBtaW5ZO1xuICAgICAgICBtYXhZID0geSA+IG1heFkgPyB5IDogbWF4WTtcbiAgICB9XG5cbiAgICAvLyBhZGQgYSBxdWFkIHRvIHRoZSBlbmQgY29zIHRoZXJlIGlzIG5vIHBvaW50IG1ha2luZyBhbm90aGVyIGJ1ZmZlciFcbiAgICBwb2ludHMucHVzaChtaW5YLCBtaW5ZLFxuICAgICAgICAgICAgICAgIG1heFgsIG1pblksXG4gICAgICAgICAgICAgICAgbWF4WCwgbWF4WSxcbiAgICAgICAgICAgICAgICBtaW5YLCBtYXhZKTtcblxuICAgIC8vIHB1c2ggYSBxdWFkIG9udG8gdGhlIGVuZC4uXG5cbiAgICAvL1RPRE8gLSB0aGlzIGFpbnQgbmVlZGVkIVxuICAgIHZhciBsZW5ndGggPSBwb2ludHMubGVuZ3RoIC8gMjtcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgaW5kaWNlcy5wdXNoKCBpICk7XG4gICAgfVxuXG59O1xuXG4vKipcbiAqIEJ1aWxkcyBhIHBvbHlnb24gdG8gZHJhd1xuICpcbiAqIEBzdGF0aWNcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0gZ3JhcGhpY3NEYXRhIHtHcmFwaGljc30gVGhlIGdyYXBoaWNzIG9iamVjdCBjb250YWluaW5nIGFsbCB0aGUgbmVjZXNzYXJ5IHByb3BlcnRpZXNcbiAqIEBwYXJhbSB3ZWJHTERhdGEge29iamVjdH1cbiAqL1xuV2ViR0xHcmFwaGljcy5idWlsZFBvbHkgPSBmdW5jdGlvbiAoZ3JhcGhpY3NEYXRhLCB3ZWJHTERhdGEpIHtcbiAgICB2YXIgcG9pbnRzID0gZ3JhcGhpY3NEYXRhLnBvaW50cztcblxuICAgIGlmIChwb2ludHMubGVuZ3RoIDwgNikge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIGdldCBmaXJzdCBhbmQgbGFzdCBwb2ludC4uIGZpZ3VyZSBvdXQgdGhlIG1pZGRsZSFcbiAgICB2YXIgdmVydHMgPSB3ZWJHTERhdGEucG9pbnRzO1xuICAgIHZhciBpbmRpY2VzID0gd2ViR0xEYXRhLmluZGljZXM7XG5cbiAgICB2YXIgbGVuZ3RoID0gcG9pbnRzLmxlbmd0aCAvIDI7XG5cbiAgICAvLyBzb3J0IGNvbG9yXG4gICAgdmFyIGNvbG9yID0gdXRpbHMuaGV4MnJnYihncmFwaGljc0RhdGEuZmlsbENvbG9yKTtcbiAgICB2YXIgYWxwaGEgPSBncmFwaGljc0RhdGEuZmlsbEFscGhhO1xuICAgIHZhciByID0gY29sb3JbMF0gKiBhbHBoYTtcbiAgICB2YXIgZyA9IGNvbG9yWzFdICogYWxwaGE7XG4gICAgdmFyIGIgPSBjb2xvclsyXSAqIGFscGhhO1xuXG4gICAgdmFyIHRyaWFuZ2xlcyA9IHV0aWxzLlBvbHlLLlRyaWFuZ3VsYXRlKHBvaW50cyk7XG5cbiAgICBpZiAoIXRyaWFuZ2xlcykge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgdmFyIHZlcnRQb3MgPSB2ZXJ0cy5sZW5ndGggLyA2O1xuXG4gICAgdmFyIGkgPSAwO1xuXG4gICAgZm9yIChpID0gMDsgaSA8IHRyaWFuZ2xlcy5sZW5ndGg7IGkrPTMpIHtcbiAgICAgICAgaW5kaWNlcy5wdXNoKHRyaWFuZ2xlc1tpXSArIHZlcnRQb3MpO1xuICAgICAgICBpbmRpY2VzLnB1c2godHJpYW5nbGVzW2ldICsgdmVydFBvcyk7XG4gICAgICAgIGluZGljZXMucHVzaCh0cmlhbmdsZXNbaSsxXSArIHZlcnRQb3MpO1xuICAgICAgICBpbmRpY2VzLnB1c2godHJpYW5nbGVzW2krMl0gK3ZlcnRQb3MpO1xuICAgICAgICBpbmRpY2VzLnB1c2godHJpYW5nbGVzW2krMl0gKyB2ZXJ0UG9zKTtcbiAgICB9XG5cbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmVydHMucHVzaChwb2ludHNbaSAqIDJdLCBwb2ludHNbaSAqIDIgKyAxXSxcbiAgICAgICAgICAgICAgICAgICByLCBnLCBiLCBhbHBoYSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG59O1xuXG5XZWJHTEdyYXBoaWNzLmdyYXBoaWNzRGF0YVBvb2wgPSBbXTtcbiIsIi8qKlxuICogQGNsYXNzXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBXZWJHTEdyYXBoaWNzRGF0YShnbCkge1xuICAgIHRoaXMuZ2wgPSBnbDtcblxuICAgIC8vVE9ETyBkb2VzIHRoaXMgbmVlZCB0byBiZSBzcGxpdCBiZWZvcmUgdXBsb2Rpbmc/P1xuICAgIHRoaXMuY29sb3IgPSBbMCwgMCwgMF07IC8vIGNvbG9yIHNwbGl0IVxuICAgIHRoaXMucG9pbnRzID0gW107XG4gICAgdGhpcy5pbmRpY2VzID0gW107XG4gICAgdGhpcy5idWZmZXIgPSBnbC5jcmVhdGVCdWZmZXIoKTtcbiAgICB0aGlzLmluZGV4QnVmZmVyID0gZ2wuY3JlYXRlQnVmZmVyKCk7XG4gICAgdGhpcy5tb2RlID0gMTtcbiAgICB0aGlzLmFscGhhID0gMTtcbiAgICB0aGlzLmRpcnR5ID0gdHJ1ZTtcbn1cblxuV2ViR0xHcmFwaGljc0RhdGEucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gV2ViR0xHcmFwaGljc0RhdGE7XG5tb2R1bGUuZXhwb3J0cyA9IFdlYkdMR3JhcGhpY3NEYXRhO1xuXG4vKipcbiAqXG4gKi9cbldlYkdMR3JhcGhpY3NEYXRhLnByb3RvdHlwZS5yZXNldCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnBvaW50cy5sZW5ndGggPSAwO1xuICAgIHRoaXMuaW5kaWNlcy5sZW5ndGggPSAwO1xufTtcblxuLyoqXG4gKlxuICovXG5XZWJHTEdyYXBoaWNzRGF0YS5wcm90b3R5cGUudXBsb2FkID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBnbCA9IHRoaXMuZ2w7XG5cbi8vICAgIHRoaXMubGFzdEluZGV4ID0gZ3JhcGhpY3MuZ3JhcGhpY3NEYXRhLmxlbmd0aDtcbiAgICB0aGlzLmdsUG9pbnRzID0gbmV3IEZsb2F0MzJBcnJheSh0aGlzLnBvaW50cyk7XG5cbiAgICBnbC5iaW5kQnVmZmVyKGdsLkFSUkFZX0JVRkZFUiwgdGhpcy5idWZmZXIpO1xuICAgIGdsLmJ1ZmZlckRhdGEoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLmdsUG9pbnRzLCBnbC5TVEFUSUNfRFJBVyk7XG5cbiAgICB0aGlzLmdsSW5kaWNpZXMgPSBuZXcgVWludDE2QXJyYXkodGhpcy5pbmRpY2VzKTtcblxuICAgIGdsLmJpbmRCdWZmZXIoZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIsIHRoaXMuaW5kZXhCdWZmZXIpO1xuICAgIGdsLmJ1ZmZlckRhdGEoZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIsIHRoaXMuZ2xJbmRpY2llcywgZ2wuU1RBVElDX0RSQVcpO1xuXG4gICAgdGhpcy5kaXJ0eSA9IGZhbHNlO1xufTtcbiIsInZhciBUZXh0dXJlVXZzID0gcmVxdWlyZSgnLi4vLi4vLi4vdGV4dHVyZXMvVGV4dHVyZVV2cycpLFxuICAgIFNoYWRlciA9IHJlcXVpcmUoJy4uL3NoYWRlcnMvU2hhZGVyJyk7XG5cbi8qKlxuICogQGF1dGhvciBNYXQgR3JvdmVzXG4gKlxuICogQmlnIHRoYW5rcyB0byB0aGUgdmVyeSBjbGV2ZXIgTWF0dCBEZXNMYXVyaWVycyA8bWF0dGRlc2w+IGh0dHBzOi8vZ2l0aHViLmNvbS9tYXR0ZGVzbC9cbiAqIGZvciBjcmVhdGluZyB0aGUgb3JpZ2luYWwgcGl4aSB2ZXJzaW9uIVxuICogQWxzbyBhIHRoYW5rcyB0byBodHRwczovL2dpdGh1Yi5jb20vYmNoZXZhbGllciBmb3IgdHdlYWtpbmcgdGhlIHRpbnQgYW5kIGFscGhhIHNvIHRoYXQgdGhleSBub3cgc2hhcmUgNCBieXRlcyBvbiB0aGUgdmVydGV4IGJ1ZmZlclxuICpcbiAqIEhlYXZpbHkgaW5zcGlyZWQgYnkgTGliR0RYJ3MgV2ViR0xTcHJpdGVCYXRjaDpcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9saWJnZHgvbGliZ2R4L2Jsb2IvbWFzdGVyL2dkeC9zcmMvY29tL2JhZGxvZ2ljL2dkeC9ncmFwaGljcy9nMmQvV2ViR0xTcHJpdGVCYXRjaC5qYXZhXG4gKi9cblxuLyoqXG4gKlxuICogQGNsYXNzXG4gKiBAcHJpdmF0ZVxuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9IFRoZSByZW5kZXJlciB0aGlzIHNwcml0ZSBiYXRjaCB3b3JrcyBmb3IuXG4gKi9cbmZ1bmN0aW9uIFdlYkdMU3ByaXRlQmF0Y2gocmVuZGVyZXIpIHtcbiAgICAvKipcbiAgICAgKlxuICAgICAqXG4gICAgICogQG1lbWJlciB7V2ViR0xSZW5kZXJlcn1cbiAgICAgKi9cbiAgICB0aGlzLnJlbmRlcmVyID0gcmVuZGVyZXI7XG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMudmVydFNpemUgPSA1O1xuXG4gICAgLyoqXG4gICAgICogVGhlIG51bWJlciBvZiBpbWFnZXMgaW4gdGhlIFNwcml0ZUJhdGNoIGJlZm9yZSBpdCBmbHVzaGVzLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMuc2l6ZSA9IDIwMDA7Ly9NYXRoLnBvdygyLCAxNikgLyAgdGhpcy52ZXJ0U2l6ZTtcblxuICAgIC8vIHRoZSB0b3RhbCBudW1iZXIgb2YgYnl0ZXMgaW4gb3VyIGJhdGNoXG4gICAgdmFyIG51bVZlcnRzID0gdGhpcy5zaXplICogNCAqIDQgKiB0aGlzLnZlcnRTaXplO1xuICAgIC8vIHRoZSB0b3RhbCBudW1iZXIgb2YgaW5kaWNlcyBpbiBvdXIgYmF0Y2hcbiAgICB2YXIgbnVtSW5kaWNlcyA9IHRoaXMuc2l6ZSAqIDY7XG5cbiAgICAvKipcbiAgICAgKiBIb2xkcyB0aGUgdmVydGljZXNcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0FycmF5QnVmZmVyfVxuICAgICAqL1xuICAgIHRoaXMudmVydGljZXMgPSBuZXcgQXJyYXlCdWZmZXIobnVtVmVydHMpO1xuXG4gICAgLyoqXG4gICAgICogVmlldyBvbiB0aGUgdmVydGljZXMgYXMgYSBGbG9hdDMyQXJyYXlcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0Zsb2F0MzJBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLnBvc2l0aW9ucyA9IG5ldyBGbG9hdDMyQXJyYXkodGhpcy52ZXJ0aWNlcyk7XG5cbiAgICAvKipcbiAgICAgKiBWaWV3IG9uIHRoZSB2ZXJ0aWNlcyBhcyBhIFVpbnQzMkFycmF5XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtVaW50MzJBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLmNvbG9ycyA9IG5ldyBVaW50MzJBcnJheSh0aGlzLnZlcnRpY2VzKTtcblxuICAgIC8qKlxuICAgICAqIEhvbGRzIHRoZSBpbmRpY2VzXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtVaW50MTZBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLmluZGljZXMgPSBuZXcgVWludDE2QXJyYXkobnVtSW5kaWNlcyk7XG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMubGFzdEluZGV4Q291bnQgPSAwO1xuXG4gICAgZm9yICh2YXIgaT0wLCBqPTA7IGkgPCBudW1JbmRpY2VzOyBpICs9IDYsIGogKz0gNCkge1xuICAgICAgICB0aGlzLmluZGljZXNbaSArIDBdID0gaiArIDA7XG4gICAgICAgIHRoaXMuaW5kaWNlc1tpICsgMV0gPSBqICsgMTtcbiAgICAgICAgdGhpcy5pbmRpY2VzW2kgKyAyXSA9IGogKyAyO1xuICAgICAgICB0aGlzLmluZGljZXNbaSArIDNdID0gaiArIDA7XG4gICAgICAgIHRoaXMuaW5kaWNlc1tpICsgNF0gPSBqICsgMjtcbiAgICAgICAgdGhpcy5pbmRpY2VzW2kgKyA1XSA9IGogKyAzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMuZHJhd2luZyA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLmN1cnJlbnRCYXRjaFNpemUgPSAwO1xuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0Jhc2VUZXh0dXJlfVxuICAgICAqL1xuICAgIHRoaXMuY3VycmVudEJhc2VUZXh0dXJlID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuXG4gICAgLyoqXG4gICAgICpcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0FycmF5fVxuICAgICAqL1xuICAgIHRoaXMudGV4dHVyZXMgPSBbXTtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLmJsZW5kTW9kZXMgPSBbXTtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLnNoYWRlcnMgPSBbXTtcblxuICAgIC8qKlxuICAgICAqXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLnNwcml0ZXMgPSBbXTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBkZWZhdWx0IHNoYWRlciB0aGF0IGlzIHVzZWQgaWYgYSBzcHJpdGUgZG9lc24ndCBoYXZlIGEgbW9yZSBzcGVjaWZpYyBvbmUuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtTaGFkZXJ9XG4gICAgICovXG4gICAgdGhpcy5zaGFkZXIgPSBudWxsO1xuXG4gICAgLy8gbGlzdGVuIGZvciBjb250ZXh0IGFuZCB1cGRhdGUgbmVjZXNzYXJ5IGJ1ZmZlcnNcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy5yZW5kZXJlci5vbignY29udGV4dCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgc2VsZi5zZXR1cENvbnRleHQoKTtcbiAgICB9KTtcbn1cblxuV2ViR0xTcHJpdGVCYXRjaC5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBXZWJHTFNwcml0ZUJhdGNoO1xubW9kdWxlLmV4cG9ydHMgPSBXZWJHTFNwcml0ZUJhdGNoO1xuXG4vKipcbiAqIEBwYXJhbSBnbCB7V2ViR0xDb250ZXh0fSB0aGUgY3VycmVudCBXZWJHTCBkcmF3aW5nIGNvbnRleHRcbiAqL1xuV2ViR0xTcHJpdGVCYXRjaC5wcm90b3R5cGUuc2V0dXBDb250ZXh0ID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBnbCA9IHRoaXMucmVuZGVyZXIuZ2w7XG5cbiAgICAvLyBzZXR1cCBkZWZhdWx0IHNoYWRlclxuICAgIHRoaXMuc2hhZGVyID0gbmV3IFNoYWRlcihnbCk7XG5cbiAgICAvLyBjcmVhdGUgYSBjb3VwbGUgb2YgYnVmZmVyc1xuICAgIHRoaXMudmVydGV4QnVmZmVyID0gZ2wuY3JlYXRlQnVmZmVyKCk7XG4gICAgdGhpcy5pbmRleEJ1ZmZlciA9IGdsLmNyZWF0ZUJ1ZmZlcigpO1xuXG4gICAgLy8gNjU1MzUgaXMgbWF4IGluZGV4LCBzbyA2NTUzNSAvIDYgPSAxMDkyMi5cblxuICAgIC8vdXBsb2FkIHRoZSBpbmRleCBkYXRhXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5FTEVNRU5UX0FSUkFZX0JVRkZFUiwgdGhpcy5pbmRleEJ1ZmZlcik7XG4gICAgZ2wuYnVmZmVyRGF0YShnbC5FTEVNRU5UX0FSUkFZX0JVRkZFUiwgdGhpcy5pbmRpY2VzLCBnbC5TVEFUSUNfRFJBVyk7XG5cbiAgICBnbC5iaW5kQnVmZmVyKGdsLkFSUkFZX0JVRkZFUiwgdGhpcy52ZXJ0ZXhCdWZmZXIpO1xuICAgIGdsLmJ1ZmZlckRhdGEoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLnZlcnRpY2VzLCBnbC5EWU5BTUlDX0RSQVcpO1xuXG4gICAgdGhpcy5jdXJyZW50QmxlbmRNb2RlID0gOTk5OTk7XG59O1xuXG4vKipcbiAqXG4gKi9cbldlYkdMU3ByaXRlQmF0Y2gucHJvdG90eXBlLmJlZ2luID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIHRoaXMuc2hhZGVyID0gdGhpcy5yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLmRlZmF1bHRTaGFkZXI7XG5cbiAgICB0aGlzLnN0YXJ0KCk7XG59O1xuXG4vKipcbiAqL1xuV2ViR0xTcHJpdGVCYXRjaC5wcm90b3R5cGUuZW5kID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZmx1c2goKTtcbn07XG5cbi8qKlxuICogQHBhcmFtIHNwcml0ZSB7U3ByaXRlfSB0aGUgc3ByaXRlIHRvIHJlbmRlciB3aGVuIHVzaW5nIHRoaXMgc3ByaXRlYmF0Y2hcbiAqL1xuV2ViR0xTcHJpdGVCYXRjaC5wcm90b3R5cGUucmVuZGVyID0gZnVuY3Rpb24gKHNwcml0ZSkge1xuICAgIHZhciB0ZXh0dXJlID0gc3ByaXRlLnRleHR1cmU7XG5cbiAgICAvL1RPRE8gc2V0IGJsZW5kIG1vZGVzLi5cbiAgICAvLyBjaGVjayB0ZXh0dXJlLi5cbiAgICBpZiAodGhpcy5jdXJyZW50QmF0Y2hTaXplID49IHRoaXMuc2l6ZSkge1xuICAgICAgICB0aGlzLmZsdXNoKCk7XG4gICAgICAgIHRoaXMuY3VycmVudEJhc2VUZXh0dXJlID0gdGV4dHVyZS5iYXNlVGV4dHVyZTtcbiAgICB9XG5cbiAgICAvLyBnZXQgdGhlIHV2cyBmb3IgdGhlIHRleHR1cmVcbiAgICB2YXIgdXZzID0gdGV4dHVyZS5fdXZzO1xuXG4gICAgLy8gaWYgdGhlIHV2cyBoYXZlIG5vdCB1cGRhdGVkIHRoZW4gbm8gcG9pbnQgcmVuZGVyaW5nIGp1c3QgeWV0IVxuICAgIGlmICghdXZzKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBUT0RPIHRyaW0/P1xuICAgIHZhciBhWCA9IHNwcml0ZS5hbmNob3IueDtcbiAgICB2YXIgYVkgPSBzcHJpdGUuYW5jaG9yLnk7XG5cbiAgICB2YXIgdzAsIHcxLCBoMCwgaDE7XG5cbiAgICBpZiAodGV4dHVyZS50cmltKSB7XG4gICAgICAgIC8vIGlmIHRoZSBzcHJpdGUgaXMgdHJpbW1lZCB0aGVuIHdlIG5lZWQgdG8gYWRkIHRoZSBleHRyYSBzcGFjZSBiZWZvcmUgdHJhbnNmb3JtaW5nIHRoZSBzcHJpdGUgY29vcmRzLi5cbiAgICAgICAgdmFyIHRyaW0gPSB0ZXh0dXJlLnRyaW07XG5cbiAgICAgICAgdzEgPSB0cmltLnggLSBhWCAqIHRyaW0ud2lkdGg7XG4gICAgICAgIHcwID0gdzEgKyB0ZXh0dXJlLmNyb3Aud2lkdGg7XG5cbiAgICAgICAgaDEgPSB0cmltLnkgLSBhWSAqIHRyaW0uaGVpZ2h0O1xuICAgICAgICBoMCA9IGgxICsgdGV4dHVyZS5jcm9wLmhlaWdodDtcblxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdzAgPSAodGV4dHVyZS5mcmFtZS53aWR0aCApICogKDEtYVgpO1xuICAgICAgICB3MSA9ICh0ZXh0dXJlLmZyYW1lLndpZHRoICkgKiAtYVg7XG5cbiAgICAgICAgaDAgPSB0ZXh0dXJlLmZyYW1lLmhlaWdodCAqICgxLWFZKTtcbiAgICAgICAgaDEgPSB0ZXh0dXJlLmZyYW1lLmhlaWdodCAqIC1hWTtcbiAgICB9XG5cbiAgICB2YXIgaW5kZXggPSB0aGlzLmN1cnJlbnRCYXRjaFNpemUgKiA0ICogdGhpcy52ZXJ0U2l6ZTtcblxuICAgIHZhciByZXNvbHV0aW9uID0gdGV4dHVyZS5iYXNlVGV4dHVyZS5yZXNvbHV0aW9uO1xuXG4gICAgdmFyIHdvcmxkVHJhbnNmb3JtID0gc3ByaXRlLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgdmFyIGEgPSB3b3JsZFRyYW5zZm9ybS5hIC8gcmVzb2x1dGlvbjtcbiAgICB2YXIgYiA9IHdvcmxkVHJhbnNmb3JtLmIgLyByZXNvbHV0aW9uO1xuICAgIHZhciBjID0gd29ybGRUcmFuc2Zvcm0uYyAvIHJlc29sdXRpb247XG4gICAgdmFyIGQgPSB3b3JsZFRyYW5zZm9ybS5kIC8gcmVzb2x1dGlvbjtcbiAgICB2YXIgdHggPSB3b3JsZFRyYW5zZm9ybS50eDtcbiAgICB2YXIgdHkgPSB3b3JsZFRyYW5zZm9ybS50eTtcblxuICAgIHZhciBjb2xvcnMgPSB0aGlzLmNvbG9ycztcbiAgICB2YXIgcG9zaXRpb25zID0gdGhpcy5wb3NpdGlvbnM7XG5cbiAgICBpZiAodGhpcy5yZW5kZXJlci5yb3VuZFBpeGVscykge1xuICAgICAgICAvLyB4eVxuICAgICAgICBwb3NpdGlvbnNbaW5kZXhdID0gYSAqIHcxICsgYyAqIGgxICsgdHggfCAwO1xuICAgICAgICBwb3NpdGlvbnNbaW5kZXgrMV0gPSBkICogaDEgKyBiICogdzEgKyB0eSB8IDA7XG5cbiAgICAgICAgLy8geHlcbiAgICAgICAgcG9zaXRpb25zW2luZGV4KzVdID0gYSAqIHcwICsgYyAqIGgxICsgdHggfCAwO1xuICAgICAgICBwb3NpdGlvbnNbaW5kZXgrNl0gPSBkICogaDEgKyBiICogdzAgKyB0eSB8IDA7XG5cbiAgICAgICAgIC8vIHh5XG4gICAgICAgIHBvc2l0aW9uc1tpbmRleCsxMF0gPSBhICogdzAgKyBjICogaDAgKyB0eCB8IDA7XG4gICAgICAgIHBvc2l0aW9uc1tpbmRleCsxMV0gPSBkICogaDAgKyBiICogdzAgKyB0eSB8IDA7XG5cbiAgICAgICAgLy8geHlcbiAgICAgICAgcG9zaXRpb25zW2luZGV4KzE1XSA9IGEgKiB3MSArIGMgKiBoMCArIHR4IHwgMDtcbiAgICAgICAgcG9zaXRpb25zW2luZGV4KzE2XSA9IGQgKiBoMCArIGIgKiB3MSArIHR5IHwgMDtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIC8vIHh5XG4gICAgICAgIHBvc2l0aW9uc1tpbmRleF0gPSBhICogdzEgKyBjICogaDEgKyB0eDtcbiAgICAgICAgcG9zaXRpb25zW2luZGV4KzFdID0gZCAqIGgxICsgYiAqIHcxICsgdHk7XG5cbiAgICAgICAgLy8geHlcbiAgICAgICAgcG9zaXRpb25zW2luZGV4KzVdID0gYSAqIHcwICsgYyAqIGgxICsgdHg7XG4gICAgICAgIHBvc2l0aW9uc1tpbmRleCs2XSA9IGQgKiBoMSArIGIgKiB3MCArIHR5O1xuXG4gICAgICAgICAvLyB4eVxuICAgICAgICBwb3NpdGlvbnNbaW5kZXgrMTBdID0gYSAqIHcwICsgYyAqIGgwICsgdHg7XG4gICAgICAgIHBvc2l0aW9uc1tpbmRleCsxMV0gPSBkICogaDAgKyBiICogdzAgKyB0eTtcblxuICAgICAgICAvLyB4eVxuICAgICAgICBwb3NpdGlvbnNbaW5kZXgrMTVdID0gYSAqIHcxICsgYyAqIGgwICsgdHg7XG4gICAgICAgIHBvc2l0aW9uc1tpbmRleCsxNl0gPSBkICogaDAgKyBiICogdzEgKyB0eTtcbiAgICB9XG5cbiAgICAvLyB1dlxuICAgIHBvc2l0aW9uc1tpbmRleCsyXSA9IHV2cy54MDtcbiAgICBwb3NpdGlvbnNbaW5kZXgrM10gPSB1dnMueTA7XG5cbiAgICAvLyB1dlxuICAgIHBvc2l0aW9uc1tpbmRleCs3XSA9IHV2cy54MTtcbiAgICBwb3NpdGlvbnNbaW5kZXgrOF0gPSB1dnMueTE7XG5cbiAgICAgLy8gdXZcbiAgICBwb3NpdGlvbnNbaW5kZXgrMTJdID0gdXZzLngyO1xuICAgIHBvc2l0aW9uc1tpbmRleCsxM10gPSB1dnMueTI7XG5cbiAgICAvLyB1dlxuICAgIHBvc2l0aW9uc1tpbmRleCsxN10gPSB1dnMueDM7XG4gICAgcG9zaXRpb25zW2luZGV4KzE4XSA9IHV2cy55MztcblxuICAgIC8vIGNvbG9yIGFuZCBhbHBoYVxuICAgIHZhciB0aW50ID0gc3ByaXRlLnRpbnQ7XG4gICAgY29sb3JzW2luZGV4KzRdID0gY29sb3JzW2luZGV4KzldID0gY29sb3JzW2luZGV4KzE0XSA9IGNvbG9yc1tpbmRleCsxOV0gPSAodGludCA+PiAxNikgKyAodGludCAmIDB4ZmYwMCkgKyAoKHRpbnQgJiAweGZmKSA8PCAxNikgKyAoc3ByaXRlLndvcmxkQWxwaGEgKiAyNTUgPDwgMjQpO1xuXG4gICAgLy8gaW5jcmVtZW50IHRoZSBiYXRjaHNpemVcbiAgICB0aGlzLnNwcml0ZXNbdGhpcy5jdXJyZW50QmF0Y2hTaXplKytdID0gc3ByaXRlO1xuXG5cbn07XG5cbi8qKlxuICogUmVuZGVycyBhIFRpbGluZ1Nwcml0ZSB1c2luZyB0aGUgc3ByaXRlQmF0Y2guXG4gKlxuICogQHBhcmFtIHNwcml0ZSB7VGlsaW5nU3ByaXRlfSB0aGUgdGlsaW5nU3ByaXRlIHRvIHJlbmRlclxuICovXG5XZWJHTFNwcml0ZUJhdGNoLnByb3RvdHlwZS5yZW5kZXJUaWxpbmdTcHJpdGUgPSBmdW5jdGlvbiAodGlsaW5nU3ByaXRlKSB7XG4gICAgdmFyIHRleHR1cmUgPSB0aWxpbmdTcHJpdGUudGlsaW5nVGV4dHVyZTtcblxuICAgIC8vIGNoZWNrIHRleHR1cmUuLlxuICAgIGlmICh0aGlzLmN1cnJlbnRCYXRjaFNpemUgPj0gdGhpcy5zaXplKSB7XG4gICAgICAgIC8vcmV0dXJuO1xuICAgICAgICB0aGlzLmZsdXNoKCk7XG4gICAgICAgIHRoaXMuY3VycmVudEJhc2VUZXh0dXJlID0gdGV4dHVyZS5iYXNlVGV4dHVyZTtcbiAgICB9XG5cbiAgICAvLyBzZXQgdGhlIHRleHR1cmVzIHV2cyB0ZW1wb3JhcmlseVxuICAgIC8vIFRPRE8gY3JlYXRlIGEgc2VwYXJhdGUgdGV4dHVyZSBzbyB0aGF0IHdlIGNhbiB0aWxlIHBhcnQgb2YgYSB0ZXh0dXJlXG5cbiAgICBpZiAoIXRpbGluZ1Nwcml0ZS5fdXZzKSB7XG4gICAgICAgIHRpbGluZ1Nwcml0ZS5fdXZzID0gbmV3IFRleHR1cmVVdnMoKTtcbiAgICB9XG5cbiAgICB2YXIgdXZzID0gdGlsaW5nU3ByaXRlLl91dnM7XG5cbiAgICB0aWxpbmdTcHJpdGUudGlsZVBvc2l0aW9uLnggJT0gdGV4dHVyZS5iYXNlVGV4dHVyZS53aWR0aCAqIHRpbGluZ1Nwcml0ZS50aWxlU2NhbGVPZmZzZXQueDtcbiAgICB0aWxpbmdTcHJpdGUudGlsZVBvc2l0aW9uLnkgJT0gdGV4dHVyZS5iYXNlVGV4dHVyZS5oZWlnaHQgKiB0aWxpbmdTcHJpdGUudGlsZVNjYWxlT2Zmc2V0Lnk7XG5cbiAgICB2YXIgb2Zmc2V0WCA9ICB0aWxpbmdTcHJpdGUudGlsZVBvc2l0aW9uLngvKHRleHR1cmUuYmFzZVRleHR1cmUud2lkdGgqdGlsaW5nU3ByaXRlLnRpbGVTY2FsZU9mZnNldC54KTtcbiAgICB2YXIgb2Zmc2V0WSA9ICB0aWxpbmdTcHJpdGUudGlsZVBvc2l0aW9uLnkvKHRleHR1cmUuYmFzZVRleHR1cmUuaGVpZ2h0KnRpbGluZ1Nwcml0ZS50aWxlU2NhbGVPZmZzZXQueSk7XG5cbiAgICB2YXIgc2NhbGVYID0gICh0aWxpbmdTcHJpdGUud2lkdGggLyB0ZXh0dXJlLmJhc2VUZXh0dXJlLndpZHRoKSAgLyAodGlsaW5nU3ByaXRlLnRpbGVTY2FsZS54ICogdGlsaW5nU3ByaXRlLnRpbGVTY2FsZU9mZnNldC54KTtcbiAgICB2YXIgc2NhbGVZID0gICh0aWxpbmdTcHJpdGUuaGVpZ2h0IC8gdGV4dHVyZS5iYXNlVGV4dHVyZS5oZWlnaHQpIC8gKHRpbGluZ1Nwcml0ZS50aWxlU2NhbGUueSAqIHRpbGluZ1Nwcml0ZS50aWxlU2NhbGVPZmZzZXQueSk7XG5cbiAgICB1dnMueDAgPSAwIC0gb2Zmc2V0WDtcbiAgICB1dnMueTAgPSAwIC0gb2Zmc2V0WTtcblxuICAgIHV2cy54MSA9ICgxICogc2NhbGVYKSAtIG9mZnNldFg7XG4gICAgdXZzLnkxID0gMCAtIG9mZnNldFk7XG5cbiAgICB1dnMueDIgPSAoMSAqIHNjYWxlWCkgLSBvZmZzZXRYO1xuICAgIHV2cy55MiA9ICgxICogc2NhbGVZKSAtIG9mZnNldFk7XG5cbiAgICB1dnMueDMgPSAwIC0gb2Zmc2V0WDtcbiAgICB1dnMueTMgPSAoMSAqIHNjYWxlWSkgLSBvZmZzZXRZO1xuXG4gICAgLy8gZ2V0IHRoZSB0aWxpbmdTcHJpdGVzIGN1cnJlbnQgYWxwaGEgYW5kIHRpbnQgYW5kIGNvbWJpbmluZyB0aGVtIGludG8gYSBzaW5nbGUgY29sb3JcbiAgICB2YXIgdGludCA9IHRpbGluZ1Nwcml0ZS50aW50O1xuICAgIHZhciBjb2xvciA9ICh0aW50ID4+IDE2KSArICh0aW50ICYgMHhmZjAwKSArICgodGludCAmIDB4ZmYpIDw8IDE2KSArICh0aWxpbmdTcHJpdGUuYWxwaGEgKiAyNTUgPDwgMjQpO1xuXG4gICAgdmFyIHBvc2l0aW9ucyA9IHRoaXMucG9zaXRpb25zO1xuICAgIHZhciBjb2xvcnMgPSB0aGlzLmNvbG9ycztcblxuICAgIHZhciB3aWR0aCA9IHRpbGluZ1Nwcml0ZS53aWR0aDtcbiAgICB2YXIgaGVpZ2h0ID0gdGlsaW5nU3ByaXRlLmhlaWdodDtcblxuICAgIC8vIFRPRE8gdHJpbT8/XG4gICAgdmFyIGFYID0gdGlsaW5nU3ByaXRlLmFuY2hvci54O1xuICAgIHZhciBhWSA9IHRpbGluZ1Nwcml0ZS5hbmNob3IueTtcbiAgICB2YXIgdzAgPSB3aWR0aCAqICgxLWFYKTtcbiAgICB2YXIgdzEgPSB3aWR0aCAqIC1hWDtcblxuICAgIHZhciBoMCA9IGhlaWdodCAqICgxLWFZKTtcbiAgICB2YXIgaDEgPSBoZWlnaHQgKiAtYVk7XG5cbiAgICB2YXIgaW5kZXggPSB0aGlzLmN1cnJlbnRCYXRjaFNpemUgKiA0ICogdGhpcy52ZXJ0U2l6ZTtcblxuICAgIHZhciByZXNvbHV0aW9uID0gdGV4dHVyZS5iYXNlVGV4dHVyZS5yZXNvbHV0aW9uO1xuXG4gICAgdmFyIHdvcmxkVHJhbnNmb3JtID0gdGlsaW5nU3ByaXRlLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgdmFyIGEgPSB3b3JsZFRyYW5zZm9ybS5hIC8gcmVzb2x1dGlvbjsvL1swXTtcbiAgICB2YXIgYiA9IHdvcmxkVHJhbnNmb3JtLmIgLyByZXNvbHV0aW9uOy8vWzNdO1xuICAgIHZhciBjID0gd29ybGRUcmFuc2Zvcm0uYyAvIHJlc29sdXRpb247Ly9bMV07XG4gICAgdmFyIGQgPSB3b3JsZFRyYW5zZm9ybS5kIC8gcmVzb2x1dGlvbjsvL1s0XTtcbiAgICB2YXIgdHggPSB3b3JsZFRyYW5zZm9ybS50eDsvL1syXTtcbiAgICB2YXIgdHkgPSB3b3JsZFRyYW5zZm9ybS50eTsvL1s1XTtcblxuICAgIC8vIHh5XG4gICAgcG9zaXRpb25zW2luZGV4KytdID0gYSAqIHcxICsgYyAqIGgxICsgdHg7XG4gICAgcG9zaXRpb25zW2luZGV4KytdID0gZCAqIGgxICsgYiAqIHcxICsgdHk7XG4gICAgLy8gdXZcbiAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSB1dnMueDA7XG4gICAgcG9zaXRpb25zW2luZGV4KytdID0gdXZzLnkwO1xuICAgIC8vIGNvbG9yXG4gICAgY29sb3JzW2luZGV4KytdID0gY29sb3I7XG5cbiAgICAvLyB4eVxuICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IChhICogdzAgKyBjICogaDEgKyB0eCk7XG4gICAgcG9zaXRpb25zW2luZGV4KytdID0gZCAqIGgxICsgYiAqIHcwICsgdHk7XG4gICAgLy8gdXZcbiAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSB1dnMueDE7XG4gICAgcG9zaXRpb25zW2luZGV4KytdID0gdXZzLnkxO1xuICAgIC8vIGNvbG9yXG4gICAgY29sb3JzW2luZGV4KytdID0gY29sb3I7XG5cbiAgICAvLyB4eVxuICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IGEgKiB3MCArIGMgKiBoMCArIHR4O1xuICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IGQgKiBoMCArIGIgKiB3MCArIHR5O1xuICAgIC8vIHV2XG4gICAgcG9zaXRpb25zW2luZGV4KytdID0gdXZzLngyO1xuICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IHV2cy55MjtcbiAgICAvLyBjb2xvclxuICAgIGNvbG9yc1tpbmRleCsrXSA9IGNvbG9yO1xuXG4gICAgLy8geHlcbiAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSBhICogdzEgKyBjICogaDAgKyB0eDtcbiAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSBkICogaDAgKyBiICogdzEgKyB0eTtcbiAgICAvLyB1dlxuICAgIHBvc2l0aW9uc1tpbmRleCsrXSA9IHV2cy54MztcbiAgICBwb3NpdGlvbnNbaW5kZXgrK10gPSB1dnMueTM7XG4gICAgLy8gY29sb3JcbiAgICBjb2xvcnNbaW5kZXgrK10gPSBjb2xvcjtcblxuICAgIC8vIGluY3JlbWVudCB0aGUgYmF0Y2hzaXplXG4gICAgdGhpcy5zcHJpdGVzW3RoaXMuY3VycmVudEJhdGNoU2l6ZSsrXSA9IHRpbGluZ1Nwcml0ZTtcbn07XG5cbi8qKlxuICogUmVuZGVycyB0aGUgY29udGVudCBhbmQgZW1wdGllcyB0aGUgY3VycmVudCBiYXRjaC5cbiAqXG4gKi9cbldlYkdMU3ByaXRlQmF0Y2gucHJvdG90eXBlLmZsdXNoID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIElmIHRoZSBiYXRjaCBpcyBsZW5ndGggMCB0aGVuIHJldHVybiBhcyB0aGVyZSBpcyBub3RoaW5nIHRvIGRyYXdcbiAgICBpZiAodGhpcy5jdXJyZW50QmF0Y2hTaXplID09PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuICAgIHZhciBzaGFkZXI7XG5cbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLmRpcnR5ID0gZmFsc2U7XG4gICAgICAgIC8vIGJpbmQgdGhlIG1haW4gdGV4dHVyZVxuICAgICAgICBnbC5hY3RpdmVUZXh0dXJlKGdsLlRFWFRVUkUwKTtcblxuICAgICAgICAvLyBiaW5kIHRoZSBidWZmZXJzXG4gICAgICAgIGdsLmJpbmRCdWZmZXIoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLnZlcnRleEJ1ZmZlcik7XG4gICAgICAgIGdsLmJpbmRCdWZmZXIoZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIsIHRoaXMuaW5kZXhCdWZmZXIpO1xuXG4gICAgICAgIC8vIHRoaXMgaXMgdGhlIHNhbWUgZm9yIGVhY2ggc2hhZGVyP1xuICAgICAgICB2YXIgc3RyaWRlID0gIHRoaXMudmVydFNpemUgKiA0O1xuICAgICAgICBnbC52ZXJ0ZXhBdHRyaWJQb2ludGVyKHRoaXMuc2hhZGVyLmF0dHJpYnV0ZXMuYVZlcnRleFBvc2l0aW9uLCAyLCBnbC5GTE9BVCwgZmFsc2UsIHN0cmlkZSwgMCk7XG4gICAgICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIodGhpcy5zaGFkZXIuYXR0cmlidXRlcy5hVGV4dHVyZUNvb3JkLCAyLCBnbC5GTE9BVCwgZmFsc2UsIHN0cmlkZSwgMiAqIDQpO1xuXG4gICAgICAgIC8vIGNvbG9yIGF0dHJpYnV0ZXMgd2lsbCBiZSBpbnRlcnByZXRlZCBhcyB1bnNpZ25lZCBieXRlcyBhbmQgbm9ybWFsaXplZFxuICAgICAgICBnbC52ZXJ0ZXhBdHRyaWJQb2ludGVyKHRoaXMuc2hhZGVyLmF0dHJpYnV0ZXMuYUNvbG9yLCA0LCBnbC5VTlNJR05FRF9CWVRFLCB0cnVlLCBzdHJpZGUsIDQgKiA0KTtcbiAgICB9XG5cbiAgICAvLyB1cGxvYWQgdGhlIHZlcnRzIHRvIHRoZSBidWZmZXJcbiAgICBpZiAodGhpcy5jdXJyZW50QmF0Y2hTaXplID4gKCB0aGlzLnNpemUgKiAwLjUgKSApIHtcbiAgICAgICAgZ2wuYnVmZmVyU3ViRGF0YShnbC5BUlJBWV9CVUZGRVIsIDAsIHRoaXMudmVydGljZXMpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdmFyIHZpZXcgPSB0aGlzLnBvc2l0aW9ucy5zdWJhcnJheSgwLCB0aGlzLmN1cnJlbnRCYXRjaFNpemUgKiA0ICogdGhpcy52ZXJ0U2l6ZSk7XG4gICAgICAgIGdsLmJ1ZmZlclN1YkRhdGEoZ2wuQVJSQVlfQlVGRkVSLCAwLCB2aWV3KTtcbiAgICB9XG5cbiAgICB2YXIgbmV4dFRleHR1cmUsIG5leHRCbGVuZE1vZGUsIG5leHRTaGFkZXI7XG4gICAgdmFyIGJhdGNoU2l6ZSA9IDA7XG4gICAgdmFyIHN0YXJ0ID0gMDtcblxuICAgIHZhciBjdXJyZW50QmFzZVRleHR1cmUgPSBudWxsO1xuICAgIHZhciBjdXJyZW50QmxlbmRNb2RlID0gdGhpcy5yZW5kZXJlci5ibGVuZE1vZGVNYW5hZ2VyLmN1cnJlbnRCbGVuZE1vZGU7XG4gICAgdmFyIGN1cnJlbnRTaGFkZXIgPSBudWxsO1xuXG4gICAgdmFyIGJsZW5kU3dhcCA9IGZhbHNlO1xuICAgIHZhciBzaGFkZXJTd2FwID0gZmFsc2U7XG4gICAgdmFyIHNwcml0ZTtcblxuICAgIGZvciAodmFyIGkgPSAwLCBqID0gdGhpcy5jdXJyZW50QmF0Y2hTaXplOyBpIDwgajsgaSsrKSB7XG5cbiAgICAgICAgc3ByaXRlID0gdGhpcy5zcHJpdGVzW2ldO1xuXG4gICAgICAgIG5leHRUZXh0dXJlID0gc3ByaXRlLnRleHR1cmUuYmFzZVRleHR1cmU7XG4gICAgICAgIG5leHRCbGVuZE1vZGUgPSBzcHJpdGUuYmxlbmRNb2RlO1xuICAgICAgICBuZXh0U2hhZGVyID0gc3ByaXRlLnNoYWRlciB8fCB0aGlzLnNoYWRlcjtcblxuICAgICAgICBibGVuZFN3YXAgPSBjdXJyZW50QmxlbmRNb2RlICE9PSBuZXh0QmxlbmRNb2RlO1xuICAgICAgICBzaGFkZXJTd2FwID0gY3VycmVudFNoYWRlciAhPT0gbmV4dFNoYWRlcjsgLy8gc2hvdWxkIEkgdXNlIHV1aWRTPz8/XG5cbiAgICAgICAgaWYgKGN1cnJlbnRCYXNlVGV4dHVyZSAhPT0gbmV4dFRleHR1cmUgfHwgYmxlbmRTd2FwIHx8IHNoYWRlclN3YXApIHtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyQmF0Y2goY3VycmVudEJhc2VUZXh0dXJlLCBiYXRjaFNpemUsIHN0YXJ0KTtcblxuICAgICAgICAgICAgc3RhcnQgPSBpO1xuICAgICAgICAgICAgYmF0Y2hTaXplID0gMDtcbiAgICAgICAgICAgIGN1cnJlbnRCYXNlVGV4dHVyZSA9IG5leHRUZXh0dXJlO1xuXG4gICAgICAgICAgICBpZiAoYmxlbmRTd2FwKSB7XG4gICAgICAgICAgICAgICAgY3VycmVudEJsZW5kTW9kZSA9IG5leHRCbGVuZE1vZGU7XG4gICAgICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5ibGVuZE1vZGVNYW5hZ2VyLnNldEJsZW5kTW9kZSggY3VycmVudEJsZW5kTW9kZSApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoc2hhZGVyU3dhcCkge1xuICAgICAgICAgICAgICAgIGN1cnJlbnRTaGFkZXIgPSBuZXh0U2hhZGVyO1xuXG4gICAgICAgICAgICAgICAgc2hhZGVyID0gY3VycmVudFNoYWRlci5zaGFkZXJzID8gY3VycmVudFNoYWRlci5zaGFkZXJzW2dsLmlkXSA6IGN1cnJlbnRTaGFkZXI7XG5cbiAgICAgICAgICAgICAgICBpZiAoIXNoYWRlcikge1xuICAgICAgICAgICAgICAgICAgICBzaGFkZXIgPSBuZXcgU2hhZGVyKGdsLCBudWxsLCBjdXJyZW50U2hhZGVyLmZyYWdtZW50U3JjLCBjdXJyZW50U2hhZGVyLnVuaWZvcm1zKTtcbiAgICAgICAgICAgICAgICAgICAgY3VycmVudFNoYWRlci5zaGFkZXJzW2dsLmlkXSA9IHNoYWRlcjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBzZXQgc2hhZGVyIGZ1bmN0aW9uPz8/XG4gICAgICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLnNldFNoYWRlcihzaGFkZXIpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHNoYWRlci5kaXJ0eSkge1xuICAgICAgICAgICAgICAgICAgICBzaGFkZXIuc3luY1VuaWZvcm1zKCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gYm90aCB0aGVhc2Ugb25seSBuZWVkIHRvIGJlIHNldCBpZiB0aGV5IGFyZSBjaGFuZ2luZy4uXG4gICAgICAgICAgICAgICAgLy8gc2V0IHRoZSBwcm9qZWN0aW9uXG4gICAgICAgICAgICAgICAgdmFyIHByb2plY3Rpb24gPSB0aGlzLnJlbmRlcmVyLnByb2plY3Rpb247XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTJmKHNoYWRlci51bmlmb3Jtcy5wcm9qZWN0aW9uVmVjdG9yLl9sb2NhdGlvbiwgcHJvamVjdGlvbi54LCBwcm9qZWN0aW9uLnkpO1xuXG4gICAgICAgICAgICAgICAgLy8gVE9ETyAtIHRoaXMgaXMgdGVtcHJvcmFyeSFcbiAgICAgICAgICAgICAgICB2YXIgb2Zmc2V0VmVjdG9yID0gdGhpcy5yZW5kZXJlci5vZmZzZXQ7XG4gICAgICAgICAgICAgICAgZ2wudW5pZm9ybTJmKHNoYWRlci51bmlmb3Jtcy5vZmZzZXRWZWN0b3IuX2xvY2F0aW9uLCBvZmZzZXRWZWN0b3IueCwgb2Zmc2V0VmVjdG9yLnkpO1xuXG4gICAgICAgICAgICAgICAgLy8gc2V0IHRoZSBwb2ludGVyc1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgYmF0Y2hTaXplKys7XG4gICAgfVxuXG4gICAgdGhpcy5yZW5kZXJCYXRjaChjdXJyZW50QmFzZVRleHR1cmUsIGJhdGNoU2l6ZSwgc3RhcnQpO1xuXG4gICAgLy8gdGhlbiByZXNldCB0aGUgYmF0Y2ghXG4gICAgdGhpcy5jdXJyZW50QmF0Y2hTaXplID0gMDtcbn07XG5cbi8qKlxuICogQHBhcmFtIHRleHR1cmUge1RleHR1cmV9XG4gKiBAcGFyYW0gc2l6ZSB7bnVtYmVyfVxuICogQHBhcmFtIHN0YXJ0SW5kZXgge251bWJlcn1cbiAqL1xuV2ViR0xTcHJpdGVCYXRjaC5wcm90b3R5cGUucmVuZGVyQmF0Y2ggPSBmdW5jdGlvbiAodGV4dHVyZSwgc2l6ZSwgc3RhcnRJbmRleCkge1xuICAgIGlmIChzaXplID09PSAwKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgZ2wgPSB0aGlzLnJlbmRlcmVyLmdsO1xuXG4gICAgaWYgKCF0ZXh0dXJlLl9nbFRleHR1cmVzW2dsLmlkXSkge1xuICAgICAgICB0aGlzLnJlbmRlcmVyLnVwZGF0ZVRleHR1cmUodGV4dHVyZSk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICAvLyBiaW5kIHRoZSBjdXJyZW50IHRleHR1cmVcbiAgICAgICAgZ2wuYmluZFRleHR1cmUoZ2wuVEVYVFVSRV8yRCwgdGV4dHVyZS5fZ2xUZXh0dXJlc1tnbC5pZF0pO1xuICAgIH1cblxuICAgIC8vIG5vdyBkcmF3IHRob3NlIHN1Y2thcyFcbiAgICBnbC5kcmF3RWxlbWVudHMoZ2wuVFJJQU5HTEVTLCBzaXplICogNiwgZ2wuVU5TSUdORURfU0hPUlQsIHN0YXJ0SW5kZXggKiA2ICogMik7XG5cbiAgICAvLyBpbmNyZW1lbnQgdGhlIGRyYXcgY291bnRcbiAgICB0aGlzLnJlbmRlcmVyLmRyYXdDb3VudCsrO1xufTtcblxuLyoqXG4gKlxuICovXG5XZWJHTFNwcml0ZUJhdGNoLnByb3RvdHlwZS5zdG9wID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZmx1c2goKTtcbiAgICB0aGlzLmRpcnR5ID0gdHJ1ZTtcbn07XG5cbi8qKlxuICpcbiAqL1xuV2ViR0xTcHJpdGVCYXRjaC5wcm90b3R5cGUuc3RhcnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5kaXJ0eSA9IHRydWU7XG59O1xuXG4vKipcbiAqIERlc3Ryb3lzIHRoZSBTcHJpdGVCYXRjaC5cbiAqXG4gKi9cbldlYkdMU3ByaXRlQmF0Y2gucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5yZW5kZXJlci5nbC5kZWxldGVCdWZmZXIodGhpcy52ZXJ0ZXhCdWZmZXIpO1xuICAgIHRoaXMucmVuZGVyZXIuZ2wuZGVsZXRlQnVmZmVyKHRoaXMuaW5kZXhCdWZmZXIpO1xuXG4gICAgdGhpcy52ZXJ0aWNlcyA9IG51bGw7XG4gICAgdGhpcy5pbmRpY2VzID0gbnVsbDtcblxuICAgIHRoaXMudmVydGV4QnVmZmVyID0gbnVsbDtcbiAgICB0aGlzLmluZGV4QnVmZmVyID0gbnVsbDtcblxuICAgIHRoaXMuY3VycmVudEJhc2VUZXh0dXJlID0gbnVsbDtcblxuICAgIHRoaXMucmVuZGVyZXIgPSBudWxsO1xufTtcbiIsInZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzJyksXG4gICAgQ09OU1QgPSByZXF1aXJlKCcuLi9jb25zdCcpO1xuXG4vKipcbiAqIEEgdGV4dHVyZSBzdG9yZXMgdGhlIGluZm9ybWF0aW9uIHRoYXQgcmVwcmVzZW50cyBhbiBpbWFnZS4gQWxsIHRleHR1cmVzIGhhdmUgYSBiYXNlIHRleHR1cmUuXG4gKlxuICogQGNsYXNzXG4gKiBAbWl4ZXMgZXZlbnRUYXJnZXRcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHNvdXJjZSB7SW1hZ2V8Q2FudmFzfSB0aGUgc291cmNlIG9iamVjdCBvZiB0aGUgdGV4dHVyZS5cbiAqIEBwYXJhbSBbc2NhbGVNb2RlPXNjYWxlTW9kZXMuREVGQVVMVF0ge251bWJlcn0gU2VlIHtAbGluayBzY2FsZU1vZGVzfSBmb3IgcG9zc2libGUgdmFsdWVzXG4gKi9cbmZ1bmN0aW9uIEJhc2VUZXh0dXJlKHNvdXJjZSwgc2NhbGVNb2RlKSB7XG4gICAgdGhpcy51dWlkID0gdXRpbHMudXVpZCgpO1xuXG4gICAgLyoqXG4gICAgICogVGhlIFJlc29sdXRpb24gb2YgdGhlIHRleHR1cmUuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5yZXNvbHV0aW9uID0gMTtcblxuICAgIC8qKlxuICAgICAqIFRoZSB3aWR0aCBvZiB0aGUgYmFzZSB0ZXh0dXJlIHNldCB3aGVuIHRoZSBpbWFnZSBoYXMgbG9hZGVkXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQHJlYWRPbmx5XG4gICAgICovXG4gICAgdGhpcy53aWR0aCA9IDEwMDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBoZWlnaHQgb2YgdGhlIGJhc2UgdGV4dHVyZSBzZXQgd2hlbiB0aGUgaW1hZ2UgaGFzIGxvYWRlZFxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEByZWFkT25seVxuICAgICAqL1xuICAgIHRoaXMuaGVpZ2h0ID0gMTAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHNjYWxlIG1vZGUgdG8gYXBwbHkgd2hlbiBzY2FsaW5nIHRoaXMgdGV4dHVyZVxuICAgICAqXG4gICAgICogQG1lbWJlciB7e251bWJlcn19XG4gICAgICogQGRlZmF1bHQgc2NhbGVNb2Rlcy5MSU5FQVJcbiAgICAgKi9cbiAgICB0aGlzLnNjYWxlTW9kZSA9IHNjYWxlTW9kZSB8fCBDT05TVC5zY2FsZU1vZGVzLkRFRkFVTFQ7XG5cbiAgICAvKipcbiAgICAgKiBTZXQgdG8gdHJ1ZSBvbmNlIHRoZSBiYXNlIHRleHR1cmUgaGFzIHN1Y2Nlc3NmdWxseSBsb2FkZWQuXG4gICAgICpcbiAgICAgKiBUaGlzIGlzIG5ldmVyIHRydWUgaWYgdGhlIHVuZGVybHlpbmcgc291cmNlIGZhaWxzIHRvIGxvYWQgb3IgaGFzIG5vIHRleHR1cmUgZGF0YS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICogQHJlYWRPbmx5XG4gICAgICovXG4gICAgdGhpcy5oYXNMb2FkZWQgPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqIFNldCB0byB0cnVlIGlmIHRoZSBzb3VyY2UgaXMgY3VycmVudGx5IGxvYWRpbmcuXG4gICAgICpcbiAgICAgKiBJZiBhbiBJbWFnZSBzb3VyY2UgaXMgbG9hZGluZyB0aGUgJ2xvYWRlZCcgb3IgJ2Vycm9yJyBldmVudCB3aWxsIGJlXG4gICAgICogZGlzcGF0Y2hlZCB3aGVuIHRoZSBvcGVyYXRpb24gZW5kcy4gQW4gdW5kZXJ5bGluZyBzb3VyY2UgdGhhdCBpc1xuICAgICAqIGltbWVkaWF0ZWx5LWF2YWlsYWJsZSBieXBhc3NlcyBsb2FkaW5nIGVudGlyZWx5LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKi9cbiAgICB0aGlzLmlzTG9hZGluZyA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGltYWdlIHNvdXJjZSB0aGF0IGlzIHVzZWQgdG8gY3JlYXRlIHRoZSB0ZXh0dXJlLlxuICAgICAqXG4gICAgICogVE9ETzogTWFrZSB0aGlzIGEgc2V0dGVyIHRoYXQgY2FsbHMgbG9hZFNvdXJjZSgpO1xuICAgICAqXG4gICAgICogQG1lbWJlciB7SW1hZ2V8Q2FudmFzfVxuICAgICAqIEByZWFkb25seVxuICAgICAqL1xuICAgIHRoaXMuc291cmNlID0gbnVsbDsgLy8gc2V0IGluIGxvYWRTb3VyY2UsIGlmIGF0IGFsbFxuXG4gICAgLyoqXG4gICAgICogQ29udHJvbHMgaWYgUkdCIGNoYW5uZWxzIHNob3VsZCBiZSBwcmUtbXVsdGlwbGllZCBieSBBbHBoYSAgKFdlYkdMIG9ubHkpXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqIEBkZWZhdWx0IHRydWVcbiAgICAgKi9cbiAgICB0aGlzLnByZW11bHRpcGxpZWRBbHBoYSA9IHRydWU7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtzdHJpbmd9XG4gICAgICovXG4gICAgdGhpcy5pbWFnZVVybCA9IG51bGw7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fcG93ZXJPZjIgPSBmYWxzZTtcblxuICAgIC8vIHVzZWQgZm9yIHdlYkdMXG5cbiAgICAvKipcbiAgICAgKlxuICAgICAqIFNldCB0aGlzIHRvIHRydWUgaWYgYSBtaXBtYXAgb2YgdGhpcyB0ZXh0dXJlIG5lZWRzIHRvIGJlIGdlbmVyYXRlZC4gVGhpcyB2YWx1ZSBuZWVkcyB0byBiZSBzZXQgYmVmb3JlIHRoZSB0ZXh0dXJlIGlzIHVzZWRcbiAgICAgKiBBbHNvIHRoZSB0ZXh0dXJlIG11c3QgYmUgYSBwb3dlciBvZiB0d28gc2l6ZSB0byB3b3JrXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMubWlwbWFwID0gZmFsc2U7XG5cbiAgICAvKipcbiAgICAgKiBBIG1hcCBvZiByZW5kZXJlciBJRHMgdG8gd2ViZ2wgdGV4dHVyZXNcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge29iamVjdDxudW1iZXIsIFdlYkdMVGV4dHVyZT59XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl9nbFRleHR1cmVzID0ge307XG5cbiAgICAvKipcbiAgICAgKiBEb2VzIHRoZSB0ZXh0dXJlIG9uIHRoZSBHUFUgbmVlZCB0byBiZSB1cGRhdGVkP1xuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuX25lZWRzVXBkYXRlID0gZmFsc2U7XG5cbiAgICAvLyBpZiBubyBzb3VyY2UgcGFzc2VkIGRvbid0IHRyeSB0byBsb2FkXG4gICAgaWYgKHNvdXJjZSkge1xuICAgICAgICB0aGlzLmxvYWRTb3VyY2Uoc291cmNlKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBGaXJlZCB3aGVuIGEgbm90LWltbWVkaWF0ZWx5LWF2YWlsYWJsZSBzb3VyY2UgZmluaXNoZXMgbG9hZGluZy5cbiAgICAgKlxuICAgICAqIEBldmVudCBsb2FkZWRcbiAgICAgKiBAcHJvdGVjdGVkXG4gICAgICovXG5cbiAgICAvKipcbiAgICAgKiBGaXJlZCB3aGVuIGEgbm90LWltbWVkaWF0ZWx5LWF2YWlsYWJsZSBzb3VyY2UgZmFpbHMgdG8gbG9hZC5cbiAgICAgKlxuICAgICAqIEBldmVudCBlcnJvclxuICAgICAqIEBwcm90ZWN0ZWRcbiAgICAgKi9cbn1cblxuQmFzZVRleHR1cmUucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQmFzZVRleHR1cmU7XG5tb2R1bGUuZXhwb3J0cyA9IEJhc2VUZXh0dXJlO1xuXG51dGlscy5ldmVudFRhcmdldC5taXhpbihCYXNlVGV4dHVyZS5wcm90b3R5cGUpO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhCYXNlVGV4dHVyZS5wcm90b3R5cGUsIHtcbiAgICBuZWVkc1VwZGF0ZToge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9uZWVkc1VwZGF0ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsKSB7XG4gICAgICAgICAgICB0aGlzLl9uZWVkc1VwZGF0ZSA9IHZhbDtcblxuICAgICAgICAgICAgaWYgKHZhbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuZW1pdCgndXBkYXRlJywgdGhpcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59KTtcblxuLyoqXG4gKiBMb2FkIGEgc291cmNlLlxuICpcbiAqIElmIHRoZSBzb3VyY2UgaXMgbm90LWltbWVkaWF0ZWx5LWF2YWlsYWJsZSwgc3VjaCBhcyBhbiBpbWFnZSB0aGF0IG5lZWRzIHRvIGJlXG4gKiBkb3dubG9hZGVkLCB0aGVuIHRoZSAnbG9hZGVkJyBvciAnZXJyb3InIGV2ZW50IHdpbGwgYmUgZGlzcGF0Y2hlZCBpbiB0aGUgZnV0dXJlXG4gKiBhbmQgYGhhc0xvYWRlZGAgd2lsbCByZW1haW4gZmFsc2UgYWZ0ZXIgdGhpcyBjYWxsLlxuICpcbiAqIFRoZSBsb2dpYyBzdGF0ZSBhZnRlciBjYWxsaW5nIGBsb2FkU291cmNlYCBkaXJlY3RseSBvciBpbmRpcmVjdGx5IChlZy4gYGZyb21JbWFnZWAsIGBuZXcgQmFzZVRleHR1cmVgKSBpczpcbiAqXG4gKiAgICAgaWYgKHRleHR1cmUuaGFzTG9hZGVkKSB7XG4gKiAgICAgICAgLy8gdGV4dHVyZSByZWFkeSBmb3IgdXNlXG4gKiAgICAgfSBlbHNlIGlmICh0ZXh0dXJlLmlzTG9hZGluZykge1xuICogICAgICAgIC8vIGxpc3RlbiB0byAnbG9hZGVkJyBhbmQvb3IgJ2Vycm9yJyBldmVudHMgb24gdGV4dHVyZVxuICogICAgIH0gZWxzZSB7XG4gKiAgICAgICAgLy8gbm90IGxvYWRpbmcsIG5vdCBnb2luZyB0byBsb2FkIFVOTEVTUyB0aGUgc291cmNlIGlzIHJlbG9hZGVkXG4gKiAgICAgICAgLy8gKGl0IG1heSBzdGlsbCBtYWtlIHNlbnNlIHRvIGxpc3RlbiB0byB0aGUgZXZlbnRzKVxuICogICAgIH1cbiAqXG4gKiBAcHJvdGVjdGVkXG4gKiBAcGFyYW0gc291cmNlIHtJbWFnZXxDYW52YXN9IHRoZSBzb3VyY2Ugb2JqZWN0IG9mIHRoZSB0ZXh0dXJlLlxuICovXG5CYXNlVGV4dHVyZS5wcm90b3R5cGUubG9hZFNvdXJjZSA9IGZ1bmN0aW9uIChzb3VyY2UpIHtcbiAgICB2YXIgd2FzTG9hZGluZyA9IHRoaXMuaXNMb2FkaW5nO1xuICAgIHRoaXMuaGFzTG9hZGVkID0gZmFsc2U7XG4gICAgdGhpcy5pc0xvYWRpbmcgPSBmYWxzZTtcblxuICAgIGlmICh3YXNMb2FkaW5nICYmIHRoaXMuc291cmNlKSB7XG4gICAgICAgIHRoaXMuc291cmNlLm9ubG9hZCA9IG51bGw7XG4gICAgICAgIHRoaXMuc291cmNlLm9uZXJyb3IgPSBudWxsO1xuICAgIH1cblxuICAgIHRoaXMuc291cmNlID0gc291cmNlO1xuXG4gICAgLy8gQXBwbHkgc291cmNlIGlmIGxvYWRlZC4gT3RoZXJ3aXNlIHNldHVwIGFwcHJvcHJpYXRlIGxvYWRpbmcgbW9uaXRvcnMuXG4gICAgaWYgKCh0aGlzLnNvdXJjZS5jb21wbGV0ZSB8fCB0aGlzLnNvdXJjZS5nZXRDb250ZXh0KSAmJiB0aGlzLnNvdXJjZS53aWR0aCAmJiB0aGlzLnNvdXJjZS5oZWlnaHQpIHtcbiAgICAgICAgdGhpcy5fc291cmNlTG9hZGVkKCk7XG4gICAgfVxuICAgIGVsc2UgIGlmKCFzb3VyY2UuZ2V0Q29udGV4dCkge1xuICAgICAgICAvLyBJbWFnZSBmYWlsIC8gbm90IHJlYWR5XG4gICAgICAgIHRoaXMuaXNMb2FkaW5nID0gdHJ1ZTtcblxuICAgICAgICB2YXIgc2NvcGUgPSB0aGlzO1xuXG4gICAgICAgIHNvdXJjZS5vbmxvYWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBzb3VyY2Uub25sb2FkID0gbnVsbDtcbiAgICAgICAgICAgIHNvdXJjZS5vbmVycm9yID0gbnVsbDtcblxuICAgICAgICAgICAgaWYoIXNjb3BlLmlzTG9hZGluZykge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2NvcGUuaXNMb2FkaW5nID0gZmFsc2U7XG4gICAgICAgICAgICBzY29wZS5fc291cmNlTG9hZGVkKCk7XG5cbiAgICAgICAgICAgIHNjb3BlLmVtaXQoJ2xvYWRlZCcsIHNjb3BlKTtcbiAgICAgICAgfTtcblxuICAgICAgICBzb3VyY2Uub25lcnJvciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHNvdXJjZS5vbmxvYWQgPSBudWxsO1xuICAgICAgICAgICAgc291cmNlLm9uZXJyb3IgPSBudWxsO1xuXG4gICAgICAgICAgICBpZighc2NvcGUuaXNMb2FkaW5nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzY29wZS5pc0xvYWRpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgIHNjb3BlLmVtaXQoJ2Vycm9yJywgc2NvcGUpO1xuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFBlciBodHRwOi8vd3d3LnczLm9yZy9UUi9odG1sNS9lbWJlZGRlZC1jb250ZW50LTAuaHRtbCN0aGUtaW1nLWVsZW1lbnRcbiAgICAgICAgLy8gICBcIlRoZSB2YWx1ZSBvZiBgY29tcGxldGVgIGNhbiB0aHVzIGNoYW5nZSB3aGlsZSBhIHNjcmlwdCBpcyBleGVjdXRpbmcuXCJcbiAgICAgICAgLy8gU28gY29tcGxldGUgbmVlZHMgdG8gYmUgcmUtY2hlY2tlZCBhZnRlciB0aGUgY2FsbGJhY2tzIGhhdmUgYmVlbiBhZGRlZC4uXG4gICAgICAgIGlmIChzb3VyY2UuY29tcGxldGUpIHtcbiAgICAgICAgICAgIHRoaXMuaXNMb2FkaW5nID0gZmFsc2U7XG5cbiAgICAgICAgICAgIC8vIC4uYW5kIGlmIHdlJ3JlIGNvbXBsZXRlIG5vdywgbm8gbmVlZCBmb3IgY2FsbGJhY2tzXG4gICAgICAgICAgICBzb3VyY2Uub25sb2FkID0gbnVsbDtcbiAgICAgICAgICAgIHNvdXJjZS5vbmVycm9yID0gbnVsbDtcblxuICAgICAgICAgICAgaWYgKHNvdXJjZS53aWR0aCAmJiBzb3VyY2UuaGVpZ2h0KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fc291cmNlTG9hZGVkKCk7XG5cbiAgICAgICAgICAgICAgICAvLyBJZiBhbnkgcHJldmlvdXMgc3Vic2NyaWJlcnMgcG9zc2libGVcbiAgICAgICAgICAgICAgICBpZiAod2FzTG9hZGluZykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2xvYWRlZCcsIHRoaXMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIElmIGFueSBwcmV2aW91cyBzdWJzY3JpYmVycyBwb3NzaWJsZVxuICAgICAgICAgICAgICAgIGlmICh3YXNMb2FkaW5nKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZW1pdCgnZXJyb3InLCB0aGlzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4vKipcbiAqIFVzZWQgaW50ZXJuYWxseSB0byB1cGRhdGUgdGhlIHdpZHRoLCBoZWlnaHQsIGFuZCBzb21lIG90aGVyIHRyYWNraW5nIHZhcnMgb25jZVxuICogYSBzb3VyY2UgaGFzIHN1Y2Nlc3NmdWxseSBsb2FkZWQuXG4gKlxuICogQHByaXZhdGVcbiAqL1xuQmFzZVRleHR1cmUucHJvdG90eXBlLl9zb3VyY2VMb2FkZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5oYXNMb2FkZWQgPSB0cnVlO1xuXG4gICAgdGhpcy53aWR0aCA9IHRoaXMuc291cmNlLm5hdHVyYWxXaWR0aCB8fCB0aGlzLnNvdXJjZS53aWR0aDtcbiAgICB0aGlzLmhlaWdodCA9IHRoaXMuc291cmNlLm5hdHVyYWxIZWlnaHQgfHwgdGhpcy5zb3VyY2UuaGVpZ2h0O1xuXG4gICAgdGhpcy5uZWVkc1VwZGF0ZSA9IHRydWU7XG59O1xuXG4vKipcbiAqIERlc3Ryb3lzIHRoaXMgYmFzZSB0ZXh0dXJlXG4gKlxuICovXG5CYXNlVGV4dHVyZS5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5pbWFnZVVybCkge1xuICAgICAgICBkZWxldGUgdXRpbHMuQmFzZVRleHR1cmVDYWNoZVt0aGlzLmltYWdlVXJsXTtcbiAgICAgICAgZGVsZXRlIHV0aWxzLlRleHR1cmVDYWNoZVt0aGlzLmltYWdlVXJsXTtcbiAgICAgICAgdGhpcy5pbWFnZVVybCA9IG51bGw7XG4gICAgICAgIGlmICghbmF2aWdhdG9yLmlzQ29jb29uSlMpIHtcbiAgICAgICAgICAgIHRoaXMuc291cmNlLnNyYyA9ICcnO1xuICAgICAgICB9XG4gICAgfVxuICAgIGVsc2UgaWYgKHRoaXMuc291cmNlICYmIHRoaXMuc291cmNlLl9waXhpSWQpIHtcbiAgICAgICAgZGVsZXRlIHV0aWxzLkJhc2VUZXh0dXJlQ2FjaGVbdGhpcy5zb3VyY2UuX3BpeGlJZF07XG4gICAgfVxuICAgIHRoaXMuc291cmNlID0gbnVsbDtcblxuICAgIHRoaXMuZGlzcG9zZSgpO1xufTtcblxuLyoqXG4gKiBGcmVlcyB0aGUgdGV4dHVyZSBmcm9tIFdlYkdMIG1lbW9yeSB3aXRob3V0IGRlc3Ryb3lpbmcgdGhpcyB0ZXh0dXJlIG9iamVjdC5cbiAqIFRoaXMgbWVhbnMgeW91IGNhbiBzdGlsbCB1c2UgdGhlIHRleHR1cmUgbGF0ZXIgd2hpY2ggd2lsbCB1cGxvYWQgaXQgdG8gR1BVXG4gKiBtZW1vcnkgYWdhaW4uXG4gKlxuICovXG5CYXNlVGV4dHVyZS5wcm90b3R5cGUuZGlzcG9zZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmVtaXQoJ2Rpc3Bvc2UnLCB0aGlzKTtcbn07XG5cbi8qKlxuICogQ2hhbmdlcyB0aGUgc291cmNlIGltYWdlIG9mIHRoZSB0ZXh0dXJlLlxuICogVGhlIG9yaWdpbmFsIHNvdXJjZSBtdXN0IGJlIGFuIEltYWdlIGVsZW1lbnQuXG4gKlxuICogQHBhcmFtIG5ld1NyYyB7c3RyaW5nfSB0aGUgcGF0aCBvZiB0aGUgaW1hZ2VcbiAqL1xuQmFzZVRleHR1cmUucHJvdG90eXBlLnVwZGF0ZVNvdXJjZUltYWdlID0gZnVuY3Rpb24gKG5ld1NyYykge1xuICAgIHRoaXMuc291cmNlLnNyYyA9IG5ld1NyYztcbiAgICB0aGlzLmxvYWRTb3VyY2UodGhpcy5zb3VyY2UpO1xufTtcblxuLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdGhhdCBjcmVhdGVzIGEgYmFzZSB0ZXh0dXJlIGZyb20gdGhlIGdpdmVuIGltYWdlIHVybC5cbiAqIElmIHRoZSBpbWFnZSBpcyBub3QgaW4gdGhlIGJhc2UgdGV4dHVyZSBjYWNoZSBpdCB3aWxsIGJlIGNyZWF0ZWQgYW5kIGxvYWRlZC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAcGFyYW0gaW1hZ2VVcmwge3N0cmluZ30gVGhlIGltYWdlIHVybCBvZiB0aGUgdGV4dHVyZVxuICogQHBhcmFtIFtjcm9zc29yaWdpbj0oYXV0byldIHtib29sZWFufSBTaG91bGQgdXNlIGFub255bW91c2UgQ09SUz8gRGVmYXVsdHMgdG8gdHJ1ZSBpZiB0aGUgVVJMIGlzIG5vdCBhIGRhdGEtVVJJLlxuICogQHBhcmFtIFtzY2FsZU1vZGU9c2NhbGVNb2Rlcy5ERUZBVUxUXSB7bnVtYmVyfSBTZWUge0BsaW5rIHNjYWxlTW9kZXN9IGZvciBwb3NzaWJsZSB2YWx1ZXNcbiAqIEByZXR1cm4gQmFzZVRleHR1cmVcbiAqL1xuQmFzZVRleHR1cmUuZnJvbUltYWdlID0gZnVuY3Rpb24gKGltYWdlVXJsLCBjcm9zc29yaWdpbiwgc2NhbGVNb2RlKSB7XG4gICAgdmFyIGJhc2VUZXh0dXJlID0gdXRpbHMuQmFzZVRleHR1cmVDYWNoZVtpbWFnZVVybF07XG5cbiAgICBpZiAoY3Jvc3NvcmlnaW4gPT09IHVuZGVmaW5lZCAmJiBpbWFnZVVybC5pbmRleE9mKCdkYXRhOicpICE9PSAwKSB7XG4gICAgICAgIGNyb3Nzb3JpZ2luID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBpZiAoIWJhc2VUZXh0dXJlKSB7XG4gICAgICAgIC8vIG5ldyBJbWFnZSgpIGJyZWFrcyB0ZXggbG9hZGluZyBpbiBzb21lIHZlcnNpb25zIG9mIENocm9tZS5cbiAgICAgICAgLy8gU2VlIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD0yMzgwNzFcbiAgICAgICAgdmFyIGltYWdlID0gbmV3IEltYWdlKCk7Ly9kb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpbWcnKTtcbiAgICAgICAgaWYgKGNyb3Nzb3JpZ2luKSB7XG4gICAgICAgICAgICBpbWFnZS5jcm9zc09yaWdpbiA9ICcnO1xuICAgICAgICB9XG5cbiAgICAgICAgaW1hZ2Uuc3JjID0gaW1hZ2VVcmw7XG4gICAgICAgIGJhc2VUZXh0dXJlID0gbmV3IEJhc2VUZXh0dXJlKGltYWdlLCBzY2FsZU1vZGUpO1xuICAgICAgICBiYXNlVGV4dHVyZS5pbWFnZVVybCA9IGltYWdlVXJsO1xuICAgICAgICB1dGlscy5CYXNlVGV4dHVyZUNhY2hlW2ltYWdlVXJsXSA9IGJhc2VUZXh0dXJlO1xuXG4gICAgICAgIC8vIGlmIHRoZXJlIGlzIGFuIEAyeCBhdCB0aGUgZW5kIG9mIHRoZSB1cmwgd2UgYXJlIGdvaW5nIHRvIGFzc3VtZSBpdHMgYSBoaWdocmVzIGltYWdlXG4gICAgICAgIGlmICggaW1hZ2VVcmwuaW5kZXhPZihDT05TVC5SRVRJTkFfUFJFRklYICsgJy4nKSAhPT0gLTEpIHtcbiAgICAgICAgICAgIGJhc2VUZXh0dXJlLnJlc29sdXRpb24gPSAyO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGJhc2VUZXh0dXJlO1xufTtcblxuLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdGhhdCBjcmVhdGVzIGEgYmFzZSB0ZXh0dXJlIGZyb20gdGhlIGdpdmVuIGNhbnZhcyBlbGVtZW50LlxuICpcbiAqIEBzdGF0aWNcbiAqIEBwYXJhbSBjYW52YXMge0NhbnZhc30gVGhlIGNhbnZhcyBlbGVtZW50IHNvdXJjZSBvZiB0aGUgdGV4dHVyZVxuICogQHBhcmFtIHNjYWxlTW9kZSB7bnVtYmVyfSBTZWUge3sjY3Jvc3NMaW5rIFwiUElYSS9zY2FsZU1vZGVzOnByb3BlcnR5XCJ9fXNjYWxlTW9kZXN7ey9jcm9zc0xpbmt9fSBmb3IgcG9zc2libGUgdmFsdWVzXG4gKiBAcmV0dXJuIEJhc2VUZXh0dXJlXG4gKi9cbkJhc2VUZXh0dXJlLmZyb21DYW52YXMgPSBmdW5jdGlvbiAoY2FudmFzLCBzY2FsZU1vZGUpIHtcbiAgICBpZiAoIWNhbnZhcy5fcGl4aUlkKSB7XG4gICAgICAgIGNhbnZhcy5fcGl4aUlkID0gJ2NhbnZhc18nICsgdXRpbHMudXVpZCgpO1xuICAgIH1cblxuICAgIHZhciBiYXNlVGV4dHVyZSA9IHV0aWxzLkJhc2VUZXh0dXJlQ2FjaGVbY2FudmFzLl9waXhpSWRdO1xuXG4gICAgaWYgKCFiYXNlVGV4dHVyZSkge1xuICAgICAgICBiYXNlVGV4dHVyZSA9IG5ldyBCYXNlVGV4dHVyZShjYW52YXMsIHNjYWxlTW9kZSk7XG4gICAgICAgIHV0aWxzLkJhc2VUZXh0dXJlQ2FjaGVbY2FudmFzLl9waXhpSWRdID0gYmFzZVRleHR1cmU7XG4gICAgfVxuXG4gICAgcmV0dXJuIGJhc2VUZXh0dXJlO1xufTtcbiIsInZhciBCYXNlVGV4dHVyZSA9IHJlcXVpcmUoJy4vQmFzZVRleHR1cmUnKSxcbiAgICBUZXh0dXJlID0gcmVxdWlyZSgnLi9UZXh0dXJlJyksXG4gICAgRmlsdGVyVGV4dHVyZSA9IHJlcXVpcmUoJy4uL3JlbmRlcmVycy93ZWJnbC91dGlscy9GaWx0ZXJUZXh0dXJlJyksXG4gICAgQ2FudmFzQnVmZmVyID0gcmVxdWlyZSgnLi4vcmVuZGVyZXJzL2NhbnZhcy91dGlscy9DYW52YXNCdWZmZXInKSxcbiAgICBtYXRoID0gcmVxdWlyZSgnLi4vbWF0aCcpLFxuICAgIENPTlNUID0gcmVxdWlyZSgnLi4vY29uc3QnKTtcblxuLyoqXG4gKiBBIFJlbmRlclRleHR1cmUgaXMgYSBzcGVjaWFsIHRleHR1cmUgdGhhdCBhbGxvd3MgYW55IFBpeGkgZGlzcGxheSBvYmplY3QgdG8gYmUgcmVuZGVyZWQgdG8gaXQuXG4gKlxuICogX19IaW50X186IEFsbCBEaXNwbGF5T2JqZWN0cyAoaS5lLiBTcHJpdGVzKSB0aGF0IHJlbmRlciB0byBhIFJlbmRlclRleHR1cmUgc2hvdWxkIGJlIHByZWxvYWRlZFxuICogb3RoZXJ3aXNlIGJsYWNrIHJlY3RhbmdsZXMgd2lsbCBiZSBkcmF3biBpbnN0ZWFkLlxuICpcbiAqIEEgUmVuZGVyVGV4dHVyZSB0YWtlcyBhIHNuYXBzaG90IG9mIGFueSBEaXNwbGF5IE9iamVjdCBnaXZlbiB0byBpdHMgcmVuZGVyIG1ldGhvZC4gVGhlIHBvc2l0aW9uXG4gKiBhbmQgcm90YXRpb24gb2YgdGhlIGdpdmVuIERpc3BsYXkgT2JqZWN0cyBpcyBpZ25vcmVkLiBGb3IgZXhhbXBsZTpcbiAqXG4gKiBgYGBqc1xuICogdmFyIHJlbmRlclRleHR1cmUgPSBuZXcgUElYSS5SZW5kZXJUZXh0dXJlKDgwMCwgNjAwKTtcbiAqIHZhciBzcHJpdGUgPSBQSVhJLlNwcml0ZS5mcm9tSW1hZ2UoXCJzcGluT2JqXzAxLnBuZ1wiKTtcbiAqXG4gKiBzcHJpdGUucG9zaXRpb24ueCA9IDgwMC8yO1xuICogc3ByaXRlLnBvc2l0aW9uLnkgPSA2MDAvMjtcbiAqIHNwcml0ZS5hbmNob3IueCA9IDAuNTtcbiAqIHNwcml0ZS5hbmNob3IueSA9IDAuNTtcbiAqXG4gKiByZW5kZXJUZXh0dXJlLnJlbmRlcihzcHJpdGUpO1xuICogYGBgXG4gKlxuICogVGhlIFNwcml0ZSBpbiB0aGlzIGNhc2Ugd2lsbCBiZSByZW5kZXJlZCB0byBhIHBvc2l0aW9uIG9mIDAsMC4gVG8gcmVuZGVyIHRoaXMgc3ByaXRlIGF0IGl0cyBhY3R1YWxcbiAqIHBvc2l0aW9uIGEgRGlzcGxheU9iamVjdENvbnRhaW5lciBzaG91bGQgYmUgdXNlZDpcbiAqXG4gKiBgYGBqc1xuICogdmFyIGRvYyA9IG5ldyBEaXNwbGF5T2JqZWN0Q29udGFpbmVyKCk7XG4gKlxuICogZG9jLmFkZENoaWxkKHNwcml0ZSk7XG4gKlxuICogcmVuZGVyVGV4dHVyZS5yZW5kZXIoZG9jKTsgIC8vIFJlbmRlcnMgdG8gY2VudGVyIG9mIHJlbmRlclRleHR1cmVcbiAqIGBgYFxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgVGV4dHVyZVxuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gcmVuZGVyZXIge0NhbnZhc1JlbmRlcmVyfFdlYkdMUmVuZGVyZXJ9IFRoZSByZW5kZXJlciB1c2VkIGZvciB0aGlzIFJlbmRlclRleHR1cmVcbiAqIEBwYXJhbSBbd2lkdGg9MTAwXSB7bnVtYmVyfSBUaGUgd2lkdGggb2YgdGhlIHJlbmRlciB0ZXh0dXJlXG4gKiBAcGFyYW0gW2hlaWdodD0xMDBdIHtudW1iZXJ9IFRoZSBoZWlnaHQgb2YgdGhlIHJlbmRlciB0ZXh0dXJlXG4gKiBAcGFyYW0gW3NjYWxlTW9kZV0ge251bWJlcn0gU2VlIHtAbGluayBzY2FsZU1vZGVzfSBmb3IgcG9zc2libGUgdmFsdWVzXG4gKiBAcGFyYW0gW3Jlc29sdXRpb249MV0ge251bWJlcn0gVGhlIHJlc29sdXRpb24gb2YgdGhlIHRleHR1cmUgYmVpbmcgZ2VuZXJhdGVkXG4gKi9cbmZ1bmN0aW9uIFJlbmRlclRleHR1cmUocmVuZGVyZXIsIHdpZHRoLCBoZWlnaHQsIHNjYWxlTW9kZSwgcmVzb2x1dGlvbikge1xuICAgIGlmICghcmVuZGVyZXIpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbmFibGUgdG8gY3JlYXRlIFJlbmRlclRleHR1cmUsIHlvdSBtdXN0IHBhc3MgYSByZW5kZXJlciBpbnRvIHRoZSBjb25zdHJ1Y3Rvci4nKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBUaGUgd2l0aCBvZiB0aGUgcmVuZGVyIHRleHR1cmVcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLndpZHRoID0gd2lkdGggfHwgMTAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGhlaWdodCBvZiB0aGUgcmVuZGVyIHRleHR1cmVcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLmhlaWdodCA9IGhlaWdodCB8fCAxMDA7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgUmVzb2x1dGlvbiBvZiB0aGUgdGV4dHVyZS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLnJlc29sdXRpb24gPSByZXNvbHV0aW9uIHx8IDE7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgZnJhbWluZyByZWN0YW5nbGUgb2YgdGhlIHJlbmRlciB0ZXh0dXJlXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtSZWN0YW5nbGV9XG4gICAgICovXG4gICAgdGhpcy5mcmFtZSA9IG5ldyBtYXRoLlJlY3RhbmdsZSgwLCAwLCB0aGlzLndpZHRoICogdGhpcy5yZXNvbHV0aW9uLCB0aGlzLmhlaWdodCAqIHRoaXMucmVzb2x1dGlvbik7XG5cbiAgICAvKipcbiAgICAgKiBUaGlzIGlzIHRoZSBhcmVhIG9mIHRoZSBCYXNlVGV4dHVyZSBpbWFnZSB0byBhY3R1YWxseSBjb3B5IHRvIHRoZSBDYW52YXMgLyBXZWJHTCB3aGVuIHJlbmRlcmluZyxcbiAgICAgKiBpcnJlc3BlY3RpdmUgb2YgdGhlIGFjdHVhbCBmcmFtZSBzaXplIG9yIHBsYWNlbWVudCAod2hpY2ggY2FuIGJlIGluZmx1ZW5jZWQgYnkgdHJpbW1lZCB0ZXh0dXJlIGF0bGFzZXMpXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtSZWN0YW5nbGV9XG4gICAgICovXG4gICAgdGhpcy5jcm9wID0gbmV3IG1hdGguUmVjdGFuZ2xlKDAsIDAsIHRoaXMud2lkdGggKiB0aGlzLnJlc29sdXRpb24sIHRoaXMuaGVpZ2h0ICogdGhpcy5yZXNvbHV0aW9uKTtcblxuICAgIC8qKlxuICAgICAqIERyYXcvcmVuZGVyIHRoZSBnaXZlbiBEaXNwbGF5T2JqZWN0IG9udG8gdGhlIHRleHR1cmUuXG4gICAgICpcbiAgICAgKiBUaGUgZGlzcGxheU9iamVjdCBhbmQgZGVzY2VuZGVudHMgYXJlIHRyYW5zZm9ybWVkIGR1cmluZyB0aGlzIG9wZXJhdGlvbi5cbiAgICAgKiBJZiBgcmVzdG9yZVdvcmxkVHJhbnNmb3JtYCBpcyB0cnVlIHRoZW4gdGhlIHRyYW5zZm9ybWF0aW9ucyB3aWxsIGJlIHJlc3RvcmVkIGJlZm9yZSB0aGVcbiAgICAgKiBtZXRob2QgcmV0dXJucy4gT3RoZXJ3aXNlIGl0IGlzIHVwIHRvIHRoZSBjYWxsaW5nIGNvZGUgdG8gY29ycmVjdGx5IHVzZSBvciByZXNldFxuICAgICAqIHRoZSB0cmFuc2Zvcm1lZCBkaXNwbGF5IG9iamVjdHMuXG4gICAgICpcbiAgICAgKiBUaGUgZGlzcGxheSBvYmplY3QgaXMgYWx3YXlzIHJlbmRlcmVkIHdpdGggYSB3b3JsZEFscGhhIHZhbHVlIG9mIDEuXG4gICAgICpcbiAgICAgKiBAbWV0aG9kXG4gICAgICogQHBhcmFtIGRpc3BsYXlPYmplY3Qge0Rpc3BsYXlPYmplY3R9IFRoZSBkaXNwbGF5IG9iamVjdCB0byByZW5kZXIgdGhpcyB0ZXh0dXJlIG9uXG4gICAgICogQHBhcmFtIFttYXRyaXhdIHtNYXRyaXh9IE9wdGlvbmFsIG1hdHJpeCB0byBhcHBseSB0byB0aGUgZGlzcGxheSBvYmplY3QgYmVmb3JlIHJlbmRlcmluZy5cbiAgICAgKiBAcGFyYW0gW2NsZWFyPWZhbHNlXSB7Ym9vbGVhbn0gSWYgdHJ1ZSB0aGUgdGV4dHVyZSB3aWxsIGJlIGNsZWFyZWQgYmVmb3JlIHRoZSBkaXNwbGF5T2JqZWN0IGlzIGRyYXduXG4gICAgICogQHBhcmFtIFtyZXN0b3JlV29ybGRUcmFuc2Zvcm09dHJ1ZV0ge2Jvb2xlYW59IElmIHRydWUgdGhlIGRpc3BsYXlPYmplY3QncyB3b3JsZFRyYW5zZm9ybS93b3JsZEFscGhhIGFuZCBhbGwgY2hpbGRyZW5cbiAgICAgKiAgdHJhbnNmb3JtYXRpb25zIHdpbGwgYmUgcmVzdG9yZWQuIE5vdCByZXN0b3JpbmcgdGhpcyBpbmZvcm1hdGlvbiB3aWxsIGJlIGEgbGl0dGxlIGZhc3Rlci5cbiAgICAgKi9cbiAgICB0aGlzLnJlbmRlciA9IG51bGw7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgYmFzZSB0ZXh0dXJlIG9iamVjdCB0aGF0IHRoaXMgdGV4dHVyZSB1c2VzXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtCYXNlVGV4dHVyZX1cbiAgICAgKi9cbiAgICB0aGlzLmJhc2VUZXh0dXJlID0gbmV3IEJhc2VUZXh0dXJlKCk7XG4gICAgdGhpcy5iYXNlVGV4dHVyZS53aWR0aCA9IHRoaXMud2lkdGggKiB0aGlzLnJlc29sdXRpb247XG4gICAgdGhpcy5iYXNlVGV4dHVyZS5oZWlnaHQgPSB0aGlzLmhlaWdodCAqIHRoaXMucmVzb2x1dGlvbjtcbiAgICB0aGlzLmJhc2VUZXh0dXJlLl9nbFRleHR1cmVzID0gW107XG4gICAgdGhpcy5iYXNlVGV4dHVyZS5yZXNvbHV0aW9uID0gdGhpcy5yZXNvbHV0aW9uO1xuXG4gICAgdGhpcy5iYXNlVGV4dHVyZS5zY2FsZU1vZGUgPSBzY2FsZU1vZGUgfHwgQ09OU1Quc2NhbGVNb2Rlcy5ERUZBVUxUO1xuXG4gICAgdGhpcy5iYXNlVGV4dHVyZS5oYXNMb2FkZWQgPSB0cnVlO1xuXG4gICAgVGV4dHVyZS5jYWxsKHRoaXMsXG4gICAgICAgIHRoaXMuYmFzZVRleHR1cmUsXG4gICAgICAgIG5ldyBtYXRoLlJlY3RhbmdsZSgwLCAwLCB0aGlzLndpZHRoLCB0aGlzLmhlaWdodClcbiAgICApO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHJlbmRlcmVyIHRoaXMgUmVuZGVyVGV4dHVyZSB1c2VzLiBBIFJlbmRlclRleHR1cmUgY2FuIG9ubHkgYmVsb25nIHRvIG9uZSByZW5kZXJlciBhdCB0aGUgbW9tZW50IGlmIGl0cyB3ZWJHTC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0NhbnZhc1JlbmRlcmVyfFdlYkdMUmVuZGVyZXJ9XG4gICAgICovXG4gICAgdGhpcy5yZW5kZXJlciA9IHJlbmRlcmVyO1xuXG4gICAgaWYgKHRoaXMucmVuZGVyZXIudHlwZSA9PT0gQ09OU1QuV0VCR0xfUkVOREVSRVIpIHtcbiAgICAgICAgdmFyIGdsID0gdGhpcy5yZW5kZXJlci5nbDtcblxuICAgICAgICB0aGlzLnRleHR1cmVCdWZmZXIgPSBuZXcgRmlsdGVyVGV4dHVyZShnbCwgdGhpcy53aWR0aCAqIHRoaXMucmVzb2x1dGlvbiwgdGhpcy5oZWlnaHQgKiB0aGlzLnJlc29sdXRpb24sIHRoaXMuYmFzZVRleHR1cmUuc2NhbGVNb2RlKTtcbiAgICAgICAgdGhpcy5iYXNlVGV4dHVyZS5fZ2xUZXh0dXJlc1tnbC5pZF0gPSAgdGhpcy50ZXh0dXJlQnVmZmVyLnRleHR1cmU7XG5cbiAgICAgICAgdGhpcy5yZW5kZXIgPSB0aGlzLnJlbmRlcldlYkdMO1xuICAgICAgICB0aGlzLnByb2plY3Rpb24gPSBuZXcgbWF0aC5Qb2ludCh0aGlzLndpZHRoKjAuNSwgLXRoaXMuaGVpZ2h0KjAuNSk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLnJlbmRlciA9IHRoaXMucmVuZGVyQ2FudmFzO1xuICAgICAgICB0aGlzLnRleHR1cmVCdWZmZXIgPSBuZXcgQ2FudmFzQnVmZmVyKHRoaXMud2lkdGgqIHRoaXMucmVzb2x1dGlvbiwgdGhpcy5oZWlnaHQqIHRoaXMucmVzb2x1dGlvbik7XG4gICAgICAgIHRoaXMuYmFzZVRleHR1cmUuc291cmNlID0gdGhpcy50ZXh0dXJlQnVmZmVyLmNhbnZhcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMudmFsaWQgPSB0cnVlO1xuXG4gICAgdGhpcy5fdXBkYXRlVXZzKCk7XG59XG5cblJlbmRlclRleHR1cmUucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShUZXh0dXJlLnByb3RvdHlwZSk7XG5SZW5kZXJUZXh0dXJlLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFJlbmRlclRleHR1cmU7XG5tb2R1bGUuZXhwb3J0cyA9IFJlbmRlclRleHR1cmU7XG5cbi8qKlxuICogUmVzaXplcyB0aGUgUmVuZGVyVGV4dHVyZS5cbiAqXG4gKiBAcGFyYW0gd2lkdGgge251bWJlcn0gVGhlIHdpZHRoIHRvIHJlc2l6ZSB0by5cbiAqIEBwYXJhbSBoZWlnaHQge251bWJlcn0gVGhlIGhlaWdodCB0byByZXNpemUgdG8uXG4gKiBAcGFyYW0gdXBkYXRlQmFzZSB7Ym9vbGVhbn0gU2hvdWxkIHRoZSBiYXNlVGV4dHVyZS53aWR0aCBhbmQgaGVpZ2h0IHZhbHVlcyBiZSByZXNpemVkIGFzIHdlbGw/XG4gKi9cblJlbmRlclRleHR1cmUucHJvdG90eXBlLnJlc2l6ZSA9IGZ1bmN0aW9uICh3aWR0aCwgaGVpZ2h0LCB1cGRhdGVCYXNlKSB7XG4gICAgaWYgKHdpZHRoID09PSB0aGlzLndpZHRoICYmIGhlaWdodCA9PT0gdGhpcy5oZWlnaHQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMudmFsaWQgPSAod2lkdGggPiAwICYmIGhlaWdodCA+IDApO1xuXG4gICAgdGhpcy53aWR0aCA9IHRoaXMuZnJhbWUud2lkdGggPSB0aGlzLmNyb3Aud2lkdGggPSB3aWR0aDtcbiAgICB0aGlzLmhlaWdodCA9ICB0aGlzLmZyYW1lLmhlaWdodCA9IHRoaXMuY3JvcC5oZWlnaHQgPSBoZWlnaHQ7XG5cbiAgICBpZiAodXBkYXRlQmFzZSkge1xuICAgICAgICB0aGlzLmJhc2VUZXh0dXJlLndpZHRoID0gdGhpcy53aWR0aDtcbiAgICAgICAgdGhpcy5iYXNlVGV4dHVyZS5oZWlnaHQgPSB0aGlzLmhlaWdodDtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5yZW5kZXJlci50eXBlID09PSBDT05TVC5XRUJHTF9SRU5ERVJFUikge1xuICAgICAgICB0aGlzLnByb2plY3Rpb24ueCA9IHRoaXMud2lkdGggLyAyO1xuICAgICAgICB0aGlzLnByb2plY3Rpb24ueSA9IC10aGlzLmhlaWdodCAvIDI7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLnZhbGlkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnRleHR1cmVCdWZmZXIucmVzaXplKHRoaXMud2lkdGggKiB0aGlzLnJlc29sdXRpb24sIHRoaXMuaGVpZ2h0ICogdGhpcy5yZXNvbHV0aW9uKTtcbn07XG5cbi8qKlxuICogQ2xlYXJzIHRoZSBSZW5kZXJUZXh0dXJlLlxuICpcbiAqL1xuUmVuZGVyVGV4dHVyZS5wcm90b3R5cGUuY2xlYXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKCF0aGlzLnZhbGlkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5yZW5kZXJlci50eXBlID09PSBDT05TVC5XRUJHTF9SRU5ERVJFUikge1xuICAgICAgICB0aGlzLnJlbmRlcmVyLmdsLmJpbmRGcmFtZWJ1ZmZlcih0aGlzLnJlbmRlcmVyLmdsLkZSQU1FQlVGRkVSLCB0aGlzLnRleHR1cmVCdWZmZXIuZnJhbWVCdWZmZXIpO1xuICAgIH1cblxuICAgIHRoaXMudGV4dHVyZUJ1ZmZlci5jbGVhcigpO1xufTtcblxuLyoqXG4gKiBJbnRlcm5hbCBtZXRob2QgYXNzaWduZWQgdG8gdGhlIGByZW5kZXJgIHByb3BlcnR5IGlmIHVzaW5nIGEgQ2FudmFzUmVuZGVyZXIuXG4gKlxuICogQHByaXZhdGVcbiAqIEBwYXJhbSBkaXNwbGF5T2JqZWN0IHtEaXNwbGF5T2JqZWN0fSBUaGUgZGlzcGxheSBvYmplY3QgdG8gcmVuZGVyIHRoaXMgdGV4dHVyZSBvblxuICogQHBhcmFtIFttYXRyaXhdIHtNYXRyaXh9IE9wdGlvbmFsIG1hdHJpeCB0byBhcHBseSB0byB0aGUgZGlzcGxheSBvYmplY3QgYmVmb3JlIHJlbmRlcmluZy5cbiAqIEBwYXJhbSBbY2xlYXI9ZmFsc2VdIHtib29sZWFufSBJZiB0cnVlIHRoZSB0ZXh0dXJlIHdpbGwgYmUgY2xlYXJlZCBiZWZvcmUgdGhlIGRpc3BsYXlPYmplY3QgaXMgZHJhd25cbiAqIEBwYXJhbSBbcmVzdG9yZVdvcmxkVHJhbnNmb3JtPXRydWVdIHtib29sZWFufSBJZiB0cnVlIHRoZSBkaXNwbGF5T2JqZWN0J3Mgd29ybGRUcmFuc2Zvcm0vd29ybGRBbHBoYSBhbmQgYWxsIGNoaWxkcmVuXG4gKiAgdHJhbnNmb3JtYXRpb25zIHdpbGwgYmUgcmVzdG9yZWQuIE5vdCByZXN0b3JpbmcgdGhpcyBpbmZvcm1hdGlvbiB3aWxsIGJlIGEgbGl0dGxlIGZhc3Rlci5cbiAqL1xuUmVuZGVyVGV4dHVyZS5wcm90b3R5cGUucmVuZGVyV2ViR0wgPSBmdW5jdGlvbiAoZGlzcGxheU9iamVjdCwgbWF0cml4LCBjbGVhciwgcmVzdG9yZVdvcmxkVHJhbnNmb3JtKSB7XG4gICAgaWYgKCF0aGlzLnZhbGlkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIHJlc3RvcmVXb3JsZFRyYW5zZm9ybSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgcmVzdG9yZVdvcmxkVHJhbnNmb3JtID0gdHJ1ZTtcbiAgICB9XG5cbiAgICB2YXIgdGVtcEFscGhhLFxuICAgICAgICB0ZW1wVHJhbnNmb3JtO1xuXG4gICAgaWYgKHJlc3RvcmVXb3JsZFRyYW5zZm9ybSkge1xuICAgICAgICB0ZW1wQWxwaGEgPSBkaXNwbGF5T2JqZWN0LndvcmxkQWxwaGE7XG4gICAgICAgIHRlbXBUcmFuc2Zvcm0gPSBkaXNwbGF5T2JqZWN0LndvcmxkVHJhbnNmb3JtLnRvQXJyYXkoKTtcbiAgICB9XG5cbiAgICAvL1RPT0QgcmVwbGFjZSBwb3NpdGlvbiB3aXRoIG1hdHJpeC4uXG5cbiAgICAvL0xldHMgY3JlYXRlIGEgbmljZSBtYXRyaXggdG8gYXBwbHkgdG8gb3VyIGRpc3BsYXkgb2JqZWN0LiBGcmFtZSBidWZmZXJzIGNvbWUgaW4gdXBzaWRlIGRvd24gc28gd2UgbmVlZCB0byBmbGlwIHRoZSBtYXRyaXhcbiAgICB2YXIgd3QgPSBkaXNwbGF5T2JqZWN0LndvcmxkVHJhbnNmb3JtO1xuXG4gICAgd3QuaWRlbnRpdHkoKTtcbiAgICB3dC50cmFuc2xhdGUoMCwgdGhpcy5wcm9qZWN0aW9uLnkgKiAyKTtcblxuICAgIGlmIChtYXRyaXgpIHtcbiAgICAgICAgd3QuYXBwZW5kKG1hdHJpeCk7XG4gICAgfVxuXG4gICAgd3Quc2NhbGUoMSwtMSk7XG5cbiAgICAvLyBzZXRXb3JsZCBBbHBoYSB0byBlbnN1cmUgdGhhdCB0aGUgb2JqZWN0IGlzIHJlbmRlcmVyIGF0IGZ1bGwgb3BhY2l0eVxuICAgIGRpc3BsYXlPYmplY3Qud29ybGRBbHBoYSA9IDE7XG5cbiAgICAvLyBUaW1lIHRvIHVwZGF0ZSBhbGwgdGhlIGNoaWxkcmVuIG9mIHRoZSBkaXNwbGF5T2JqZWN0IHdpdGggdGhlIG5ldyBtYXRyaXguLlxuICAgIHZhciBjaGlsZHJlbiA9IGRpc3BsYXlPYmplY3QuY2hpbGRyZW47XG4gICAgdmFyIGksIGo7XG5cbiAgICBmb3IgKGkgPSAwLCBqID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgKytpKSB7XG4gICAgICAgIGNoaWxkcmVuW2ldLnVwZGF0ZVRyYW5zZm9ybSgpO1xuICAgIH1cblxuICAgIC8vIHRpbWUgZm9yIHRoZSB3ZWJHTCBmdW4gc3R1ZmYhXG4gICAgdmFyIGdsID0gdGhpcy5yZW5kZXJlci5nbDtcblxuICAgIGdsLnZpZXdwb3J0KDAsIDAsIHRoaXMud2lkdGggKiB0aGlzLnJlc29sdXRpb24sIHRoaXMuaGVpZ2h0ICogdGhpcy5yZXNvbHV0aW9uKTtcblxuICAgIGdsLmJpbmRGcmFtZWJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgdGhpcy50ZXh0dXJlQnVmZmVyLmZyYW1lQnVmZmVyICk7XG5cbiAgICBpZiAoY2xlYXIpIHtcbiAgICAgICAgdGhpcy50ZXh0dXJlQnVmZmVyLmNsZWFyKCk7XG4gICAgfVxuXG4gICAgdGhpcy5yZW5kZXJlci5zcHJpdGVCYXRjaC5kaXJ0eSA9IHRydWU7XG5cbiAgICB0aGlzLnJlbmRlcmVyLnJlbmRlckRpc3BsYXlPYmplY3QoZGlzcGxheU9iamVjdCwgdGhpcy5wcm9qZWN0aW9uLCB0aGlzLnRleHR1cmVCdWZmZXIuZnJhbWVCdWZmZXIpO1xuXG4gICAgdGhpcy5yZW5kZXJlci5zcHJpdGVCYXRjaC5kaXJ0eSA9IHRydWU7XG5cbiAgICBpZiAocmVzdG9yZVdvcmxkVHJhbnNmb3JtKSB7XG4gICAgICAgIGRpc3BsYXlPYmplY3Qud29ybGRBbHBoYSA9IHRlbXBBbHBoYTtcbiAgICAgICAgZGlzcGxheU9iamVjdC53b3JsZFRyYW5zZm9ybS5mcm9tQXJyYXkodGVtcFRyYW5zZm9ybSk7XG5cbiAgICAgICAgZm9yIChpID0gMCwgaiA9IGNoaWxkcmVuLmxlbmd0aDsgaSA8IGo7ICsraSkge1xuICAgICAgICAgICAgY2hpbGRyZW5baV0udXBkYXRlVHJhbnNmb3JtKCk7XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG5cbi8qKlxuICogSW50ZXJuYWwgbWV0aG9kIGFzc2lnbmVkIHRvIHRoZSBgcmVuZGVyYCBwcm9wZXJ0eSBpZiB1c2luZyBhIENhbnZhc1JlbmRlcmVyLlxuICpcbiAqIEBwcml2YXRlXG4gKiBAcGFyYW0gZGlzcGxheU9iamVjdCB7RGlzcGxheU9iamVjdH0gVGhlIGRpc3BsYXkgb2JqZWN0IHRvIHJlbmRlciB0aGlzIHRleHR1cmUgb25cbiAqIEBwYXJhbSBbbWF0cml4XSB7TWF0cml4fSBPcHRpb25hbCBtYXRyaXggdG8gYXBwbHkgdG8gdGhlIGRpc3BsYXkgb2JqZWN0IGJlZm9yZSByZW5kZXJpbmcuXG4gKiBAcGFyYW0gW2NsZWFyXSB7Ym9vbGVhbn0gSWYgdHJ1ZSB0aGUgdGV4dHVyZSB3aWxsIGJlIGNsZWFyZWQgYmVmb3JlIHRoZSBkaXNwbGF5T2JqZWN0IGlzIGRyYXduXG4gKiBAcGFyYW0gW3Jlc3RvcmVXb3JsZFRyYW5zZm9ybT10cnVlXSB7Ym9vbGVhbn0gSWYgdHJ1ZSB0aGUgZGlzcGxheU9iamVjdCdzIHdvcmxkVHJhbnNmb3JtL3dvcmxkQWxwaGEgYW5kIGFsbCBjaGlsZHJlblxuICogIHRyYW5zZm9ybWF0aW9ucyB3aWxsIGJlIHJlc3RvcmVkLiBOb3QgcmVzdG9yaW5nIHRoaXMgaW5mb3JtYXRpb24gd2lsbCBiZSBhIGxpdHRsZSBmYXN0ZXIuXG4gKi9cblJlbmRlclRleHR1cmUucHJvdG90eXBlLnJlbmRlckNhbnZhcyA9IGZ1bmN0aW9uIChkaXNwbGF5T2JqZWN0LCBtYXRyaXgsIGNsZWFyLCByZXN0b3JlV29ybGRUcmFuc2Zvcm0pIHtcbiAgICBpZiAoIXRoaXMudmFsaWQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgcmVzdG9yZVdvcmxkVHJhbnNmb3JtID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICByZXN0b3JlV29ybGRUcmFuc2Zvcm0gPSB0cnVlO1xuICAgIH1cblxuICAgIHZhciB0ZW1wQWxwaGEsXG4gICAgICAgIHRlbXBUcmFuc2Zvcm07XG5cbiAgICBpZiAocmVzdG9yZVdvcmxkVHJhbnNmb3JtKSB7XG4gICAgICAgIHRlbXBBbHBoYSA9IGRpc3BsYXlPYmplY3Qud29ybGRBbHBoYTtcbiAgICAgICAgdGVtcFRyYW5zZm9ybSA9IGRpc3BsYXlPYmplY3Qud29ybGRUcmFuc2Zvcm0udG9BcnJheSgpO1xuICAgIH1cblxuICAgIHZhciB3dCA9IGRpc3BsYXlPYmplY3Qud29ybGRUcmFuc2Zvcm07XG4gICAgd3QuaWRlbnRpdHkoKTtcbiAgICBpZiAobWF0cml4KSB7XG4gICAgICAgIHd0LmFwcGVuZChtYXRyaXgpO1xuICAgIH1cblxuICAgIC8vIHNldFdvcmxkIEFscGhhIHRvIGVuc3VyZSB0aGF0IHRoZSBvYmplY3QgaXMgcmVuZGVyZXIgYXQgZnVsbCBvcGFjaXR5XG4gICAgZGlzcGxheU9iamVjdC53b3JsZEFscGhhID0gMTtcblxuICAgIC8vIFRpbWUgdG8gdXBkYXRlIGFsbCB0aGUgY2hpbGRyZW4gb2YgdGhlIGRpc3BsYXlPYmplY3Qgd2l0aCB0aGUgbmV3IG1hdHJpeC4uXG4gICAgdmFyIGNoaWxkcmVuID0gZGlzcGxheU9iamVjdC5jaGlsZHJlbjtcbiAgICB2YXIgaSwgajtcblxuICAgIGZvciAoaSA9IDAsIGogPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyArK2kpIHtcbiAgICAgICAgY2hpbGRyZW5baV0udXBkYXRlVHJhbnNmb3JtKCk7XG4gICAgfVxuXG4gICAgaWYgKGNsZWFyKSB7XG4gICAgICAgIHRoaXMudGV4dHVyZUJ1ZmZlci5jbGVhcigpO1xuICAgIH1cblxuICAgIHZhciBjb250ZXh0ID0gdGhpcy50ZXh0dXJlQnVmZmVyLmNvbnRleHQ7XG5cbiAgICB2YXIgcmVhbFJlc29sdXRpb24gPSB0aGlzLnJlbmRlcmVyLnJlc29sdXRpb247XG5cbiAgICB0aGlzLnJlbmRlcmVyLnJlc29sdXRpb24gPSB0aGlzLnJlc29sdXRpb247XG5cbiAgICB0aGlzLnJlbmRlcmVyLnJlbmRlckRpc3BsYXlPYmplY3QoZGlzcGxheU9iamVjdCwgY29udGV4dCk7XG5cbiAgICB0aGlzLnJlbmRlcmVyLnJlc29sdXRpb24gPSByZWFsUmVzb2x1dGlvbjtcblxuICAgIGlmIChyZXN0b3JlV29ybGRUcmFuc2Zvcm0pIHtcbiAgICAgICAgZGlzcGxheU9iamVjdC53b3JsZEFscGhhID0gdGVtcEFscGhhO1xuICAgICAgICBkaXNwbGF5T2JqZWN0LndvcmxkVHJhbnNmb3JtLmZyb21BcnJheSh0ZW1wVHJhbnNmb3JtKTtcblxuICAgICAgICBmb3IgKGkgPSAwLCBqID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgKytpKSB7XG4gICAgICAgICAgICBjaGlsZHJlbltpXS51cGRhdGVUcmFuc2Zvcm0oKTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cbi8qKlxuICogV2lsbCByZXR1cm4gYSBIVE1MIEltYWdlIG9mIHRoZSB0ZXh0dXJlXG4gKlxuICogQHJldHVybiB7SW1hZ2V9XG4gKi9cblJlbmRlclRleHR1cmUucHJvdG90eXBlLmdldEltYWdlID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBpbWFnZSA9IG5ldyBJbWFnZSgpO1xuICAgIGltYWdlLnNyYyA9IHRoaXMuZ2V0QmFzZTY0KCk7XG4gICAgcmV0dXJuIGltYWdlO1xufTtcblxuLyoqXG4gKiBXaWxsIHJldHVybiBhIGEgYmFzZTY0IGVuY29kZWQgc3RyaW5nIG9mIHRoaXMgdGV4dHVyZS4gSXQgd29ya3MgYnkgY2FsbGluZyBSZW5kZXJUZXh0dXJlLmdldENhbnZhcyBhbmQgdGhlbiBydW5uaW5nIHRvRGF0YVVSTCBvbiB0aGF0LlxuICpcbiAqIEByZXR1cm4ge3N0cmluZ30gQSBiYXNlNjQgZW5jb2RlZCBzdHJpbmcgb2YgdGhlIHRleHR1cmUuXG4gKi9cblJlbmRlclRleHR1cmUucHJvdG90eXBlLmdldEJhc2U2NCA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5nZXRDYW52YXMoKS50b0RhdGFVUkwoKTtcbn07XG5cbi8qKlxuICogQ3JlYXRlcyBhIENhbnZhcyBlbGVtZW50LCByZW5kZXJzIHRoaXMgUmVuZGVyVGV4dHVyZSB0byBpdCBhbmQgdGhlbiByZXR1cm5zIGl0LlxuICpcbiAqIEByZXR1cm4ge0hUTUxDYW52YXNFbGVtZW50fSBBIENhbnZhcyBlbGVtZW50IHdpdGggdGhlIHRleHR1cmUgcmVuZGVyZWQgb24uXG4gKi9cblJlbmRlclRleHR1cmUucHJvdG90eXBlLmdldENhbnZhcyA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5yZW5kZXJlci50eXBlID09PSBDT05TVC5XRUJHTF9SRU5ERVJFUikge1xuICAgICAgICB2YXIgZ2wgPSAgdGhpcy5yZW5kZXJlci5nbDtcbiAgICAgICAgdmFyIHdpZHRoID0gdGhpcy50ZXh0dXJlQnVmZmVyLndpZHRoO1xuICAgICAgICB2YXIgaGVpZ2h0ID0gdGhpcy50ZXh0dXJlQnVmZmVyLmhlaWdodDtcblxuICAgICAgICB2YXIgd2ViR0xQaXhlbHMgPSBuZXcgVWludDhBcnJheSg0ICogd2lkdGggKiBoZWlnaHQpO1xuXG4gICAgICAgIGdsLmJpbmRGcmFtZWJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgdGhpcy50ZXh0dXJlQnVmZmVyLmZyYW1lQnVmZmVyKTtcbiAgICAgICAgZ2wucmVhZFBpeGVscygwLCAwLCB3aWR0aCwgaGVpZ2h0LCBnbC5SR0JBLCBnbC5VTlNJR05FRF9CWVRFLCB3ZWJHTFBpeGVscyk7XG4gICAgICAgIGdsLmJpbmRGcmFtZWJ1ZmZlcihnbC5GUkFNRUJVRkZFUiwgbnVsbCk7XG5cbiAgICAgICAgdmFyIHRlbXBDYW52YXMgPSBuZXcgQ2FudmFzQnVmZmVyKHdpZHRoLCBoZWlnaHQpO1xuICAgICAgICB2YXIgY2FudmFzRGF0YSA9IHRlbXBDYW52YXMuY29udGV4dC5nZXRJbWFnZURhdGEoMCwgMCwgd2lkdGgsIGhlaWdodCk7XG4gICAgICAgIGNhbnZhc0RhdGEuZGF0YS5zZXQod2ViR0xQaXhlbHMpO1xuXG4gICAgICAgIHRlbXBDYW52YXMuY29udGV4dC5wdXRJbWFnZURhdGEoY2FudmFzRGF0YSwgMCwgMCk7XG5cbiAgICAgICAgcmV0dXJuIHRlbXBDYW52YXMuY2FudmFzO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudGV4dHVyZUJ1ZmZlci5jYW52YXM7XG4gICAgfVxufTtcbiIsInZhciBCYXNlVGV4dHVyZSA9IHJlcXVpcmUoJy4vQmFzZVRleHR1cmUnKSxcbiAgICBWaWRlb0Jhc2VUZXh0dXJlID0gcmVxdWlyZSgnLi9WaWRlb0Jhc2VUZXh0dXJlJyksXG4gICAgVGV4dHVyZVV2cyA9IHJlcXVpcmUoJy4vVGV4dHVyZVV2cycpLFxuICAgIGV2ZW50VGFyZ2V0ID0gcmVxdWlyZSgnLi4vdXRpbHMvZXZlbnRUYXJnZXQnKSxcbiAgICBtYXRoID0gcmVxdWlyZSgnLi4vbWF0aCcpLFxuICAgIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMnKTtcblxuLyoqXG4gKiBBIHRleHR1cmUgc3RvcmVzIHRoZSBpbmZvcm1hdGlvbiB0aGF0IHJlcHJlc2VudHMgYW4gaW1hZ2Ugb3IgcGFydCBvZiBhbiBpbWFnZS4gSXQgY2Fubm90IGJlIGFkZGVkXG4gKiB0byB0aGUgZGlzcGxheSBsaXN0IGRpcmVjdGx5LiBJbnN0ZWFkIHVzZSBpdCBhcyB0aGUgdGV4dHVyZSBmb3IgYSBTcHJpdGUuIElmIG5vIGZyYW1lIGlzIHByb3ZpZGVkIHRoZW4gdGhlIHdob2xlIGltYWdlIGlzIHVzZWQuXG4gKlxuICogQGNsYXNzXG4gKiBAbWl4ZXMgZXZlbnRUYXJnZXRcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIGJhc2VUZXh0dXJlIHtCYXNlVGV4dHVyZX0gVGhlIGJhc2UgdGV4dHVyZSBzb3VyY2UgdG8gY3JlYXRlIHRoZSB0ZXh0dXJlIGZyb21cbiAqIEBwYXJhbSBbZnJhbWVdIHtSZWN0YW5nbGV9IFRoZSByZWN0YW5nbGUgZnJhbWUgb2YgdGhlIHRleHR1cmUgdG8gc2hvd1xuICogQHBhcmFtIFtjcm9wXSB7UmVjdGFuZ2xlfSBUaGUgYXJlYSBvZiBvcmlnaW5hbCB0ZXh0dXJlXG4gKiBAcGFyYW0gW3RyaW1dIHtSZWN0YW5nbGV9IFRyaW1tZWQgdGV4dHVyZSByZWN0YW5nbGVcbiAqL1xuZnVuY3Rpb24gVGV4dHVyZShiYXNlVGV4dHVyZSwgZnJhbWUsIGNyb3AsIHRyaW0pIHtcbiAgICAvKipcbiAgICAgKiBEb2VzIHRoaXMgVGV4dHVyZSBoYXZlIGFueSBmcmFtZSBkYXRhIGFzc2lnbmVkIHRvIGl0P1xuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLm5vRnJhbWUgPSBmYWxzZTtcblxuICAgIGlmICghZnJhbWUpIHtcbiAgICAgICAgdGhpcy5ub0ZyYW1lID0gdHJ1ZTtcbiAgICAgICAgZnJhbWUgPSBuZXcgbWF0aC5SZWN0YW5nbGUoMCwgMCwgMSwgMSk7XG4gICAgfVxuXG4gICAgaWYgKGJhc2VUZXh0dXJlIGluc3RhbmNlb2YgVGV4dHVyZSkge1xuICAgICAgICBiYXNlVGV4dHVyZSA9IGJhc2VUZXh0dXJlLmJhc2VUZXh0dXJlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRoZSBiYXNlIHRleHR1cmUgdGhhdCB0aGlzIHRleHR1cmUgdXNlcy5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0Jhc2VUZXh0dXJlfVxuICAgICAqL1xuICAgIHRoaXMuYmFzZVRleHR1cmUgPSBiYXNlVGV4dHVyZTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBmcmFtZSBzcGVjaWZpZXMgdGhlIHJlZ2lvbiBvZiB0aGUgYmFzZSB0ZXh0dXJlIHRoYXQgdGhpcyB0ZXh0dXJlIHVzZXNcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1JlY3RhbmdsZX1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuX2ZyYW1lID0gZnJhbWU7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdGV4dHVyZSB0cmltIGRhdGEuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtSZWN0YW5nbGV9XG4gICAgICovXG4gICAgdGhpcy50cmltID0gdHJpbTtcblxuICAgIC8qKlxuICAgICAqIFRoaXMgd2lsbCBsZXQgdGhlIHJlbmRlcmVyIGtub3cgaWYgdGhlIHRleHR1cmUgaXMgdmFsaWQuIElmIGl0J3Mgbm90IHRoZW4gaXQgY2Fubm90IGJlIHJlbmRlcmVkLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLnZhbGlkID0gZmFsc2U7XG5cbiAgICAvKipcbiAgICAgKiBUaGlzIHdpbGwgbGV0IGEgcmVuZGVyZXIga25vdyB0aGF0IGEgdGV4dHVyZSBoYXMgYmVlbiB1cGRhdGVkICh1c2VkIG1haW5seSBmb3Igd2ViR0wgdXYgdXBkYXRlcylcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5yZXF1aXJlc1VwZGF0ZSA9IGZhbHNlO1xuXG4gICAgLyoqXG4gICAgICogVGhlIFdlYkdMIFVWIGRhdGEgY2FjaGUuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtvYmplY3R9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl91dnMgPSBudWxsO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHdpZHRoIG9mIHRoZSBUZXh0dXJlIGluIHBpeGVscy5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLndpZHRoID0gMDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBoZWlnaHQgb2YgdGhlIFRleHR1cmUgaW4gcGl4ZWxzLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMuaGVpZ2h0ID0gMDtcblxuICAgIC8qKlxuICAgICAqIFRoaXMgaXMgdGhlIGFyZWEgb2YgdGhlIEJhc2VUZXh0dXJlIGltYWdlIHRvIGFjdHVhbGx5IGNvcHkgdG8gdGhlIENhbnZhcyAvIFdlYkdMIHdoZW4gcmVuZGVyaW5nLFxuICAgICAqIGlycmVzcGVjdGl2ZSBvZiB0aGUgYWN0dWFsIGZyYW1lIHNpemUgb3IgcGxhY2VtZW50ICh3aGljaCBjYW4gYmUgaW5mbHVlbmNlZCBieSB0cmltbWVkIHRleHR1cmUgYXRsYXNlcylcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1JlY3RhbmdsZX1cbiAgICAgKi9cbiAgICB0aGlzLmNyb3AgPSBjcm9wIHx8IG5ldyBtYXRoLlJlY3RhbmdsZSgwLCAwLCAxLCAxKTtcblxuICAgIGlmIChiYXNlVGV4dHVyZS5oYXNMb2FkZWQpIHtcbiAgICAgICAgaWYgKHRoaXMubm9GcmFtZSkge1xuICAgICAgICAgICAgZnJhbWUgPSBuZXcgbWF0aC5SZWN0YW5nbGUoMCwgMCwgYmFzZVRleHR1cmUud2lkdGgsIGJhc2VUZXh0dXJlLmhlaWdodCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5mcmFtZSA9IGZyYW1lO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgYmFzZVRleHR1cmUuYWRkRXZlbnRMaXN0ZW5lcignbG9hZGVkJywgdGhpcy5vbkJhc2VUZXh0dXJlTG9hZGVkLmJpbmQodGhpcykpO1xuICAgIH1cbn1cblxuVGV4dHVyZS5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBUZXh0dXJlO1xubW9kdWxlLmV4cG9ydHMgPSBUZXh0dXJlO1xuXG5ldmVudFRhcmdldC5taXhpbihUZXh0dXJlLnByb3RvdHlwZSk7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKFRleHR1cmUucHJvdG90eXBlLCB7XG4gICAgbmVlZHNVcGRhdGU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5iYXNlVGV4dHVyZS5uZWVkc1VwZGF0ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsKSB7XG4gICAgICAgICAgICB0aGlzLmJhc2VUZXh0dXJlLm5lZWRzVXBkYXRlID0gdmFsO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIGZyYW1lOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2ZyYW1lO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uIChmcmFtZSkge1xuICAgICAgICAgICAgdGhpcy5fZnJhbWUgPSBmcmFtZTtcblxuICAgICAgICAgICAgdGhpcy5ub0ZyYW1lID0gZmFsc2U7XG5cbiAgICAgICAgICAgIHRoaXMud2lkdGggPSBmcmFtZS53aWR0aDtcbiAgICAgICAgICAgIHRoaXMuaGVpZ2h0ID0gZnJhbWUuaGVpZ2h0O1xuXG4gICAgICAgICAgICB0aGlzLmNyb3AueCA9IGZyYW1lLng7XG4gICAgICAgICAgICB0aGlzLmNyb3AueSA9IGZyYW1lLnk7XG4gICAgICAgICAgICB0aGlzLmNyb3Aud2lkdGggPSBmcmFtZS53aWR0aDtcbiAgICAgICAgICAgIHRoaXMuY3JvcC5oZWlnaHQgPSBmcmFtZS5oZWlnaHQ7XG5cbiAgICAgICAgICAgIGlmICghdGhpcy50cmltICYmIChmcmFtZS54ICsgZnJhbWUud2lkdGggPiB0aGlzLmJhc2VUZXh0dXJlLndpZHRoIHx8IGZyYW1lLnkgKyBmcmFtZS5oZWlnaHQgPiB0aGlzLmJhc2VUZXh0dXJlLmhlaWdodCkpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1RleHR1cmUgRXJyb3I6IGZyYW1lIGRvZXMgbm90IGZpdCBpbnNpZGUgdGhlIGJhc2UgVGV4dHVyZSBkaW1lbnNpb25zICcgKyB0aGlzKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy52YWxpZCA9IGZyYW1lICYmIGZyYW1lLndpZHRoICYmIGZyYW1lLmhlaWdodCAmJiB0aGlzLmJhc2VUZXh0dXJlLnNvdXJjZSAmJiB0aGlzLmJhc2VUZXh0dXJlLmhhc0xvYWRlZDtcblxuICAgICAgICAgICAgaWYgKHRoaXMudHJpbSkge1xuICAgICAgICAgICAgICAgIHRoaXMud2lkdGggPSB0aGlzLnRyaW0ud2lkdGg7XG4gICAgICAgICAgICAgICAgdGhpcy5oZWlnaHQgPSB0aGlzLnRyaW0uaGVpZ2h0O1xuICAgICAgICAgICAgICAgIHRoaXMuX2ZyYW1lLndpZHRoID0gdGhpcy50cmltLndpZHRoO1xuICAgICAgICAgICAgICAgIHRoaXMuX2ZyYW1lLmhlaWdodCA9IHRoaXMudHJpbS5oZWlnaHQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0aGlzLnZhbGlkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fdXBkYXRlVXZzKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59KTtcblxuLyoqXG4gKiBDYWxsZWQgd2hlbiB0aGUgYmFzZSB0ZXh0dXJlIGlzIGxvYWRlZFxuICpcbiAqIEBwcml2YXRlXG4gKi9cblRleHR1cmUucHJvdG90eXBlLm9uQmFzZVRleHR1cmVMb2FkZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGJhc2VUZXh0dXJlID0gdGhpcy5iYXNlVGV4dHVyZTtcbiAgICBiYXNlVGV4dHVyZS5yZW1vdmVFdmVudExpc3RlbmVyKCdsb2FkZWQnLCB0aGlzLm9uTG9hZGVkKTtcblxuICAgIGlmICh0aGlzLm5vRnJhbWUpIHtcbiAgICAgICAgdGhpcy5mcmFtZSA9IG5ldyBtYXRoLlJlY3RhbmdsZSgwLCAwLCBiYXNlVGV4dHVyZS53aWR0aCwgYmFzZVRleHR1cmUuaGVpZ2h0KTtcbiAgICB9XG5cbiAgICB0aGlzLmRpc3BhdGNoRXZlbnQoIHsgdHlwZTogJ3VwZGF0ZScsIGNvbnRlbnQ6IHRoaXMgfSApO1xufTtcblxuLyoqXG4gKiBEZXN0cm95cyB0aGlzIHRleHR1cmVcbiAqXG4gKiBAcGFyYW0gZGVzdHJveUJhc2Uge2Jvb2xlYW59IFdoZXRoZXIgdG8gZGVzdHJveSB0aGUgYmFzZSB0ZXh0dXJlIGFzIHdlbGxcbiAqL1xuVGV4dHVyZS5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uIChkZXN0cm95QmFzZSkge1xuICAgIGlmIChkZXN0cm95QmFzZSkge1xuICAgICAgICB0aGlzLmJhc2VUZXh0dXJlLmRlc3Ryb3koKTtcbiAgICB9XG5cbiAgICB0aGlzLnZhbGlkID0gZmFsc2U7XG59O1xuXG4vKipcbiAqIFVwZGF0ZXMgdGhlIGludGVybmFsIFdlYkdMIFVWIGNhY2hlLlxuICpcbiAqIEBwcml2YXRlXG4gKi9cblRleHR1cmUucHJvdG90eXBlLl91cGRhdGVVdnMgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKCF0aGlzLl91dnMpIHtcbiAgICAgICAgdGhpcy5fdXZzID0gbmV3IFRleHR1cmVVdnMoKTtcbiAgICB9XG5cbiAgICB2YXIgZnJhbWUgPSB0aGlzLmNyb3A7XG4gICAgdmFyIHR3ID0gdGhpcy5iYXNlVGV4dHVyZS53aWR0aDtcbiAgICB2YXIgdGggPSB0aGlzLmJhc2VUZXh0dXJlLmhlaWdodDtcblxuICAgIHRoaXMuX3V2cy54MCA9IGZyYW1lLnggLyB0dztcbiAgICB0aGlzLl91dnMueTAgPSBmcmFtZS55IC8gdGg7XG5cbiAgICB0aGlzLl91dnMueDEgPSAoZnJhbWUueCArIGZyYW1lLndpZHRoKSAvIHR3O1xuICAgIHRoaXMuX3V2cy55MSA9IGZyYW1lLnkgLyB0aDtcblxuICAgIHRoaXMuX3V2cy54MiA9IChmcmFtZS54ICsgZnJhbWUud2lkdGgpIC8gdHc7XG4gICAgdGhpcy5fdXZzLnkyID0gKGZyYW1lLnkgKyBmcmFtZS5oZWlnaHQpIC8gdGg7XG5cbiAgICB0aGlzLl91dnMueDMgPSBmcmFtZS54IC8gdHc7XG4gICAgdGhpcy5fdXZzLnkzID0gKGZyYW1lLnkgKyBmcmFtZS5oZWlnaHQpIC8gdGg7XG59O1xuXG4vKipcbiAqIEhlbHBlciBmdW5jdGlvbiB0aGF0IGNyZWF0ZXMgYSBUZXh0dXJlIG9iamVjdCBmcm9tIHRoZSBnaXZlbiBpbWFnZSB1cmwuXG4gKiBJZiB0aGUgaW1hZ2UgaXMgbm90IGluIHRoZSB0ZXh0dXJlIGNhY2hlIGl0IHdpbGwgYmUgIGNyZWF0ZWQgYW5kIGxvYWRlZC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAcGFyYW0gaW1hZ2VVcmwge3N0cmluZ30gVGhlIGltYWdlIHVybCBvZiB0aGUgdGV4dHVyZVxuICogQHBhcmFtIGNyb3Nzb3JpZ2luIHtib29sZWFufSBXaGV0aGVyIHJlcXVlc3RzIHNob3VsZCBiZSB0cmVhdGVkIGFzIGNyb3Nzb3JpZ2luXG4gKiBAcGFyYW0gc2NhbGVNb2RlIHtudW1iZXJ9IFNlZSB7eyNjcm9zc0xpbmsgXCJQSVhJL3NjYWxlTW9kZXM6cHJvcGVydHlcIn19c2NhbGVNb2Rlc3t7L2Nyb3NzTGlua319IGZvciBwb3NzaWJsZSB2YWx1ZXNcbiAqIEByZXR1cm4gVGV4dHVyZVxuICovXG5UZXh0dXJlLmZyb21JbWFnZSA9IGZ1bmN0aW9uIChpbWFnZVVybCwgY3Jvc3NvcmlnaW4sIHNjYWxlTW9kZSkge1xuICAgIHZhciB0ZXh0dXJlID0gdXRpbHMuVGV4dHVyZUNhY2hlW2ltYWdlVXJsXTtcblxuICAgIGlmICghdGV4dHVyZSkge1xuICAgICAgICB0ZXh0dXJlID0gbmV3IFRleHR1cmUoQmFzZVRleHR1cmUuZnJvbUltYWdlKGltYWdlVXJsLCBjcm9zc29yaWdpbiwgc2NhbGVNb2RlKSk7XG4gICAgICAgIHV0aWxzLlRleHR1cmVDYWNoZVtpbWFnZVVybF0gPSB0ZXh0dXJlO1xuICAgIH1cblxuICAgIHJldHVybiB0ZXh0dXJlO1xufTtcblxuLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdGhhdCByZXR1cm5zIGEgVGV4dHVyZSBvYmplY3RlZCBiYXNlZCBvbiB0aGUgZ2l2ZW4gZnJhbWUgaWQuXG4gKiBJZiB0aGUgZnJhbWUgaWQgaXMgbm90IGluIHRoZSB0ZXh0dXJlIGNhY2hlIGFuIGVycm9yIHdpbGwgYmUgdGhyb3duLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBwYXJhbSBmcmFtZUlkIHtzdHJpbmd9IFRoZSBmcmFtZSBpZCBvZiB0aGUgdGV4dHVyZVxuICogQHJldHVybiBUZXh0dXJlXG4gKi9cblRleHR1cmUuZnJvbUZyYW1lID0gZnVuY3Rpb24gKGZyYW1lSWQpIHtcbiAgICB2YXIgdGV4dHVyZSA9IHV0aWxzLlRleHR1cmVDYWNoZVtmcmFtZUlkXTtcbiAgICBpZiAoIXRleHR1cmUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdUaGUgZnJhbWVJZCBcIicgKyBmcmFtZUlkICsgJ1wiIGRvZXMgbm90IGV4aXN0IGluIHRoZSB0ZXh0dXJlIGNhY2hlICcpO1xuICAgIH1cbiAgICByZXR1cm4gdGV4dHVyZTtcbn07XG5cbi8qKlxuICogSGVscGVyIGZ1bmN0aW9uIHRoYXQgY3JlYXRlcyBhIG5ldyBUZXh0dXJlIGJhc2VkIG9uIHRoZSBnaXZlbiBjYW52YXMgZWxlbWVudC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAcGFyYW0gY2FudmFzIHtDYW52YXN9IFRoZSBjYW52YXMgZWxlbWVudCBzb3VyY2Ugb2YgdGhlIHRleHR1cmVcbiAqIEBwYXJhbSBzY2FsZU1vZGUge251bWJlcn0gU2VlIHt7I2Nyb3NzTGluayBcIlBJWEkvc2NhbGVNb2Rlczpwcm9wZXJ0eVwifX1zY2FsZU1vZGVze3svY3Jvc3NMaW5rfX0gZm9yIHBvc3NpYmxlIHZhbHVlc1xuICogQHJldHVybiB7VGV4dHVyZX1cbiAqL1xuVGV4dHVyZS5mcm9tQ2FudmFzID0gZnVuY3Rpb24gKGNhbnZhcywgc2NhbGVNb2RlKSB7XG4gICAgcmV0dXJuIG5ldyBUZXh0dXJlKEJhc2VUZXh0dXJlLmZyb21DYW52YXMoY2FudmFzLCBzY2FsZU1vZGUpKTtcbn07XG5cbi8qKlxuICogSGVscGVyIGZ1bmN0aW9uIHRoYXQgY3JlYXRlcyBhIG5ldyBUZXh0dXJlIGJhc2VkIG9uIHRoZSBnaXZlbiB2aWRlbyBlbGVtZW50LlxuICpcbiAqIEBzdGF0aWNcbiAqIEBwYXJhbSB2aWRlbyB7SFRNTFZpZGVvRWxlbWVudH1cbiAqIEBwYXJhbSBzY2FsZU1vZGUge251bWJlcn0gU2VlIHt7I2Nyb3NzTGluayBcIlBJWEkvc2NhbGVNb2Rlczpwcm9wZXJ0eVwifX1zY2FsZU1vZGVze3svY3Jvc3NMaW5rfX0gZm9yIHBvc3NpYmxlIHZhbHVlc1xuICogQHJldHVybiB7VGV4dHVyZX0gQSBUZXh0dXJlXG4gKi9cblRleHR1cmUuZnJvbVZpZGVvID0gZnVuY3Rpb24gKHZpZGVvLCBzY2FsZU1vZGUpIHtcbiAgICByZXR1cm4gbmV3IFRleHR1cmUoVmlkZW9CYXNlVGV4dHVyZS5iYXNlVGV4dHVyZUZyb21WaWRlbyh2aWRlbywgc2NhbGVNb2RlKSk7XG59O1xuXG4vKipcbiAqIEFkZHMgYSB0ZXh0dXJlIHRvIHRoZSBnbG9iYWwgdXRpbHMuVGV4dHVyZUNhY2hlLiBUaGlzIGNhY2hlIGlzIHNoYXJlZCBhY3Jvc3MgdGhlIHdob2xlIFBJWEkgb2JqZWN0LlxuICpcbiAqIEBzdGF0aWNcbiAqIEBwYXJhbSB0ZXh0dXJlIHtUZXh0dXJlfSBUaGUgVGV4dHVyZSB0byBhZGQgdG8gdGhlIGNhY2hlLlxuICogQHBhcmFtIGlkIHtzdHJpbmd9IFRoZSBpZCB0aGF0IHRoZSB0ZXh0dXJlIHdpbGwgYmUgc3RvcmVkIGFnYWluc3QuXG4gKi9cblRleHR1cmUuYWRkVGV4dHVyZVRvQ2FjaGUgPSBmdW5jdGlvbiAodGV4dHVyZSwgaWQpIHtcbiAgICB1dGlscy5UZXh0dXJlQ2FjaGVbaWRdID0gdGV4dHVyZTtcbn07XG5cbi8qKlxuICogUmVtb3ZlIGEgdGV4dHVyZSBmcm9tIHRoZSBnbG9iYWwgdXRpbHMuVGV4dHVyZUNhY2hlLlxuICpcbiAqIEBzdGF0aWNcbiAqIEBwYXJhbSBpZCB7c3RyaW5nfSBUaGUgaWQgb2YgdGhlIHRleHR1cmUgdG8gYmUgcmVtb3ZlZFxuICogQHJldHVybiB7VGV4dHVyZX0gVGhlIHRleHR1cmUgdGhhdCB3YXMgcmVtb3ZlZFxuICovXG5UZXh0dXJlLnJlbW92ZVRleHR1cmVGcm9tQ2FjaGUgPSBmdW5jdGlvbiAoaWQpIHtcbiAgICB2YXIgdGV4dHVyZSA9IHV0aWxzLlRleHR1cmVDYWNoZVtpZF07XG5cbiAgICBkZWxldGUgdXRpbHMuVGV4dHVyZUNhY2hlW2lkXTtcbiAgICBkZWxldGUgdXRpbHMuQmFzZVRleHR1cmVDYWNoZVtpZF07XG5cbiAgICByZXR1cm4gdGV4dHVyZTtcbn07XG5cblRleHR1cmUuZW1wdHlUZXh0dXJlID0gbmV3IFRleHR1cmUobmV3IEJhc2VUZXh0dXJlKCkpO1xuIiwiZnVuY3Rpb24gVGV4dHVyZVV2cygpIHtcbiAgICB0aGlzLngwID0gMDtcbiAgICB0aGlzLnkwID0gMDtcblxuICAgIHRoaXMueDEgPSAwO1xuICAgIHRoaXMueTEgPSAwO1xuXG4gICAgdGhpcy54MiA9IDA7XG4gICAgdGhpcy55MiA9IDA7XG5cbiAgICB0aGlzLngzID0gMDtcbiAgICB0aGlzLnkzID0gMDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBUZXh0dXJlVXZzO1xuIiwidmFyIEJhc2VUZXh0dXJlID0gcmVxdWlyZSgnLi9CYXNlVGV4dHVyZScpLFxuICAgIHV0aWxzID0gcmVxdWlyZSgnLi4vdXRpbHMnKTtcblxuLyoqXG4gKiBBIHRleHR1cmUgb2YgYSBbcGxheWluZ10gVmlkZW8uXG4gKlxuICogU2VlIHRoZSBbXCJkZXVzXCIgZGVtb10oaHR0cDovL3d3dy5nb29kYm95ZGlnaXRhbC5jb20vcGl4aWpzL2V4YW1wbGVzL2RldXMvKS5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEJhc2VUZXh0dXJlXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSBzb3VyY2Uge0hUTUxWaWRlb0VsZW1lbnR9XG4gKiBAcGFyYW0gW3NjYWxlTW9kZV0ge251bWJlcn0gU2VlIHtAbGluayBzY2FsZU1vZGVzfSBmb3IgcG9zc2libGUgdmFsdWVzXG4gKi9cbmZ1bmN0aW9uIFZpZGVvQmFzZVRleHR1cmUoc291cmNlLCBzY2FsZU1vZGUpIHtcbiAgICBpZiAoIXNvdXJjZSl7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gdmlkZW8gc291cmNlIGVsZW1lbnQgc3BlY2lmaWVkLicpO1xuICAgIH1cblxuICAgIC8vIGhvb2sgaW4gaGVyZSB0byBjaGVjayBpZiB2aWRlbyBpcyBhbHJlYWR5IGF2YWlsYWJsZS5cbiAgICAvLyBCYXNlVGV4dHVyZSBsb29rcyBmb3IgYSBzb3VyY2UuY29tcGxldGUgYm9vbGVhbiwgcGx1cyB3aWR0aCAmIGhlaWdodC5cblxuICAgIGlmICgoc291cmNlLnJlYWR5U3RhdGUgPT09IHNvdXJjZS5IQVZFX0VOT1VHSF9EQVRBIHx8IHNvdXJjZS5yZWFkeVN0YXRlID09PSBzb3VyY2UuSEFWRV9GVVRVUkVfREFUQSkgJiYgc291cmNlLndpZHRoICYmIHNvdXJjZS5oZWlnaHQpIHtcbiAgICAgICAgc291cmNlLmNvbXBsZXRlID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBCYXNlVGV4dHVyZS5jYWxsKHRoaXMsIHNvdXJjZSwgc2NhbGVNb2RlKTtcblxuICAgIHRoaXMuYXV0b1VwZGF0ZSA9IGZhbHNlO1xuXG4gICAgdGhpcy5fYm91bmRPblVwZGF0ZSA9IHRoaXMuX29uVXBkYXRlLmJpbmQodGhpcyk7XG4gICAgdGhpcy5fYm91bmRPbkNhblBsYXkgPSB0aGlzLl9vbkNhblBsYXkuYmluZCh0aGlzKTtcblxuICAgIGlmICghc291cmNlLmNvbXBsZXRlKSB7XG4gICAgICAgIHNvdXJjZS5hZGRFdmVudExpc3RlbmVyKCdjYW5wbGF5JywgdGhpcy5fYm91bmRPbkNhblBsYXkpO1xuICAgICAgICBzb3VyY2UuYWRkRXZlbnRMaXN0ZW5lcignY2FucGxheXRocm91Z2gnLCB0aGlzLl9ib3VuZE9uQ2FuUGxheSk7XG5cbiAgICAgICAgLy8gc3RhcnRlZCBwbGF5aW5nLi5cbiAgICAgICAgc291cmNlLmFkZEV2ZW50TGlzdGVuZXIoJ3BsYXknLCB0aGlzLl9vblBsYXlTdGFydC5iaW5kKHRoaXMpKTtcbiAgICAgICAgc291cmNlLmFkZEV2ZW50TGlzdGVuZXIoJ3BhdXNlJywgdGhpcy5fb25QbGF5U3RvcC5iaW5kKHRoaXMpKTtcbiAgICB9XG5cbiAgICB0aGlzLl9fbG9hZGVkID0gZmFsc2U7XG59XG5cblZpZGVvQmFzZVRleHR1cmUucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShCYXNlVGV4dHVyZS5wcm90b3R5cGUpO1xuVmlkZW9CYXNlVGV4dHVyZS5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBWaWRlb0Jhc2VUZXh0dXJlO1xubW9kdWxlLmV4cG9ydHMgPSBWaWRlb0Jhc2VUZXh0dXJlO1xuXG5WaWRlb0Jhc2VUZXh0dXJlLnByb3RvdHlwZS5fb25VcGRhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHRoaXMuYXV0b1VwZGF0ZSkge1xuICAgICAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKHRoaXMuX2JvdW5kT25VcGRhdGUpO1xuICAgICAgICB0aGlzLm5lZWRzVXBkYXRlID0gdHJ1ZTtcbiAgICB9XG59O1xuXG5WaWRlb0Jhc2VUZXh0dXJlLnByb3RvdHlwZS5fb25QbGF5U3RhcnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKCF0aGlzLmF1dG9VcGRhdGUpIHtcbiAgICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSh0aGlzLl9ib3VuZE9uVXBkYXRlKTtcbiAgICAgICAgdGhpcy5hdXRvVXBkYXRlID0gdHJ1ZTtcbiAgICB9XG59O1xuXG5WaWRlb0Jhc2VUZXh0dXJlLnByb3RvdHlwZS5fb25QbGF5U3RvcCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmF1dG9VcGRhdGUgPSBmYWxzZTtcbn07XG5cblZpZGVvQmFzZVRleHR1cmUucHJvdG90eXBlLl9vbkNhblBsYXkgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5oYXNMb2FkZWQgPSB0cnVlO1xuXG4gICAgaWYgKHRoaXMuc291cmNlKSB7XG4gICAgICAgIHRoaXMuc291cmNlLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2NhbnBsYXknLCB0aGlzLl9ib3VuZE9uQ2FuUGxheSk7XG4gICAgICAgIHRoaXMuc291cmNlLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2NhbnBsYXl0aHJvdWdoJywgdGhpcy5fYm91bmRPbkNhblBsYXkpO1xuXG4gICAgICAgIHRoaXMud2lkdGggPSB0aGlzLnNvdXJjZS52aWRlb1dpZHRoO1xuICAgICAgICB0aGlzLmhlaWdodCA9IHRoaXMuc291cmNlLnZpZGVvSGVpZ2h0O1xuXG4gICAgICAgIHRoaXMuc291cmNlLnBsYXkoKTtcblxuICAgICAgICAvLyBwcmV2ZW50IG11bHRpcGxlIGxvYWRlZCBkaXNwYXRjaGVzLi5cbiAgICAgICAgaWYoIXRoaXMuX19sb2FkZWQpe1xuICAgICAgICAgICAgdGhpcy5fX2xvYWRlZCA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLmVtaXQoJ2xvYWRlZCcsIHRoaXMpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuVmlkZW9CYXNlVGV4dHVyZS5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5zb3VyY2UgJiYgdGhpcy5zb3VyY2UuX3BpeGlJZCkge1xuICAgICAgICB1dGlscy5CYXNlVGV4dHVyZUNhY2hlWyB0aGlzLnNvdXJjZS5fcGl4aUlkIF0gPSBudWxsO1xuICAgICAgICBkZWxldGUgdXRpbHMuQmFzZVRleHR1cmVDYWNoZVsgdGhpcy5zb3VyY2UuX3BpeGlJZCBdO1xuXG4gICAgICAgIHRoaXMuc291cmNlLl9waXhpSWQgPSBudWxsO1xuICAgICAgICBkZWxldGUgdGhpcy5zb3VyY2UuX3BpeGlJZDtcbiAgICB9XG5cbiAgICBCYXNlVGV4dHVyZS5wcm90b3R5cGUuZGVzdHJveS5jYWxsKHRoaXMpO1xufTtcblxuLyoqXG4gKiBNaW1pYyBQaXhpIEJhc2VUZXh0dXJlLmZyb20uLi4uIG1ldGhvZC5cbiAqXG4gKiBAc3RhdGljXG4gKiBAcGFyYW0gdmlkZW8ge0hUTUxWaWRlb0VsZW1lbnR9XG4gKiBAcGFyYW0gc2NhbGVNb2RlIHtudW1iZXJ9IFNlZSB7QGxpbmsgc2NhbGVNb2Rlc30gZm9yIHBvc3NpYmxlIHZhbHVlc1xuICogQHJldHVybiB7VmlkZW9CYXNlVGV4dHVyZX1cbiAqL1xuVmlkZW9CYXNlVGV4dHVyZS5mcm9tVmlkZW8gPSBmdW5jdGlvbiAodmlkZW8sIHNjYWxlTW9kZSkge1xuICAgIGlmICghdmlkZW8uX3BpeGlJZCkge1xuICAgICAgICB2aWRlby5fcGl4aUlkID0gJ3ZpZGVvXycgKyB1dGlscy51dWlkKCk7XG4gICAgfVxuXG4gICAgdmFyIGJhc2VUZXh0dXJlID0gdXRpbHMuQmFzZVRleHR1cmVDYWNoZVt2aWRlby5fcGl4aUlkXTtcblxuICAgIGlmICghYmFzZVRleHR1cmUpIHtcbiAgICAgICAgYmFzZVRleHR1cmUgPSBuZXcgVmlkZW9CYXNlVGV4dHVyZSh2aWRlbywgc2NhbGVNb2RlKTtcbiAgICAgICAgdXRpbHMuQmFzZVRleHR1cmVDYWNoZVsgdmlkZW8uX3BpeGlJZCBdID0gYmFzZVRleHR1cmU7XG4gICAgfVxuXG4gICAgcmV0dXJuIGJhc2VUZXh0dXJlO1xufTtcblxuLyoqXG4gKiBNaW1pYyBQaXhpIEJhc2VUZXh0dXJlLmZyb20uLi4uIG1ldGhvZC5cbiAqXG4gKiBUaGlzIGNhbiBiZSB1c2VkIGluIGEgY291cGxlIHdheXMsIHN1Y2ggYXM6XG4gKlxuICogYGBganNcbiAqIHZhciB0ZXh0dXJlID0gUElYSS5WaWRlb0Jhc2VUZXh0dXJlLmZyb21VcmwoJ2h0dHA6Ly9teWRvbWFpbi5jb20vdmlkZW8ubXA0Jyk7XG4gKlxuICogdmFyIHRleHR1cmUgPSBQSVhJLlZpZGVvQmFzZVRleHR1cmUuZnJvbVVybCh7IHNyYzogJ2h0dHA6Ly9teWRvbWFpbi5jb20vdmlkZW8ubXA0JywgbWltZTogJ3ZpZGVvL21wNCcgfSk7XG4gKlxuICogdmFyIHRleHR1cmUgPSBQSVhJLlZpZGVvQmFzZVRleHR1cmUuZnJvbVVybHMoWycvdmlkZW8ud2VibScsICcvdmlkZW8ubXA0J10pO1xuICpcbiAqIHZhciB0ZXh0dXJlID0gUElYSS5WaWRlb0Jhc2VUZXh0dXJlLmZyb21VcmxzKFtcbiAqICAgICB7IHNyYzogJy92aWRlby53ZWJtJywgbWltZTogJ3ZpZGVvL3dlYm0nIH0sXG4gKiAgICAgeyBzcmM6ICcvdmlkZW8ubXA0JywgbWltZTogJ3ZpZGVvL21wNCcgfVxuICogXSk7XG4gKiBgYGBcbiAqXG4gKiBAYWxpYXMgZnJvbVVybHNcbiAqIEBzdGF0aWNcbiAqIEBwYXJhbSB2aWRlb1NyYyB7c3RyaW5nfG9iamVjdHxzdHJpbmdbXXxvYmplY3RbXX0gVGhlIFVSTChzKSBmb3IgdGhlIHZpZGVvLlxuICogQHBhcmFtIFt2aWRlb1NyYy5zcmNdIHtzdHJpbmd9IE9uZSBvZiB0aGUgc291cmNlIHVybHMgZm9yIHRoZSB2aWRlb1xuICogQHBhcmFtIFt2aWRlb1NyYy5taW1lXSB7c3RyaW5nfSBUaGUgbWltZXR5cGUgb2YgdGhlIHZpZGVvIChlLmcuICd2aWRlby9tcDQnKS4gSWYgbm90IHNwZWNpZmllZFxuICogIHRoZSB1cmwncyBleHRlbnNpb24gd2lsbCBiZSB1c2VkIGFzIHRoZSBzZWNvbmQgcGFydCBvZiB0aGUgbWltZSB0eXBlLlxuICogQHBhcmFtIHNjYWxlTW9kZSB7bnVtYmVyfSBTZWUge0BsaW5rIHNjYWxlTW9kZXN9IGZvciBwb3NzaWJsZSB2YWx1ZXNcbiAqIEByZXR1cm4ge1ZpZGVvQmFzZVRleHR1cmV9XG4gKi9cblZpZGVvQmFzZVRleHR1cmUuZnJvbVVybCA9IGZ1bmN0aW9uICh2aWRlb1NyYywgc2NhbGVNb2RlKSB7XG4gICAgdmFyIHZpZGVvID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndmlkZW8nKTtcblxuICAgIC8vIGFycmF5IG9mIG9iamVjdHMgb3Igc3RyaW5nc1xuICAgIGlmIChBcnJheS5pc0FycmF5KHZpZGVvU3JjKSkge1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZpZGVvU3JjLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICB2aWRlby5hcHBlbmRDaGlsZChjcmVhdGVTb3VyY2UodmlkZW9TcmMuc3JjIHx8IHZpZGVvU3JjLCB2aWRlb1NyYy5taW1lKSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gc2luZ2xlIG9iamVjdCBvciBzdHJpbmdcbiAgICBlbHNlIHtcbiAgICAgICAgdmlkZW8uYXBwZW5kQ2hpbGQoY3JlYXRlU291cmNlKHZpZGVvU3JjLnNyYyB8fCB2aWRlb1NyYywgdmlkZW9TcmMubWltZSkpO1xuICAgIH1cblxuICAgIHZpZGVvLmxvYWQoKTtcbiAgICB2aWRlby5wbGF5KCk7XG5cbiAgICByZXR1cm4gVmlkZW9CYXNlVGV4dHVyZS50ZXh0dXJlRnJvbVZpZGVvKHZpZGVvLCBzY2FsZU1vZGUpO1xufTtcblxuVmlkZW9CYXNlVGV4dHVyZS5mcm9tVXJscyA9IFZpZGVvQmFzZVRleHR1cmUuZnJvbVVybDtcblxuZnVuY3Rpb24gY3JlYXRlU291cmNlKHBhdGgsIHR5cGUpIHtcbiAgICBpZiAoIXR5cGUpIHtcbiAgICAgICAgdHlwZSA9ICd2aWRlby8nICsgcGF0aC5zdWJzdHIocGF0aC5sYXN0SW5kZXhPZignLicpICsgMSk7XG4gICAgfVxuXG4gICAgdmFyIHNvdXJjZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NvdXJjZScpO1xuXG4gICAgc291cmNlLnNyYyA9IHBhdGg7XG4gICAgc291cmNlLnR5cGUgPSB0eXBlO1xuXG4gICAgcmV0dXJuIHNvdXJjZTtcbn1cbiIsIi8qKlxuICogQ3JlYXRlcyBhbiBob21vZ2Vub3VzIG9iamVjdCBmb3IgdHJhY2tpbmcgZXZlbnRzIHNvIHVzZXJzIGNhbiBrbm93IHdoYXQgdG8gZXhwZWN0LlxuICpcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gdGFyZ2V0IHtvYmplY3R9IFRoZSB0YXJnZXQgb2JqZWN0IHRoYXQgdGhlIGV2ZW50IGlzIGNhbGxlZCBvblxuICogQHBhcmFtIG5hbWUge3N0cmluZ30gVGhlIHN0cmluZyBuYW1lIG9mIHRoZSBldmVudCB0aGF0IHdhcyB0cmlnZ2VyZWRcbiAqIEBwYXJhbSBkYXRhIHtvYmplY3R9IEFyYml0cmFyeSBldmVudCBkYXRhIHRvIHBhc3MgYWxvbmdcbiAqL1xuZnVuY3Rpb24gRXZlbnREYXRhKHRhcmdldCwgbmFtZSwgZGF0YSkge1xuICAgIC8vIGZvciBkdWNrIHR5cGluZyBpbiB0aGUgXCIub24oKVwiIGZ1bmN0aW9uXG4gICAgdGhpcy5fX2lzRXZlbnRPYmplY3QgPSB0cnVlO1xuXG4gICAgLyoqXG4gICAgICogVHJhY2tzIHRoZSBzdGF0ZSBvZiBidWJibGluZyBwcm9wYWdhdGlvbi4gRG8gbm90XG4gICAgICogc2V0IHRoaXMgZGlyZWN0bHksIGluc3RlYWQgdXNlIGBldmVudC5zdG9wUHJvcGFnYXRpb24oKWBcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKi9cbiAgICB0aGlzLnN0b3BwZWQgPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqIFRyYWNrcyB0aGUgc3RhdGUgb2Ygc2libGluZyBsaXN0ZW5lciBwcm9wYWdhdGlvbi4gRG8gbm90XG4gICAgICogc2V0IHRoaXMgZGlyZWN0bHksIGluc3RlYWQgdXNlIGBldmVudC5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKWBcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKi9cbiAgICB0aGlzLnN0b3BwZWRJbW1lZGlhdGUgPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBvcmlnaW5hbCB0YXJnZXQgdGhlIGV2ZW50IHRyaWdnZXJlZCBvbi5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge29iamVjdH1cbiAgICAgKiBAcmVhZG9ubHlcbiAgICAgKi9cbiAgICB0aGlzLnRhcmdldCA9IHRhcmdldDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBzdHJpbmcgbmFtZSBvZiB0aGUgZXZlbnQgdGhhdCB0aGlzIHJlcHJlc2VudHMuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtzdHJpbmd9XG4gICAgICogQHJlYWRvbmx5XG4gICAgICovXG4gICAgdGhpcy50eXBlID0gbmFtZTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBkYXRhIHRoYXQgd2FzIHBhc3NlZCBpbiB3aXRoIHRoaXMgZXZlbnQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtvYmplY3R9XG4gICAgICogQHJlYWRvbmx5XG4gICAgICovXG4gICAgdGhpcy5kYXRhID0gZGF0YTtcblxuICAgIC8qKlxuICAgICAqIFRoZSB0aW1lc3RhbXAgd2hlbiB0aGUgZXZlbnQgb2NjdXJyZWQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQHJlYWRvbmx5XG4gICAgICovXG4gICAgdGhpcy50aW1lU3RhbXAgPSBEYXRlLm5vdygpO1xufVxuXG5FdmVudERhdGEucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gRXZlbnREYXRhO1xubW9kdWxlLmV4cG9ydHMgPSBFdmVudERhdGE7XG5cbi8qKlxuICogU3RvcHMgdGhlIHByb3BhZ2F0aW9uIG9mIGV2ZW50cyB1cCB0aGUgc2NlbmUgZ3JhcGggKHByZXZlbnRzIGJ1YmJsaW5nKS5cbiAqXG4gKi9cbkV2ZW50RGF0YS5wcm90b3R5cGUuc3RvcFByb3BhZ2F0aW9uID0gZnVuY3Rpb24gc3RvcFByb3BhZ2F0aW9uKCkge1xuICAgIHRoaXMuc3RvcHBlZCA9IHRydWU7XG59O1xuXG4vKipcbiAqIFN0b3BzIHRoZSBwcm9wYWdhdGlvbiBvZiBldmVudHMgdG8gc2libGluZyBsaXN0ZW5lcnMgKG5vIGxvbmdlciBjYWxscyBhbnkgbGlzdGVuZXJzKS5cbiAqXG4gKi9cbkV2ZW50RGF0YS5wcm90b3R5cGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uID0gZnVuY3Rpb24gc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCkge1xuICAgIHRoaXMuc3RvcHBlZEltbWVkaWF0ZSA9IHRydWU7XG59O1xuIiwiLy9UT0RPOiBIYXZlIEdyYXBoaWNzIHVzZSBodHRwczovL2dpdGh1Yi5jb20vbWF0dGRlc2wvc2hhcGUyZFxuLy8gYW5kIGh0dHBzOi8vZ2l0aHViLmNvbS9tYXR0ZGVzbC9zaGFwZTJkLXRyaWFuZ3VsYXRlIGluc3RlYWQgb2YgY3VzdG9tIGNvZGUuXG5cbi8qXG4gICAgUG9seUsgbGlicmFyeVxuICAgIHVybDogaHR0cDovL3BvbHlrLml2YW5rLm5ldFxuICAgIFJlbGVhc2VkIHVuZGVyIE1JVCBsaWNlbmNlLlxuXG4gICAgQ29weXJpZ2h0IChjKSAyMDEyIEl2YW4gS3Vja2lyXG5cbiAgICBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvblxuICAgIG9idGFpbmluZyBhIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uXG4gICAgZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0byBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0XG4gICAgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsXG4gICAgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcbiAgICBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGVcbiAgICBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZ1xuICAgIGNvbmRpdGlvbnM6XG5cbiAgICBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZVxuICAgIGluY2x1ZGVkIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuXG4gICAgVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCxcbiAgICBFWFBSRVNTIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVNcbiAgICBPRiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORFxuICAgIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUXG4gICAgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksXG4gICAgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HXG4gICAgRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUlxuICAgIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS5cblxuICAgIFRoaXMgaXMgYW4gYW1hemluZyBsaWIhXG5cbiAgICBTbGlnaHRseSBtb2RpZmllZCBieSBNYXQgR3JvdmVzIChtYXRncm92ZXMuY29tKTtcbiovXG5cbi8qKlxuICogQmFzZWQgb24gdGhlIFBvbHlrIGxpYnJhcnkgaHR0cDovL3BvbHlrLml2YW5rLm5ldCByZWxlYXNlZCB1bmRlciBNSVQgbGljZW5jZS5cbiAqIFRoaXMgaXMgYW4gYW1hemluZyBsaWIhXG4gKiBTbGlnaHRseSBtb2RpZmllZCBieSBNYXQgR3JvdmVzIChtYXRncm92ZXMuY29tKTtcbiAqXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xudmFyIFBvbHlLID0gbW9kdWxlLmV4cG9ydHMgPSB7fTtcblxuLyoqXG4gKiBUcmlhbmd1bGF0ZXMgc2hhcGVzIGZvciB3ZWJHTCBncmFwaGljIGZpbGxzLlxuICpcbiAqL1xuUG9seUsuVHJpYW5ndWxhdGUgPSBmdW5jdGlvbiAocCkge1xuICAgIHZhciBzaWduID0gdHJ1ZTtcblxuICAgIHZhciBuID0gcC5sZW5ndGggPj4gMTtcbiAgICBpZiAobiA8IDMpIHJldHVybiBbXTtcblxuICAgIHZhciB0Z3MgPSBbXTtcbiAgICB2YXIgYXZsID0gW107XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuOyBpKyspIGF2bC5wdXNoKGkpO1xuXG4gICAgaSA9IDA7XG4gICAgdmFyIGFsID0gbjtcbiAgICB3aGlsZShhbCA+IDMpIHtcbiAgICAgICAgdmFyIGkwID0gYXZsWyhpKzApJWFsXTtcbiAgICAgICAgdmFyIGkxID0gYXZsWyhpKzEpJWFsXTtcbiAgICAgICAgdmFyIGkyID0gYXZsWyhpKzIpJWFsXTtcblxuICAgICAgICB2YXIgYXggPSBwWzIqaTBdLCAgYXkgPSBwWzIqaTArMV07XG4gICAgICAgIHZhciBieCA9IHBbMippMV0sICBieSA9IHBbMippMSsxXTtcbiAgICAgICAgdmFyIGN4ID0gcFsyKmkyXSwgIGN5ID0gcFsyKmkyKzFdO1xuXG4gICAgICAgIHZhciBlYXJGb3VuZCA9IGZhbHNlO1xuICAgICAgICBpZiAoUG9seUsuX2NvbnZleChheCwgYXksIGJ4LCBieSwgY3gsIGN5LCBzaWduKSkge1xuICAgICAgICAgICAgZWFyRm91bmQgPSB0cnVlO1xuICAgICAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBhbDsgaisrKSB7XG4gICAgICAgICAgICAgICAgdmFyIHZpID0gYXZsW2pdO1xuICAgICAgICAgICAgICAgIGlmICh2aSA9PT0gaTAgfHwgdmkgPT09IGkxIHx8IHZpID09PSBpMikgY29udGludWU7XG5cbiAgICAgICAgICAgICAgICBpZiAoUG9seUsuX1BvaW50SW5UcmlhbmdsZShwWzIqdmldLCBwWzIqdmkrMV0sIGF4LCBheSwgYngsIGJ5LCBjeCwgY3kpKSB7XG4gICAgICAgICAgICAgICAgICAgIGVhckZvdW5kID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChlYXJGb3VuZCkge1xuICAgICAgICAgICAgdGdzLnB1c2goaTAsIGkxLCBpMik7XG4gICAgICAgICAgICBhdmwuc3BsaWNlKChpKzEpJWFsLCAxKTtcbiAgICAgICAgICAgIGFsLS07XG4gICAgICAgICAgICBpID0gMDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChpKysgPiAzKmFsKSB7XG4gICAgICAgICAgICAvLyBuZWVkIHRvIGZsaXAgZmxpcCByZXZlcnNlIGl0IVxuICAgICAgICAgICAgLy8gcmVzZXQhXG4gICAgICAgICAgICBpZiAoc2lnbikge1xuICAgICAgICAgICAgICAgIHRncyA9IFtdO1xuICAgICAgICAgICAgICAgIGF2bCA9IFtdO1xuICAgICAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBuOyBpKyspIGF2bC5wdXNoKGkpO1xuXG4gICAgICAgICAgICAgICAgaSA9IDA7XG4gICAgICAgICAgICAgICAgYWwgPSBuO1xuXG4gICAgICAgICAgICAgICAgc2lnbiA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgLy8gICB3aW5kb3cuY29uc29sZS5sb2coXCJQSVhJIFdhcm5pbmc6IHNoYXBlIHRvbyBjb21wbGV4IHRvIGZpbGxcIik7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB0Z3MucHVzaChhdmxbMF0sIGF2bFsxXSwgYXZsWzJdKTtcbiAgICByZXR1cm4gdGdzO1xufTtcblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciBhIHBvaW50IGlzIHdpdGhpbiBhIHRyaWFuZ2xlXG4gKlxuICogQHBhcmFtIHB4IHtudW1iZXJ9IHggY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHBhcmFtIHB5IHtudW1iZXJ9IHkgY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnQgdG8gdGVzdFxuICogQHBhcmFtIGF4IHtudW1iZXJ9IHggY29vcmRpbmF0ZSBvZiB0aGUgYSBwb2ludCBvZiB0aGUgdHJpYW5nbGVcbiAqIEBwYXJhbSBheSB7bnVtYmVyfSB5IGNvb3JkaW5hdGUgb2YgdGhlIGEgcG9pbnQgb2YgdGhlIHRyaWFuZ2xlXG4gKiBAcGFyYW0gYngge251bWJlcn0geCBjb29yZGluYXRlIG9mIHRoZSBiIHBvaW50IG9mIHRoZSB0cmlhbmdsZVxuICogQHBhcmFtIGJ5IHtudW1iZXJ9IHkgY29vcmRpbmF0ZSBvZiB0aGUgYiBwb2ludCBvZiB0aGUgdHJpYW5nbGVcbiAqIEBwYXJhbSBjeCB7bnVtYmVyfSB4IGNvb3JkaW5hdGUgb2YgdGhlIGMgcG9pbnQgb2YgdGhlIHRyaWFuZ2xlXG4gKiBAcGFyYW0gY3kge251bWJlcn0geSBjb29yZGluYXRlIG9mIHRoZSBjIHBvaW50IG9mIHRoZSB0cmlhbmdsZVxuICogQHByaXZhdGVcbiAqIEByZXR1cm4ge2Jvb2xlYW59XG4gKi9cblBvbHlLLl9Qb2ludEluVHJpYW5nbGUgPSBmdW5jdGlvbiAocHgsIHB5LCBheCwgYXksIGJ4LCBieSwgY3gsIGN5KSB7XG4gICAgdmFyIHYweCA9IGN4LWF4O1xuICAgIHZhciB2MHkgPSBjeS1heTtcbiAgICB2YXIgdjF4ID0gYngtYXg7XG4gICAgdmFyIHYxeSA9IGJ5LWF5O1xuICAgIHZhciB2MnggPSBweC1heDtcbiAgICB2YXIgdjJ5ID0gcHktYXk7XG5cbiAgICB2YXIgZG90MDAgPSB2MHgqdjB4K3YweSp2MHk7XG4gICAgdmFyIGRvdDAxID0gdjB4KnYxeCt2MHkqdjF5O1xuICAgIHZhciBkb3QwMiA9IHYweCp2MngrdjB5KnYyeTtcbiAgICB2YXIgZG90MTEgPSB2MXgqdjF4K3YxeSp2MXk7XG4gICAgdmFyIGRvdDEyID0gdjF4KnYyeCt2MXkqdjJ5O1xuXG4gICAgdmFyIGludkRlbm9tID0gMSAvIChkb3QwMCAqIGRvdDExIC0gZG90MDEgKiBkb3QwMSk7XG4gICAgdmFyIHUgPSAoZG90MTEgKiBkb3QwMiAtIGRvdDAxICogZG90MTIpICogaW52RGVub207XG4gICAgdmFyIHYgPSAoZG90MDAgKiBkb3QxMiAtIGRvdDAxICogZG90MDIpICogaW52RGVub207XG5cbiAgICAvLyBDaGVjayBpZiBwb2ludCBpcyBpbiB0cmlhbmdsZVxuICAgIHJldHVybiAodSA+PSAwKSAmJiAodiA+PSAwKSAmJiAodSArIHYgPCAxKTtcbn07XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgYSBzaGFwZSBpcyBjb252ZXhcbiAqXG4gKiBAcHJpdmF0ZVxuICogQHJldHVybiB7Ym9vbGVhbn1cbiAqL1xuUG9seUsuX2NvbnZleCA9IGZ1bmN0aW9uIChheCwgYXksIGJ4LCBieSwgY3gsIGN5LCBzaWduKSB7XG4gICAgcmV0dXJuICgoYXktYnkpKihjeC1ieCkgKyAoYngtYXgpKihjeS1ieSkgPj0gMCkgPT09IHNpZ247XG59O1xuIiwidmFyIEV2ZW50RGF0YSA9IHJlcXVpcmUoJy4vRXZlbnREYXRhJyk7XG5cbi8qKlxuICogTWl4aW5zIGV2ZW50IGVtaXR0ZXIgZnVuY3Rpb25hbGl0eSB0byBhbiBvYmplY3QuXG4gKlxuICogQG1peGluXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBleGFtcGxlXG4gKiAgICAgIGZ1bmN0aW9uIE15RW1pdHRlcigpIHt9XG4gKlxuICogICAgICBldmVudFRhcmdldC5taXhpbihNeUVtaXR0ZXIucHJvdG90eXBlKTtcbiAqXG4gKiAgICAgIHZhciBlbSA9IG5ldyBNeUVtaXR0ZXIoKTtcbiAqICAgICAgZW0uZW1pdCgnZXZlbnROYW1lJywgJ3NvbWUgZGF0YScsICdzb21lIG1vcmUgZGF0YScsIHt9LCBudWxsLCAuLi4pO1xuICovXG5mdW5jdGlvbiBldmVudFRhcmdldChvYmopIHtcbiAgICAvKipcbiAgICAgKiBSZXR1cm4gYSBsaXN0IG9mIGFzc2lnbmVkIGV2ZW50IGxpc3RlbmVycy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBldmVudE5hbWUge3N0cmluZ30gVGhlIGV2ZW50cyB0aGF0IHNob3VsZCBiZSBsaXN0ZWQuXG4gICAgICogQHJldHVybiB7QXJyYXl9IEFuIGFycmF5IG9mIGxpc3RlbmVyIGZ1bmN0aW9uc1xuICAgICAqL1xuICAgIG9iai5saXN0ZW5lcnMgPSBmdW5jdGlvbiBsaXN0ZW5lcnMoZXZlbnROYW1lKSB7XG4gICAgICAgIHRoaXMuX2xpc3RlbmVycyA9IHRoaXMuX2xpc3RlbmVycyB8fCB7fTtcblxuICAgICAgICByZXR1cm4gdGhpcy5fbGlzdGVuZXJzW2V2ZW50TmFtZV0gPyB0aGlzLl9saXN0ZW5lcnNbZXZlbnROYW1lXS5zbGljZSgpIDogW107XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEVtaXQgYW4gZXZlbnQgdG8gYWxsIHJlZ2lzdGVyZWQgZXZlbnQgbGlzdGVuZXJzLlxuICAgICAqXG4gICAgICogQGFsaWFzIGRpc3BhdGNoRXZlbnRcbiAgICAgKiBAcGFyYW0gZXZlbnROYW1lIHtzdHJpbmd9IFRoZSBuYW1lIG9mIHRoZSBldmVudC5cbiAgICAgKiBAcmV0dXJuIHtib29sZWFufSBJbmRpY2F0aW9uIGlmIHdlJ3ZlIGVtaXR0ZWQgYW4gZXZlbnQuXG4gICAgICovXG4gICAgb2JqLmVtaXQgPSBvYmouZGlzcGF0Y2hFdmVudCA9IGZ1bmN0aW9uIGVtaXQoZXZlbnROYW1lLCBkYXRhKSB7XG4gICAgICAgIHRoaXMuX2xpc3RlbmVycyA9IHRoaXMuX2xpc3RlbmVycyB8fCB7fTtcblxuICAgICAgICAvLyBmYXN0IHJldHVybiB3aGVuIHRoZXJlIGFyZSBubyBsaXN0ZW5lcnNcbiAgICAgICAgaWYgKCF0aGlzLl9saXN0ZW5lcnNbZXZlbnROYW1lXSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy9iYWNrd2FyZHMgY29tcGF0IHdpdGggb2xkIG1ldGhvZCBcIi5lbWl0KHsgdHlwZTogJ3NvbWV0aGluZycgfSlcIlxuICAgICAgICBpZiAodHlwZW9mIGV2ZW50TmFtZSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIGRhdGEgPSBldmVudE5hbWU7XG4gICAgICAgICAgICBldmVudE5hbWUgPSBldmVudE5hbWUudHlwZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vZW5zdXJlIHdlIGFyZSB1c2luZyBhIHJlYWwgcGl4aSBldmVudFxuICAgICAgICBpZiAoIWRhdGEgfHwgZGF0YS5fX2lzRXZlbnRPYmplY3QgIT09IHRydWUpIHtcbiAgICAgICAgICAgIGRhdGEgPSBuZXcgRXZlbnREYXRhKHRoaXMsIGV2ZW50TmFtZSwgZGF0YSk7XG4gICAgICAgIH1cblxuICAgICAgICAvL2l0ZXJhdGUgdGhlIGxpc3RlbmVyc1xuICAgICAgICB2YXIgbGlzdGVuZXJzID0gdGhpcy5fbGlzdGVuZXJzW2V2ZW50TmFtZV0uc2xpY2UoMCksXG4gICAgICAgICAgICBsZW5ndGggPSBsaXN0ZW5lcnMubGVuZ3RoLFxuICAgICAgICAgICAgZm4gPSBsaXN0ZW5lcnNbMF0sXG4gICAgICAgICAgICBpO1xuXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBsZW5ndGg7IGZuID0gbGlzdGVuZXJzWysraV0pIHtcbiAgICAgICAgICAgIC8vY2FsbCB0aGUgZXZlbnQgbGlzdGVuZXJcbiAgICAgICAgICAgIGZuLmNhbGwodGhpcywgZGF0YSk7XG5cbiAgICAgICAgICAgIC8vaWYgXCJzdG9wSW1tZWRpYXRlUHJvcGFnYXRpb25cIiBpcyBjYWxsZWQsIHN0b3AgY2FsbGluZyBzaWJsaW5nIGV2ZW50c1xuICAgICAgICAgICAgaWYgKGRhdGEuc3RvcHBlZEltbWVkaWF0ZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy9pZiBcInN0b3BQcm9wYWdhdGlvblwiIGlzIGNhbGxlZCB0aGVuIGRvbid0IGJ1YmJsZSB0aGUgZXZlbnRcbiAgICAgICAgaWYgKGRhdGEuc3RvcHBlZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICAvL2J1YmJsZSB0aGlzIGV2ZW50IHVwIHRoZSBzY2VuZSBncmFwaFxuICAgICAgICBpZiAodGhpcy5wYXJlbnQgJiYgdGhpcy5wYXJlbnQuZW1pdCkge1xuICAgICAgICAgICAgdGhpcy5wYXJlbnQuZW1pdC5jYWxsKHRoaXMucGFyZW50LCBldmVudE5hbWUsIGRhdGEpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlZ2lzdGVyIGEgbmV3IEV2ZW50TGlzdGVuZXIgZm9yIHRoZSBnaXZlbiBldmVudC5cbiAgICAgKlxuICAgICAqIEBhbGlhcyBhZGRFdmVudExpc3RlbmVyXG4gICAgICogQHBhcmFtIGV2ZW50TmFtZSB7c3RyaW5nfSBOYW1lIG9mIHRoZSBldmVudC5cbiAgICAgKiBAcGFyYW0gY2FsbGJhY2sge0Z1bmN0b259IGZuIENhbGxiYWNrIGZ1bmN0aW9uLlxuICAgICAqL1xuICAgIG9iai5vbiA9IG9iai5hZGRFdmVudExpc3RlbmVyID0gZnVuY3Rpb24gb24oZXZlbnROYW1lLCBmbikge1xuICAgICAgICB0aGlzLl9saXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnMgfHwge307XG5cbiAgICAgICAgKHRoaXMuX2xpc3RlbmVyc1tldmVudE5hbWVdID0gdGhpcy5fbGlzdGVuZXJzW2V2ZW50TmFtZV0gfHwgW10pXG4gICAgICAgICAgICAucHVzaChmbik7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEFkZCBhbiBFdmVudExpc3RlbmVyIHRoYXQncyBvbmx5IGNhbGxlZCBvbmNlLlxuICAgICAqXG4gICAgICogQHBhcmFtIGV2ZW50TmFtZSB7c3RyaW5nfSBOYW1lIG9mIHRoZSBldmVudC5cbiAgICAgKiBAcGFyYW0gY2FsbGJhY2sge0Z1bmN0aW9ufSBDYWxsYmFjayBmdW5jdGlvbi5cbiAgICAgKi9cbiAgICBvYmoub25jZSA9IGZ1bmN0aW9uIG9uY2UoZXZlbnROYW1lLCBmbikge1xuICAgICAgICB0aGlzLl9saXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnMgfHwge307XG5cbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICBmdW5jdGlvbiBvbmNlSGFuZGxlcldyYXBwZXIoKSB7XG4gICAgICAgICAgICBmbi5hcHBseShzZWxmLm9mZihldmVudE5hbWUsIG9uY2VIYW5kbGVyV3JhcHBlciksIGFyZ3VtZW50cyk7XG4gICAgICAgIH1cbiAgICAgICAgb25jZUhhbmRsZXJXcmFwcGVyLl9vcmlnaW5hbEhhbmRsZXIgPSBmbjtcblxuICAgICAgICByZXR1cm4gdGhpcy5vbihldmVudE5hbWUsIG9uY2VIYW5kbGVyV3JhcHBlcik7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlbW92ZSBldmVudCBsaXN0ZW5lcnMuXG4gICAgICpcbiAgICAgKiBAYWxpYXMgcmVtb3ZlRXZlbnRMaXN0ZW5lclxuICAgICAqIEBwYXJhbSBldmVudE5hbWUge3N0cmluZ30gVGhlIGV2ZW50IHdlIHdhbnQgdG8gcmVtb3ZlLlxuICAgICAqIEBwYXJhbSBjYWxsYmFjayB7RnVuY3Rpb259IFRoZSBsaXN0ZW5lciB0aGF0IHdlIG5lZWQgdG8gZmluZC5cbiAgICAgKi9cbiAgICBvYmoub2ZmID0gb2JqLnJlbW92ZUV2ZW50TGlzdGVuZXIgPSBmdW5jdGlvbiBvZmYoZXZlbnROYW1lLCBmbikge1xuICAgICAgICB0aGlzLl9saXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnMgfHwge307XG5cbiAgICAgICAgaWYgKCF0aGlzLl9saXN0ZW5lcnNbZXZlbnROYW1lXSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgbGlzdCA9IHRoaXMuX2xpc3RlbmVyc1tldmVudE5hbWVdLFxuICAgICAgICAgICAgaSA9IGZuID8gbGlzdC5sZW5ndGggOiAwO1xuXG4gICAgICAgIHdoaWxlKGktLSA+IDApIHtcbiAgICAgICAgICAgIGlmIChsaXN0W2ldID09PSBmbiB8fCBsaXN0W2ldLl9vcmlnaW5hbEhhbmRsZXIgPT09IGZuKSB7XG4gICAgICAgICAgICAgICAgbGlzdC5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobGlzdC5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLl9saXN0ZW5lcnNbZXZlbnROYW1lXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmUgYWxsIGxpc3RlbmVycyBvciBvbmx5IHRoZSBsaXN0ZW5lcnMgZm9yIHRoZSBzcGVjaWZpZWQgZXZlbnQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gZXZlbnROYW1lIHtzdHJpbmd9IFRoZSBldmVudCB5b3Ugd2FudCB0byByZW1vdmUgYWxsIGxpc3RlbmVycyBmb3IuXG4gICAgICovXG4gICAgb2JqLnJlbW92ZUFsbExpc3RlbmVycyA9IGZ1bmN0aW9uIHJlbW92ZUFsbExpc3RlbmVycyhldmVudE5hbWUpIHtcbiAgICAgICAgdGhpcy5fbGlzdGVuZXJzID0gdGhpcy5fbGlzdGVuZXJzIHx8IHt9O1xuXG4gICAgICAgIGlmICghdGhpcy5fbGlzdGVuZXJzW2V2ZW50TmFtZV0pIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9XG5cbiAgICAgICAgZGVsZXRlIHRoaXMuX2xpc3RlbmVyc1tldmVudE5hbWVdO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH07XG59XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIC8qKlxuICAgICAqIE1peGVzIGluIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBldmVudFRhcmdldCBwcm90b3R5cGUgb250byBhbm90aGVyIG9iamVjdFxuICAgICAqXG4gICAgICogQHBhcmFtIG9iamVjdCB7b2JqZWN0fSBUaGUgb2JqIHRvIG1peCBpbnRvXG4gICAgICovXG4gICAgbWl4aW46IGZ1bmN0aW9uIG1peGluKG9iaikge1xuICAgICAgICBldmVudFRhcmdldChvYmopO1xuICAgIH1cbn07XG4iLCJ2YXIgQ09OU1QgPSByZXF1aXJlKCcuLi9jb25zdCcpO1xuXG4vKipcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG52YXIgdXRpbHMgPSBtb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBfdWlkOiAwLFxuICAgIF9zYWlkSGVsbG86IGZhbHNlLFxuXG4gICAgUG9seUs6ICAgICAgcmVxdWlyZSgnLi9Qb2x5SycpLFxuICAgIEV2ZW50RGF0YTogIHJlcXVpcmUoJy4vRXZlbnREYXRhJyksXG4gICAgZXZlbnRUYXJnZXQ6IHJlcXVpcmUoJy4vZXZlbnRUYXJnZXQnKSxcblxuICAgIC8qKlxuICAgICAqIEdldHMgdGhlIG5leHQgdXVpZFxuICAgICAqXG4gICAgICogQHJldHVybiB7bnVtYmVyfSBUaGUgbmV4dCB1dWlkIHRvIHVzZS5cbiAgICAgKi9cbiAgICB1dWlkOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiArK3V0aWxzLl91aWQ7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENvbnZlcnRzIGEgaGV4IGNvbG9yIG51bWJlciB0byBhbiBbUiwgRywgQl0gYXJyYXlcbiAgICAgKlxuICAgICAqIEBwYXJhbSBoZXgge251bWJlcn1cbiAgICAgKiBAcmV0dXJuIHtudW1iZXJbXX0gQW4gYXJyYXkgcmVwcmVzZW50aW5nIHRoZSBbUiwgRywgQl0gb2YgdGhlIGNvbG9yLlxuICAgICAqL1xuICAgIGhleDJyZ2I6IGZ1bmN0aW9uIChoZXgsIG91dCkge1xuICAgICAgICBvdXQgPSBvdXQgfHwgW107XG5cbiAgICAgICAgb3V0WzBdID0gKGhleCA+PiAxNiAmIDB4RkYpIC8gMjU1O1xuICAgICAgICBvdXRbMV0gPSAoaGV4ID4+IDggJiAweEZGKSAvIDI1NTtcbiAgICAgICAgb3V0WzJdID0gKGhleCAmIDB4RkYpIC8gMjU1O1xuXG4gICAgICAgIHJldHVybiBvdXQ7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENvbnZlcnRzIGEgaGV4IGNvbG9yIG51bWJlciB0byBhIHN0cmluZy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBoZXgge251bWJlcn1cbiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBzdHJpbmcgY29sb3IuXG4gICAgICovXG4gICAgaGV4MnN0cmluZzogZnVuY3Rpb24gKGhleCkge1xuICAgICAgICBoZXggPSBoZXgudG9TdHJpbmcoMTYpO1xuICAgICAgICBoZXggPSAnMDAwMDAwJy5zdWJzdHIoMCwgNiAtIGhleC5sZW5ndGgpICsgaGV4O1xuXG4gICAgICAgIHJldHVybiAnIycgKyBoZXg7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENvbnZlcnRzIGEgY29sb3IgYXMgYW4gW1IsIEcsIEJdIGFycmF5IHRvIGEgaGV4IG51bWJlclxuICAgICAqXG4gICAgICogQHBhcmFtIHJnYiB7bnVtYmVyW119XG4gICAgICogQHJldHVybiB7bnVtYmVyfSBUaGUgY29sb3IgbnVtYmVyXG4gICAgICovXG4gICAgcmdiMmhleDogZnVuY3Rpb24gKHJnYikge1xuICAgICAgICByZXR1cm4gKChyZ2JbMF0qMjU1IDw8IDE2KSArIChyZ2JbMV0qMjU1IDw8IDgpICsgcmdiWzJdKjI1NSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIENoZWNrcyB3aGV0aGVyIHRoZSBDYW52YXMgQmxlbmRNb2RlcyBhcmUgc3VwcG9ydGVkIGJ5IHRoZSBjdXJyZW50IGJyb3dzZXJcbiAgICAgKlxuICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IHdoZXRoZXIgdGhleSBhcmUgc3VwcG9ydGVkXG4gICAgICovXG4gICAgY2FuVXNlTmV3Q2FudmFzQmxlbmRNb2RlczogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodHlwZW9mIGRvY3VtZW50ID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpLFxuICAgICAgICAgICAgY29udGV4dCA9IGNhbnZhcy5nZXRDb250ZXh0KCcyZCcpO1xuXG4gICAgICAgIGNhbnZhcy53aWR0aCA9IDE7XG4gICAgICAgIGNhbnZhcy5oZWlnaHQgPSAxO1xuXG4gICAgICAgIGNvbnRleHQuZmlsbFN0eWxlID0gJyMwMDAnO1xuICAgICAgICBjb250ZXh0LmZpbGxSZWN0KDAsIDAsIDEsIDEpO1xuXG4gICAgICAgIGNvbnRleHQuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uID0gJ211bHRpcGx5JztcblxuICAgICAgICBjb250ZXh0LmZpbGxTdHlsZSA9ICcjZmZmJztcbiAgICAgICAgY29udGV4dC5maWxsUmVjdCgwLCAwLCAxLCAxKTtcblxuICAgICAgICByZXR1cm4gY29udGV4dC5nZXRJbWFnZURhdGEoMCwwLDEsMSkuZGF0YVswXSA9PT0gMDtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogR2l2ZW4gYSBudW1iZXIsIHRoaXMgZnVuY3Rpb24gcmV0dXJucyB0aGUgY2xvc2VzdCBudW1iZXIgdGhhdCBpcyBhIHBvd2VyIG9mIHR3b1xuICAgICAqIHRoaXMgZnVuY3Rpb24gaXMgdGFrZW4gZnJvbSBTdGFybGluZyBGcmFtZXdvcmsgYXMgaXRzIHByZXR0eSBuZWF0IDspXG4gICAgICpcbiAgICAgKiBAcGFyYW0gbnVtYmVyIHtudW1iZXJ9XG4gICAgICogQHJldHVybiB7bnVtYmVyfSB0aGUgY2xvc2VzdCBudW1iZXIgdGhhdCBpcyBhIHBvd2VyIG9mIHR3b1xuICAgICAqL1xuICAgIGdldE5leHRQb3dlck9mVHdvOiBmdW5jdGlvbiAobnVtYmVyKSB7XG4gICAgICAgIC8vIHNlZTogaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Qb3dlcl9vZl90d28jRmFzdF9hbGdvcml0aG1fdG9fY2hlY2tfaWZfYV9wb3NpdGl2ZV9udW1iZXJfaXNfYV9wb3dlcl9vZl90d29cbiAgICAgICAgaWYgKG51bWJlciA+IDAgJiYgKG51bWJlciAmIChudW1iZXIgLSAxKSkgPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybiBudW1iZXI7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gMTtcblxuICAgICAgICAgICAgd2hpbGUgKHJlc3VsdCA8IG51bWJlcikge1xuICAgICAgICAgICAgICAgIHJlc3VsdCA8PD0gMTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBjaGVja3MgaWYgdGhlIGdpdmVuIHdpZHRoIGFuZCBoZWlnaHQgbWFrZSBhIHBvd2VyIG9mIHR3byByZWN0YW5nbGVcbiAgICAgKlxuICAgICAqIEBwYXJhbSB3aWR0aCB7bnVtYmVyfVxuICAgICAqIEBwYXJhbSBoZWlnaHQge251bWJlcn1cbiAgICAgKiBAcmV0dXJuIHtib29sZWFufVxuICAgICAqL1xuICAgIGlzUG93ZXJPZlR3bzogZnVuY3Rpb24gKHdpZHRoLCBoZWlnaHQpIHtcbiAgICAgICAgcmV0dXJuICh3aWR0aCA+IDAgJiYgKHdpZHRoICYgKHdpZHRoIC0gMSkpID09PSAwICYmIGhlaWdodCA+IDAgJiYgKGhlaWdodCAmIChoZWlnaHQgLSAxKSkgPT09IDApO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBMb2dzIG91dCB0aGUgdmVyc2lvbiBhbmQgcmVuZGVyZXIgaW5mb3JtYXRpb24gZm9yIHRoaXMgcnVubmluZyBpbnN0YW5jZSBvZiBQSVhJLlxuICAgICAqIElmIHlvdSBkb24ndCB3YW50IHRvIHNlZSB0aGlzIG1lc3NhZ2UgeW91IGNhbiBzZXQgYFBJWEkudXRpbHMuX3NhaWRIZWxsbyA9IHRydWU7YFxuICAgICAqIHNvIHRoZSBsaWJyYXJ5IHRoaW5rcyBpdCBhbHJlYWR5IHNhaWQgaXQuIEtlZXAgaW4gbWluZCB0aGF0IGRvaW5nIHRoYXQgd2lsbCBmb3JldmVyXG4gICAgICogbWFrZXMgeW91IGEgamVyayBmYWNlLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgc3RyaW5nIHJlbmRlcmVyIHR5cGUgdG8gbG9nLlxuICAgICAqIEBjb25zdGFudFxuICAgICAqIEBzdGF0aWNcbiAgICAgKi9cbiAgICBzYXlIZWxsbzogZnVuY3Rpb24gKHR5cGUpIHtcbiAgICAgICAgaWYgKHV0aWxzLl9zYWlkSGVsbG8pIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChuYXZpZ2F0b3IudXNlckFnZW50LnRvTG93ZXJDYXNlKCkuaW5kZXhPZignY2hyb21lJykgPiAtMSkge1xuICAgICAgICAgICAgdmFyIGFyZ3MgPSBbXG4gICAgICAgICAgICAgICAgJyVjICVjICVjIFBpeGkuanMgJyArIENPTlNULlZFUlNJT04gKyAnIC0gJyArIHR5cGUgKyAnICAlYyAnICsgJyAlYyAnICsgJyBodHRwOi8vd3d3LnBpeGlqcy5jb20vICAlYyAlYyDimaUlY+KZpSVj4pmlICcsXG4gICAgICAgICAgICAgICAgJ2JhY2tncm91bmQ6ICNmZjY2YTUnLFxuICAgICAgICAgICAgICAgICdiYWNrZ3JvdW5kOiAjZmY2NmE1JyxcbiAgICAgICAgICAgICAgICAnY29sb3I6ICNmZjY2YTU7IGJhY2tncm91bmQ6ICMwMzAzMDc7JyxcbiAgICAgICAgICAgICAgICAnYmFja2dyb3VuZDogI2ZmNjZhNScsXG4gICAgICAgICAgICAgICAgJ2JhY2tncm91bmQ6ICNmZmMzZGMnLFxuICAgICAgICAgICAgICAgICdiYWNrZ3JvdW5kOiAjZmY2NmE1JyxcbiAgICAgICAgICAgICAgICAnY29sb3I6ICNmZjI0MjQ7IGJhY2tncm91bmQ6ICNmZmYnLFxuICAgICAgICAgICAgICAgICdjb2xvcjogI2ZmMjQyNDsgYmFja2dyb3VuZDogI2ZmZicsXG4gICAgICAgICAgICAgICAgJ2NvbG9yOiAjZmYyNDI0OyBiYWNrZ3JvdW5kOiAjZmZmJ1xuICAgICAgICAgICAgXTtcblxuICAgICAgICAgICAgY29uc29sZS5sb2cuYXBwbHkoY29uc29sZSwgYXJncyk7IC8vanNoaW50IGlnbm9yZTpsaW5lXG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAod2luZG93LmNvbnNvbGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdQaXhpLmpzICcgKyBDT05TVC5WRVJTSU9OICsgJyAtICcgKyB0eXBlICsgJyAtIGh0dHA6Ly93d3cucGl4aWpzLmNvbS8nKTsgLy9qc2hpbnQgaWdub3JlOmxpbmVcbiAgICAgICAgfVxuXG4gICAgICAgIHV0aWxzLl9zYWlkSGVsbG8gPSB0cnVlO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBBIHdyYXBwZXIgZm9yIGFqYXggcmVxdWVzdHMgdG8gYmUgaGFuZGxlZCBjcm9zcyBicm93c2VyXG4gICAgICpcbiAgICAgKiBUT0RPOiBSZXBsYWNlIHRoaXMgd2lsIHN1cGVyYWdlbnRcbiAgICAgKlxuICAgICAqIEBjbGFzc1xuICAgICAqIEBuYW1lc3BhY2UgUElYSVxuICAgICAqL1xuICAgIEFqYXhSZXF1ZXN0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBhY3RpdmV4bW9kZXMgPSBbJ01zeG1sMi5YTUxIVFRQLjYuMCcsICdNc3htbDIuWE1MSFRUUC4zLjAnLCAnTWljcm9zb2Z0LlhNTEhUVFAnXTsgLy9hY3RpdmVYIHZlcnNpb25zIHRvIGNoZWNrIGZvciBpbiBJRVxuXG4gICAgICAgIGlmICh3aW5kb3cuQWN0aXZlWE9iamVjdCkgeyAvL1Rlc3QgZm9yIHN1cHBvcnQgZm9yIEFjdGl2ZVhPYmplY3QgaW4gSUUgZmlyc3QgKGFzIFhNTEh0dHBSZXF1ZXN0IGluIElFNyBpcyBicm9rZW4pXG4gICAgICAgICAgICBmb3IgKHZhciBpPTA7IGk8YWN0aXZleG1vZGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgdHJ5e1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbmV3IHdpbmRvdy5BY3RpdmVYT2JqZWN0KGFjdGl2ZXhtb2Rlc1tpXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhdGNoKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgLy9zdXBwcmVzcyBlcnJvclxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh3aW5kb3cuWE1MSHR0cFJlcXVlc3QpIC8vIGlmIE1vemlsbGEsIFNhZmFyaSBldGNcbiAgICAgICAge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyB3aW5kb3cuWE1MSHR0cFJlcXVlc3QoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvLyBUT0RPOiByZWZhY3RvciBvdXQgdGhpc1xuICAgIEFuaW1DYWNoZToge30sXG4gICAgRnJhbWVDYWNoZToge30sXG4gICAgVGV4dHVyZUNhY2hlOiB7fSxcbiAgICBCYXNlVGV4dHVyZUNhY2hlOiB7fVxufTtcbiIsInZhciBjb3JlID0gcmVxdWlyZSgnLi4vY29yZScpO1xuXG4vKipcbiAqIEEgTW92aWVDbGlwIGlzIGEgc2ltcGxlIHdheSB0byBkaXNwbGF5IGFuIGFuaW1hdGlvbiBkZXBpY3RlZCBieSBhIGxpc3Qgb2YgdGV4dHVyZXMuXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBTcHJpdGVcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHRleHR1cmVzIHtUZXh0dXJlW119IGFuIGFycmF5IG9mIHtUZXh0dXJlfSBvYmplY3RzIHRoYXQgbWFrZSB1cCB0aGUgYW5pbWF0aW9uXG4gKi9cbmZ1bmN0aW9uIE1vdmllQ2xpcCh0ZXh0dXJlcykge1xuICAgIGNvcmUuU3ByaXRlLmNhbGwodGhpcywgdGV4dHVyZXNbMF0pO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGFycmF5IG9mIHRleHR1cmVzIHRoYXQgbWFrZSB1cCB0aGUgYW5pbWF0aW9uXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIFRleHR1cmVbXVxuICAgICAqL1xuICAgIHRoaXMudGV4dHVyZXMgPSB0ZXh0dXJlcztcblxuICAgIC8qKlxuICAgICAqIFRoZSBzcGVlZCB0aGF0IHRoZSBNb3ZpZUNsaXAgd2lsbCBwbGF5IGF0LiBIaWdoZXIgaXMgZmFzdGVyLCBsb3dlciBpcyBzbG93ZXJcbiAgICAgKlxuICAgICAqIEBtZW1iZXIgbnVtYmVyXG4gICAgICogQGRlZmF1bHQgMVxuICAgICAqL1xuICAgIHRoaXMuYW5pbWF0aW9uU3BlZWQgPSAxO1xuXG4gICAgLyoqXG4gICAgICogV2hldGhlciBvciBub3QgdGhlIG1vdmllIGNsaXAgcmVwZWF0cyBhZnRlciBwbGF5aW5nLlxuICAgICAqXG4gICAgICogQG1lbWJlciBib29sZWFuXG4gICAgICogQGRlZmF1bHQgdHJ1ZVxuICAgICAqL1xuICAgIHRoaXMubG9vcCA9IHRydWU7XG5cbiAgICAvKipcbiAgICAgKiBGdW5jdGlvbiB0byBjYWxsIHdoZW4gYSBNb3ZpZUNsaXAgZmluaXNoZXMgcGxheWluZ1xuICAgICAqXG4gICAgICogQG1ldGhvZFxuICAgICAqIEBtZW1iZXJvZiBNb3ZpZUNsaXAjXG4gICAgICovXG4gICAgdGhpcy5vbkNvbXBsZXRlID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBNb3ZpZUNsaXBzIGN1cnJlbnQgZnJhbWUgaW5kZXggKHRoaXMgbWF5IG5vdCBoYXZlIHRvIGJlIGEgd2hvbGUgbnVtYmVyKVxuICAgICAqXG4gICAgICogQG1lbWJlciBudW1iZXJcbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICogQHJlYWRvbmx5XG4gICAgICovXG4gICAgdGhpcy5jdXJyZW50RnJhbWUgPSAwO1xuXG4gICAgLyoqXG4gICAgICogSW5kaWNhdGVzIGlmIHRoZSBNb3ZpZUNsaXAgaXMgY3VycmVudGx5IHBsYXlpbmdcbiAgICAgKlxuICAgICAqIEBtZW1iZXIgYm9vbGVhblxuICAgICAqIEByZWFkb25seVxuICAgICAqL1xuICAgIHRoaXMucGxheWluZyA9IGZhbHNlO1xufVxuXG4vLyBjb25zdHJ1Y3RvclxuTW92aWVDbGlwLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoY29yZS5TcHJpdGUucHJvdG90eXBlKTtcbk1vdmllQ2xpcC5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBNb3ZpZUNsaXA7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKE1vdmllQ2xpcC5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiB0b3RhbEZyYW1lcyBpcyB0aGUgdG90YWwgbnVtYmVyIG9mIGZyYW1lcyBpbiB0aGUgTW92aWVDbGlwLiBUaGlzIGlzIHRoZSBzYW1lIGFzIG51bWJlciBvZiB0ZXh0dXJlc1xuICAgICAqIGFzc2lnbmVkIHRvIHRoZSBNb3ZpZUNsaXAuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyXG4gICAgICogQG1lbWJlcm9mIE1vdmllQ2xpcCNcbiAgICAgKiBAZGVmYXVsdCAwXG4gICAgICogQHJlYWRvbmx5XG4gICAgICovXG4gICAgdG90YWxGcmFtZXM6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnRleHR1cmVzLmxlbmd0aDtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG4vKipcbiAqIFN0b3BzIHRoZSBNb3ZpZUNsaXBcbiAqXG4gKi9cbk1vdmllQ2xpcC5wcm90b3R5cGUuc3RvcCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnBsYXlpbmcgPSBmYWxzZTtcbn07XG5cbi8qKlxuICogUGxheXMgdGhlIE1vdmllQ2xpcFxuICpcbiAqL1xuTW92aWVDbGlwLnByb3RvdHlwZS5wbGF5ID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMucGxheWluZyA9IHRydWU7XG59O1xuXG4vKipcbiAqIFN0b3BzIHRoZSBNb3ZpZUNsaXAgYW5kIGdvZXMgdG8gYSBzcGVjaWZpYyBmcmFtZVxuICpcbiAqIEBwYXJhbSBmcmFtZU51bWJlciB7bnVtYmVyfSBmcmFtZSBpbmRleCB0byBzdG9wIGF0XG4gKi9cbk1vdmllQ2xpcC5wcm90b3R5cGUuZ290b0FuZFN0b3AgPSBmdW5jdGlvbiAoZnJhbWVOdW1iZXIpIHtcbiAgICB0aGlzLnBsYXlpbmcgPSBmYWxzZTtcbiAgICB0aGlzLmN1cnJlbnRGcmFtZSA9IGZyYW1lTnVtYmVyO1xuXG4gICAgdmFyIHJvdW5kID0gTWF0aC5yb3VuZCh0aGlzLmN1cnJlbnRGcmFtZSk7XG4gICAgdGhpcy5zZXRUZXh0dXJlKHRoaXMudGV4dHVyZXNbcm91bmQgJSB0aGlzLnRleHR1cmVzLmxlbmd0aF0pO1xufTtcblxuLyoqXG4gKiBHb2VzIHRvIGEgc3BlY2lmaWMgZnJhbWUgYW5kIGJlZ2lucyBwbGF5aW5nIHRoZSBNb3ZpZUNsaXBcbiAqXG4gKiBAcGFyYW0gZnJhbWVOdW1iZXIge251bWJlcn0gZnJhbWUgaW5kZXggdG8gc3RhcnQgYXRcbiAqL1xuTW92aWVDbGlwLnByb3RvdHlwZS5nb3RvQW5kUGxheSA9IGZ1bmN0aW9uIChmcmFtZU51bWJlcikge1xuICAgIHRoaXMuY3VycmVudEZyYW1lID0gZnJhbWVOdW1iZXI7XG4gICAgdGhpcy5wbGF5aW5nID0gdHJ1ZTtcbn07XG5cbi8qXG4gKiBVcGRhdGVzIHRoZSBvYmplY3QgdHJhbnNmb3JtIGZvciByZW5kZXJpbmdcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5Nb3ZpZUNsaXAucHJvdG90eXBlLnVwZGF0ZVRyYW5zZm9ybSA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmRpc3BsYXlPYmplY3RDb250YWluZXJVcGRhdGVUcmFuc2Zvcm0oKTtcblxuICAgIGlmICghdGhpcy5wbGF5aW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmN1cnJlbnRGcmFtZSArPSB0aGlzLmFuaW1hdGlvblNwZWVkO1xuXG4gICAgdmFyIHJvdW5kID0gTWF0aC5yb3VuZCh0aGlzLmN1cnJlbnRGcmFtZSk7XG5cbiAgICBpZiAocm91bmQgPCAwKSB7XG4gICAgICAgIGlmICh0aGlzLmxvb3ApIHtcbiAgICAgICAgICAgIHRoaXMuY3VycmVudEZyYW1lICs9IHRoaXMudGV4dHVyZXMubGVuZ3RoO1xuICAgICAgICAgICAgdGhpcy50ZXh0dXJlID0gdGhpcy50ZXh0dXJlc1t0aGlzLmN1cnJlbnRGcmFtZV07XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmdvdG9BbmRTdG9wKDApO1xuXG4gICAgICAgICAgICBpZiAodGhpcy5vbkNvbXBsZXRlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5vbkNvbXBsZXRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSBpZiAodGhpcy5sb29wIHx8IHJvdW5kIDwgdGhpcy50ZXh0dXJlcy5sZW5ndGgpIHtcbiAgICAgICAgdGhpcy50ZXh0dXJlID0gdGhpcy50ZXh0dXJlc1tyb3VuZCAlIHRoaXMudGV4dHVyZXMubGVuZ3RoXTtcbiAgICB9XG4gICAgZWxzZSBpZiAocm91bmQgPj0gdGhpcy50ZXh0dXJlcy5sZW5ndGgpIHtcbiAgICAgICAgdGhpcy5nb3RvQW5kU3RvcCh0aGlzLnRleHR1cmVzLmxlbmd0aCAtIDEpO1xuXG4gICAgICAgIGlmICh0aGlzLm9uQ29tcGxldGUpIHtcbiAgICAgICAgICAgIHRoaXMub25Db21wbGV0ZSgpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuLyoqXG4gKiBBIHNob3J0IGhhbmQgd2F5IG9mIGNyZWF0aW5nIGEgbW92aWVjbGlwIGZyb20gYW4gYXJyYXkgb2YgZnJhbWUgaWRzXG4gKlxuICogQHN0YXRpY1xuICogQHBhcmFtIGZyYW1lcyB7c3RyaW5nW119IHRoZSBhcnJheSBvZiBmcmFtZXMgaWRzIHRoZSBtb3ZpZWNsaXAgd2lsbCB1c2UgYXMgaXRzIHRleHR1cmUgZnJhbWVzXG4gKi9cbk1vdmllQ2xpcC5mcm9tRnJhbWVzID0gZnVuY3Rpb24gKGZyYW1lcykge1xuICAgIHZhciB0ZXh0dXJlcyA9IFtdO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBmcmFtZXMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgdGV4dHVyZXMucHVzaChuZXcgY29yZS5UZXh0dXJlLmZyb21GcmFtZShmcmFtZXNbaV0pKTtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IE1vdmllQ2xpcCh0ZXh0dXJlcyk7XG59O1xuXG4vKipcbiAqIEEgc2hvcnQgaGFuZCB3YXkgb2YgY3JlYXRpbmcgYSBtb3ZpZWNsaXAgZnJvbSBhbiBhcnJheSBvZiBpbWFnZSBpZHNcbiAqXG4gKiBAc3RhdGljXG4gKiBAcGFyYW0gaW1hZ2VzIHtzdHJpbmdbXX0gdGhlIGFycmF5IG9mIGltYWdlIHVybHMgdGhlIG1vdmllY2xpcCB3aWxsIHVzZSBhcyBpdHMgdGV4dHVyZSBmcmFtZXNcbiAqL1xuTW92aWVDbGlwLmZyb21JbWFnZXMgPSBmdW5jdGlvbiAoaW1hZ2VzKSB7XG4gICAgdmFyIHRleHR1cmVzID0gW107XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGltYWdlcy5sZW5ndGg7ICsraSkge1xuICAgICAgICB0ZXh0dXJlcy5wdXNoKG5ldyBjb3JlLlRleHR1cmUuZnJvbUltYWdlKGltYWdlc1tpXSkpO1xuICAgIH1cblxuICAgIHJldHVybiBuZXcgTW92aWVDbGlwKHRleHR1cmVzKTtcbn07XG4iLCJ2YXIgU3RyaXAgPSByZXF1aXJlKCcuL1N0cmlwJyk7XG5cbi8qKlxuICpcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAZXh0ZW5kcyBTdHJpcFxuICogQHBhcmFtIHtUZXh0dXJlfSB0ZXh0dXJlIC0gVGhlIHRleHR1cmUgdG8gdXNlIG9uIHRoZSByb3BlLlxuICogQHBhcmFtIHtBcnJheX0gcG9pbnRzIC0gQW4gYXJyYXkgb2Yge1BvaW50fS5cbiAqXG4gKi9cbmZ1bmN0aW9uIFJvcGUodGV4dHVyZSwgcG9pbnRzKSB7XG4gICAgU3RyaXAuY2FsbCh0aGlzLCB0ZXh0dXJlKTtcbiAgICB0aGlzLnBvaW50cyA9IHBvaW50cztcblxuICAgIHRoaXMudmVydGljZXMgPSBuZXcgRmxvYXQzMkFycmF5KHBvaW50cy5sZW5ndGggKiA0KTtcbiAgICB0aGlzLnV2cyA9IG5ldyBGbG9hdDMyQXJyYXkocG9pbnRzLmxlbmd0aCAqIDQpO1xuICAgIHRoaXMuY29sb3JzID0gbmV3IEZsb2F0MzJBcnJheShwb2ludHMubGVuZ3RoICogMik7XG4gICAgdGhpcy5pbmRpY2VzID0gbmV3IFVpbnQxNkFycmF5KHBvaW50cy5sZW5ndGggKiAyKTtcblxuICAgIHRoaXMucmVmcmVzaCgpO1xufVxuXG5cbi8vIGNvbnN0cnVjdG9yXG5Sb3BlLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoU3RyaXAucHJvdG90eXBlKTtcblJvcGUucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gUm9wZTtcbm1vZHVsZS5leHBvcnRzID0gUm9wZTtcblxuLyoqXG4gKiBSZWZyZXNoZXNcbiAqXG4gKi9cblJvcGUucHJvdG90eXBlLnJlZnJlc2ggPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIHBvaW50cyA9IHRoaXMucG9pbnRzO1xuXG4gICAgaWYgKHBvaW50cy5sZW5ndGggPCAxKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgdXZzID0gdGhpcy51dnM7XG5cbiAgICB2YXIgaW5kaWNlcyA9IHRoaXMuaW5kaWNlcztcbiAgICB2YXIgY29sb3JzID0gdGhpcy5jb2xvcnM7XG5cbiAgICAvLyB0aGlzLmNvdW50IC09IDAuMjtcblxuICAgIHV2c1swXSA9IDA7XG4gICAgdXZzWzFdID0gMDtcbiAgICB1dnNbMl0gPSAwO1xuICAgIHV2c1szXSA9IDE7XG5cbiAgICBjb2xvcnNbMF0gPSAxO1xuICAgIGNvbG9yc1sxXSA9IDE7XG5cbiAgICBpbmRpY2VzWzBdID0gMDtcbiAgICBpbmRpY2VzWzFdID0gMTtcblxuICAgIHZhciB0b3RhbCA9IHBvaW50cy5sZW5ndGgsXG4gICAgICAgIHBvaW50LCBpbmRleCwgYW1vdW50O1xuXG4gICAgZm9yICh2YXIgaSA9IDE7IGkgPCB0b3RhbDsgaSsrKSB7XG4gICAgICAgIHBvaW50ID0gcG9pbnRzW2ldO1xuICAgICAgICBpbmRleCA9IGkgKiA0O1xuICAgICAgICAvLyB0aW1lIHRvIGRvIHNvbWUgc21hcnQgZHJhd2luZyFcbiAgICAgICAgYW1vdW50ID0gaSAvICh0b3RhbC0xKTtcblxuICAgICAgICBpZiAoaSUyKSB7XG4gICAgICAgICAgICB1dnNbaW5kZXhdID0gYW1vdW50O1xuICAgICAgICAgICAgdXZzW2luZGV4KzFdID0gMDtcblxuICAgICAgICAgICAgdXZzW2luZGV4KzJdID0gYW1vdW50O1xuICAgICAgICAgICAgdXZzW2luZGV4KzNdID0gMTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHV2c1tpbmRleF0gPSBhbW91bnQ7XG4gICAgICAgICAgICB1dnNbaW5kZXgrMV0gPSAwO1xuXG4gICAgICAgICAgICB1dnNbaW5kZXgrMl0gPSBhbW91bnQ7XG4gICAgICAgICAgICB1dnNbaW5kZXgrM10gPSAxO1xuICAgICAgICB9XG5cbiAgICAgICAgaW5kZXggPSBpICogMjtcbiAgICAgICAgY29sb3JzW2luZGV4XSA9IDE7XG4gICAgICAgIGNvbG9yc1tpbmRleCsxXSA9IDE7XG5cbiAgICAgICAgaW5kZXggPSBpICogMjtcbiAgICAgICAgaW5kaWNlc1tpbmRleF0gPSBpbmRleDtcbiAgICAgICAgaW5kaWNlc1tpbmRleCArIDFdID0gaW5kZXggKyAxO1xuICAgIH1cbn07XG5cbi8qXG4gKiBVcGRhdGVzIHRoZSBvYmplY3QgdHJhbnNmb3JtIGZvciByZW5kZXJpbmdcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5Sb3BlLnByb3RvdHlwZS51cGRhdGVUcmFuc2Zvcm0gPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIHBvaW50cyA9IHRoaXMucG9pbnRzO1xuXG4gICAgaWYgKHBvaW50cy5sZW5ndGggPCAxKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgbGFzdFBvaW50ID0gcG9pbnRzWzBdO1xuICAgIHZhciBuZXh0UG9pbnQ7XG4gICAgdmFyIHBlcnBYID0gMDtcbiAgICB2YXIgcGVycFkgPSAwO1xuXG4gICAgLy8gdGhpcy5jb3VudCAtPSAwLjI7XG5cbiAgICB2YXIgdmVydGljZXMgPSB0aGlzLnZlcnRpY2VzO1xuICAgIHZhciB0b3RhbCA9IHBvaW50cy5sZW5ndGgsXG4gICAgICAgIHBvaW50LCBpbmRleCwgcmF0aW8sIHBlcnBMZW5ndGgsIG51bTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdG90YWw7IGkrKykge1xuICAgICAgICBwb2ludCA9IHBvaW50c1tpXTtcbiAgICAgICAgaW5kZXggPSBpICogNDtcblxuICAgICAgICBpZiAoaSA8IHBvaW50cy5sZW5ndGgtMSkge1xuICAgICAgICAgICAgbmV4dFBvaW50ID0gcG9pbnRzW2krMV07XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBuZXh0UG9pbnQgPSBwb2ludDtcbiAgICAgICAgfVxuXG4gICAgICAgIHBlcnBZID0gLShuZXh0UG9pbnQueCAtIGxhc3RQb2ludC54KTtcbiAgICAgICAgcGVycFggPSBuZXh0UG9pbnQueSAtIGxhc3RQb2ludC55O1xuXG4gICAgICAgIHJhdGlvID0gKDEgLSAoaSAvICh0b3RhbC0xKSkpICogMTA7XG5cbiAgICAgICAgaWYgKHJhdGlvID4gMSkge1xuICAgICAgICAgICAgcmF0aW8gPSAxO1xuICAgICAgICB9XG5cbiAgICAgICAgcGVycExlbmd0aCA9IE1hdGguc3FydChwZXJwWCAqIHBlcnBYICsgcGVycFkgKiBwZXJwWSk7XG4gICAgICAgIG51bSA9IHRoaXMudGV4dHVyZS5oZWlnaHQgLyAyOyAvLygyMCArIE1hdGguYWJzKE1hdGguc2luKChpICsgdGhpcy5jb3VudCkgKiAwLjMpICogNTApICkqIHJhdGlvO1xuICAgICAgICBwZXJwWCAvPSBwZXJwTGVuZ3RoO1xuICAgICAgICBwZXJwWSAvPSBwZXJwTGVuZ3RoO1xuXG4gICAgICAgIHBlcnBYICo9IG51bTtcbiAgICAgICAgcGVycFkgKj0gbnVtO1xuXG4gICAgICAgIHZlcnRpY2VzW2luZGV4XSA9IHBvaW50LnggKyBwZXJwWDtcbiAgICAgICAgdmVydGljZXNbaW5kZXgrMV0gPSBwb2ludC55ICsgcGVycFk7XG4gICAgICAgIHZlcnRpY2VzW2luZGV4KzJdID0gcG9pbnQueCAtIHBlcnBYO1xuICAgICAgICB2ZXJ0aWNlc1tpbmRleCszXSA9IHBvaW50LnkgLSBwZXJwWTtcblxuICAgICAgICBsYXN0UG9pbnQgPSBwb2ludDtcbiAgICB9XG5cbiAgICB0aGlzLmRpc3BsYXlPYmplY3RDb250YWluZXJVcGRhdGVUcmFuc2Zvcm0oKTtcbn07XG5cbi8qKlxuICogU2V0cyB0aGUgdGV4dHVyZSB0aGF0IHRoZSBSb3BlIHdpbGwgdXNlXG4gKlxuICogQHBhcmFtIHRleHR1cmUge1RleHR1cmV9IHRoZSB0ZXh0dXJlIHRoYXQgd2lsbCBiZSB1c2VkXG4gKi9cblJvcGUucHJvdG90eXBlLnNldFRleHR1cmUgPSBmdW5jdGlvbiAodGV4dHVyZSkge1xuICAgIC8vIHN0b3AgY3VycmVudCB0ZXh0dXJlXG4gICAgdGhpcy50ZXh0dXJlID0gdGV4dHVyZTtcbiAgICAvL3RoaXMudXBkYXRlRnJhbWUgPSB0cnVlO1xufTtcbiIsInZhciBjb3JlID0gcmVxdWlyZSgnLi4vY29yZScpO1xuXG4vKipcbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIERpc3BsYXlPYmplY3RDb250YWluZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHRleHR1cmUge1RleHR1cmV9IFRoZSB0ZXh0dXJlIHRvIHVzZVxuICogQHBhcmFtIHdpZHRoIHtudW1iZXJ9IHRoZSB3aWR0aFxuICogQHBhcmFtIGhlaWdodCB7bnVtYmVyfSB0aGUgaGVpZ2h0XG4gKlxuICovXG5mdW5jdGlvbiBTdHJpcCh0ZXh0dXJlKSB7XG4gICAgY29yZS5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLmNhbGwodGhpcyk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdGV4dHVyZSBvZiB0aGUgc3RyaXBcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1RleHR1cmV9XG4gICAgICovXG4gICAgdGhpcy50ZXh0dXJlID0gdGV4dHVyZTtcblxuICAgIC8vIHNldCB1cCB0aGUgbWFpbiBiaXRzLi5cbiAgICB0aGlzLnV2cyA9IG5ldyBGbG9hdDMyQXJyYXkoWzAsIDEsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxLCAxLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMSwgMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAsIDFdKTtcblxuICAgIHRoaXMudmVydGljZXMgPSBuZXcgRmxvYXQzMkFycmF5KFswLCAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAxMDAsIDAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDEwMCwgMTAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCAxMDBdKTtcblxuICAgIHRoaXMuY29sb3JzID0gbmV3IEZsb2F0MzJBcnJheShbMSwgMSwgMSwgMV0pO1xuXG4gICAgdGhpcy5pbmRpY2VzID0gbmV3IFVpbnQxNkFycmF5KFswLCAxLCAyLCAzXSk7XG5cbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRoZSBzdHJpcCBpcyBkaXJ0eSBvciBub3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5kaXJ0eSA9IHRydWU7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgYmxlbmQgbW9kZSB0byBiZSBhcHBsaWVkIHRvIHRoZSBzcHJpdGUuIFNldCB0byBibGVuZE1vZGVzLk5PUk1BTCB0byByZW1vdmUgYW55IGJsZW5kIG1vZGUuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgQ09OU1QuYmxlbmRNb2Rlcy5OT1JNQUw7XG4gICAgICovXG4gICAgdGhpcy5ibGVuZE1vZGUgPSBjb3JlLkNPTlNULmJsZW5kTW9kZXMuTk9STUFMO1xuXG4gICAgLyoqXG4gICAgICogVHJpYW5nbGVzIGluIGNhbnZhcyBtb2RlIGFyZSBhdXRvbWF0aWNhbGx5IGFudGlhbGlhc2VkLCB1c2UgdGhpcyB2YWx1ZSB0byBmb3JjZSB0cmlhbmdsZXMgdG8gb3ZlcmxhcCBhIGJpdCB3aXRoIGVhY2ggb3RoZXIuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5jYW52YXNQYWRkaW5nID0gMDtcblxuICAgIHRoaXMuZHJhd01vZGUgPSBTdHJpcC5EcmF3TW9kZXMuVFJJQU5HTEVfU1RSSVA7XG59XG5cbi8vIGNvbnN0cnVjdG9yXG5TdHJpcC5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKGNvcmUuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUpO1xuU3RyaXAucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gU3RyaXA7XG5tb2R1bGUuZXhwb3J0cyA9IFN0cmlwO1xuXG4vKipcbiAqIFJlbmRlcnMgdGhlIG9iamVjdCB1c2luZyB0aGUgV2ViR0wgcmVuZGVyZXJcbiAqXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9XG4gKi9cblN0cmlwLnByb3RvdHlwZS5yZW5kZXJXZWJHTCA9IGZ1bmN0aW9uIChyZW5kZXJlcikge1xuICAgIC8vIGlmIHRoZSBzcHJpdGUgaXMgbm90IHZpc2libGUgb3IgdGhlIGFscGhhIGlzIDAgdGhlbiBubyBuZWVkIHRvIHJlbmRlciB0aGlzIGVsZW1lbnRcbiAgICBpZiAoIXRoaXMudmlzaWJsZSB8fCB0aGlzLmFscGhhIDw9IDApIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIHJlbmRlciB0cmlhbmdsZSBzdHJpcC4uXG5cbiAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5zdG9wKCk7XG5cbiAgICAvLyBpbml0ISBpbml0IVxuICAgIGlmICghdGhpcy5fdmVydGV4QnVmZmVyKSB7XG4gICAgICAgIHRoaXMuX2luaXRXZWJHTChyZW5kZXJlcik7XG4gICAgfVxuXG4gICAgcmVuZGVyZXIuc2hhZGVyTWFuYWdlci5zZXRTaGFkZXIocmVuZGVyZXIuc2hhZGVyTWFuYWdlci5zdHJpcFNoYWRlcik7XG5cbiAgICB0aGlzLl9yZW5kZXJTdHJpcChyZW5kZXJlcik7XG5cbiAgICAvLy9yZW5kZXJlci5zaGFkZXJNYW5hZ2VyLmFjdGl2YXRlRGVmYXVsdFNoYWRlcigpO1xuXG4gICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guc3RhcnQoKTtcblxuICAgIC8vVE9ETyBjaGVjayBjdWxsaW5nXG59O1xuXG5TdHJpcC5wcm90b3R5cGUuX2luaXRXZWJHTCA9IGZ1bmN0aW9uIChyZW5kZXJlcikge1xuICAgIC8vIGJ1aWxkIHRoZSBzdHJpcCFcbiAgICB2YXIgZ2wgPSByZW5kZXJlci5nbDtcblxuICAgIHRoaXMuX3ZlcnRleEJ1ZmZlciA9IGdsLmNyZWF0ZUJ1ZmZlcigpO1xuICAgIHRoaXMuX2luZGV4QnVmZmVyID0gZ2wuY3JlYXRlQnVmZmVyKCk7XG4gICAgdGhpcy5fdXZCdWZmZXIgPSBnbC5jcmVhdGVCdWZmZXIoKTtcbiAgICB0aGlzLl9jb2xvckJ1ZmZlciA9IGdsLmNyZWF0ZUJ1ZmZlcigpO1xuXG4gICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMuX3ZlcnRleEJ1ZmZlcik7XG4gICAgZ2wuYnVmZmVyRGF0YShnbC5BUlJBWV9CVUZGRVIsIHRoaXMudmVydGljZXMsIGdsLkRZTkFNSUNfRFJBVyk7XG5cbiAgICBnbC5iaW5kQnVmZmVyKGdsLkFSUkFZX0JVRkZFUiwgdGhpcy5fdXZCdWZmZXIpO1xuICAgIGdsLmJ1ZmZlckRhdGEoZ2wuQVJSQVlfQlVGRkVSLCAgdGhpcy51dnMsIGdsLlNUQVRJQ19EUkFXKTtcblxuICAgIGdsLmJpbmRCdWZmZXIoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLl9jb2xvckJ1ZmZlcik7XG4gICAgZ2wuYnVmZmVyRGF0YShnbC5BUlJBWV9CVUZGRVIsIHRoaXMuY29sb3JzLCBnbC5TVEFUSUNfRFJBVyk7XG5cbiAgICBnbC5iaW5kQnVmZmVyKGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCB0aGlzLl9pbmRleEJ1ZmZlcik7XG4gICAgZ2wuYnVmZmVyRGF0YShnbC5FTEVNRU5UX0FSUkFZX0JVRkZFUiwgdGhpcy5pbmRpY2VzLCBnbC5TVEFUSUNfRFJBVyk7XG59O1xuXG5TdHJpcC5wcm90b3R5cGUuX3JlbmRlclN0cmlwID0gZnVuY3Rpb24gKHJlbmRlcmVyKSB7XG4gICAgdmFyIGdsID0gcmVuZGVyZXIuZ2w7XG4gICAgdmFyIHByb2plY3Rpb24gPSByZW5kZXJlci5wcm9qZWN0aW9uLFxuICAgICAgICBvZmZzZXQgPSByZW5kZXJlci5vZmZzZXQsXG4gICAgICAgIHNoYWRlciA9IHJlbmRlcmVyLnNoYWRlck1hbmFnZXIuc3RyaXBTaGFkZXI7XG5cbiAgICB2YXIgZHJhd01vZGUgPSB0aGlzLmRyYXdNb2RlID09PSBTdHJpcC5EcmF3TW9kZXMuVFJJQU5HTEVfU1RSSVAgPyBnbC5UUklBTkdMRV9TVFJJUCA6IGdsLlRSSUFOR0xFUztcblxuICAgIC8vIGdsLnVuaWZvcm1NYXRyaXg0ZnYoc2hhZGVyUHJvZ3JhbS5tdk1hdHJpeFVuaWZvcm0sIGZhbHNlLCBtYXQ0UmVhbCk7XG5cbiAgICByZW5kZXJlci5ibGVuZE1vZGVNYW5hZ2VyLnNldEJsZW5kTW9kZSh0aGlzLmJsZW5kTW9kZSk7XG5cblxuICAgIC8vIHNldCB1bmlmb3Jtc1xuICAgIGdsLnVuaWZvcm1NYXRyaXgzZnYoc2hhZGVyLnRyYW5zbGF0aW9uTWF0cml4LCBmYWxzZSwgdGhpcy53b3JsZFRyYW5zZm9ybS50b0FycmF5KHRydWUpKTtcbiAgICBnbC51bmlmb3JtMmYoc2hhZGVyLnByb2plY3Rpb25WZWN0b3IsIHByb2plY3Rpb24ueCwgLXByb2plY3Rpb24ueSk7XG4gICAgZ2wudW5pZm9ybTJmKHNoYWRlci5vZmZzZXRWZWN0b3IsIC1vZmZzZXQueCwgLW9mZnNldC55KTtcbiAgICBnbC51bmlmb3JtMWYoc2hhZGVyLmFscGhhLCB0aGlzLndvcmxkQWxwaGEpO1xuXG4gICAgaWYgKCF0aGlzLmRpcnR5KSB7XG5cbiAgICAgICAgZ2wuYmluZEJ1ZmZlcihnbC5BUlJBWV9CVUZGRVIsIHRoaXMuX3ZlcnRleEJ1ZmZlcik7XG4gICAgICAgIGdsLmJ1ZmZlclN1YkRhdGEoZ2wuQVJSQVlfQlVGRkVSLCAwLCB0aGlzLnZlcnRpY2VzKTtcbiAgICAgICAgZ2wudmVydGV4QXR0cmliUG9pbnRlcihzaGFkZXIuYVZlcnRleFBvc2l0aW9uLCAyLCBnbC5GTE9BVCwgZmFsc2UsIDAsIDApO1xuXG4gICAgICAgIC8vIHVwZGF0ZSB0aGUgdXZzXG4gICAgICAgIGdsLmJpbmRCdWZmZXIoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLl91dkJ1ZmZlcik7XG4gICAgICAgIGdsLnZlcnRleEF0dHJpYlBvaW50ZXIoc2hhZGVyLmFUZXh0dXJlQ29vcmQsIDIsIGdsLkZMT0FULCBmYWxzZSwgMCwgMCk7XG5cbiAgICAgICAgZ2wuYWN0aXZlVGV4dHVyZShnbC5URVhUVVJFMCk7XG5cbiAgICAgICAgLy8gY2hlY2sgaWYgYSB0ZXh0dXJlIGlzIGRpcnR5Li5cbiAgICAgICAgaWYgKHRoaXMudGV4dHVyZS5iYXNlVGV4dHVyZS5fZGlydHlbZ2wuaWRdKSB7XG4gICAgICAgICAgICByZW5kZXJlci51cGRhdGVUZXh0dXJlKHRoaXMudGV4dHVyZS5iYXNlVGV4dHVyZSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyBiaW5kIHRoZSBjdXJyZW50IHRleHR1cmVcbiAgICAgICAgICAgIGdsLmJpbmRUZXh0dXJlKGdsLlRFWFRVUkVfMkQsIHRoaXMudGV4dHVyZS5iYXNlVGV4dHVyZS5fZ2xUZXh0dXJlc1tnbC5pZF0pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG9udCBuZWVkIHRvIHVwbG9hZCFcbiAgICAgICAgZ2wuYmluZEJ1ZmZlcihnbC5FTEVNRU5UX0FSUkFZX0JVRkZFUiwgdGhpcy5faW5kZXhCdWZmZXIpO1xuXG5cbiAgICB9XG4gICAgZWxzZSB7XG5cbiAgICAgICAgdGhpcy5kaXJ0eSA9IGZhbHNlO1xuICAgICAgICBnbC5iaW5kQnVmZmVyKGdsLkFSUkFZX0JVRkZFUiwgdGhpcy5fdmVydGV4QnVmZmVyKTtcbiAgICAgICAgZ2wuYnVmZmVyRGF0YShnbC5BUlJBWV9CVUZGRVIsIHRoaXMudmVydGljZXMsIGdsLlNUQVRJQ19EUkFXKTtcbiAgICAgICAgZ2wudmVydGV4QXR0cmliUG9pbnRlcihzaGFkZXIuYVZlcnRleFBvc2l0aW9uLCAyLCBnbC5GTE9BVCwgZmFsc2UsIDAsIDApO1xuXG4gICAgICAgIC8vIHVwZGF0ZSB0aGUgdXZzXG4gICAgICAgIGdsLmJpbmRCdWZmZXIoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLl91dkJ1ZmZlcik7XG4gICAgICAgIGdsLmJ1ZmZlckRhdGEoZ2wuQVJSQVlfQlVGRkVSLCB0aGlzLnV2cywgZ2wuU1RBVElDX0RSQVcpO1xuICAgICAgICBnbC52ZXJ0ZXhBdHRyaWJQb2ludGVyKHNoYWRlci5hVGV4dHVyZUNvb3JkLCAyLCBnbC5GTE9BVCwgZmFsc2UsIDAsIDApO1xuXG4gICAgICAgIGdsLmFjdGl2ZVRleHR1cmUoZ2wuVEVYVFVSRTApO1xuXG4gICAgICAgIC8vIGNoZWNrIGlmIGEgdGV4dHVyZSBpcyBkaXJ0eS4uXG4gICAgICAgIGlmICh0aGlzLnRleHR1cmUuYmFzZVRleHR1cmUuX2RpcnR5W2dsLmlkXSkge1xuICAgICAgICAgICAgcmVuZGVyZXIudXBkYXRlVGV4dHVyZSh0aGlzLnRleHR1cmUuYmFzZVRleHR1cmUpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZ2wuYmluZFRleHR1cmUoZ2wuVEVYVFVSRV8yRCwgdGhpcy50ZXh0dXJlLmJhc2VUZXh0dXJlLl9nbFRleHR1cmVzW2dsLmlkXSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBkb250IG5lZWQgdG8gdXBsb2FkIVxuICAgICAgICBnbC5iaW5kQnVmZmVyKGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCB0aGlzLl9pbmRleEJ1ZmZlcik7XG4gICAgICAgIGdsLmJ1ZmZlckRhdGEoZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIsIHRoaXMuaW5kaWNlcywgZ2wuU1RBVElDX0RSQVcpO1xuXG4gICAgfVxuICAgIC8vY29uc29sZS5sb2coZ2wuVFJJQU5HTEVfU1RSSVApXG4gICAgLy9cbiAgICAvL1xuICAgIGdsLmRyYXdFbGVtZW50cyhkcmF3TW9kZSwgdGhpcy5pbmRpY2VzLmxlbmd0aCwgZ2wuVU5TSUdORURfU0hPUlQsIDApO1xuXG5cbn07XG5cbi8qKlxuICogUmVuZGVycyB0aGUgb2JqZWN0IHVzaW5nIHRoZSBDYW52YXMgcmVuZGVyZXJcbiAqXG4gKiBAcGFyYW0gcmVuZGVyZXIge0NhbnZhc1JlbmRlcmVyfVxuICovXG5TdHJpcC5wcm90b3R5cGUucmVuZGVyQ2FudmFzID0gZnVuY3Rpb24gKHJlbmRlcmVyKSB7XG4gICAgdmFyIGNvbnRleHQgPSByZW5kZXJlci5jb250ZXh0O1xuXG4gICAgdmFyIHRyYW5zZm9ybSA9IHRoaXMud29ybGRUcmFuc2Zvcm07XG5cbiAgICBpZiAocmVuZGVyZXIucm91bmRQaXhlbHMpIHtcbiAgICAgICAgY29udGV4dC5zZXRUcmFuc2Zvcm0odHJhbnNmb3JtLmEsIHRyYW5zZm9ybS5iLCB0cmFuc2Zvcm0uYywgdHJhbnNmb3JtLmQsIHRyYW5zZm9ybS50eCB8IDAsIHRyYW5zZm9ybS50eSB8IDApO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgY29udGV4dC5zZXRUcmFuc2Zvcm0odHJhbnNmb3JtLmEsIHRyYW5zZm9ybS5iLCB0cmFuc2Zvcm0uYywgdHJhbnNmb3JtLmQsIHRyYW5zZm9ybS50eCwgdHJhbnNmb3JtLnR5KTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5kcmF3TW9kZSA9PT0gU3RyaXAuRHJhd01vZGVzLlRSSUFOR0xFX1NUUklQKSB7XG4gICAgICAgIHRoaXMuX3JlbmRlckNhbnZhc1RyaWFuZ2xlU3RyaXAoY29udGV4dCk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLl9yZW5kZXJDYW52YXNUcmlhbmdsZXMoY29udGV4dCk7XG4gICAgfVxufTtcblxuU3RyaXAucHJvdG90eXBlLl9yZW5kZXJDYW52YXNUcmlhbmdsZVN0cmlwID0gZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICAvLyBkcmF3IHRyaWFuZ2xlcyEhXG4gICAgdmFyIHZlcnRpY2VzID0gdGhpcy52ZXJ0aWNlcztcbiAgICB2YXIgdXZzID0gdGhpcy51dnM7XG5cbiAgICB2YXIgbGVuZ3RoID0gdmVydGljZXMubGVuZ3RoIC8gMjtcbiAgICAvLyB0aGlzLmNvdW50Kys7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aCAtIDI7IGkrKykge1xuICAgICAgICAvLyBkcmF3IHNvbWUgdHJpYW5nbGVzIVxuICAgICAgICB2YXIgaW5kZXggPSBpICogMjtcbiAgICAgICAgdGhpcy5fcmVuZGVyQ2FudmFzRHJhd1RyaWFuZ2xlKGNvbnRleHQsIHZlcnRpY2VzLCB1dnMsIGluZGV4LCAoaW5kZXggKyAyKSwgKGluZGV4ICsgNCkpO1xuICAgIH1cbn07XG5cblN0cmlwLnByb3RvdHlwZS5fcmVuZGVyQ2FudmFzVHJpYW5nbGVzID0gZnVuY3Rpb24gKGNvbnRleHQpIHtcbiAgICAvLyBkcmF3IHRyaWFuZ2xlcyEhXG4gICAgdmFyIHZlcnRpY2VzID0gdGhpcy52ZXJ0aWNlcztcbiAgICB2YXIgdXZzID0gdGhpcy51dnM7XG4gICAgdmFyIGluZGljZXMgPSB0aGlzLmluZGljZXM7XG5cbiAgICB2YXIgbGVuZ3RoID0gaW5kaWNlcy5sZW5ndGg7XG4gICAgLy8gdGhpcy5jb3VudCsrO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkgKz0gMykge1xuICAgICAgICAvLyBkcmF3IHNvbWUgdHJpYW5nbGVzIVxuICAgICAgICB2YXIgaW5kZXgwID0gaW5kaWNlc1tpXSAqIDIsIGluZGV4MSA9IGluZGljZXNbaSArIDFdICogMiwgaW5kZXgyID0gaW5kaWNlc1tpICsgMl0gKiAyO1xuICAgICAgICB0aGlzLl9yZW5kZXJDYW52YXNEcmF3VHJpYW5nbGUoY29udGV4dCwgdmVydGljZXMsIHV2cywgaW5kZXgwLCBpbmRleDEsIGluZGV4Mik7XG4gICAgfVxufTtcblxuU3RyaXAucHJvdG90eXBlLl9yZW5kZXJDYW52YXNEcmF3VHJpYW5nbGUgPSBmdW5jdGlvbiAoY29udGV4dCwgdmVydGljZXMsIHV2cywgaW5kZXgwLCBpbmRleDEsIGluZGV4Mikge1xuICAgIHZhciB0ZXh0dXJlU291cmNlID0gdGhpcy50ZXh0dXJlLmJhc2VUZXh0dXJlLnNvdXJjZTtcbiAgICB2YXIgdGV4dHVyZVdpZHRoID0gdGhpcy50ZXh0dXJlLndpZHRoO1xuICAgIHZhciB0ZXh0dXJlSGVpZ2h0ID0gdGhpcy50ZXh0dXJlLmhlaWdodDtcblxuICAgIHZhciB4MCA9IHZlcnRpY2VzW2luZGV4MF0sIHgxID0gdmVydGljZXNbaW5kZXgxXSwgeDIgPSB2ZXJ0aWNlc1tpbmRleDJdO1xuICAgIHZhciB5MCA9IHZlcnRpY2VzW2luZGV4MCArIDFdLCB5MSA9IHZlcnRpY2VzW2luZGV4MSArIDFdLCB5MiA9IHZlcnRpY2VzW2luZGV4MiArIDFdO1xuXG4gICAgdmFyIHUwID0gdXZzW2luZGV4MF0gKiB0ZXh0dXJlV2lkdGgsIHUxID0gdXZzW2luZGV4MV0gKiB0ZXh0dXJlV2lkdGgsIHUyID0gdXZzW2luZGV4Ml0gKiB0ZXh0dXJlV2lkdGg7XG4gICAgdmFyIHYwID0gdXZzW2luZGV4MCArIDFdICogdGV4dHVyZUhlaWdodCwgdjEgPSB1dnNbaW5kZXgxICsgMV0gKiB0ZXh0dXJlSGVpZ2h0LCB2MiA9IHV2c1tpbmRleDIgKyAxXSAqIHRleHR1cmVIZWlnaHQ7XG5cbiAgICBpZiAodGhpcy5jYW52YXNQYWRkaW5nID4gMCkge1xuICAgICAgICB2YXIgcGFkZGluZ1ggPSB0aGlzLmNhbnZhc1BhZGRpbmcgLyB0aGlzLndvcmxkVHJhbnNmb3JtLmE7XG4gICAgICAgIHZhciBwYWRkaW5nWSA9IHRoaXMuY2FudmFzUGFkZGluZyAvIHRoaXMud29ybGRUcmFuc2Zvcm0uZDtcbiAgICAgICAgdmFyIGNlbnRlclggPSAoeDAgKyB4MSArIHgyKSAvIDM7XG4gICAgICAgIHZhciBjZW50ZXJZID0gKHkwICsgeTEgKyB5MikgLyAzO1xuXG4gICAgICAgIHZhciBub3JtWCA9IHgwIC0gY2VudGVyWDtcbiAgICAgICAgdmFyIG5vcm1ZID0geTAgLSBjZW50ZXJZO1xuXG4gICAgICAgIHZhciBkaXN0ID0gTWF0aC5zcXJ0KG5vcm1YICogbm9ybVggKyBub3JtWSAqIG5vcm1ZKTtcbiAgICAgICAgeDAgPSBjZW50ZXJYICsgKG5vcm1YIC8gZGlzdCkgKiAoZGlzdCArIHBhZGRpbmdYKTtcbiAgICAgICAgeTAgPSBjZW50ZXJZICsgKG5vcm1ZIC8gZGlzdCkgKiAoZGlzdCArIHBhZGRpbmdZKTtcblxuICAgICAgICAvL1xuXG4gICAgICAgIG5vcm1YID0geDEgLSBjZW50ZXJYO1xuICAgICAgICBub3JtWSA9IHkxIC0gY2VudGVyWTtcblxuICAgICAgICBkaXN0ID0gTWF0aC5zcXJ0KG5vcm1YICogbm9ybVggKyBub3JtWSAqIG5vcm1ZKTtcbiAgICAgICAgeDEgPSBjZW50ZXJYICsgKG5vcm1YIC8gZGlzdCkgKiAoZGlzdCArIHBhZGRpbmdYKTtcbiAgICAgICAgeTEgPSBjZW50ZXJZICsgKG5vcm1ZIC8gZGlzdCkgKiAoZGlzdCArIHBhZGRpbmdZKTtcblxuICAgICAgICBub3JtWCA9IHgyIC0gY2VudGVyWDtcbiAgICAgICAgbm9ybVkgPSB5MiAtIGNlbnRlclk7XG5cbiAgICAgICAgZGlzdCA9IE1hdGguc3FydChub3JtWCAqIG5vcm1YICsgbm9ybVkgKiBub3JtWSk7XG4gICAgICAgIHgyID0gY2VudGVyWCArIChub3JtWCAvIGRpc3QpICogKGRpc3QgKyBwYWRkaW5nWCk7XG4gICAgICAgIHkyID0gY2VudGVyWSArIChub3JtWSAvIGRpc3QpICogKGRpc3QgKyBwYWRkaW5nWSk7XG4gICAgfVxuXG4gICAgY29udGV4dC5zYXZlKCk7XG4gICAgY29udGV4dC5iZWdpblBhdGgoKTtcblxuXG4gICAgY29udGV4dC5tb3ZlVG8oeDAsIHkwKTtcbiAgICBjb250ZXh0LmxpbmVUbyh4MSwgeTEpO1xuICAgIGNvbnRleHQubGluZVRvKHgyLCB5Mik7XG5cbiAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xuXG4gICAgY29udGV4dC5jbGlwKCk7XG5cbiAgICAvLyBDb21wdXRlIG1hdHJpeCB0cmFuc2Zvcm1cbiAgICB2YXIgZGVsdGEgPSAgKHUwICogdjEpICAgICAgKyAodjAgKiB1MikgICAgICArICh1MSAqIHYyKSAgICAgIC0gKHYxICogdTIpICAgICAgLSAodjAgKiB1MSkgICAgICAtICh1MCAqIHYyKTtcbiAgICB2YXIgZGVsdGFBID0gKHgwICogdjEpICAgICAgKyAodjAgKiB4MikgICAgICArICh4MSAqIHYyKSAgICAgIC0gKHYxICogeDIpICAgICAgLSAodjAgKiB4MSkgICAgICAtICh4MCAqIHYyKTtcbiAgICB2YXIgZGVsdGFCID0gKHUwICogeDEpICAgICAgKyAoeDAgKiB1MikgICAgICArICh1MSAqIHgyKSAgICAgIC0gKHgxICogdTIpICAgICAgLSAoeDAgKiB1MSkgICAgICAtICh1MCAqIHgyKTtcbiAgICB2YXIgZGVsdGFDID0gKHUwICogdjEgKiB4MikgKyAodjAgKiB4MSAqIHUyKSArICh4MCAqIHUxICogdjIpIC0gKHgwICogdjEgKiB1MikgLSAodjAgKiB1MSAqIHgyKSAtICh1MCAqIHgxICogdjIpO1xuICAgIHZhciBkZWx0YUQgPSAoeTAgKiB2MSkgICAgICArICh2MCAqIHkyKSAgICAgICsgKHkxICogdjIpICAgICAgLSAodjEgKiB5MikgICAgICAtICh2MCAqIHkxKSAgICAgIC0gKHkwICogdjIpO1xuICAgIHZhciBkZWx0YUUgPSAodTAgKiB5MSkgICAgICArICh5MCAqIHUyKSAgICAgICsgKHUxICogeTIpICAgICAgLSAoeTEgKiB1MikgICAgICAtICh5MCAqIHUxKSAgICAgIC0gKHUwICogeTIpO1xuICAgIHZhciBkZWx0YUYgPSAodTAgKiB2MSAqIHkyKSArICh2MCAqIHkxICogdTIpICsgKHkwICogdTEgKiB2MikgLSAoeTAgKiB2MSAqIHUyKSAtICh2MCAqIHUxICogeTIpIC0gKHUwICogeTEgKiB2Mik7XG5cbiAgICBjb250ZXh0LnRyYW5zZm9ybShkZWx0YUEgLyBkZWx0YSwgZGVsdGFEIC8gZGVsdGEsXG4gICAgICAgIGRlbHRhQiAvIGRlbHRhLCBkZWx0YUUgLyBkZWx0YSxcbiAgICAgICAgZGVsdGFDIC8gZGVsdGEsIGRlbHRhRiAvIGRlbHRhKTtcblxuICAgIGNvbnRleHQuZHJhd0ltYWdlKHRleHR1cmVTb3VyY2UsIDAsIDApO1xuICAgIGNvbnRleHQucmVzdG9yZSgpO1xufTtcblxuXG5cbi8qKlxuICogUmVuZGVycyBhIGZsYXQgc3RyaXBcbiAqXG4gKiBAcGFyYW0gc3RyaXAge1N0cmlwfSBUaGUgU3RyaXAgdG8gcmVuZGVyXG4gKiBAcHJpdmF0ZVxuICovXG5TdHJpcC5wcm90b3R5cGUucmVuZGVyU3RyaXBGbGF0ID0gZnVuY3Rpb24gKHN0cmlwKSB7XG4gICAgdmFyIGNvbnRleHQgPSB0aGlzLmNvbnRleHQ7XG4gICAgdmFyIHZlcnRpY2VzID0gc3RyaXAudmVydGljZXM7XG5cbiAgICB2YXIgbGVuZ3RoID0gdmVydGljZXMubGVuZ3RoLzI7XG4gICAgLy8gdGhpcy5jb3VudCsrO1xuXG4gICAgY29udGV4dC5iZWdpblBhdGgoKTtcbiAgICBmb3IgKHZhciBpPTE7IGkgPCBsZW5ndGgtMjsgaSsrKSB7XG4gICAgICAgIC8vIGRyYXcgc29tZSB0cmlhbmdsZXMhXG4gICAgICAgIHZhciBpbmRleCA9IGkqMjtcblxuICAgICAgICB2YXIgeDAgPSB2ZXJ0aWNlc1tpbmRleF0sICAgeDEgPSB2ZXJ0aWNlc1tpbmRleCsyXSwgeDIgPSB2ZXJ0aWNlc1tpbmRleCs0XTtcbiAgICAgICAgdmFyIHkwID0gdmVydGljZXNbaW5kZXgrMV0sIHkxID0gdmVydGljZXNbaW5kZXgrM10sIHkyID0gdmVydGljZXNbaW5kZXgrNV07XG5cbiAgICAgICAgY29udGV4dC5tb3ZlVG8oeDAsIHkwKTtcbiAgICAgICAgY29udGV4dC5saW5lVG8oeDEsIHkxKTtcbiAgICAgICAgY29udGV4dC5saW5lVG8oeDIsIHkyKTtcbiAgICB9XG5cbiAgICBjb250ZXh0LmZpbGxTdHlsZSA9ICcjRkYwMDAwJztcbiAgICBjb250ZXh0LmZpbGwoKTtcbiAgICBjb250ZXh0LmNsb3NlUGF0aCgpO1xufTtcblxuLypcblN0cmlwLnByb3RvdHlwZS5zZXRUZXh0dXJlID0gZnVuY3Rpb24gKHRleHR1cmUpIHtcbiAgICAvL1RPRE8gU0VUIFRIRSBURVhUVVJFU1xuICAgIC8vVE9ETyBWSVNJQklMSVRZXG5cbiAgICAvLyBzdG9wIGN1cnJlbnQgdGV4dHVyZVxuICAgIHRoaXMudGV4dHVyZSA9IHRleHR1cmU7XG4gICAgdGhpcy53aWR0aCAgID0gdGV4dHVyZS5mcmFtZS53aWR0aDtcbiAgICB0aGlzLmhlaWdodCAgPSB0ZXh0dXJlLmZyYW1lLmhlaWdodDtcbiAgICB0aGlzLnVwZGF0ZUZyYW1lID0gdHJ1ZTtcbn07XG4gKi9cblxuLyoqXG4gKiBXaGVuIHRoZSB0ZXh0dXJlIGlzIHVwZGF0ZWQsIHRoaXMgZXZlbnQgd2lsbCBmaXJlIHRvIHVwZGF0ZSB0aGUgc2NhbGUgYW5kIGZyYW1lXG4gKlxuICogQHBhcmFtIGV2ZW50XG4gKiBAcHJpdmF0ZVxuICovXG5cblN0cmlwLnByb3RvdHlwZS5vblRleHR1cmVVcGRhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy51cGRhdGVGcmFtZSA9IHRydWU7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdGhlIGJvdW5kcyBvZiB0aGUgbWVzaCBhcyBhIHJlY3RhbmdsZS4gVGhlIGJvdW5kcyBjYWxjdWxhdGlvbiB0YWtlcyB0aGUgd29ybGRUcmFuc2Zvcm0gaW50byBhY2NvdW50LlxuICpcbiAqIEBwYXJhbSBtYXRyaXgge01hdHJpeH0gdGhlIHRyYW5zZm9ybWF0aW9uIG1hdHJpeCBvZiB0aGUgc3ByaXRlXG4gKiBAcmV0dXJuIHtSZWN0YW5nbGV9IHRoZSBmcmFtaW5nIHJlY3RhbmdsZVxuICovXG5TdHJpcC5wcm90b3R5cGUuZ2V0Qm91bmRzID0gZnVuY3Rpb24gKG1hdHJpeCkge1xuICAgIHZhciB3b3JsZFRyYW5zZm9ybSA9IG1hdHJpeCB8fCB0aGlzLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgdmFyIGEgPSB3b3JsZFRyYW5zZm9ybS5hO1xuICAgIHZhciBiID0gd29ybGRUcmFuc2Zvcm0uYjtcbiAgICB2YXIgYyA9IHdvcmxkVHJhbnNmb3JtLmM7XG4gICAgdmFyIGQgPSB3b3JsZFRyYW5zZm9ybS5kO1xuICAgIHZhciB0eCA9IHdvcmxkVHJhbnNmb3JtLnR4O1xuICAgIHZhciB0eSA9IHdvcmxkVHJhbnNmb3JtLnR5O1xuXG4gICAgdmFyIG1heFggPSAtSW5maW5pdHk7XG4gICAgdmFyIG1heFkgPSAtSW5maW5pdHk7XG5cbiAgICB2YXIgbWluWCA9IEluZmluaXR5O1xuICAgIHZhciBtaW5ZID0gSW5maW5pdHk7XG5cbiAgICB2YXIgdmVydGljZXMgPSB0aGlzLnZlcnRpY2VzO1xuICAgIGZvciAodmFyIGkgPSAwLCBuID0gdmVydGljZXMubGVuZ3RoOyBpIDwgbjsgaSArPSAyKSB7XG4gICAgICAgIHZhciByYXdYID0gdmVydGljZXNbaV0sIHJhd1kgPSB2ZXJ0aWNlc1tpICsgMV07XG4gICAgICAgIHZhciB4ID0gKGEgKiByYXdYKSArIChjICogcmF3WSkgKyB0eDtcbiAgICAgICAgdmFyIHkgPSAoZCAqIHJhd1kpICsgKGIgKiByYXdYKSArIHR5O1xuXG4gICAgICAgIG1pblggPSB4IDwgbWluWCA/IHggOiBtaW5YO1xuICAgICAgICBtaW5ZID0geSA8IG1pblkgPyB5IDogbWluWTtcblxuICAgICAgICBtYXhYID0geCA+IG1heFggPyB4IDogbWF4WDtcbiAgICAgICAgbWF4WSA9IHkgPiBtYXhZID8geSA6IG1heFk7XG4gICAgfVxuXG4gICAgaWYgKG1pblggPT09IC1JbmZpbml0eSB8fCBtYXhZID09PSBJbmZpbml0eSkge1xuICAgICAgICByZXR1cm4gY29yZS5tYXRoLlJlY3RhbmdsZS5FTVBUWTtcbiAgICB9XG5cbiAgICB2YXIgYm91bmRzID0gdGhpcy5fYm91bmRzO1xuXG4gICAgYm91bmRzLnggPSBtaW5YO1xuICAgIGJvdW5kcy53aWR0aCA9IG1heFggLSBtaW5YO1xuXG4gICAgYm91bmRzLnkgPSBtaW5ZO1xuICAgIGJvdW5kcy5oZWlnaHQgPSBtYXhZIC0gbWluWTtcblxuICAgIC8vIHN0b3JlIGEgcmVmZXJlbmNlIHNvIHRoYXQgaWYgdGhpcyBmdW5jdGlvbiBnZXRzIGNhbGxlZCBhZ2FpbiBpbiB0aGUgcmVuZGVyIGN5Y2xlIHdlIGRvIG5vdCBoYXZlIHRvIHJlY2FsY3VsYXRlXG4gICAgdGhpcy5fY3VycmVudEJvdW5kcyA9IGJvdW5kcztcblxuICAgIHJldHVybiBib3VuZHM7XG59O1xuXG4vKipcbiAqIERpZmZlcmVudCBkcmF3aW5nIGJ1ZmZlciBtb2RlcyBzdXBwb3J0ZWRcbiAqXG4gKiBAc3RhdGljXG4gKiBAY29uc3RhbnRcbiAqIEBwcm9wZXJ0eSB7b2JqZWN0fSBEcmF3TW9kZXNcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBEcmF3TW9kZXMuVFJJQU5HTEVfU1RSSVBcbiAqIEBwcm9wZXJ0eSB7bnVtYmVyfSBEcmF3TW9kZXMuVFJJQU5HTEVTXG4gKi9cblN0cmlwLkRyYXdNb2RlcyA9IHtcbiAgICBUUklBTkdMRV9TVFJJUDogMCxcbiAgICBUUklBTkdMRVM6IDFcbn07XG4iLCJ2YXIgY29yZSA9IHJlcXVpcmUoJy4uL2NvcmUnKTtcblxuLyoqXG4gKiBBIHRpbGluZyBzcHJpdGUgaXMgYSBmYXN0IHdheSBvZiByZW5kZXJpbmcgYSB0aWxpbmcgaW1hZ2VcbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIFNwcml0ZVxuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gdGV4dHVyZSB7VGV4dHVyZX0gdGhlIHRleHR1cmUgb2YgdGhlIHRpbGluZyBzcHJpdGVcbiAqIEBwYXJhbSB3aWR0aCB7bnVtYmVyfSAgdGhlIHdpZHRoIG9mIHRoZSB0aWxpbmcgc3ByaXRlXG4gKiBAcGFyYW0gaGVpZ2h0IHtudW1iZXJ9IHRoZSBoZWlnaHQgb2YgdGhlIHRpbGluZyBzcHJpdGVcbiAqL1xuZnVuY3Rpb24gVGlsaW5nU3ByaXRlKHRleHR1cmUsIHdpZHRoLCBoZWlnaHQpIHtcbiAgICBjb3JlLlNwcml0ZS5jYWxsKCB0aGlzLCB0ZXh0dXJlKTtcblxuICAgIC8qKlxuICAgICAqIFRoZSB3aXRoIG9mIHRoZSB0aWxpbmcgc3ByaXRlXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5fd2lkdGggPSB3aWR0aCB8fCAxMDA7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgaGVpZ2h0IG9mIHRoZSB0aWxpbmcgc3ByaXRlXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5faGVpZ2h0ID0gaGVpZ2h0IHx8IDEwMDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBzY2FsaW5nIG9mIHRoZSBpbWFnZSB0aGF0IGlzIGJlaW5nIHRpbGVkXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKi9cbiAgICB0aGlzLnRpbGVTY2FsZSA9IG5ldyBjb3JlLm1hdGguUG9pbnQoMSwxKTtcblxuICAgIC8qKlxuICAgICAqIEEgcG9pbnQgdGhhdCByZXByZXNlbnRzIHRoZSBzY2FsZSBvZiB0aGUgdGV4dHVyZSBvYmplY3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1BvaW50fVxuICAgICAqL1xuICAgIHRoaXMudGlsZVNjYWxlT2Zmc2V0ID0gbmV3IGNvcmUubWF0aC5Qb2ludCgxLDEpO1xuXG4gICAgLyoqXG4gICAgICogVGhlIG9mZnNldCBwb3NpdGlvbiBvZiB0aGUgaW1hZ2UgdGhhdCBpcyBiZWluZyB0aWxlZFxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICovXG4gICAgdGhpcy50aWxlUG9zaXRpb24gPSBuZXcgY29yZS5tYXRoLlBvaW50KDAsMCk7XG5cbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRoaXMgc3ByaXRlIGlzIHJlbmRlcmFibGUgb3Igbm90XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqIEBkZWZhdWx0IHRydWVcbiAgICAgKi9cbiAgICB0aGlzLnJlbmRlcmFibGUgPSB0cnVlO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHRpbnQgYXBwbGllZCB0byB0aGUgc3ByaXRlLiBUaGlzIGlzIGEgaGV4IHZhbHVlXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQGRlZmF1bHQgMHhGRkZGRkZcbiAgICAgKi9cbiAgICB0aGlzLnRpbnQgPSAweEZGRkZGRjtcblxuICAgIC8qKlxuICAgICAqIFRoZSBibGVuZCBtb2RlIHRvIGJlIGFwcGxpZWQgdG8gdGhlIHNwcml0ZVxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBkZWZhdWx0IGJsZW5kTW9kZXMuTk9STUFMO1xuICAgICAqL1xuICAgIHRoaXMuYmxlbmRNb2RlID0gY29yZS5DT05TVC5ibGVuZE1vZGVzLk5PUk1BTDtcbn1cblxuVGlsaW5nU3ByaXRlLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoY29yZS5TcHJpdGUucHJvdG90eXBlKTtcblRpbGluZ1Nwcml0ZS5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBUaWxpbmdTcHJpdGU7XG5tb2R1bGUuZXhwb3J0cyA9IFRpbGluZ1Nwcml0ZTtcblxuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhUaWxpbmdTcHJpdGUucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHdpZHRoIG9mIHRoZSBzcHJpdGUsIHNldHRpbmcgdGhpcyB3aWxsIGFjdHVhbGx5IG1vZGlmeSB0aGUgc2NhbGUgdG8gYWNoaWV2ZSB0aGUgdmFsdWUgc2V0XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIFRpbGluZ1Nwcml0ZSNcbiAgICAgKi9cbiAgICB3aWR0aDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl93aWR0aDtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuX3dpZHRoID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIGhlaWdodCBvZiB0aGUgVGlsaW5nU3ByaXRlLCBzZXR0aW5nIHRoaXMgd2lsbCBhY3R1YWxseSBtb2RpZnkgdGhlIHNjYWxlIHRvIGFjaGlldmUgdGhlIHZhbHVlIHNldFxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUaWxpbmdTcHJpdGUjXG4gICAgICovXG4gICAgaGVpZ2h0OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2hlaWdodDtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuX2hlaWdodCA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIHRleHR1cmU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fdGV4dHVyZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLl90ZXh0dXJlID09PSB2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5fdGV4dHVyZSA9IHZhbHVlO1xuICAgICAgICAgICAgdGhpcy5yZWZyZXNoVGV4dHVyZSA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLmNhY2hlZFRpbnQgPSAweEZGRkZGRjtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG4vKipcbiAqIFJlbmRlcnMgdGhlIG9iamVjdCB1c2luZyB0aGUgV2ViR0wgcmVuZGVyZXJcbiAqXG4gKiBAcGFyYW0gcmVuZGVyZXIge1dlYkdMUmVuZGVyZXJ9XG4gKi9cblRpbGluZ1Nwcml0ZS5wcm90b3R5cGUucmVuZGVyV2ViR0wgPSBmdW5jdGlvbiAocmVuZGVyZXIpIHtcbiAgICBpZiAoIXRoaXMudmlzaWJsZSB8fCB0aGlzLmFscGhhIDw9IDApIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciBpLCBqO1xuXG4gICAgaWYgKHRoaXMuX21hc2spIHtcbiAgICAgICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guc3RvcCgpO1xuICAgICAgICByZW5kZXJlci5tYXNrTWFuYWdlci5wdXNoTWFzayh0aGlzLm1hc2ssIHJlbmRlcmVyKTtcbiAgICAgICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guc3RhcnQoKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fZmlsdGVycykge1xuICAgICAgICByZW5kZXJlci5zcHJpdGVCYXRjaC5mbHVzaCgpO1xuICAgICAgICByZW5kZXJlci5maWx0ZXJNYW5hZ2VyLnB1c2hGaWx0ZXIodGhpcy5fZmlsdGVyQmxvY2spO1xuICAgIH1cblxuXG5cbiAgICBpZiAoIXRoaXMudGlsaW5nVGV4dHVyZSB8fCB0aGlzLnJlZnJlc2hUZXh0dXJlKSB7XG4gICAgICAgIHRoaXMuZ2VuZXJhdGVUaWxpbmdUZXh0dXJlKHRydWUpO1xuXG4gICAgICAgIGlmICh0aGlzLnRpbGluZ1RleHR1cmUgJiYgdGhpcy50aWxpbmdUZXh0dXJlLm5lZWRzVXBkYXRlKSB7XG4gICAgICAgICAgICAvL1RPRE8gLSB0d2Vha2luZ1xuICAgICAgICAgICAgcmVuZGVyZXIudXBkYXRlVGV4dHVyZSh0aGlzLnRpbGluZ1RleHR1cmUuYmFzZVRleHR1cmUpO1xuICAgICAgICAgICAgdGhpcy50aWxpbmdUZXh0dXJlLm5lZWRzVXBkYXRlID0gZmFsc2U7XG4gICAgICAgICAgIC8vIHRoaXMudGlsaW5nVGV4dHVyZS5fdXZzID0gbnVsbDtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2gucmVuZGVyVGlsaW5nU3ByaXRlKHRoaXMpO1xuICAgIH1cbiAgICAvLyBzaW1wbGUgcmVuZGVyIGNoaWxkcmVuIVxuICAgIGZvciAoaT0wLGo9dGhpcy5jaGlsZHJlbi5sZW5ndGg7IGk8ajsgaSsrKSB7XG4gICAgICAgIHRoaXMuY2hpbGRyZW5baV0ucmVuZGVyV2ViR0wocmVuZGVyZXIpO1xuICAgIH1cblxuICAgIHJlbmRlcmVyLnNwcml0ZUJhdGNoLnN0b3AoKTtcblxuICAgIGlmICh0aGlzLl9maWx0ZXJzKSB7XG4gICAgICAgIHJlbmRlcmVyLmZpbHRlck1hbmFnZXIucG9wRmlsdGVyKCk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX21hc2spIHtcbiAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucG9wTWFzayh0aGlzLl9tYXNrLCByZW5kZXJlcik7XG4gICAgfVxuXG4gICAgcmVuZGVyZXIuc3ByaXRlQmF0Y2guc3RhcnQoKTtcbn07XG5cbi8qKlxuICogUmVuZGVycyB0aGUgb2JqZWN0IHVzaW5nIHRoZSBDYW52YXMgcmVuZGVyZXJcbiAqXG4gKiBAcGFyYW0gcmVuZGVyZXIge0NhbnZhc1JlbmRlcmVyfVxuICovXG5UaWxpbmdTcHJpdGUucHJvdG90eXBlLnJlbmRlckNhbnZhcyA9IGZ1bmN0aW9uIChyZW5kZXJlcikge1xuICAgIGlmICghdGhpcy52aXNpYmxlIHx8IHRoaXMuYWxwaGEgPD0gMCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIGNvbnRleHQgPSByZW5kZXJlci5jb250ZXh0O1xuXG4gICAgaWYgKHRoaXMuX21hc2spIHtcbiAgICAgICAgcmVuZGVyZXIubWFza01hbmFnZXIucHVzaE1hc2sodGhpcy5fbWFzaywgY29udGV4dCk7XG4gICAgfVxuXG4gICAgY29udGV4dC5nbG9iYWxBbHBoYSA9IHRoaXMud29ybGRBbHBoYTtcblxuICAgIHZhciB0cmFuc2Zvcm0gPSB0aGlzLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgdmFyIGksajtcblxuICAgIHZhciByZXNvbHV0aW9uID0gcmVuZGVyZXIucmVzb2x1dGlvbjtcblxuICAgIGNvbnRleHQuc2V0VHJhbnNmb3JtKHRyYW5zZm9ybS5hICogcmVzb2x1dGlvbixcbiAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0uYiAqIHJlc29sdXRpb24sXG4gICAgICAgICAgICAgICAgICAgICAgICAgdHJhbnNmb3JtLmMgKiByZXNvbHV0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybS5kICogcmVzb2x1dGlvbixcbiAgICAgICAgICAgICAgICAgICAgICAgICB0cmFuc2Zvcm0udHggKiByZXNvbHV0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zZm9ybS50eSAqIHJlc29sdXRpb24pO1xuXG4gICAgaWYgKCF0aGlzLl9fdGlsZVBhdHRlcm4gfHwgIHRoaXMucmVmcmVzaFRleHR1cmUpIHtcbiAgICAgICAgdGhpcy5nZW5lcmF0ZVRpbGluZ1RleHR1cmUoZmFsc2UpO1xuXG4gICAgICAgIGlmICh0aGlzLnRpbGluZ1RleHR1cmUpIHtcbiAgICAgICAgICAgIHRoaXMuX190aWxlUGF0dGVybiA9IGNvbnRleHQuY3JlYXRlUGF0dGVybih0aGlzLnRpbGluZ1RleHR1cmUuYmFzZVRleHR1cmUuc291cmNlLCAncmVwZWF0Jyk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBjaGVjayBibGVuZCBtb2RlXG4gICAgaWYgKHRoaXMuYmxlbmRNb2RlICE9PSByZW5kZXJlci5jdXJyZW50QmxlbmRNb2RlKSB7XG4gICAgICAgIHJlbmRlcmVyLmN1cnJlbnRCbGVuZE1vZGUgPSB0aGlzLmJsZW5kTW9kZTtcbiAgICAgICAgY29udGV4dC5nbG9iYWxDb21wb3NpdGVPcGVyYXRpb24gPSByZW5kZXJlci5ibGVuZE1vZGVzW3JlbmRlcmVyLmN1cnJlbnRCbGVuZE1vZGVdO1xuICAgIH1cblxuICAgIHZhciB0aWxlUG9zaXRpb24gPSB0aGlzLnRpbGVQb3NpdGlvbjtcbiAgICB2YXIgdGlsZVNjYWxlID0gdGhpcy50aWxlU2NhbGU7XG5cbiAgICB0aWxlUG9zaXRpb24ueCAlPSB0aGlzLnRpbGluZ1RleHR1cmUuYmFzZVRleHR1cmUud2lkdGg7XG4gICAgdGlsZVBvc2l0aW9uLnkgJT0gdGhpcy50aWxpbmdUZXh0dXJlLmJhc2VUZXh0dXJlLmhlaWdodDtcblxuICAgIC8vIG9mZnNldCAtIG1ha2Ugc3VyZSB0byBhY2NvdW50IGZvciB0aGUgYW5jaG9yIHBvaW50Li5cbiAgICBjb250ZXh0LnNjYWxlKHRpbGVTY2FsZS54LHRpbGVTY2FsZS55KTtcbiAgICBjb250ZXh0LnRyYW5zbGF0ZSh0aWxlUG9zaXRpb24ueCArICh0aGlzLmFuY2hvci54ICogLXRoaXMuX3dpZHRoKSwgdGlsZVBvc2l0aW9uLnkgKyAodGhpcy5hbmNob3IueSAqIC10aGlzLl9oZWlnaHQpKTtcblxuICAgIGNvbnRleHQuZmlsbFN0eWxlID0gdGhpcy5fX3RpbGVQYXR0ZXJuO1xuXG4gICAgY29udGV4dC5maWxsUmVjdCgtdGlsZVBvc2l0aW9uLngsXG4gICAgICAgICAgICAgICAgICAgIC10aWxlUG9zaXRpb24ueSxcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fd2lkdGggLyB0aWxlU2NhbGUueCxcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5faGVpZ2h0IC8gdGlsZVNjYWxlLnkpO1xuXG4gICAgY29udGV4dC50cmFuc2xhdGUoLXRpbGVQb3NpdGlvbi54ICsgKHRoaXMuYW5jaG9yLnggKiB0aGlzLl93aWR0aCksIC10aWxlUG9zaXRpb24ueSArICh0aGlzLmFuY2hvci55ICogdGhpcy5faGVpZ2h0KSk7XG4gICAgY29udGV4dC5zY2FsZSgxIC8gdGlsZVNjYWxlLngsIDEgLyB0aWxlU2NhbGUueSk7XG5cbiAgICBpZiAodGhpcy5fbWFzaykge1xuICAgICAgICByZW5kZXJlci5tYXNrTWFuYWdlci5wb3BNYXNrKHJlbmRlcmVyLmNvbnRleHQpO1xuICAgIH1cblxuICAgIGZvciAoaSA9IDAsIGogPSB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGo7ICsraSkge1xuICAgICAgICB0aGlzLmNoaWxkcmVuW2ldLnJlbmRlckNhbnZhcyhyZW5kZXJlcik7XG4gICAgfVxufTtcblxuXG4vKipcbiAqIFJldHVybnMgdGhlIGZyYW1pbmcgcmVjdGFuZ2xlIG9mIHRoZSBzcHJpdGUgYXMgYSBSZWN0YW5nbGUgb2JqZWN0XG4qXG4gKiBAcmV0dXJuIHtSZWN0YW5nbGV9IHRoZSBmcmFtaW5nIHJlY3RhbmdsZVxuICovXG5UaWxpbmdTcHJpdGUucHJvdG90eXBlLmdldEJvdW5kcyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgd2lkdGggPSB0aGlzLl93aWR0aDtcbiAgICB2YXIgaGVpZ2h0ID0gdGhpcy5faGVpZ2h0O1xuXG4gICAgdmFyIHcwID0gd2lkdGggKiAoMS10aGlzLmFuY2hvci54KTtcbiAgICB2YXIgdzEgPSB3aWR0aCAqIC10aGlzLmFuY2hvci54O1xuXG4gICAgdmFyIGgwID0gaGVpZ2h0ICogKDEtdGhpcy5hbmNob3IueSk7XG4gICAgdmFyIGgxID0gaGVpZ2h0ICogLXRoaXMuYW5jaG9yLnk7XG5cbiAgICB2YXIgd29ybGRUcmFuc2Zvcm0gPSB0aGlzLndvcmxkVHJhbnNmb3JtO1xuXG4gICAgdmFyIGEgPSB3b3JsZFRyYW5zZm9ybS5hO1xuICAgIHZhciBiID0gd29ybGRUcmFuc2Zvcm0uYjtcbiAgICB2YXIgYyA9IHdvcmxkVHJhbnNmb3JtLmM7XG4gICAgdmFyIGQgPSB3b3JsZFRyYW5zZm9ybS5kO1xuICAgIHZhciB0eCA9IHdvcmxkVHJhbnNmb3JtLnR4O1xuICAgIHZhciB0eSA9IHdvcmxkVHJhbnNmb3JtLnR5O1xuXG4gICAgdmFyIHgxID0gYSAqIHcxICsgYyAqIGgxICsgdHg7XG4gICAgdmFyIHkxID0gZCAqIGgxICsgYiAqIHcxICsgdHk7XG5cbiAgICB2YXIgeDIgPSBhICogdzAgKyBjICogaDEgKyB0eDtcbiAgICB2YXIgeTIgPSBkICogaDEgKyBiICogdzAgKyB0eTtcblxuICAgIHZhciB4MyA9IGEgKiB3MCArIGMgKiBoMCArIHR4O1xuICAgIHZhciB5MyA9IGQgKiBoMCArIGIgKiB3MCArIHR5O1xuXG4gICAgdmFyIHg0ID0gIGEgKiB3MSArIGMgKiBoMCArIHR4O1xuICAgIHZhciB5NCA9ICBkICogaDAgKyBiICogdzEgKyB0eTtcblxuICAgIHZhciBtaW5YLFxuICAgICAgICBtYXhYLFxuICAgICAgICBtaW5ZLFxuICAgICAgICBtYXhZO1xuXG4gICAgbWluWCA9IHgxO1xuICAgIG1pblggPSB4MiA8IG1pblggPyB4MiA6IG1pblg7XG4gICAgbWluWCA9IHgzIDwgbWluWCA/IHgzIDogbWluWDtcbiAgICBtaW5YID0geDQgPCBtaW5YID8geDQgOiBtaW5YO1xuXG4gICAgbWluWSA9IHkxO1xuICAgIG1pblkgPSB5MiA8IG1pblkgPyB5MiA6IG1pblk7XG4gICAgbWluWSA9IHkzIDwgbWluWSA/IHkzIDogbWluWTtcbiAgICBtaW5ZID0geTQgPCBtaW5ZID8geTQgOiBtaW5ZO1xuXG4gICAgbWF4WCA9IHgxO1xuICAgIG1heFggPSB4MiA+IG1heFggPyB4MiA6IG1heFg7XG4gICAgbWF4WCA9IHgzID4gbWF4WCA/IHgzIDogbWF4WDtcbiAgICBtYXhYID0geDQgPiBtYXhYID8geDQgOiBtYXhYO1xuXG4gICAgbWF4WSA9IHkxO1xuICAgIG1heFkgPSB5MiA+IG1heFkgPyB5MiA6IG1heFk7XG4gICAgbWF4WSA9IHkzID4gbWF4WSA/IHkzIDogbWF4WTtcbiAgICBtYXhZID0geTQgPiBtYXhZID8geTQgOiBtYXhZO1xuXG4gICAgdmFyIGJvdW5kcyA9IHRoaXMuX2JvdW5kcztcblxuICAgIGJvdW5kcy54ID0gbWluWDtcbiAgICBib3VuZHMud2lkdGggPSBtYXhYIC0gbWluWDtcblxuICAgIGJvdW5kcy55ID0gbWluWTtcbiAgICBib3VuZHMuaGVpZ2h0ID0gbWF4WSAtIG1pblk7XG5cbiAgICAvLyBzdG9yZSBhIHJlZmVyZW5jZSBzbyB0aGF0IGlmIHRoaXMgZnVuY3Rpb24gZ2V0cyBjYWxsZWQgYWdhaW4gaW4gdGhlIHJlbmRlciBjeWNsZSB3ZSBkbyBub3QgaGF2ZSB0byByZWNhbGN1bGF0ZVxuICAgIHRoaXMuX2N1cnJlbnRCb3VuZHMgPSBib3VuZHM7XG5cbiAgICByZXR1cm4gYm91bmRzO1xufTtcblxuLyoqXG4gKiBXaGVuIHRoZSB0ZXh0dXJlIGlzIHVwZGF0ZWQsIHRoaXMgZXZlbnQgd2lsbCBmaXJlIHRvIHVwZGF0ZSB0aGUgc2NhbGUgYW5kIGZyYW1lXG4gKlxuICogQHBhcmFtIGV2ZW50XG4gKiBAcHJpdmF0ZVxuICovXG5UaWxpbmdTcHJpdGUucHJvdG90eXBlLm9uVGV4dHVyZVVwZGF0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgIC8vIG92ZXJyaWRpbmcgdGhlIHNwcml0ZSB2ZXJzaW9uIG9mIHRoaXMhXG59O1xuXG4vKipcbiAqXG4gKiBAcGFyYW0gZm9yY2VQb3dlck9mVHdvIHtib29sZWFufSBXaGV0aGVyIHdlIHdhbnQgdG8gZm9yY2UgdGhlIHRleHR1cmUgdG8gYmUgYSBwb3dlciBvZiB0d29cbiAqL1xuVGlsaW5nU3ByaXRlLnByb3RvdHlwZS5nZW5lcmF0ZVRpbGluZ1RleHR1cmUgPSBmdW5jdGlvbiAoZm9yY2VQb3dlck9mVHdvKSB7XG4gICAgaWYgKCF0aGlzLnRleHR1cmUuYmFzZVRleHR1cmUuaGFzTG9hZGVkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgdGV4dHVyZSA9IHRoaXMub3JpZ2luYWxUZXh0dXJlIHx8IHRoaXMudGV4dHVyZTtcbiAgICB2YXIgZnJhbWUgPSB0ZXh0dXJlLmZyYW1lO1xuICAgIHZhciB0YXJnZXRXaWR0aCwgdGFyZ2V0SGVpZ2h0O1xuXG4gICAgLy8gIENoZWNrIHRoYXQgdGhlIGZyYW1lIGlzIHRoZSBzYW1lIHNpemUgYXMgdGhlIGJhc2UgdGV4dHVyZS5cbiAgICB2YXIgaXNGcmFtZSA9IGZyYW1lLndpZHRoICE9PSB0ZXh0dXJlLmJhc2VUZXh0dXJlLndpZHRoIHx8IGZyYW1lLmhlaWdodCAhPT0gdGV4dHVyZS5iYXNlVGV4dHVyZS5oZWlnaHQ7XG5cbiAgICB2YXIgbmV3VGV4dHVyZVJlcXVpcmVkID0gZmFsc2U7XG5cbiAgICBpZiAoIWZvcmNlUG93ZXJPZlR3bykge1xuICAgICAgICBpZiAoaXNGcmFtZSkge1xuICAgICAgICAgICAgdGFyZ2V0V2lkdGggPSBmcmFtZS53aWR0aDtcbiAgICAgICAgICAgIHRhcmdldEhlaWdodCA9IGZyYW1lLmhlaWdodDtcblxuICAgICAgICAgICAgbmV3VGV4dHVyZVJlcXVpcmVkID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdGFyZ2V0V2lkdGggPSBjb3JlLnV0aWxzLmdldE5leHRQb3dlck9mVHdvKGZyYW1lLndpZHRoKTtcbiAgICAgICAgdGFyZ2V0SGVpZ2h0ID0gY29yZS51dGlscy5nZXROZXh0UG93ZXJPZlR3byhmcmFtZS5oZWlnaHQpO1xuXG4gICAgICAgIC8vICBJZiB0aGUgQmFzZVRleHR1cmUgZGltZW5zaW9ucyBkb24ndCBtYXRjaCB0aGUgdGV4dHVyZSBmcmFtZSB0aGVuIHdlIG5lZWQgYSBuZXcgdGV4dHVyZSBhbnl3YXkgYmVjYXVzZSBpdCdzIHBhcnQgb2YgYSB0ZXh0dXJlIGF0bGFzXG4gICAgICAgIGlmIChmcmFtZS53aWR0aCAhPT0gdGFyZ2V0V2lkdGggfHwgZnJhbWUuaGVpZ2h0ICE9PSB0YXJnZXRIZWlnaHQgfHwgdGV4dHVyZS5iYXNlVGV4dHVyZS53aWR0aCAhPT0gdGFyZ2V0V2lkdGggfHwgdGV4dHVyZS5iYXNlVGV4dHVyZS5oZWlnaHQgfHwgdGFyZ2V0SGVpZ2h0KSB7XG4gICAgICAgICAgICBuZXdUZXh0dXJlUmVxdWlyZWQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG5ld1RleHR1cmVSZXF1aXJlZCkge1xuICAgICAgICB2YXIgY2FudmFzQnVmZmVyO1xuXG4gICAgICAgIGlmICh0aGlzLnRpbGluZ1RleHR1cmUgJiYgdGhpcy50aWxpbmdUZXh0dXJlLmlzVGlsaW5nKSB7XG4gICAgICAgICAgICBjYW52YXNCdWZmZXIgPSB0aGlzLnRpbGluZ1RleHR1cmUuY2FudmFzQnVmZmVyO1xuICAgICAgICAgICAgY2FudmFzQnVmZmVyLnJlc2l6ZSh0YXJnZXRXaWR0aCwgdGFyZ2V0SGVpZ2h0KTtcbiAgICAgICAgICAgIHRoaXMudGlsaW5nVGV4dHVyZS5iYXNlVGV4dHVyZS53aWR0aCA9IHRhcmdldFdpZHRoO1xuICAgICAgICAgICAgdGhpcy50aWxpbmdUZXh0dXJlLmJhc2VUZXh0dXJlLmhlaWdodCA9IHRhcmdldEhlaWdodDtcbiAgICAgICAgICAgIHRoaXMudGlsaW5nVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBjYW52YXNCdWZmZXIgPSBuZXcgY29yZS5DYW52YXNCdWZmZXIodGFyZ2V0V2lkdGgsIHRhcmdldEhlaWdodCk7XG5cbiAgICAgICAgICAgIHRoaXMudGlsaW5nVGV4dHVyZSA9IGNvcmUuVGV4dHVyZS5mcm9tQ2FudmFzKGNhbnZhc0J1ZmZlci5jYW52YXMpO1xuICAgICAgICAgICAgdGhpcy50aWxpbmdUZXh0dXJlLmNhbnZhc0J1ZmZlciA9IGNhbnZhc0J1ZmZlcjtcbiAgICAgICAgICAgIHRoaXMudGlsaW5nVGV4dHVyZS5pc1RpbGluZyA9IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICBjYW52YXNCdWZmZXIuY29udGV4dC5kcmF3SW1hZ2UodGV4dHVyZS5iYXNlVGV4dHVyZS5zb3VyY2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dHVyZS5jcm9wLngsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dHVyZS5jcm9wLnksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dHVyZS5jcm9wLndpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHR1cmUuY3JvcC5oZWlnaHQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldFdpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldEhlaWdodCk7XG5cbiAgICAgICAgdGhpcy50aWxlU2NhbGVPZmZzZXQueCA9IGZyYW1lLndpZHRoIC8gdGFyZ2V0V2lkdGg7XG4gICAgICAgIHRoaXMudGlsZVNjYWxlT2Zmc2V0LnkgPSBmcmFtZS5oZWlnaHQgLyB0YXJnZXRIZWlnaHQ7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICAvLyAgVE9ETyAtIHN3aXRjaGluZz9cbiAgICAgICAgaWYgKHRoaXMudGlsaW5nVGV4dHVyZSAmJiB0aGlzLnRpbGluZ1RleHR1cmUuaXNUaWxpbmcpIHtcbiAgICAgICAgICAgIC8vIGRlc3Ryb3kgdGhlIHRpbGluZyB0ZXh0dXJlIVxuICAgICAgICAgICAgLy8gVE9ETyBjb3VsZCBzdG9yZSB0aGlzIHNvbWV3aGVyZT9cbiAgICAgICAgICAgIHRoaXMudGlsaW5nVGV4dHVyZS5kZXN0cm95KHRydWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy50aWxlU2NhbGVPZmZzZXQueCA9IDE7XG4gICAgICAgIHRoaXMudGlsZVNjYWxlT2Zmc2V0LnkgPSAxO1xuICAgICAgICB0aGlzLnRpbGluZ1RleHR1cmUgPSB0ZXh0dXJlO1xuICAgIH1cblxuICAgIHRoaXMucmVmcmVzaFRleHR1cmUgPSBmYWxzZTtcblxuICAgIHRoaXMub3JpZ2luYWxUZXh0dXJlID0gdGhpcy50ZXh0dXJlO1xuICAgIHRoaXMudGV4dHVyZSA9IHRoaXMudGlsaW5nVGV4dHVyZTtcblxuICAgIHRoaXMudGlsaW5nVGV4dHVyZS5iYXNlVGV4dHVyZS5fcG93ZXJPZjIgPSB0cnVlO1xufTtcbiIsIi8qKlxuICogQGZpbGUgICAgICAgIE1haW4gZXhwb3J0IG9mIHRoZSBQSVhJIGV4dHJhcyBsaWJyYXJ5XG4gKiBAYXV0aG9yICAgICAgTWF0IEdyb3ZlcyA8bWF0QGdvb2Rib3lkaWdpdGFsLmNvbT5cbiAqIEBjb3B5cmlnaHQgICAyMDEzLTIwMTUgR29vZEJveURpZ2l0YWxcbiAqIEBsaWNlbnNlICAgICB7QGxpbmsgaHR0cHM6Ly9naXRodWIuY29tL0dvb2RCb3lEaWdpdGFsL3BpeGkuanMvYmxvYi9tYXN0ZXIvTElDRU5TRXxNSVQgTGljZW5zZX1cbiAqL1xuXG4vKipcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBNb3ZpZUNsaXA6ICAgICAgcmVxdWlyZSgnLi9Nb3ZpZUNsaXAnKSxcbiAgICBSb3BlOiAgICAgICAgICAgcmVxdWlyZSgnLi9Sb3BlJyksXG4gICAgU3RyaXA6ICAgICAgICAgIHJlcXVpcmUoJy4vU3RyaXAnKSxcbiAgICBUaWxpbmdTcHJpdGU6ICAgcmVxdWlyZSgnLi9UaWxpbmdTcHJpdGUnKVxufTtcbiIsIi8qKlxuICogVGhpcyBpcyB0aGUgYmFzZSBjbGFzcyBmb3IgY3JlYXRpbmcgYSBQSVhJIGZpbHRlci4gQ3VycmVudGx5IG9ubHkgV2ViR0wgc3VwcG9ydHMgZmlsdGVycy5cbiAqIElmIHlvdSB3YW50IHRvIG1ha2UgYSBjdXN0b20gZmlsdGVyIHRoaXMgc2hvdWxkIGJlIHlvdXIgYmFzZSBjbGFzcy5cbiAqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIGZyYWdtZW50U3JjIHtzdHJpbmd8c3RyaW5nW119IFRoZSBmcmFnbWVudCBzb3VyY2UgaW4gYW4gYXJyYXkgb2Ygc3RyaW5ncy5cbiAqIEBwYXJhbSB1bmlmb3JtcyB7b2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgdW5pZm9ybXMgZm9yIHRoaXMgZmlsdGVyLlxuICovXG5mdW5jdGlvbiBBYnN0cmFjdEZpbHRlcihmcmFnbWVudFNyYywgdW5pZm9ybXMpIHtcbiAgICAvKipcbiAgICAgKiBBbiBhcnJheSBvZiBwYXNzZXMgLSBzb21lIGZpbHRlcnMgY29udGFpbiBhIGZldyBzdGVwcyB0aGlzIGFycmF5IHNpbXBseSBzdG9yZXMgdGhlIHN0ZXBzIGluIGEgbGluaWVhciBmYXNoaW9uLlxuICAgICAqIEZvciBleGFtcGxlIHRoZSBibHVyIGZpbHRlciBoYXMgdHdvIHBhc3NlcyBibHVyWCBhbmQgYmx1clkuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtBYnN0cmFjdEZpbHRlcltdfVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5wYXNzZXMgPSBbdGhpc107XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtTaGFkZXJbXX1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuc2hhZGVycyA9IFtdO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMucGFkZGluZyA9IDA7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtvYmplY3R9XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLnVuaWZvcm1zID0gdW5pZm9ybXMgfHwge307XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtzdHJpbmdbXX1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSB0eXBlb2YgZnJhZ21lbnRTcmMgPT09ICdzdHJpbmcnID8gZnJhZ21lbnRTcmMuc3BsaXQoJycpIDogKGZyYWdtZW50U3JjIHx8IFtdKTtcbn1cblxuQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQWJzdHJhY3RGaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IEFic3RyYWN0RmlsdGVyO1xuXG4vKipcbiAqIFN5bmNzIHRoZSB1bmlmb3JtcyBiZXR3ZWVuIHRoZSBjbGFzcyBvYmplY3QgYW5kIHRoZSBzaGFkZXJzLlxuICpcbiAqL1xuQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlLnN5bmNVbmlmb3JtcyA9IGZ1bmN0aW9uICgpIHtcbiAgICBmb3IgKHZhciBpID0gMCwgaiA9IHRoaXMuc2hhZGVycy5sZW5ndGg7IGkgPCBqOyArK2kpIHtcbiAgICAgICAgdGhpcy5zaGFkZXJzW2ldLmRpcnR5ID0gdHJ1ZTtcbiAgICB9XG59O1xuXG4vKlxuQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlLmFwcGx5ID0gZnVuY3Rpb24gKGZyYW1lQnVmZmVyKSB7XG4gICAgLy8gVE9ETyA6KVxufTtcbiovXG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyk7XG5cbi8qKlxuICogVGhlIEFscGhhTWFza0ZpbHRlciBjbGFzcyB1c2VzIHRoZSBwaXhlbCB2YWx1ZXMgZnJvbSB0aGUgc3BlY2lmaWVkIHRleHR1cmUgKGNhbGxlZCB0aGUgZGlzcGxhY2VtZW50IG1hcCkgdG8gcGVyZm9ybSBhIGRpc3BsYWNlbWVudCBvZiBhbiBvYmplY3QuXG4gKiBZb3UgY2FuIHVzZSB0aGlzIGZpbHRlciB0byBhcHBseSBhbGwgbWFub3Igb2YgY3Jhenkgd2FycGluZyBlZmZlY3RzXG4gKiBDdXJyZW50bHkgdGhlIHIgcHJvcGVydHkgb2YgdGhlIHRleHR1cmUgaXMgdXNlZCB0byBvZmZzZXQgdGhlIHggYW5kIHRoZSBnIHByb3BlcnR5IG9mIHRoZSB0ZXh0dXJlIGlzIHVzZWQgdG8gb2Zmc2V0IHRoZSB5LlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHRleHR1cmUge1RleHR1cmV9IFRoZSB0ZXh0dXJlIHVzZWQgZm9yIHRoZSBkaXNwbGFjZW1lbnQgbWFwICogbXVzdCBiZSBwb3dlciBvZiAyIHRleHR1cmUgYXQgdGhlIG1vbWVudFxuICovXG5mdW5jdGlvbiBBbHBoYU1hc2tGaWx0ZXIodGV4dHVyZSkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLl9wb3dlck9mMiA9IHRydWU7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgbWFzazogICAgICAgICAgIHsgdHlwZTogJ3NhbXBsZXIyRCcsICAgIHZhbHVlOiB0ZXh0dXJlIH0sXG4gICAgICAgIG1hcERpbWVuc2lvbnM6ICB7IHR5cGU6ICcyZicsICAgICAgICAgICB2YWx1ZTogeyB4OiAxLCB5OiA1MTEyIH0gfSxcbiAgICAgICAgZGltZW5zaW9uczogICAgIHsgdHlwZTogJzRmdicsICAgICAgICAgIHZhbHVlOiBbMCwgMCwgMCwgMF0gfSxcbiAgICAgICAgb2Zmc2V0OiAgICAgICAgIHsgdHlwZTogJzJmJywgICAgICAgICAgIHZhbHVlOiB7IHg6IDAsIHk6IDAgfSB9XG4gICAgfTtcblxuICAgIGlmICh0ZXh0dXJlLmJhc2VUZXh0dXJlLmhhc0xvYWRlZCkge1xuICAgICAgICB0aGlzLnVuaWZvcm1zLm1hc2sudmFsdWUueCA9IHRleHR1cmUud2lkdGg7XG4gICAgICAgIHRoaXMudW5pZm9ybXMubWFzay52YWx1ZS55ID0gdGV4dHVyZS5oZWlnaHQ7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLmJvdW5kTG9hZGVkRnVuY3Rpb24gPSB0aGlzLm9uVGV4dHVyZUxvYWRlZC5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHRleHR1cmUuYmFzZVRleHR1cmUub24oJ2xvYWRlZCcsIHRoaXMuYm91bmRMb2FkZWRGdW5jdGlvbik7XG4gICAgfVxuXG4gICAgdGhpcy5mcmFnbWVudFNyYyA9IFtcbiAgICAgICAgJ3ByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OycsXG5cbiAgICAgICAgJ3ZhcnlpbmcgdmVjMiB2VGV4dHVyZUNvb3JkOycsXG4gICAgICAgICd2YXJ5aW5nIHZlYzQgdkNvbG9yOycsXG5cbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCBtYXNrOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzIgbWFwRGltZW5zaW9uczsnLFxuICAgICAgICAndW5pZm9ybSB2ZWM0IGRpbWVuc2lvbnM7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBvZmZzZXQ7JyxcblxuICAgICAgICAndm9pZCBtYWluKCkgeycsXG4gICAgICAgICcgICB2ZWMyIG1hcENvcmRzID0gdlRleHR1cmVDb29yZC54eTsnLFxuICAgICAgICAnICAgbWFwQ29yZHMgKz0gKGRpbWVuc2lvbnMuencgKyBvZmZzZXQpLyBkaW1lbnNpb25zLnh5IDsnLFxuICAgICAgICAnICAgbWFwQ29yZHMueSAqPSAtMS4wOycsXG4gICAgICAgICcgICBtYXBDb3Jkcy55ICs9IDEuMDsnLFxuICAgICAgICAnICAgbWFwQ29yZHMgKj0gZGltZW5zaW9ucy54eSAvIG1hcERpbWVuc2lvbnM7JyxcblxuICAgICAgICAnICAgdmVjNCBvcmlnaW5hbCA9ICB0ZXh0dXJlMkQodVNhbXBsZXIsIHZUZXh0dXJlQ29vcmQpOycsXG4gICAgICAgICcgICBmbG9hdCBtYXNrQWxwaGEgPSAgdGV4dHVyZTJEKG1hc2ssIG1hcENvcmRzKS5yOycsXG4gICAgICAgICcgICBvcmlnaW5hbCAqPSBtYXNrQWxwaGE7JyxcbiAgICAgICAgLy8nICAgb3JpZ2luYWwucmdiICo9IG1hc2tBbHBoYTsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gIG9yaWdpbmFsOycsXG4gICAgICAgIC8vJyAgIGdsX0ZyYWdDb2xvciA9IGdsX0ZyYWdDb2xvcjsnLFxuICAgICAgICAnfSdcbiAgICBdO1xufVxuXG5BbHBoYU1hc2tGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuQWxwaGFNYXNrRmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEFscGhhTWFza0ZpbHRlcjtcbm1vZHVsZS5leHBvcnRzID0gQWxwaGFNYXNrRmlsdGVyO1xuXG4vKipcbiAqIFNldHMgdGhlIG1hcCBkaW1lbnNpb25zIHVuaWZvcm1zIHdoZW4gdGhlIHRleHR1cmUgYmVjb21lcyBhdmFpbGFibGUuXG4gKlxuICovXG5BbHBoYU1hc2tGaWx0ZXIucHJvdG90eXBlLm9uVGV4dHVyZUxvYWRlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnVuaWZvcm1zLm1hcERpbWVuc2lvbnMudmFsdWUueCA9IHRoaXMudW5pZm9ybXMubWFzay52YWx1ZS53aWR0aDtcbiAgICB0aGlzLnVuaWZvcm1zLm1hcERpbWVuc2lvbnMudmFsdWUueSA9IHRoaXMudW5pZm9ybXMubWFzay52YWx1ZS5oZWlnaHQ7XG5cbiAgICB0aGlzLnVuaWZvcm1zLm1hc2sudmFsdWUuYmFzZVRleHR1cmUub2ZmKCdsb2FkZWQnLCB0aGlzLmJvdW5kTG9hZGVkRnVuY3Rpb24pO1xufTtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQWxwaGFNYXNrRmlsdGVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSB0ZXh0dXJlIHVzZWQgZm9yIHRoZSBkaXNwbGFjZW1lbnQgbWFwLiBNdXN0IGJlIHBvd2VyIG9mIDIgc2l6ZWQgdGV4dHVyZS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1RleHR1cmV9XG4gICAgICogQG1lbWJlcm9mIEFscGhhTWFza0ZpbHRlciNcbiAgICAgKi9cbiAgICBtYXA6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5tYXNrLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5tYXNrLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIG9mZnNldCB1c2VkIHRvIG1vdmUgdGhlIGRpc3BsYWNlbWVudCBtYXAuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKiBAbWVtYmVyb2YgQWxwaGFNYXNrRmlsdGVyI1xuICAgICAqL1xuICAgIG9mZnNldDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudW5pZm9ybXMub2Zmc2V0LnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLm9mZnNldC52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyk7XG5cbi8qKlxuICogQGF1dGhvciBWaWNvIEB2aWNvY290ZWFcbiAqIG9yaWdpbmFsIHNoYWRlciA6IGh0dHBzOi8vd3d3LnNoYWRlcnRveS5jb20vdmlldy9sc3NHRGogYnkgQG1vdkFYMTNoXG4gKi9cblxuLyoqXG4gKiBBbiBBU0NJSSBmaWx0ZXIuXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBBYnN0cmFjdEZpbHRlclxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbmZ1bmN0aW9uIEFzY2lpRmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgZGltZW5zaW9uczogeyB0eXBlOiAnNGZ2JywgdmFsdWU6IG5ldyBGbG9hdDMyQXJyYXkoWzEwMDAwLCAxMDAsIDEwLCAxMF0pIH0sXG4gICAgICAgIHBpeGVsU2l6ZTogIHsgdHlwZTogJzFmJywgdmFsdWU6IDh9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd1bmlmb3JtIHZlYzQgZGltZW5zaW9uczsnLFxuICAgICAgICAndW5pZm9ybSBmbG9hdCBwaXhlbFNpemU7JyxcbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG5cbiAgICAgICAgJ2Zsb2F0IGNoYXJhY3RlcihmbG9hdCBuLCB2ZWMyIHApJyxcbiAgICAgICAgJ3snLFxuICAgICAgICAnICAgIHAgPSBmbG9vcihwKnZlYzIoNC4wLCAtNC4wKSArIDIuNSk7JyxcbiAgICAgICAgJyAgICBpZiAoY2xhbXAocC54LCAwLjAsIDQuMCkgPT0gcC54ICYmIGNsYW1wKHAueSwgMC4wLCA0LjApID09IHAueSknLFxuICAgICAgICAnICAgIHsnLFxuICAgICAgICAnICAgICAgICBpZiAoaW50KG1vZChuL2V4cDIocC54ICsgNS4wKnAueSksIDIuMCkpID09IDEpIHJldHVybiAxLjA7JyxcbiAgICAgICAgJyAgICB9JyxcbiAgICAgICAgJyAgICByZXR1cm4gMC4wOycsXG4gICAgICAgICd9JyxcblxuICAgICAgICAndm9pZCBtYWluKCknLFxuICAgICAgICAneycsXG4gICAgICAgICcgICAgdmVjMiB1diA9IGdsX0ZyYWdDb29yZC54eTsnLFxuICAgICAgICAnICAgIHZlYzMgY29sID0gdGV4dHVyZTJEKHVTYW1wbGVyLCBmbG9vciggdXYgLyBwaXhlbFNpemUgKSAqIHBpeGVsU2l6ZSAvIGRpbWVuc2lvbnMueHkpLnJnYjsnLFxuXG4gICAgICAgICcgICAgI2lmZGVmIEhBU19HUkVFTlNDUkVFTicsXG4gICAgICAgICcgICAgZmxvYXQgZ3JheSA9IChjb2wuciArIGNvbC5iKS8yLjA7JyxcbiAgICAgICAgJyAgICAjZWxzZScsXG4gICAgICAgICcgICAgZmxvYXQgZ3JheSA9IChjb2wuciArIGNvbC5nICsgY29sLmIpLzMuMDsnLFxuICAgICAgICAnICAgICNlbmRpZicsXG5cbiAgICAgICAgJyAgICBmbG9hdCBuID0gIDY1NTM2LjA7ICAgICAgICAgICAgIC8vIC4nLFxuICAgICAgICAnICAgIGlmIChncmF5ID4gMC4yKSBuID0gNjU2MDAuMDsgICAgLy8gOicsXG4gICAgICAgICcgICAgaWYgKGdyYXkgPiAwLjMpIG4gPSAzMzI3NzIuMDsgICAvLyAqJyxcbiAgICAgICAgJyAgICBpZiAoZ3JheSA+IDAuNCkgbiA9IDE1MjU1MDg2LjA7IC8vIG8nLFxuICAgICAgICAnICAgIGlmIChncmF5ID4gMC41KSBuID0gMjMzODUxNjQuMDsgLy8gJicsXG4gICAgICAgICcgICAgaWYgKGdyYXkgPiAwLjYpIG4gPSAxNTI1MjAxNC4wOyAvLyA4JyxcbiAgICAgICAgJyAgICBpZiAoZ3JheSA+IDAuNykgbiA9IDEzMTk5NDUyLjA7IC8vIEAnLFxuICAgICAgICAnICAgIGlmIChncmF5ID4gMC44KSBuID0gMTE1MTI4MTAuMDsgLy8gIycsXG5cbiAgICAgICAgJyAgICB2ZWMyIHAgPSBtb2QoIHV2IC8gKCBwaXhlbFNpemUgKiAwLjUgKSwgMi4wKSAtIHZlYzIoMS4wKTsnLFxuICAgICAgICAnICAgIGNvbCA9IGNvbCAqIGNoYXJhY3RlcihuLCBwKTsnLFxuXG4gICAgICAgICcgICAgZ2xfRnJhZ0NvbG9yID0gdmVjNChjb2wsIDEuMCk7JyxcbiAgICAgICAgJ30nXG4gICAgXTtcbn1cblxuQXNjaWlGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuQXNjaWlGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQXNjaWlGaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IEFzY2lpRmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhBc2NpaUZpbHRlci5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBUaGUgcGl4ZWwgc2l6ZSB1c2VkIGJ5IHRoZSBmaWx0ZXIuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIEFzY2lpRmlsdGVyI1xuICAgICAqL1xuICAgIHNpemU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5waXhlbFNpemUudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLnBpeGVsU2l6ZS52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyksXG4gICAgQmx1clhGaWx0ZXIgPSByZXF1aXJlKCcuL0JsdXJYRmlsdGVyJyksXG4gICAgQmx1cllGaWx0ZXIgPSByZXF1aXJlKCcuL0JsdXJZRmlsdGVyJyk7XG5cbi8qKlxuICogVGhlIEJsdXJGaWx0ZXIgYXBwbGllcyBhIEdhdXNzaWFuIGJsdXIgdG8gYW4gb2JqZWN0LlxuICogVGhlIHN0cmVuZ3RoIG9mIHRoZSBibHVyIGNhbiBiZSBzZXQgZm9yIHgtIGFuZCB5LWF4aXMgc2VwYXJhdGVseS5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gQmx1ckZpbHRlcigpIHtcbiAgICBBYnN0cmFjdEZpbHRlci5jYWxsKHRoaXMpO1xuXG4gICAgdGhpcy5ibHVyWEZpbHRlciA9IG5ldyBCbHVyWEZpbHRlcigpO1xuICAgIHRoaXMuYmx1cllGaWx0ZXIgPSBuZXcgQmx1cllGaWx0ZXIoKTtcblxuICAgIHRoaXMucGFzc2VzID0gW3RoaXMuYmx1clhGaWx0ZXIsIHRoaXMuYmx1cllGaWx0ZXJdO1xufVxuXG5CbHVyRmlsdGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlKTtcbkJsdXJGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQmx1ckZpbHRlcjtcbm1vZHVsZS5leHBvcnRzID0gQmx1ckZpbHRlcjtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQmx1ckZpbHRlci5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBzdHJlbmd0aCBvZiBib3RoIHRoZSBibHVyWCBhbmQgYmx1clkgcHJvcGVydGllcyBzaW11bHRhbmVvdXNseVxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJPZiBCbHVyRmlsdGVyI1xuICAgICAqIEBkZWZhdWx0IDJcbiAgICAgKi9cbiAgICBibHVyOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuYmx1clhGaWx0ZXIuYmx1cjtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuYmx1clhGaWx0ZXIuYmx1ciA9IHRoaXMuYmx1cllGaWx0ZXIuYmx1ciA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFNldHMgdGhlIHN0cmVuZ3RoIG9mIHRoZSBibHVyWCBwcm9wZXJ0eVxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJPZiBCbHVyRmlsdGVyI1xuICAgICAqIEBkZWZhdWx0IDJcbiAgICAgKi9cbiAgICBibHVyWDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmJsdXJYRmlsdGVyLmJsdXI7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLmJsdXJYRmlsdGVyLmJsdXIgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBzdHJlbmd0aCBvZiB0aGUgYmx1clkgcHJvcGVydHlcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyT2YgQmx1ckZpbHRlciNcbiAgICAgKiBAZGVmYXVsdCAyXG4gICAgICovXG4gICAgYmx1clk6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5ibHVyWUZpbHRlci5ibHVyO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy5ibHVyWUZpbHRlci5ibHVyID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKSxcbiAgICBibHVyRmFjdG9yID0gMSAvIDcwMDA7XG5cbi8qKlxuICogVGhlIEJsdXJYRmlsdGVyIGFwcGxpZXMgYSBob3Jpem9udGFsIEdhdXNzaWFuIGJsdXIgdG8gYW4gb2JqZWN0LlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBCbHVyWEZpbHRlcigpIHtcbiAgICBBYnN0cmFjdEZpbHRlci5jYWxsKHRoaXMpO1xuXG4gICAgLy8gc2V0IHRoZSB1bmlmb3Jtc1xuICAgIHRoaXMudW5pZm9ybXMgPSB7XG4gICAgICAgIGJsdXI6IHsgdHlwZTogJzFmJywgdmFsdWU6IDEgLyA1MTIgfVxuICAgIH07XG5cbiAgICB0aGlzLmZyYWdtZW50U3JjID0gW1xuICAgICAgICAncHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7JyxcblxuICAgICAgICAndmFyeWluZyB2ZWMyIHZUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAndW5pZm9ybSBmbG9hdCBibHVyOycsXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCB1U2FtcGxlcjsnLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICB2ZWM0IHN1bSA9IHZlYzQoMC4wKTsnLFxuXG4gICAgICAgICcgICBzdW0gKz0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCAtIDQuMCpibHVyLCB2VGV4dHVyZUNvb3JkLnkpKSAqIDAuMDU7JyxcbiAgICAgICAgJyAgIHN1bSArPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZlYzIodlRleHR1cmVDb29yZC54IC0gMy4wKmJsdXIsIHZUZXh0dXJlQ29vcmQueSkpICogMC4wOTsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLnggLSAyLjAqYmx1ciwgdlRleHR1cmVDb29yZC55KSkgKiAwLjEyOycsXG4gICAgICAgICcgICBzdW0gKz0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCAtIGJsdXIsIHZUZXh0dXJlQ29vcmQueSkpICogMC4xNTsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLngsIHZUZXh0dXJlQ29vcmQueSkpICogMC4xNjsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLnggKyBibHVyLCB2VGV4dHVyZUNvb3JkLnkpKSAqIDAuMTU7JyxcbiAgICAgICAgJyAgIHN1bSArPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZlYzIodlRleHR1cmVDb29yZC54ICsgMi4wKmJsdXIsIHZUZXh0dXJlQ29vcmQueSkpICogMC4xMjsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLnggKyAzLjAqYmx1ciwgdlRleHR1cmVDb29yZC55KSkgKiAwLjA5OycsXG4gICAgICAgICcgICBzdW0gKz0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCArIDQuMCpibHVyLCB2VGV4dHVyZUNvb3JkLnkpKSAqIDAuMDU7JyxcblxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gc3VtOycsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cbkJsdXJYRmlsdGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlKTtcbkJsdXJYRmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEJsdXJYRmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBCbHVyWEZpbHRlcjtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQmx1clhGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgc3RyZW5ndGggb2YgYm90aCB0aGUgYmx1ci5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgQmx1clhGaWx0ZXIjXG4gICAgICogQGRlZmF1bHQgMlxuICAgICAqL1xuICAgIGJsdXI6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5ibHVyLnZhbHVlIC8gYmx1ckZhY3RvcjtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuYmx1ci52YWx1ZSA9IGJsdXJGYWN0b3IgKiB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuIiwidmFyIEFic3RyYWN0RmlsdGVyID0gcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpLFxuICAgIGJsdXJGYWN0b3IgPSAxIC8gNzAwMDtcblxuLyoqXG4gKiBUaGUgQmx1cllGaWx0ZXIgYXBwbGllcyBhIHZlcnRpY2FsIEdhdXNzaWFuIGJsdXIgdG8gYW4gb2JqZWN0LlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBCbHVyWUZpbHRlcigpIHtcbiAgICBBYnN0cmFjdEZpbHRlci5jYWxsKHRoaXMpO1xuXG4gICAgLy8gc2V0IHRoZSB1bmlmb3Jtc1xuICAgIHRoaXMudW5pZm9ybXMgPSB7XG4gICAgICAgIGJsdXI6IHsgdHlwZTogJzFmJywgdmFsdWU6IDEgLyA1MTIgfVxuICAgIH07XG5cbiAgICB0aGlzLmZyYWdtZW50U3JjID0gW1xuICAgICAgICAncHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7JyxcblxuICAgICAgICAndmFyeWluZyB2ZWMyIHZUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAndW5pZm9ybSBmbG9hdCBibHVyOycsXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCB1U2FtcGxlcjsnLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICB2ZWM0IHN1bSA9IHZlYzQoMC4wKTsnLFxuXG4gICAgICAgICcgICBzdW0gKz0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCwgdlRleHR1cmVDb29yZC55IC0gNC4wKmJsdXIpKSAqIDAuMDU7JyxcbiAgICAgICAgJyAgIHN1bSArPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZlYzIodlRleHR1cmVDb29yZC54LCB2VGV4dHVyZUNvb3JkLnkgLSAzLjAqYmx1cikpICogMC4wOTsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLngsIHZUZXh0dXJlQ29vcmQueSAtIDIuMCpibHVyKSkgKiAwLjEyOycsXG4gICAgICAgICcgICBzdW0gKz0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCwgdlRleHR1cmVDb29yZC55IC0gYmx1cikpICogMC4xNTsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLngsIHZUZXh0dXJlQ29vcmQueSkpICogMC4xNjsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLngsIHZUZXh0dXJlQ29vcmQueSArIGJsdXIpKSAqIDAuMTU7JyxcbiAgICAgICAgJyAgIHN1bSArPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZlYzIodlRleHR1cmVDb29yZC54LCB2VGV4dHVyZUNvb3JkLnkgKyAyLjAqYmx1cikpICogMC4xMjsnLFxuICAgICAgICAnICAgc3VtICs9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLngsIHZUZXh0dXJlQ29vcmQueSArIDMuMCpibHVyKSkgKiAwLjA5OycsXG4gICAgICAgICcgICBzdW0gKz0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCwgdlRleHR1cmVDb29yZC55ICsgNC4wKmJsdXIpKSAqIDAuMDU7JyxcblxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gc3VtOycsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cbkJsdXJZRmlsdGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlKTtcbkJsdXJZRmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEJsdXJZRmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBCbHVyWUZpbHRlcjtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQmx1cllGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgc3RyZW5ndGggb2YgYm90aCB0aGUgYmx1ci5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgQmx1cllGaWx0ZXJcbiAgICAgKiBAZGVmYXVsdCAyXG4gICAgICovXG4gICAgYmx1cjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmJsdXIudmFsdWUgLyBibHVyRmFjdG9yO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgLy90aGlzLnBhZGRpbmcgPSB2YWx1ZTtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuYmx1ci52YWx1ZSA9IGJsdXJGYWN0b3IgKiB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuIiwidmFyIEFic3RyYWN0RmlsdGVyID0gcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpO1xuXG4vKipcbiAqIFRoZSBDb2xvck1hdHJpeEZpbHRlciBjbGFzcyBsZXRzIHlvdSBhcHBseSBhIDR4NCBtYXRyaXggdHJhbnNmb3JtYXRpb24gb24gdGhlIFJHQkFcbiAqIGNvbG9yIGFuZCBhbHBoYSB2YWx1ZXMgb2YgZXZlcnkgcGl4ZWwgb24geW91ciBkaXNwbGF5T2JqZWN0IHRvIHByb2R1Y2UgYSByZXN1bHRcbiAqIHdpdGggYSBuZXcgc2V0IG9mIFJHQkEgY29sb3IgYW5kIGFscGhhIHZhbHVlcy4gSXQncyBwcmV0dHkgcG93ZXJmdWwhXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBBYnN0cmFjdEZpbHRlclxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbmZ1bmN0aW9uIENvbG9yTWF0cml4RmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgbWF0cml4OiB7IHR5cGU6ICdtYXQ0JywgdmFsdWU6IFsxLCAwLCAwLCAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDAsIDEsIDAsIDAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMCwgMCwgMSwgMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAwLCAwLCAwLCAxXSB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IGludmVydDsnLFxuICAgICAgICAndW5pZm9ybSBtYXQ0IG1hdHJpeDsnLFxuICAgICAgICAndW5pZm9ybSBzYW1wbGVyMkQgdVNhbXBsZXI7JyxcblxuICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkKSAqIG1hdHJpeDsnLFxuICAgICAgICAnfSdcbiAgICBdO1xufVxuXG5Db2xvck1hdHJpeEZpbHRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEFic3RyYWN0RmlsdGVyLnByb3RvdHlwZSk7XG5Db2xvck1hdHJpeEZpbHRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDb2xvck1hdHJpeEZpbHRlcjtcbm1vZHVsZS5leHBvcnRzID0gQ29sb3JNYXRyaXhGaWx0ZXI7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKENvbG9yTWF0cml4RmlsdGVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFNldHMgdGhlIG1hdHJpeCBvZiB0aGUgY29sb3IgbWF0cml4IGZpbHRlclxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyW119XG4gICAgICogQG1lbWJlcm9mIENvbG9yTWF0cml4RmlsdGVyI1xuICAgICAqIEBkZWZhdWx0IFsxLCAwLCAwLCAwLCAwLCAxLCAwLCAwLCAwLCAwLCAxLCAwLCAwLCAwLCAwLCAxXVxuICAgICAqL1xuICAgIG1hdHJpeDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLm1hdHJpeC52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMubWF0cml4LnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKTtcblxuLyoqXG4gKiBUaGlzIGxvd2VycyB0aGUgY29sb3IgZGVwdGggb2YgeW91ciBpbWFnZSBieSB0aGUgZ2l2ZW4gYW1vdW50LCBwcm9kdWNpbmcgYW4gaW1hZ2Ugd2l0aCBhIHNtYWxsZXIgcGFsZXR0ZS5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gQ29sb3JTdGVwRmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgc3RlcDogeyB0eXBlOiAnMWYnLCB2YWx1ZTogNSB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuICAgICAgICAndmFyeWluZyB2ZWMyIHZUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IHN0ZXA7JyxcblxuICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAnICAgdmVjNCBjb2xvciA9IHRleHR1cmUyRCh1U2FtcGxlciwgdlRleHR1cmVDb29yZCk7JyxcbiAgICAgICAgJyAgIGNvbG9yID0gZmxvb3IoY29sb3IgKiBzdGVwKSAvIHN0ZXA7JyxcbiAgICAgICAgJyAgIGdsX0ZyYWdDb2xvciA9IGNvbG9yOycsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cbkNvbG9yU3RlcEZpbHRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEFic3RyYWN0RmlsdGVyLnByb3RvdHlwZSk7XG5Db2xvclN0ZXBGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQ29sb3JTdGVwRmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBDb2xvclN0ZXBGaWx0ZXI7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKENvbG9yU3RlcEZpbHRlci5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBUaGUgbnVtYmVyIG9mIHN0ZXBzIHRvIHJlZHVjZSB0aGUgcGFsZXR0ZSBieS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgQ29sb3JTdGVwRmlsdGVyI1xuICAgICAqL1xuICAgIHN0ZXA6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5zdGVwLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5zdGVwLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKTtcblxuLyoqXG4gKiBUaGUgQ29udm9sdXRpb25GaWx0ZXIgY2xhc3MgYXBwbGllcyBhIG1hdHJpeCBjb252b2x1dGlvbiBmaWx0ZXIgZWZmZWN0LlxuICogQSBjb252b2x1dGlvbiBjb21iaW5lcyBwaXhlbHMgaW4gdGhlIGlucHV0IGltYWdlIHdpdGggbmVpZ2hib3JpbmcgcGl4ZWxzIHRvIHByb2R1Y2UgYSBuZXcgaW1hZ2UuXG4gKiBBIHdpZGUgdmFyaWV0eSBvZiBpbWFnZSBlZmZlY3RzIGNhbiBiZSBhY2hpZXZlZCB0aHJvdWdoIGNvbnZvbHV0aW9ucywgaW5jbHVkaW5nIGJsdXJyaW5nLCBlZGdlXG4gKiBkZXRlY3Rpb24sIHNoYXJwZW5pbmcsIGVtYm9zc2luZywgYW5kIGJldmVsaW5nLiBUaGUgbWF0cml4IHNob3VsZCBiZSBzcGVjaWZpZWQgYXMgYSA5IHBvaW50IEFycmF5LlxuICogU2VlIGh0dHA6Ly9kb2NzLmdpbXAub3JnL2VuL3BsdWctaW4tY29udm1hdHJpeC5odG1sIGZvciBtb3JlIGluZm8uXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBBYnN0cmFjdEZpbHRlclxuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gbWF0cml4IHtudW1iZXJbXX0gQW4gYXJyYXkgb2YgdmFsdWVzIHVzZWQgZm9yIG1hdHJpeCB0cmFuc2Zvcm1hdGlvbi4gU3BlY2lmaWVkIGFzIGEgOSBwb2ludCBBcnJheS5cbiAqIEBwYXJhbSB3aWR0aCB7bnVtYmVyfSBXaWR0aCBvZiB0aGUgb2JqZWN0IHlvdSBhcmUgdHJhbnNmb3JtaW5nXG4gKiBAcGFyYW0gaGVpZ2h0IHtudW1iZXJ9IEhlaWdodCBvZiB0aGUgb2JqZWN0IHlvdSBhcmUgdHJhbnNmb3JtaW5nXG4gKi9cbmZ1bmN0aW9uIENvbnZvbHV0aW9uRmlsdGVyKG1hdHJpeCwgd2lkdGgsIGhlaWdodCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgbWF0cml4OiAgICAgeyB0eXBlOiAnMWZ2JywgdmFsdWU6IG5ldyBGbG9hdDMyQXJyYXkobWF0cml4KSB9LFxuICAgICAgICB0ZXhlbFNpemVYOiB7IHR5cGU6ICcxZicsIHZhbHVlOiAxIC8gd2lkdGggfSxcbiAgICAgICAgdGV4ZWxTaXplWTogeyB0eXBlOiAnMWYnLCB2YWx1ZTogMSAvIGhlaWdodCB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIG1lZGl1bXAgdmVjMiB2VGV4dHVyZUNvb3JkOycsXG5cbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHRleHR1cmU7JyxcbiAgICAgICAgJ3VuaWZvcm0gZmxvYXQgdGV4ZWxTaXplWDsnLFxuICAgICAgICAndW5pZm9ybSBmbG9hdCB0ZXhlbFNpemVZOycsXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IG1hdHJpeFs5XTsnLFxuXG4gICAgICAgICd2ZWMyIHB4ID0gdmVjMih0ZXhlbFNpemVYLCB0ZXhlbFNpemVZKTsnLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICB2ZWM0IGMxMSA9IHRleHR1cmUyRCh0ZXh0dXJlLCB2VGV4dHVyZUNvb3JkIC0gcHgpOycsIC8vIHRvcCBsZWZ0XG4gICAgICAgICcgICB2ZWM0IGMxMiA9IHRleHR1cmUyRCh0ZXh0dXJlLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCwgdlRleHR1cmVDb29yZC55IC0gcHgueSkpOycsIC8vIHRvcCBjZW50ZXJcbiAgICAgICAgJyAgIHZlYzQgYzEzID0gdGV4dHVyZTJEKHRleHR1cmUsIHZlYzIodlRleHR1cmVDb29yZC54ICsgcHgueCwgdlRleHR1cmVDb29yZC55IC0gcHgueSkpOycsIC8vIHRvcCByaWdodFxuXG4gICAgICAgICcgICB2ZWM0IGMyMSA9IHRleHR1cmUyRCh0ZXh0dXJlLCB2ZWMyKHZUZXh0dXJlQ29vcmQueCAtIHB4LngsIHZUZXh0dXJlQ29vcmQueSkgKTsnLCAvLyBtaWQgbGVmdFxuICAgICAgICAnICAgdmVjNCBjMjIgPSB0ZXh0dXJlMkQodGV4dHVyZSwgdlRleHR1cmVDb29yZCk7JywgLy8gbWlkIGNlbnRlclxuICAgICAgICAnICAgdmVjNCBjMjMgPSB0ZXh0dXJlMkQodGV4dHVyZSwgdmVjMih2VGV4dHVyZUNvb3JkLnggKyBweC54LCB2VGV4dHVyZUNvb3JkLnkpICk7JywgLy8gbWlkIHJpZ2h0XG5cbiAgICAgICAgJyAgIHZlYzQgYzMxID0gdGV4dHVyZTJEKHRleHR1cmUsIHZlYzIodlRleHR1cmVDb29yZC54IC0gcHgueCwgdlRleHR1cmVDb29yZC55ICsgcHgueSkgKTsnLCAvLyBib3R0b20gbGVmdFxuICAgICAgICAnICAgdmVjNCBjMzIgPSB0ZXh0dXJlMkQodGV4dHVyZSwgdmVjMih2VGV4dHVyZUNvb3JkLngsIHZUZXh0dXJlQ29vcmQueSArIHB4LnkpICk7JywgLy8gYm90dG9tIGNlbnRlclxuICAgICAgICAnICAgdmVjNCBjMzMgPSB0ZXh0dXJlMkQodGV4dHVyZSwgdlRleHR1cmVDb29yZCArIHB4ICk7JywgLy8gYm90dG9tIHJpZ2h0XG5cbiAgICAgICAgJyAgIGdsX0ZyYWdDb2xvciA9ICcsXG4gICAgICAgICcgICAgICAgYzExICogbWF0cml4WzBdICsgYzEyICogbWF0cml4WzFdICsgYzEzICogbWF0cml4WzJdICsnLFxuICAgICAgICAnICAgICAgIGMyMSAqIG1hdHJpeFszXSArIGMyMiAqIG1hdHJpeFs0XSArIGMyMyAqIG1hdHJpeFs1XSArJyxcbiAgICAgICAgJyAgICAgICBjMzEgKiBtYXRyaXhbNl0gKyBjMzIgKiBtYXRyaXhbN10gKyBjMzMgKiBtYXRyaXhbOF07JyxcbiAgICAgICAgJyAgIGdsX0ZyYWdDb2xvci5hID0gYzIyLmE7JyxcbiAgICAgICAgJ30nXG4gICAgXTtcbn1cblxuQ29udm9sdXRpb25GaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuQ29udm9sdXRpb25GaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQ29udm9sdXRpb25GaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IENvbnZvbHV0aW9uRmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhDb252b2x1dGlvbkZpbHRlci5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBBbiBhcnJheSBvZiB2YWx1ZXMgdXNlZCBmb3IgbWF0cml4IHRyYW5zZm9ybWF0aW9uLiBTcGVjaWZpZWQgYXMgYSA5IHBvaW50IEFycmF5LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyW119XG4gICAgICogQG1lbWJlcm9mIENvbnZvbHV0aW9uRmlsdGVyI1xuICAgICAqL1xuICAgIG1hdHJpeDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLm1hdHJpeC52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMubWF0cml4LnZhbHVlID0gbmV3IEZsb2F0MzJBcnJheSh2YWx1ZSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogV2lkdGggb2YgdGhlIG9iamVjdCB5b3UgYXJlIHRyYW5zZm9ybWluZ1xuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBDb252b2x1dGlvbkZpbHRlciNcbiAgICAgKi9cbiAgICB3aWR0aDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLnRleGVsU2l6ZVgudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLnRleGVsU2l6ZVgudmFsdWUgPSAxL3ZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEhlaWdodCBvZiB0aGUgb2JqZWN0IHlvdSBhcmUgdHJhbnNmb3JtaW5nXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIENvbnZvbHV0aW9uRmlsdGVyI1xuICAgICAqL1xuICAgIGhlaWdodDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLnRleGVsU2l6ZVkudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLnRleGVsU2l6ZVkudmFsdWUgPSAxL3ZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyk7XG5cbi8qKlxuICogQSBDcm9zcyBIYXRjaCBlZmZlY3QgZmlsdGVyLlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBDcm9zc0hhdGNoRmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgYmx1cjogeyB0eXBlOiAnMWYnLCB2YWx1ZTogMSAvIDUxMiB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IGJsdXI7JyxcbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG5cbiAgICAgICAgJ3ZvaWQgbWFpbih2b2lkKSB7JyxcbiAgICAgICAgJyAgICBmbG9hdCBsdW0gPSBsZW5ndGgodGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkLnh5KS5yZ2IpOycsXG5cbiAgICAgICAgJyAgICBnbF9GcmFnQ29sb3IgPSB2ZWM0KDEuMCwgMS4wLCAxLjAsIDEuMCk7JyxcblxuICAgICAgICAnICAgIGlmIChsdW0gPCAxLjAwKSB7JyxcbiAgICAgICAgJyAgICAgICAgaWYgKG1vZChnbF9GcmFnQ29vcmQueCArIGdsX0ZyYWdDb29yZC55LCAxMC4wKSA9PSAwLjApIHsnLFxuICAgICAgICAnICAgICAgICAgICAgZ2xfRnJhZ0NvbG9yID0gdmVjNCgwLjAsIDAuMCwgMC4wLCAxLjApOycsXG4gICAgICAgICcgICAgICAgIH0nLFxuICAgICAgICAnICAgIH0nLFxuXG4gICAgICAgICcgICAgaWYgKGx1bSA8IDAuNzUpIHsnLFxuICAgICAgICAnICAgICAgICBpZiAobW9kKGdsX0ZyYWdDb29yZC54IC0gZ2xfRnJhZ0Nvb3JkLnksIDEwLjApID09IDAuMCkgeycsXG4gICAgICAgICcgICAgICAgICAgICBnbF9GcmFnQ29sb3IgPSB2ZWM0KDAuMCwgMC4wLCAwLjAsIDEuMCk7JyxcbiAgICAgICAgJyAgICAgICAgfScsXG4gICAgICAgICcgICAgfScsXG5cbiAgICAgICAgJyAgICBpZiAobHVtIDwgMC41MCkgeycsXG4gICAgICAgICcgICAgICAgIGlmIChtb2QoZ2xfRnJhZ0Nvb3JkLnggKyBnbF9GcmFnQ29vcmQueSAtIDUuMCwgMTAuMCkgPT0gMC4wKSB7JyxcbiAgICAgICAgJyAgICAgICAgICAgIGdsX0ZyYWdDb2xvciA9IHZlYzQoMC4wLCAwLjAsIDAuMCwgMS4wKTsnLFxuICAgICAgICAnICAgICAgICB9JyxcbiAgICAgICAgJyAgICB9JyxcblxuICAgICAgICAnICAgIGlmIChsdW0gPCAwLjMpIHsnLFxuICAgICAgICAnICAgICAgICBpZiAobW9kKGdsX0ZyYWdDb29yZC54IC0gZ2xfRnJhZ0Nvb3JkLnkgLSA1LjAsIDEwLjApID09IDAuMCkgeycsXG4gICAgICAgICcgICAgICAgICAgICBnbF9GcmFnQ29sb3IgPSB2ZWM0KDAuMCwgMC4wLCAwLjAsIDEuMCk7JyxcbiAgICAgICAgJyAgICAgICAgfScsXG4gICAgICAgICcgICAgfScsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cbkNyb3NzSGF0Y2hGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuQ3Jvc3NIYXRjaEZpbHRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDcm9zc0hhdGNoRmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBDcm9zc0hhdGNoRmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhDcm9zc0hhdGNoRmlsdGVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFNldHMgdGhlIHN0cmVuZ3RoIG9mIGJvdGggdGhlIGJsdXIuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIENyb3NzSGF0Y2hGaWx0ZXIjXG4gICAgICogQGRlZmF1bHQgMlxuICAgICAqL1xuICAgIGJsdXI6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5ibHVyLnZhbHVlIC8gKDEvNzAwMCk7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICAvL3RoaXMucGFkZGluZyA9IHZhbHVlO1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5ibHVyLnZhbHVlID0gKDEvNzAwMCkgKiB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuIiwidmFyIEFic3RyYWN0RmlsdGVyID0gcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpO1xuXG4vKipcbiAqIFRoZSBEaXNwbGFjZW1lbnRGaWx0ZXIgY2xhc3MgdXNlcyB0aGUgcGl4ZWwgdmFsdWVzIGZyb20gdGhlIHNwZWNpZmllZCB0ZXh0dXJlIChjYWxsZWQgdGhlIGRpc3BsYWNlbWVudCBtYXApIHRvIHBlcmZvcm0gYSBkaXNwbGFjZW1lbnQgb2YgYW4gb2JqZWN0LlxuICogWW91IGNhbiB1c2UgdGhpcyBmaWx0ZXIgdG8gYXBwbHkgYWxsIG1hbm9yIG9mIGNyYXp5IHdhcnBpbmcgZWZmZWN0c1xuICogQ3VycmVudGx5IHRoZSByIHByb3BlcnR5IG9mIHRoZSB0ZXh0dXJlIGlzIHVzZWQgb2Zmc2V0IHRoZSB4IGFuZCB0aGUgZyBwcm9wZXJ0eSBvZiB0aGUgdGV4dHVyZSBpcyB1c2VkIHRvIG9mZnNldCB0aGUgeS5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSB0ZXh0dXJlIHtUZXh0dXJlfSBUaGUgdGV4dHVyZSB1c2VkIGZvciB0aGUgZGlzcGxhY2VtZW50IG1hcCAqIG11c3QgYmUgcG93ZXIgb2YgMiB0ZXh0dXJlIGF0IHRoZSBtb21lbnRcbiAqL1xuZnVuY3Rpb24gRGlzcGxhY2VtZW50RmlsdGVyKHRleHR1cmUpIHtcbiAgICBBYnN0cmFjdEZpbHRlci5jYWxsKHRoaXMpO1xuXG4gICAgdGV4dHVyZS5iYXNlVGV4dHVyZS5fcG93ZXJPZjIgPSB0cnVlO1xuXG4gICAgLy8gc2V0IHRoZSB1bmlmb3Jtc1xuICAgIHRoaXMudW5pZm9ybXMgPSB7XG4gICAgICAgIGRpc3BsYWNlbWVudE1hcDogeyB0eXBlOiAnc2FtcGxlcjJEJywgdmFsdWU6IHRleHR1cmUgfSxcbiAgICAgICAgc2NhbGU6ICAgICAgICAgICB7IHR5cGU6ICcyZicsICB2YWx1ZTogeyB4OiAzMCwgeTogMzAgfSB9LFxuICAgICAgICBvZmZzZXQ6ICAgICAgICAgIHsgdHlwZTogJzJmJywgIHZhbHVlOiB7IHg6IDAsICB5OiAwIH0gfSxcbiAgICAgICAgbWFwRGltZW5zaW9uczogICB7IHR5cGU6ICcyZicsICB2YWx1ZTogeyB4OiAxLCAgeTogNTExMiB9IH0sXG4gICAgICAgIGRpbWVuc2lvbnM6ICAgICAgeyB0eXBlOiAnNGZ2JywgdmFsdWU6IFswLCAwLCAwLCAwXSB9XG4gICAgfTtcblxuICAgIGlmICh0ZXh0dXJlLmJhc2VUZXh0dXJlLmhhc0xvYWRlZCkge1xuICAgICAgICB0aGlzLm9uVGV4dHVyZUxvYWRlZCgpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdGhpcy5ib3VuZExvYWRlZEZ1bmN0aW9uID0gdGhpcy5vblRleHR1cmVMb2FkZWQuYmluZCh0aGlzKTtcblxuICAgICAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLm9uKCdsb2FkZWQnLCB0aGlzLmJvdW5kTG9hZGVkRnVuY3Rpb24pO1xuICAgIH1cblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCBkaXNwbGFjZW1lbnRNYXA7JyxcbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzIgc2NhbGU7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBvZmZzZXQ7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjNCBkaW1lbnNpb25zOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzIgbWFwRGltZW5zaW9uczsnLC8vID0gdmVjMigyNTYuMCwgMjU2LjApOycsXG4gICAgICAgIC8vICdjb25zdCB2ZWMyIHRleHR1cmVEaW1lbnNpb25zID0gdmVjMig3NTAuMCwgNzUwLjApOycsXG5cbiAgICAgICAgJ3ZvaWQgbWFpbih2b2lkKSB7JyxcbiAgICAgICAgJyAgIHZlYzIgbWFwQ29yZHMgPSB2VGV4dHVyZUNvb3JkLnh5OycsXG4gICAgICAgICcgICBtYXBDb3JkcyArPSAoZGltZW5zaW9ucy56dyArIG9mZnNldCkvIGRpbWVuc2lvbnMueHkgOycsXG4gICAgICAgICcgICBtYXBDb3Jkcy55ICo9IC0xLjA7JyxcbiAgICAgICAgJyAgIG1hcENvcmRzLnkgKz0gMS4wOycsXG5cbiAgICAgICAgJyAgIHZlYzIgbWF0U2FtcGxlID0gdGV4dHVyZTJEKGRpc3BsYWNlbWVudE1hcCwgbWFwQ29yZHMpLnh5OycsXG4gICAgICAgICcgICBtYXRTYW1wbGUgLT0gMC41OycsXG4gICAgICAgICcgICBtYXRTYW1wbGUgKj0gc2NhbGU7JyxcbiAgICAgICAgJyAgIG1hdFNhbXBsZSAvPSBtYXBEaW1lbnNpb25zOycsXG5cbiAgICAgICAgJyAgIGdsX0ZyYWdDb2xvciA9IHRleHR1cmUyRCh1U2FtcGxlciwgdmVjMih2VGV4dHVyZUNvb3JkLnggKyBtYXRTYW1wbGUueCwgdlRleHR1cmVDb29yZC55ICsgbWF0U2FtcGxlLnkpKTsnLFxuXG4gICAgICAgIC8vVE9ETzogSXMgdGhpcyBuZWVkZWQ/XG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IucmdiID0gbWl4KCBnbF9GcmFnQ29sb3IucmdiLCBnbF9GcmFnQ29sb3IucmdiLCAxLjApOycsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cbkRpc3BsYWNlbWVudEZpbHRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEFic3RyYWN0RmlsdGVyLnByb3RvdHlwZSk7XG5EaXNwbGFjZW1lbnRGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gRGlzcGxhY2VtZW50RmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBEaXNwbGFjZW1lbnRGaWx0ZXI7XG5cbi8qKlxuICogU2V0cyB0aGUgbWFwIGRpbWVuc2lvbnMgdW5pZm9ybXMgd2hlbiB0aGUgdGV4dHVyZSBiZWNvbWVzIGF2YWlsYWJsZS5cbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5EaXNwbGFjZW1lbnRGaWx0ZXIucHJvdG90eXBlLm9uVGV4dHVyZUxvYWRlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnVuaWZvcm1zLm1hcERpbWVuc2lvbnMudmFsdWUueCA9IHRoaXMudW5pZm9ybXMuZGlzcGxhY2VtZW50TWFwLnZhbHVlLndpZHRoO1xuICAgIHRoaXMudW5pZm9ybXMubWFwRGltZW5zaW9ucy52YWx1ZS55ID0gdGhpcy51bmlmb3Jtcy5kaXNwbGFjZW1lbnRNYXAudmFsdWUuaGVpZ2h0O1xuXG4gICAgdGhpcy51bmlmb3Jtcy5kaXNwbGFjZW1lbnRNYXAudmFsdWUuYmFzZVRleHR1cmUub2ZmKCdsb2FkZWQnLCB0aGlzLmJvdW5kTG9hZGVkRnVuY3Rpb24pO1xufTtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoRGlzcGxhY2VtZW50RmlsdGVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSB0ZXh0dXJlIHVzZWQgZm9yIHRoZSBkaXNwbGFjZW1lbnQgbWFwLiBNdXN0IGJlIHBvd2VyIG9mIDIgdGV4dHVyZS5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1RleHR1cmV9XG4gICAgICogQG1lbWJlcm9mIERpc3BsYWNlbWVudEZpbHRlciNcbiAgICAgKi9cbiAgICBtYXA6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5kaXNwbGFjZW1lbnRNYXAudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLmRpc3BsYWNlbWVudE1hcC52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBtdWx0aXBsaWVyIHVzZWQgdG8gc2NhbGUgdGhlIGRpc3BsYWNlbWVudCByZXN1bHQgZnJvbSB0aGUgbWFwIGNhbGN1bGF0aW9uLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICogQG1lbWJlcm9mIERpc3BsYWNlbWVudEZpbHRlciNcbiAgICAgKi9cbiAgICBzY2FsZToge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLnNjYWxlLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5zY2FsZS52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBvZmZzZXQgdXNlZCB0byBtb3ZlIHRoZSBkaXNwbGFjZW1lbnQgbWFwLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICogQG1lbWJlcm9mIERpc3BsYWNlbWVudEZpbHRlciNcbiAgICAgKi9cbiAgICBvZmZzZXQ6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5vZmZzZXQudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLm9mZnNldC52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyk7XG5cbi8qKlxuICogQGF1dGhvciBNYXQgR3JvdmVzIGh0dHA6Ly9tYXRncm92ZXMuY29tLyBARG9vcm1hdDIzXG4gKiBvcmlnaW5hbCBmaWx0ZXI6IGh0dHBzOi8vZ2l0aHViLmNvbS9ldmFudy9nbGZ4LmpzL2Jsb2IvbWFzdGVyL3NyYy9maWx0ZXJzL2Z1bi9kb3RzY3JlZW4uanNcbiAqL1xuXG4vKipcbiAqIFRoaXMgZmlsdGVyIGFwcGxpZXMgYSBkb3RzY3JlZW4gZWZmZWN0IG1ha2luZyBkaXNwbGF5IG9iamVjdHMgYXBwZWFyIHRvIGJlIG1hZGUgb3V0IG9mXG4gKiBibGFjayBhbmQgd2hpdGUgaGFsZnRvbmUgZG90cyBsaWtlIGFuIG9sZCBwcmludGVyLlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBEb3RTY3JlZW5GaWx0ZXIoKSB7XG4gICAgQWJzdHJhY3RGaWx0ZXIuY2FsbCh0aGlzKTtcblxuICAgIC8vIHNldCB0aGUgdW5pZm9ybXNcbiAgICB0aGlzLnVuaWZvcm1zID0ge1xuICAgICAgICBzY2FsZTogICAgICB7IHR5cGU6ICcxZicsIHZhbHVlOiAxIH0sXG4gICAgICAgIGFuZ2xlOiAgICAgIHsgdHlwZTogJzFmJywgdmFsdWU6IDUgfSxcbiAgICAgICAgZGltZW5zaW9uczogeyB0eXBlOiAnNGZ2JywgdmFsdWU6IFswLCAwLCAwLCAwXSB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIHZlYzQgZGltZW5zaW9uczsnLFxuICAgICAgICAndW5pZm9ybSBzYW1wbGVyMkQgdVNhbXBsZXI7JyxcblxuICAgICAgICAndW5pZm9ybSBmbG9hdCBhbmdsZTsnLFxuICAgICAgICAndW5pZm9ybSBmbG9hdCBzY2FsZTsnLFxuXG4gICAgICAgICdmbG9hdCBwYXR0ZXJuKCkgeycsXG4gICAgICAgICcgICBmbG9hdCBzID0gc2luKGFuZ2xlKSwgYyA9IGNvcyhhbmdsZSk7JyxcbiAgICAgICAgJyAgIHZlYzIgdGV4ID0gdlRleHR1cmVDb29yZCAqIGRpbWVuc2lvbnMueHk7JyxcbiAgICAgICAgJyAgIHZlYzIgcG9pbnQgPSB2ZWMyKCcsXG4gICAgICAgICcgICAgICAgYyAqIHRleC54IC0gcyAqIHRleC55LCcsXG4gICAgICAgICcgICAgICAgcyAqIHRleC54ICsgYyAqIHRleC55JyxcbiAgICAgICAgJyAgICkgKiBzY2FsZTsnLFxuICAgICAgICAnICAgcmV0dXJuIChzaW4ocG9pbnQueCkgKiBzaW4ocG9pbnQueSkpICogNC4wOycsXG4gICAgICAgICd9JyxcblxuICAgICAgICAndm9pZCBtYWluKCkgeycsXG4gICAgICAgICcgICB2ZWM0IGNvbG9yID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkKTsnLFxuICAgICAgICAnICAgZmxvYXQgYXZlcmFnZSA9IChjb2xvci5yICsgY29sb3IuZyArIGNvbG9yLmIpIC8gMy4wOycsXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IgPSB2ZWM0KHZlYzMoYXZlcmFnZSAqIDEwLjAgLSA1LjAgKyBwYXR0ZXJuKCkpLCBjb2xvci5hKTsnLFxuICAgICAgICAnfSdcbiAgICBdO1xufVxuXG5Eb3RTY3JlZW5GaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuRG90U2NyZWVuRmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IERvdFNjcmVlbkZpbHRlcjtcbm1vZHVsZS5leHBvcnRzID0gRG90U2NyZWVuRmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhEb3RTY3JlZW5GaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHNjYWxlIG9mIHRoZSBlZmZlY3QuXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBEb3RTY3JlZW5GaWx0ZXIjXG4gICAgICovXG4gICAgc2NhbGU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5zY2FsZS52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuc2NhbGUudmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgcmFkaXVzIG9mIHRoZSBlZmZlY3QuXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBEb3RTY3JlZW5GaWx0ZXIjXG4gICAgICovXG4gICAgYW5nbGU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5hbmdsZS52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuYW5nbGUudmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuIiwiLyoqXG4gKiBBIHRhcmdldCBhbmQgcGFzcyBpbmZvIG9iamVjdCBmb3IgZmlsdGVycy5cbiAqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBGaWx0ZXJCbG9jaygpIHtcbiAgICAvKipcbiAgICAgKiBUaGUgdmlzaWJsZSBzdGF0ZSBvZiB0aGlzIEZpbHRlckJsb2NrLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLnZpc2libGUgPSB0cnVlO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHJlbmRlcmFibGUgc3RhdGUgb2YgdGhpcyBGaWx0ZXJCbG9jay5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5yZW5kZXJhYmxlID0gdHJ1ZTtcbn1cblxuRmlsdGVyQmxvY2sucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gRmlsdGVyQmxvY2s7XG5tb2R1bGUuZXhwb3J0cyA9IEZpbHRlckJsb2NrO1xuIiwidmFyIEFic3RyYWN0RmlsdGVyID0gcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpO1xuXG4vKipcbiAqIFRoaXMgZ3JleXNjYWxlcyB0aGUgcGFsZXR0ZSBvZiB5b3VyIERpc3BsYXkgT2JqZWN0cy5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gR3JheUZpbHRlcigpIHtcbiAgICBBYnN0cmFjdEZpbHRlci5jYWxsKHRoaXMpO1xuXG4gICAgLy8gc2V0IHRoZSB1bmlmb3Jtc1xuICAgIHRoaXMudW5pZm9ybXMgPSB7XG4gICAgICAgIGdyYXk6IHsgdHlwZTogJzFmJywgdmFsdWU6IDEgfVxuICAgIH07XG5cbiAgICB0aGlzLmZyYWdtZW50U3JjID0gW1xuICAgICAgICAncHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7JyxcblxuICAgICAgICAndmFyeWluZyB2ZWMyIHZUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAndW5pZm9ybSBzYW1wbGVyMkQgdVNhbXBsZXI7JyxcbiAgICAgICAgJ3VuaWZvcm0gZmxvYXQgZ3JheTsnLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IgPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZUZXh0dXJlQ29vcmQpOycsXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IucmdiID0gbWl4KGdsX0ZyYWdDb2xvci5yZ2IsIHZlYzMoMC4yMTI2KmdsX0ZyYWdDb2xvci5yICsgMC43MTUyKmdsX0ZyYWdDb2xvci5nICsgMC4wNzIyKmdsX0ZyYWdDb2xvci5iKSwgZ3JheSk7JyxcbiAgICAgLy8gICAnICAgZ2xfRnJhZ0NvbG9yID0gZ2xfRnJhZ0NvbG9yOycsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cbkdyYXlGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuR3JheUZpbHRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBHcmF5RmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBHcmF5RmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhHcmF5RmlsdGVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSBzdHJlbmd0aCBvZiB0aGUgZ3JheS4gMSB3aWxsIG1ha2UgdGhlIG9iamVjdCBibGFjayBhbmQgd2hpdGUsIDAgd2lsbCBtYWtlIHRoZSBvYmplY3QgaXRzIG5vcm1hbCBjb2xvci5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgR3JheUZpbHRlciNcbiAgICAgKi9cbiAgICBncmF5OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudW5pZm9ybXMuZ3JheS52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuZ3JheS52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyk7XG5cbi8qKlxuICogVGhpcyBpbnZlcnRzIHlvdXIgRGlzcGxheSBPYmplY3RzIGNvbG9ycy5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gSW52ZXJ0RmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgaW52ZXJ0OiB7IHR5cGU6ICcxZicsIHZhbHVlOiAxIH1cbiAgICB9O1xuXG4gICAgdGhpcy5mcmFnbWVudFNyYyA9IFtcbiAgICAgICAgJ3ByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OycsXG5cbiAgICAgICAgJ3ZhcnlpbmcgdmVjMiB2VGV4dHVyZUNvb3JkOycsXG4gICAgICAgICd2YXJ5aW5nIHZlYzQgdkNvbG9yOycsXG5cbiAgICAgICAgJ3VuaWZvcm0gZmxvYXQgaW52ZXJ0OycsXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCB1U2FtcGxlcjsnLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IgPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZUZXh0dXJlQ29vcmQpOycsXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IucmdiID0gbWl4KCAodmVjMygxKS1nbF9GcmFnQ29sb3IucmdiKSAqIGdsX0ZyYWdDb2xvci5hLCBnbF9GcmFnQ29sb3IucmdiLCAxLjAgLSBpbnZlcnQpOycsXG4gICAgICAgIC8vJyAgIGdsX0ZyYWdDb2xvci5yZ2IgPSBnbF9GcmFnQ29sb3IucmdiICAqIGdsX0ZyYWdDb2xvci5hOycsXG4gICAgICAvLyAgJyAgIGdsX0ZyYWdDb2xvciA9IGdsX0ZyYWdDb2xvciAqIHZDb2xvcjsnLFxuICAgICAgICAnfSdcbiAgICBdO1xufVxuXG5JbnZlcnRGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuSW52ZXJ0RmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEludmVydEZpbHRlcjtcbm1vZHVsZS5leHBvcnRzID0gSW52ZXJ0RmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhJbnZlcnRGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHN0cmVuZ3RoIG9mIHRoZSBpbnZlcnQuIDEgd2lsbCBmdWxseSBpbnZlcnQgdGhlIGNvbG9ycywgMCB3aWxsIG1ha2UgdGhlIG9iamVjdCBpdHMgbm9ybWFsIGNvbG9yXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIEludmVydEZpbHRlciNcbiAgICAgKi9cbiAgICBpbnZlcnQ6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5pbnZlcnQudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLmludmVydC52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyk7XG5cbi8qKlxuICogQGF1dGhvciBWaWNvIEB2aWNvY290ZWFcbiAqIG9yaWdpbmFsIGZpbHRlcjogaHR0cHM6Ly9naXRodWIuY29tL2V2YW53L2dsZnguanMvYmxvYi9tYXN0ZXIvc3JjL2ZpbHRlcnMvYWRqdXN0L25vaXNlLmpzXG4gKi9cblxuLyoqXG4gKiBBIE5vaXNlIGVmZmVjdCBmaWx0ZXIuXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBBYnN0cmFjdEZpbHRlclxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbmZ1bmN0aW9uIE5vaXNlRmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgbm9pc2U6IHsgdHlwZTogJzFmJywgdmFsdWU6IDAuNSB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IG5vaXNlOycsXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCB1U2FtcGxlcjsnLFxuXG4gICAgICAgICdmbG9hdCByYW5kKHZlYzIgY28pIHsnLFxuICAgICAgICAnICAgIHJldHVybiBmcmFjdChzaW4oZG90KGNvLnh5ICx2ZWMyKDEyLjk4OTgsNzguMjMzKSkpICogNDM3NTguNTQ1Myk7JyxcbiAgICAgICAgJ30nLFxuXG4gICAgICAgICd2b2lkIG1haW4oKSB7JyxcbiAgICAgICAgJyAgICB2ZWM0IGNvbG9yID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkKTsnLFxuXG4gICAgICAgICcgICAgZmxvYXQgZGlmZiA9IChyYW5kKHZUZXh0dXJlQ29vcmQpIC0gMC41KSAqIG5vaXNlOycsXG4gICAgICAgICcgICAgY29sb3IuciArPSBkaWZmOycsXG4gICAgICAgICcgICAgY29sb3IuZyArPSBkaWZmOycsXG4gICAgICAgICcgICAgY29sb3IuYiArPSBkaWZmOycsXG5cbiAgICAgICAgJyAgICBnbF9GcmFnQ29sb3IgPSBjb2xvcjsnLFxuICAgICAgICAnfSdcbiAgICBdO1xufVxuXG5Ob2lzZUZpbHRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEFic3RyYWN0RmlsdGVyLnByb3RvdHlwZSk7XG5Ob2lzZUZpbHRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBOb2lzZUZpbHRlcjtcbm1vZHVsZS5leHBvcnRzID0gTm9pc2VGaWx0ZXI7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKE5vaXNlRmlsdGVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSBhbW91bnQgb2Ygbm9pc2UgdG8gYXBwbHkuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIE5vaXNlRmlsdGVyI1xuICAgICAqIEBkZWZhdWx0IDAuNVxuICAgICAqL1xuICAgIG5vaXNlOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudW5pZm9ybXMubm9pc2UudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLmRpcnR5ID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMubm9pc2UudmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuIiwidmFyIEFic3RyYWN0RmlsdGVyID0gcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpO1xuXG4vKipcbiAqIFRoZSBOb3JtYWxNYXBGaWx0ZXIgY2xhc3MgdXNlcyB0aGUgcGl4ZWwgdmFsdWVzIGZyb20gdGhlIHNwZWNpZmllZCB0ZXh0dXJlIChjYWxsZWQgdGhlIGRpc3BsYWNlbWVudCBtYXApIHRvIHBlcmZvcm0gYSBkaXNwbGFjZW1lbnQgb2YgYW4gb2JqZWN0LlxuICogWW91IGNhbiB1c2UgdGhpcyBmaWx0ZXIgdG8gYXBwbHkgYWxsIG1hbm9yIG9mIGNyYXp5IHdhcnBpbmcgZWZmZWN0c1xuICogQ3VycmVudGx5IHRoZSByIHByb3BlcnR5IG9mIHRoZSB0ZXh0dXJlIGlzIHVzZWQgb2Zmc2V0IHRoZSB4IGFuZCB0aGUgZyBwcm9wZXJ0eSBvZiB0aGUgdGV4dHVyZSBpcyB1c2VkIHRvIG9mZnNldCB0aGUgeS5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSB0ZXh0dXJlIHtUZXh0dXJlfSBUaGUgdGV4dHVyZSB1c2VkIGZvciB0aGUgbm9ybWFsIG1hcCwgbXVzdCBiZSBwb3dlciBvZiAyIHRleHR1cmUgYXQgdGhlIG1vbWVudFxuICovXG5mdW5jdGlvbiBOb3JtYWxNYXBGaWx0ZXIodGV4dHVyZSkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICB0ZXh0dXJlLmJhc2VUZXh0dXJlLl9wb3dlck9mMiA9IHRydWU7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgZGlzcGxhY2VtZW50TWFwOiAgeyB0eXBlOiAnc2FtcGxlcjJEJywgdmFsdWU6IHRleHR1cmUgfSxcbiAgICAgICAgc2NhbGU6ICAgICAgICAgICAgeyB0eXBlOiAnMmYnLCB2YWx1ZTogeyB4OiAxNSwgeTogMTUgfSB9LFxuICAgICAgICBvZmZzZXQ6ICAgICAgICAgICB7IHR5cGU6ICcyZicsIHZhbHVlOiB7IHg6IDAsICB5OiAwIH0gfSxcbiAgICAgICAgbWFwRGltZW5zaW9uczogICAgeyB0eXBlOiAnMmYnLCB2YWx1ZTogeyB4OiAxLCAgeTogMSB9IH0sXG4gICAgICAgIGRpbWVuc2lvbnM6ICAgICAgIHsgdHlwZTogJzRmJywgdmFsdWU6IFswLCAwLCAwLCAwXSB9LFxuICAgICAgICAvLyBMaWdodERpcjogICAgICAgICB7IHR5cGU6ICdmMycsIHZhbHVlOiBbMCwgMSwgMF0gfSxcbiAgICAgICAgTGlnaHRQb3M6ICAgICAgICAgeyB0eXBlOiAnM2YnLCB2YWx1ZTogWzAsIDEsIDBdIH1cbiAgICB9O1xuXG4gICAgaWYgKHRleHR1cmUuYmFzZVRleHR1cmUuaGFzTG9hZGVkKSB7XG4gICAgICAgIHRoaXMub25UZXh0dXJlTG9hZGVkKCk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLmJvdW5kTG9hZGVkRnVuY3Rpb24gPSB0aGlzLm9uVGV4dHVyZUxvYWRlZC5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHRleHR1cmUuYmFzZVRleHR1cmUub24oJ2xvYWRlZCcsIHRoaXMuYm91bmRMb2FkZWRGdW5jdGlvbik7XG4gICAgfVxuXG4gICAgdGhpcy5mcmFnbWVudFNyYyA9IFtcbiAgICAgICAgJ3ByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OycsXG5cbiAgICAgICAgJ3ZhcnlpbmcgdmVjMiB2VGV4dHVyZUNvb3JkOycsXG4gICAgICAgICd2YXJ5aW5nIGZsb2F0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCBkaXNwbGFjZW1lbnRNYXA7JyxcbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG5cbiAgICAgICAgJ3VuaWZvcm0gdmVjNCBkaW1lbnNpb25zOycsXG5cbiAgICAgICAgJ2NvbnN0IHZlYzIgUmVzb2x1dGlvbiA9IHZlYzIoMS4wLDEuMCk7JywgICAgICAvL3Jlc29sdXRpb24gb2Ygc2NyZWVuXG4gICAgICAgICd1bmlmb3JtIHZlYzMgTGlnaHRQb3M7JywgICAgLy9saWdodCBwb3NpdGlvbiwgbm9ybWFsaXplZFxuICAgICAgICAnY29uc3QgdmVjNCBMaWdodENvbG9yID0gdmVjNCgxLjAsIDEuMCwgMS4wLCAxLjApOycsICAgICAgLy9saWdodCBSR0JBIC0tIGFscGhhIGlzIGludGVuc2l0eVxuICAgICAgICAnY29uc3QgdmVjNCBBbWJpZW50Q29sb3IgPSB2ZWM0KDEuMCwgMS4wLCAxLjAsIDAuNSk7JywgICAgLy9hbWJpZW50IFJHQkEgLS0gYWxwaGEgaXMgaW50ZW5zaXR5XG4gICAgICAgICdjb25zdCB2ZWMzIEZhbGxvZmYgPSB2ZWMzKDAuMCwgMS4wLCAwLjIpOycsICAgICAgICAgLy9hdHRlbnVhdGlvbiBjb2VmZmljaWVudHNcblxuICAgICAgICAndW5pZm9ybSB2ZWMzIExpZ2h0RGlyOycsLy8nID0gdmVjMygxLjAsIDAuMCwgMS4wKTsnLFxuXG5cbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBtYXBEaW1lbnNpb25zOycsLy8gPSB2ZWMyKDI1Ni4wLCAyNTYuMCk7JyxcblxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICB2ZWMyIG1hcENvcmRzID0gdlRleHR1cmVDb29yZC54eTsnLFxuXG4gICAgICAgICcgICB2ZWM0IGNvbG9yID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkLnN0KTsnLFxuICAgICAgICAnICAgdmVjMyBuQ29sb3IgPSB0ZXh0dXJlMkQoZGlzcGxhY2VtZW50TWFwLCB2VGV4dHVyZUNvb3JkLnN0KS5yZ2I7JyxcblxuXG4gICAgICAgICcgICBtYXBDb3JkcyAqPSB2ZWMyKGRpbWVuc2lvbnMueC81MTIuMCwgZGltZW5zaW9ucy55LzUxMi4wKTsnLFxuXG4gICAgICAgICcgICBtYXBDb3Jkcy55ICo9IC0xLjA7JyxcbiAgICAgICAgJyAgIG1hcENvcmRzLnkgKz0gMS4wOycsXG5cbiAgICAgICAgLy9SR0JBIG9mIG91ciBkaWZmdXNlIGNvbG9yXG4gICAgICAgICcgICB2ZWM0IERpZmZ1c2VDb2xvciA9IHRleHR1cmUyRCh1U2FtcGxlciwgdlRleHR1cmVDb29yZCk7JyxcblxuICAgICAgICAvL1JHQiBvZiBvdXIgbm9ybWFsIG1hcFxuICAgICAgICAnICAgdmVjMyBOb3JtYWxNYXAgPSB0ZXh0dXJlMkQoZGlzcGxhY2VtZW50TWFwLCBtYXBDb3JkcykucmdiOycsXG5cbiAgICAgICAgLy9UaGUgZGVsdGEgcG9zaXRpb24gb2YgbGlnaHRcbiAgICAgICAgLy8ndmVjMyBMaWdodERpciA9IHZlYzMoTGlnaHRQb3MueHkgLSAoZ2xfRnJhZ0Nvb3JkLnh5IC8gUmVzb2x1dGlvbi54eSksIExpZ2h0UG9zLnopOycsXG4gICAgICAgICcgICB2ZWMzIExpZ2h0RGlyID0gdmVjMyhMaWdodFBvcy54eSAtIChtYXBDb3Jkcy54eSksIExpZ2h0UG9zLnopOycsXG4gICAgICAgIC8vQ29ycmVjdCBmb3IgYXNwZWN0IHJhdGlvXG4gICAgICAgIC8vICcgICBMaWdodERpci54ICo9IFJlc29sdXRpb24ueCAvIFJlc29sdXRpb24ueTsnLFxuXG4gICAgICAgIC8vRGV0ZXJtaW5lIGRpc3RhbmNlICh1c2VkIGZvciBhdHRlbnVhdGlvbikgQkVGT1JFIHdlIG5vcm1hbGl6ZSBvdXIgTGlnaHREaXJcbiAgICAgICAgJyAgIGZsb2F0IEQgPSBsZW5ndGgoTGlnaHREaXIpOycsXG5cbiAgICAgICAgLy9ub3JtYWxpemUgb3VyIHZlY3RvcnNcbiAgICAgICAgJyAgIHZlYzMgTiA9IG5vcm1hbGl6ZShOb3JtYWxNYXAgKiAyLjAgLSAxLjApOycsXG4gICAgICAgICcgICB2ZWMzIEwgPSBub3JtYWxpemUoTGlnaHREaXIpOycsXG5cbiAgICAgICAgLy9QcmUtbXVsdGlwbHkgbGlnaHQgY29sb3Igd2l0aCBpbnRlbnNpdHlcbiAgICAgICAgLy9UaGVuIHBlcmZvcm0gJ04gZG90IEwnIHRvIGRldGVybWluZSBvdXIgZGlmZnVzZSB0ZXJtXG4gICAgICAgICcgICB2ZWMzIERpZmZ1c2UgPSAoTGlnaHRDb2xvci5yZ2IgKiBMaWdodENvbG9yLmEpICogbWF4KGRvdChOLCBMKSwgMC4wKTsnLFxuXG4gICAgICAgIC8vcHJlLW11bHRpcGx5IGFtYmllbnQgY29sb3Igd2l0aCBpbnRlbnNpdHlcbiAgICAgICAgJyAgIHZlYzMgQW1iaWVudCA9IEFtYmllbnRDb2xvci5yZ2IgKiBBbWJpZW50Q29sb3IuYTsnLFxuXG4gICAgICAgIC8vY2FsY3VsYXRlIGF0dGVudWF0aW9uXG4gICAgICAgICcgICBmbG9hdCBBdHRlbnVhdGlvbiA9IDEuMCAvICggRmFsbG9mZi54ICsgKEZhbGxvZmYueSpEKSArIChGYWxsb2ZmLnoqRCpEKSApOycsXG5cbiAgICAgICAgLy90aGUgY2FsY3VsYXRpb24gd2hpY2ggYnJpbmdzIGl0IGFsbCB0b2dldGhlclxuICAgICAgICAnICAgdmVjMyBJbnRlbnNpdHkgPSBBbWJpZW50ICsgRGlmZnVzZSAqIEF0dGVudWF0aW9uOycsXG4gICAgICAgICcgICB2ZWMzIEZpbmFsQ29sb3IgPSBEaWZmdXNlQ29sb3IucmdiICogSW50ZW5zaXR5OycsXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IgPSB2Q29sb3IgKiB2ZWM0KEZpbmFsQ29sb3IsIERpZmZ1c2VDb2xvci5hKTsnLFxuICAgICAgICAvLyAnICAgZ2xfRnJhZ0NvbG9yID0gdmVjNCgxLjAsIDAuMCwgMC4wLCBBdHRlbnVhdGlvbik7JywvL3ZDb2xvciAqIHZlYzQoRmluYWxDb2xvciwgRGlmZnVzZUNvbG9yLmEpOycsXG5cbiAgICAgICAgLyovLyBub3JtYWxpc2UgY29sb3JcbiAgICAgICAgJyAgIHZlYzMgbm9ybWFsID0gbm9ybWFsaXplKG5Db2xvciAqIDIuMCAtIDEuMCk7JyxcblxuICAgICAgICAnICAgdmVjMyBkZWx0YVBvcyA9IHZlYzMoIChsaWdodC54eSAtIGdsX0ZyYWdDb29yZC54eSkgLyByZXNvbHV0aW9uLnh5LCBsaWdodC56ICk7JyxcblxuICAgICAgICAnICAgZmxvYXQgbGFtYmVydCA9IGNsYW1wKGRvdChub3JtYWwsIGxpZ2h0RGlyKSwgMC4wLCAxLjApOycsXG5cbiAgICAgICAgJyAgIGZsb2F0IGQgPSBzcXJ0KGRvdChkZWx0YVBvcywgZGVsdGFQb3MpKTsnLFxuICAgICAgICAnICAgZmxvYXQgYXR0ID0gMS4wIC8gKCBhdHRlbnVhdGlvbi54ICsgKGF0dGVudWF0aW9uLnkqZCkgKyAoYXR0ZW51YXRpb24ueipkKmQpICk7JyxcblxuICAgICAgICAnICAgdmVjMyByZXN1bHQgPSAoYW1iaWVudENvbG9yICogYW1iaWVudEludGVuc2l0eSkgKyAobGlnaHRDb2xvci5yZ2IgKiBsYW1iZXJ0KSAqIGF0dDsnLFxuICAgICAgICAnICAgcmVzdWx0ICo9IGNvbG9yLnJnYjsnLFxuXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IgPSB2ZWM0KHJlc3VsdCwgMS4wKTsnLCovXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cbk5vcm1hbE1hcEZpbHRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEFic3RyYWN0RmlsdGVyLnByb3RvdHlwZSk7XG5Ob3JtYWxNYXBGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gTm9ybWFsTWFwRmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBOb3JtYWxNYXBGaWx0ZXI7XG5cbi8qKlxuICogU2V0cyB0aGUgbWFwIGRpbWVuc2lvbnMgdW5pZm9ybXMgd2hlbiB0aGUgdGV4dHVyZSBiZWNvbWVzIGF2YWlsYWJsZS5cbiAqXG4gKi9cbk5vcm1hbE1hcEZpbHRlci5wcm90b3R5cGUub25UZXh0dXJlTG9hZGVkID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMudW5pZm9ybXMubWFwRGltZW5zaW9ucy52YWx1ZS54ID0gdGhpcy51bmlmb3Jtcy5kaXNwbGFjZW1lbnRNYXAudmFsdWUud2lkdGg7XG4gICAgdGhpcy51bmlmb3Jtcy5tYXBEaW1lbnNpb25zLnZhbHVlLnkgPSB0aGlzLnVuaWZvcm1zLmRpc3BsYWNlbWVudE1hcC52YWx1ZS5oZWlnaHQ7XG5cbiAgICB0aGlzLnVuaWZvcm1zLmRpc3BsYWNlbWVudE1hcC52YWx1ZS5iYXNlVGV4dHVyZS5vZmYoJ2xvYWRlZCcsIHRoaXMuYm91bmRMb2FkZWRGdW5jdGlvbik7XG59O1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhOb3JtYWxNYXBGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHRleHR1cmUgdXNlZCBmb3IgdGhlIGRpc3BsYWNlbWVudCBtYXAuIE11c3QgYmUgcG93ZXIgb2YgMiB0ZXh0dXJlLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7VGV4dHVyZX1cbiAgICAgKiBAbWVtYmVyb2YgTm9ybWFsTWFwRmlsdGVyI1xuICAgICAqL1xuICAgIG1hcDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmRpc3BsYWNlbWVudE1hcC52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuZGlzcGxhY2VtZW50TWFwLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIG11bHRpcGxpZXIgdXNlZCB0byBzY2FsZSB0aGUgZGlzcGxhY2VtZW50IHJlc3VsdCBmcm9tIHRoZSBtYXAgY2FsY3VsYXRpb24uXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKiBAbWVtYmVyb2YgTm9ybWFsTWFwRmlsdGVyI1xuICAgICAqL1xuICAgIHNjYWxlOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudW5pZm9ybXMuc2NhbGUudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLnNjYWxlLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIG9mZnNldCB1c2VkIHRvIG1vdmUgdGhlIGRpc3BsYWNlbWVudCBtYXAuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKiBAbWVtYmVyb2YgTm9ybWFsTWFwRmlsdGVyI1xuICAgICAqL1xuICAgIG9mZnNldDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLm9mZnNldC52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMub2Zmc2V0LnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKTtcblxuLyoqXG4gKiBUaGlzIGZpbHRlciBhcHBsaWVzIGEgcGl4ZWxhdGUgZWZmZWN0IG1ha2luZyBkaXNwbGF5IG9iamVjdHMgYXBwZWFyICdibG9ja3knLlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBQaXhlbGF0ZUZpbHRlcigpIHtcbiAgICBBYnN0cmFjdEZpbHRlci5jYWxsKHRoaXMpO1xuXG4gICAgLy8gc2V0IHRoZSB1bmlmb3Jtc1xuICAgIHRoaXMudW5pZm9ybXMgPSB7XG4gICAgICAgIGludmVydDogICAgIHsgdHlwZTogJzFmJywgICB2YWx1ZTogMCB9LFxuICAgICAgICBkaW1lbnNpb25zOiB7IHR5cGU6ICc0ZnYnLCAgdmFsdWU6IG5ldyBGbG9hdDMyQXJyYXkoWzEwMDAwLCAxMDAsIDEwLCAxMF0pIH0sXG4gICAgICAgIHBpeGVsU2l6ZTogIHsgdHlwZTogJzJmJywgICB2YWx1ZTogeyB4OiAxMCwgeTogMTAgfSB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIHZlYzIgdGVzdERpbTsnLFxuICAgICAgICAndW5pZm9ybSB2ZWM0IGRpbWVuc2lvbnM7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBwaXhlbFNpemU7JyxcbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG5cbiAgICAgICAgJ3ZvaWQgbWFpbih2b2lkKSB7JyxcbiAgICAgICAgJyAgIHZlYzIgY29vcmQgPSB2VGV4dHVyZUNvb3JkOycsXG5cbiAgICAgICAgJyAgIHZlYzIgc2l6ZSA9IGRpbWVuc2lvbnMueHkvcGl4ZWxTaXplOycsXG5cbiAgICAgICAgJyAgIHZlYzIgY29sb3IgPSBmbG9vciggKCB2VGV4dHVyZUNvb3JkICogc2l6ZSApICkgLyBzaXplICsgcGl4ZWxTaXplL2RpbWVuc2lvbnMueHkgKiAwLjU7JyxcbiAgICAgICAgJyAgIGdsX0ZyYWdDb2xvciA9IHRleHR1cmUyRCh1U2FtcGxlciwgY29sb3IpOycsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cblBpeGVsYXRlRmlsdGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlKTtcblBpeGVsYXRlRmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFBpeGVsYXRlRmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBQaXhlbGF0ZUZpbHRlcjtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoUGl4ZWxhdGVGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhpcyBhIHBvaW50IHRoYXQgZGVzY3JpYmVzIHRoZSBzaXplIG9mIHRoZSBibG9ja3MuIHggaXMgdGhlIHdpZHRoIG9mIHRoZSBibG9jayBhbmQgeSBpcyB0aGUgaGVpZ2h0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICogQG1lbWJlcm9mIFBpeGVsYXRlRmlsdGVyI1xuICAgICAqL1xuICAgIHNpemU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5waXhlbFNpemUudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLnBpeGVsU2l6ZS52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCJ2YXIgQWJzdHJhY3RGaWx0ZXIgPSByZXF1aXJlKCcuL0Fic3RyYWN0RmlsdGVyJyk7XG5cbi8qKlxuICogQW4gUkdCIFNwbGl0IEZpbHRlci5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gUkdCU3BsaXRGaWx0ZXIoKSB7XG4gICAgQWJzdHJhY3RGaWx0ZXIuY2FsbCh0aGlzKTtcblxuICAgIHRoaXMucGFzc2VzID0gW3RoaXNdO1xuXG4gICAgLy8gc2V0IHRoZSB1bmlmb3Jtc1xuICAgIHRoaXMudW5pZm9ybXMgPSB7XG4gICAgICAgIHJlZDogICAgICAgIHsgdHlwZTogJzJmJywgdmFsdWU6IHsgeDogMjAsIHk6IDIwIH0gfSxcbiAgICAgICAgZ3JlZW46ICAgICAgeyB0eXBlOiAnMmYnLCB2YWx1ZTogeyB4OiAtMjAsIHk6IDIwIH0gfSxcbiAgICAgICAgYmx1ZTogICAgICAgeyB0eXBlOiAnMmYnLCB2YWx1ZTogeyB4OiAyMCwgeTogLTIwIH0gfSxcbiAgICAgICAgZGltZW5zaW9uczogeyB0eXBlOiAnNGZ2JywgdmFsdWU6IFswLCAwLCAwLCAwXSB9XG4gICAgfTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuICAgICAgICAndmFyeWluZyB2ZWM0IHZDb2xvcjsnLFxuXG4gICAgICAgICd1bmlmb3JtIHZlYzIgcmVkOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzIgZ3JlZW47JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBibHVlOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzQgZGltZW5zaW9uczsnLFxuICAgICAgICAndW5pZm9ybSBzYW1wbGVyMkQgdVNhbXBsZXI7JyxcblxuICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yLnIgPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZUZXh0dXJlQ29vcmQgKyByZWQvZGltZW5zaW9ucy54eSkucjsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yLmcgPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZUZXh0dXJlQ29vcmQgKyBncmVlbi9kaW1lbnNpb25zLnh5KS5nOycsXG4gICAgICAgICcgICBnbF9GcmFnQ29sb3IuYiA9IHRleHR1cmUyRCh1U2FtcGxlciwgdlRleHR1cmVDb29yZCArIGJsdWUvZGltZW5zaW9ucy54eSkuYjsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yLmEgPSB0ZXh0dXJlMkQodVNhbXBsZXIsIHZUZXh0dXJlQ29vcmQpLmE7JyxcbiAgICAgICAgJ30nXG4gICAgXTtcbn1cblxuUkdCU3BsaXRGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuUkdCU3BsaXRGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gUkdCU3BsaXRGaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFJHQlNwbGl0RmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhSR0JTcGxpdEZpbHRlci5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBSZWQgY2hhbm5lbCBvZmZzZXQuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKiBAbWVtYmVyb2YgUkdCU3BsaXRGaWx0ZXIjXG4gICAgICovXG4gICAgcmVkOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudW5pZm9ybXMucmVkLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5yZWQudmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBHcmVlbiBjaGFubmVsIG9mZnNldC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1BvaW50fVxuICAgICAqIEBtZW1iZXJvZiBSR0JTcGxpdEZpbHRlciNcbiAgICAgKi9cbiAgICBncmVlbjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmdyZWVuLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5ncmVlbi52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEJsdWUgb2Zmc2V0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICogQG1lbWJlcm9mIFJHQlNwbGl0RmlsdGVyI1xuICAgICAqL1xuICAgIGJsdWU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5ibHVlLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5ibHVlLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKTtcblxuLyoqXG4gKiBUaGlzIGFwcGxpZXMgYSBzZXBpYSBlZmZlY3QgdG8geW91ciBEaXNwbGF5IE9iamVjdHMuXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBBYnN0cmFjdEZpbHRlclxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbmZ1bmN0aW9uIFNlcGlhRmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgc2VwaWE6IHsgdHlwZTogJzFmJywgdmFsdWU6IDEgfVxuICAgIH07XG5cbiAgICB0aGlzLmZyYWdtZW50U3JjID0gW1xuICAgICAgICAncHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7JyxcblxuICAgICAgICAndmFyeWluZyB2ZWMyIHZUZXh0dXJlQ29vcmQ7JyxcbiAgICAgICAgJ3ZhcnlpbmcgdmVjNCB2Q29sb3I7JyxcblxuICAgICAgICAndW5pZm9ybSBmbG9hdCBzZXBpYTsnLFxuICAgICAgICAndW5pZm9ybSBzYW1wbGVyMkQgdVNhbXBsZXI7JyxcblxuICAgICAgICAnY29uc3QgbWF0MyBzZXBpYU1hdHJpeCA9IG1hdDMoMC4zNTg4LCAwLjcwNDQsIDAuMTM2OCwgMC4yOTkwLCAwLjU4NzAsIDAuMTE0MCwgMC4yMzkyLCAwLjQ2OTYsIDAuMDkxMik7JyxcblxuICAgICAgICAndm9pZCBtYWluKHZvaWQpIHsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkKTsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yLnJnYiA9IG1peCggZ2xfRnJhZ0NvbG9yLnJnYiwgZ2xfRnJhZ0NvbG9yLnJnYiAqIHNlcGlhTWF0cml4LCBzZXBpYSk7JyxcbiAgICAgICAgJ30nXG4gICAgXTtcbn1cblxuU2VwaWFGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuU2VwaWFGaWx0ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gU2VwaWFGaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFNlcGlhRmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhTZXBpYUZpbHRlci5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBUaGUgc3RyZW5ndGggb2YgdGhlIHNlcGlhLiAxIHdpbGwgYXBwbHkgdGhlIGZ1bGwgc2VwaWEgZWZmZWN0LCAwIHdpbGwgbWFrZSB0aGUgb2JqZWN0IGl0cyBub3JtYWwgY29sb3IuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIFNlcGlhRmlsdGVyI1xuICAgICAqL1xuICAgIHNlcGlhOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudW5pZm9ybXMuc2VwaWEudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLnNlcGlhLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKTtcblxuLyoqXG4gKiBBIFNtYXJ0IEJsdXIgRmlsdGVyLlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBTbWFydEJsdXJGaWx0ZXIoKSB7XG4gICAgQWJzdHJhY3RGaWx0ZXIuY2FsbCh0aGlzKTtcblxuICAgIHRoaXMuZnJhZ21lbnRTcmMgPSBbXG4gICAgICAgICdwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDsnLFxuXG4gICAgICAgICd2YXJ5aW5nIHZlYzIgdlRleHR1cmVDb29yZDsnLFxuXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCB1U2FtcGxlcjsnLFxuICAgICAgICAnY29uc3QgdmVjMiBkZWx0YSA9IHZlYzIoMS4wLzEwLjAsIDAuMCk7JyxcblxuICAgICAgICAnZmxvYXQgcmFuZG9tKHZlYzMgc2NhbGUsIGZsb2F0IHNlZWQpIHsnLFxuICAgICAgICAnICAgcmV0dXJuIGZyYWN0KHNpbihkb3QoZ2xfRnJhZ0Nvb3JkLnh5eiArIHNlZWQsIHNjYWxlKSkgKiA0Mzc1OC41NDUzICsgc2VlZCk7JyxcbiAgICAgICAgJ30nLFxuXG5cbiAgICAgICAgJ3ZvaWQgbWFpbih2b2lkKSB7JyxcbiAgICAgICAgJyAgIHZlYzQgY29sb3IgPSB2ZWM0KDAuMCk7JyxcbiAgICAgICAgJyAgIGZsb2F0IHRvdGFsID0gMC4wOycsXG5cbiAgICAgICAgJyAgIGZsb2F0IG9mZnNldCA9IHJhbmRvbSh2ZWMzKDEyLjk4OTgsIDc4LjIzMywgMTUxLjcxODIpLCAwLjApOycsXG5cbiAgICAgICAgJyAgIGZvciAoZmxvYXQgdCA9IC0zMC4wOyB0IDw9IDMwLjA7IHQrKykgeycsXG4gICAgICAgICcgICAgICAgZmxvYXQgcGVyY2VudCA9ICh0ICsgb2Zmc2V0IC0gMC41KSAvIDMwLjA7JyxcbiAgICAgICAgJyAgICAgICBmbG9hdCB3ZWlnaHQgPSAxLjAgLSBhYnMocGVyY2VudCk7JyxcbiAgICAgICAgJyAgICAgICB2ZWM0IHNhbXBsZSA9IHRleHR1cmUyRCh1U2FtcGxlciwgdlRleHR1cmVDb29yZCArIGRlbHRhICogcGVyY2VudCk7JyxcbiAgICAgICAgJyAgICAgICBzYW1wbGUucmdiICo9IHNhbXBsZS5hOycsXG4gICAgICAgICcgICAgICAgY29sb3IgKz0gc2FtcGxlICogd2VpZ2h0OycsXG4gICAgICAgICcgICAgICAgdG90YWwgKz0gd2VpZ2h0OycsXG4gICAgICAgICcgICB9JyxcblxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gY29sb3IgLyB0b3RhbDsnLFxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yLnJnYiAvPSBnbF9GcmFnQ29sb3IuYSArIDAuMDAwMDE7JyxcbiAgICAgICAgJ30nXG4gICAgXTtcbn1cblxuU21hcnRCbHVyRmlsdGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlKTtcblNtYXJ0Qmx1ckZpbHRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBTbWFydEJsdXJGaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFNtYXJ0Qmx1ckZpbHRlcjtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKSxcbiAgICBUaWx0U2hpZnRYRmlsdGVyID0gcmVxdWlyZSgnLi9UaWx0U2hpZnRYRmlsdGVyJyksXG4gICAgVGlsdFNoaWZ0WUZpbHRlciA9IHJlcXVpcmUoJy4vVGlsdFNoaWZ0WUZpbHRlcicpO1xuXG4vKipcbiAqIEBhdXRob3IgVmljbyBAdmljb2NvdGVhXG4gKiBvcmlnaW5hbCBmaWx0ZXIgaHR0cHM6Ly9naXRodWIuY29tL2V2YW53L2dsZnguanMvYmxvYi9tYXN0ZXIvc3JjL2ZpbHRlcnMvYmx1ci90aWx0c2hpZnQuanMgYnkgRXZhbiBXYWxsYWNlIDogaHR0cDovL21hZGVieWV2YW4uY29tL1xuICovXG5cbi8qKlxuICogQSBUaWx0U2hpZnQgRmlsdGVyLiBNYW5hZ2VzIHRoZSBwYXNzIG9mIGJvdGggYSBUaWx0U2hpZnRYRmlsdGVyIGFuZCBUaWx0U2hpZnRZRmlsdGVyLlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBUaWx0U2hpZnRGaWx0ZXIoKSB7XG4gICAgQWJzdHJhY3RGaWx0ZXIuY2FsbCh0aGlzKTtcblxuICAgIHRoaXMudGlsdFNoaWZ0WEZpbHRlciA9IG5ldyBUaWx0U2hpZnRYRmlsdGVyKCk7XG4gICAgdGhpcy50aWx0U2hpZnRZRmlsdGVyID0gbmV3IFRpbHRTaGlmdFlGaWx0ZXIoKTtcblxuICAgIHRoaXMudGlsdFNoaWZ0WEZpbHRlci51cGRhdGVEZWx0YSgpO1xuICAgIHRoaXMudGlsdFNoaWZ0WEZpbHRlci51cGRhdGVEZWx0YSgpO1xuXG4gICAgdGhpcy5wYXNzZXMgPSBbdGhpcy50aWx0U2hpZnRYRmlsdGVyLCB0aGlzLnRpbHRTaGlmdFlGaWx0ZXJdO1xufVxuXG5UaWx0U2hpZnRGaWx0ZXIucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShBYnN0cmFjdEZpbHRlci5wcm90b3R5cGUpO1xuVGlsdFNoaWZ0RmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFRpbHRTaGlmdEZpbHRlcjtcbm1vZHVsZS5leHBvcnRzID0gVGlsdFNoaWZ0RmlsdGVyO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhUaWx0U2hpZnRGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHN0cmVuZ3RoIG9mIHRoZSBibHVyLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUaWx0U2hpZnRGaWx0ZXIjXG4gICAgICovXG4gICAgYmx1cjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnRpbHRTaGlmdFhGaWx0ZXIuYmx1cjtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudGlsdFNoaWZ0WEZpbHRlci5ibHVyID0gdGhpcy50aWx0U2hpZnRZRmlsdGVyLmJsdXIgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgc3RyZW5ndGggb2YgdGhlIGdyYWRpZW50IGJsdXIuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIFRpbHRTaGlmdEZpbHRlciNcbiAgICAgKi9cbiAgICBncmFkaWVudEJsdXI6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy50aWx0U2hpZnRYRmlsdGVyLmdyYWRpZW50Qmx1cjtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudGlsdFNoaWZ0WEZpbHRlci5ncmFkaWVudEJsdXIgPSB0aGlzLnRpbHRTaGlmdFlGaWx0ZXIuZ3JhZGllbnRCbHVyID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIFkgdmFsdWUgdG8gc3RhcnQgdGhlIGVmZmVjdCBhdC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgVGlsdFNoaWZ0RmlsdGVyI1xuICAgICAqL1xuICAgIHN0YXJ0OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudGlsdFNoaWZ0WEZpbHRlci5zdGFydDtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudGlsdFNoaWZ0WEZpbHRlci5zdGFydCA9IHRoaXMudGlsdFNoaWZ0WUZpbHRlci5zdGFydCA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBZIHZhbHVlIHRvIGVuZCB0aGUgZWZmZWN0IGF0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUaWx0U2hpZnRGaWx0ZXIjXG4gICAgICovXG4gICAgZW5kOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudGlsdFNoaWZ0WEZpbHRlci5lbmQ7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnRpbHRTaGlmdFhGaWx0ZXIuZW5kID0gdGhpcy50aWx0U2hpZnRZRmlsdGVyLmVuZCA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcbn0pO1xuIiwidmFyIEFic3RyYWN0RmlsdGVyID0gcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpO1xuXG4vKipcbiAqIEBhdXRob3IgVmljbyBAdmljb2NvdGVhXG4gKiBvcmlnaW5hbCBmaWx0ZXIgaHR0cHM6Ly9naXRodWIuY29tL2V2YW53L2dsZnguanMvYmxvYi9tYXN0ZXIvc3JjL2ZpbHRlcnMvYmx1ci90aWx0c2hpZnQuanMgYnkgRXZhbiBXYWxsYWNlIDogaHR0cDovL21hZGVieWV2YW4uY29tL1xuICovXG5cbi8qKlxuICogQSBUaWx0U2hpZnRYRmlsdGVyLlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBUaWx0U2hpZnRYRmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgYmx1cjogICAgICAgICAgIHsgdHlwZTogJzFmJywgdmFsdWU6IDEwMCB9LFxuICAgICAgICBncmFkaWVudEJsdXI6ICAgeyB0eXBlOiAnMWYnLCB2YWx1ZTogNjAwIH0sXG4gICAgICAgIHN0YXJ0OiAgICAgICAgICB7IHR5cGU6ICcyZicsIHZhbHVlOiB7IHg6IDAsICAgIHk6IHdpbmRvdy5zY3JlZW5IZWlnaHQgLyAyIH0gfSxcbiAgICAgICAgZW5kOiAgICAgICAgICAgIHsgdHlwZTogJzJmJywgdmFsdWU6IHsgeDogNjAwLCAgeTogd2luZG93LnNjcmVlbkhlaWdodCAvIDIgfSB9LFxuICAgICAgICBkZWx0YTogICAgICAgICAgeyB0eXBlOiAnMmYnLCB2YWx1ZTogeyB4OiAzMCwgICB5OiAzMCB9IH0sXG4gICAgICAgIHRleFNpemU6ICAgICAgICB7IHR5cGU6ICcyZicsIHZhbHVlOiB7IHg6IHdpbmRvdy5zY3JlZW5XaWR0aCwgeTogd2luZG93LnNjcmVlbkhlaWdodCB9IH1cbiAgICB9O1xuXG4gICAgdGhpcy51cGRhdGVEZWx0YSgpO1xuXG4gICAgdGhpcy5mcmFnbWVudFNyYyA9IFtcbiAgICAgICAgJ3ByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OycsXG5cbiAgICAgICAgJ3ZhcnlpbmcgdmVjMiB2VGV4dHVyZUNvb3JkOycsXG5cbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IGJsdXI7JyxcbiAgICAgICAgJ3VuaWZvcm0gZmxvYXQgZ3JhZGllbnRCbHVyOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzIgc3RhcnQ7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBlbmQ7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBkZWx0YTsnLFxuICAgICAgICAndW5pZm9ybSB2ZWMyIHRleFNpemU7JyxcblxuICAgICAgICAnZmxvYXQgcmFuZG9tKHZlYzMgc2NhbGUsIGZsb2F0IHNlZWQpIHsnLFxuICAgICAgICAnICAgcmV0dXJuIGZyYWN0KHNpbihkb3QoZ2xfRnJhZ0Nvb3JkLnh5eiArIHNlZWQsIHNjYWxlKSkgKiA0Mzc1OC41NDUzICsgc2VlZCk7JyxcbiAgICAgICAgJ30nLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICAgdmVjNCBjb2xvciA9IHZlYzQoMC4wKTsnLFxuICAgICAgICAnICAgIGZsb2F0IHRvdGFsID0gMC4wOycsXG5cbiAgICAgICAgJyAgICBmbG9hdCBvZmZzZXQgPSByYW5kb20odmVjMygxMi45ODk4LCA3OC4yMzMsIDE1MS43MTgyKSwgMC4wKTsnLFxuICAgICAgICAnICAgIHZlYzIgbm9ybWFsID0gbm9ybWFsaXplKHZlYzIoc3RhcnQueSAtIGVuZC55LCBlbmQueCAtIHN0YXJ0LngpKTsnLFxuICAgICAgICAnICAgIGZsb2F0IHJhZGl1cyA9IHNtb290aHN0ZXAoMC4wLCAxLjAsIGFicyhkb3QodlRleHR1cmVDb29yZCAqIHRleFNpemUgLSBzdGFydCwgbm9ybWFsKSkgLyBncmFkaWVudEJsdXIpICogYmx1cjsnLFxuXG4gICAgICAgICcgICAgZm9yIChmbG9hdCB0ID0gLTMwLjA7IHQgPD0gMzAuMDsgdCsrKSB7JyxcbiAgICAgICAgJyAgICAgICAgZmxvYXQgcGVyY2VudCA9ICh0ICsgb2Zmc2V0IC0gMC41KSAvIDMwLjA7JyxcbiAgICAgICAgJyAgICAgICAgZmxvYXQgd2VpZ2h0ID0gMS4wIC0gYWJzKHBlcmNlbnQpOycsXG4gICAgICAgICcgICAgICAgIHZlYzQgc2FtcGxlID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkICsgZGVsdGEgLyB0ZXhTaXplICogcGVyY2VudCAqIHJhZGl1cyk7JyxcbiAgICAgICAgJyAgICAgICAgc2FtcGxlLnJnYiAqPSBzYW1wbGUuYTsnLFxuICAgICAgICAnICAgICAgICBjb2xvciArPSBzYW1wbGUgKiB3ZWlnaHQ7JyxcbiAgICAgICAgJyAgICAgICAgdG90YWwgKz0gd2VpZ2h0OycsXG4gICAgICAgICcgICAgfScsXG5cbiAgICAgICAgJyAgICBnbF9GcmFnQ29sb3IgPSBjb2xvciAvIHRvdGFsOycsXG4gICAgICAgICcgICAgZ2xfRnJhZ0NvbG9yLnJnYiAvPSBnbF9GcmFnQ29sb3IuYSArIDAuMDAwMDE7JyxcbiAgICAgICAgJ30nXG4gICAgXTtcbn1cblxuVGlsdFNoaWZ0WEZpbHRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEFic3RyYWN0RmlsdGVyLnByb3RvdHlwZSk7XG5UaWx0U2hpZnRYRmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFRpbHRTaGlmdFhGaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFRpbHRTaGlmdFhGaWx0ZXI7XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgZmlsdGVyIGRlbHRhIHZhbHVlcy5cbiAqXG4gKi9cblRpbHRTaGlmdFhGaWx0ZXIucHJvdG90eXBlLnVwZGF0ZURlbHRhID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBkeCA9IHRoaXMudW5pZm9ybXMuZW5kLnZhbHVlLnggLSB0aGlzLnVuaWZvcm1zLnN0YXJ0LnZhbHVlLng7XG4gICAgdmFyIGR5ID0gdGhpcy51bmlmb3Jtcy5lbmQudmFsdWUueSAtIHRoaXMudW5pZm9ybXMuc3RhcnQudmFsdWUueTtcbiAgICB2YXIgZCA9IE1hdGguc3FydChkeCAqIGR4ICsgZHkgKiBkeSk7XG5cbiAgICB0aGlzLnVuaWZvcm1zLmRlbHRhLnZhbHVlLnggPSBkeCAvIGQ7XG4gICAgdGhpcy51bmlmb3Jtcy5kZWx0YS52YWx1ZS55ID0gZHkgLyBkO1xufTtcblxuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhUaWx0U2hpZnRYRmlsdGVyLnByb3RvdHlwZSwge1xuICAgIC8qKlxuICAgICAqIFRoZSBzdHJlbmd0aCBvZiB0aGUgYmx1ci5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgVGlsdHRTaGlmdFhGaWx0ZXIjXG4gICAgICovXG4gICAgYmx1cjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmJsdXIudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLmJsdXIudmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgc3RyZW5ndGggb2YgdGhlIGdyYWRpZW50IGJsdXIuXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIFRpbHR0U2hpZnRYRmlsdGVyI1xuICAgICAqL1xuICAgIGdyYWRpZW50Qmx1cjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmdyYWRpZW50Qmx1ci52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuZ3JhZGllbnRCbHVyLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIFggdmFsdWUgdG8gc3RhcnQgdGhlIGVmZmVjdCBhdC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgVGlsdHRTaGlmdFhGaWx0ZXIjXG4gICAgICovXG4gICAgc3RhcnQ6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5zdGFydC52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuc3RhcnQudmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlRGVsdGEoKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgWCB2YWx1ZSB0byBlbmQgdGhlIGVmZmVjdCBhdC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgVGlsdHRTaGlmdFhGaWx0ZXIjXG4gICAgICovXG4gICAgZW5kOiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudW5pZm9ybXMuZW5kLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5lbmQudmFsdWUgPSB2YWx1ZTtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlRGVsdGEoKTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuIiwidmFyIEFic3RyYWN0RmlsdGVyID0gcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpO1xuXG4vKipcbiAqIEBhdXRob3IgVmljbyBAdmljb2NvdGVhXG4gKiBvcmlnaW5hbCBmaWx0ZXIgaHR0cHM6Ly9naXRodWIuY29tL2V2YW53L2dsZnguanMvYmxvYi9tYXN0ZXIvc3JjL2ZpbHRlcnMvYmx1ci90aWx0c2hpZnQuanMgYnkgRXZhbiBXYWxsYWNlIDogaHR0cDovL21hZGVieWV2YW4uY29tL1xuICovXG5cbi8qKlxuICogQSBUaWx0U2hpZnRZRmlsdGVyLlxuICpcbiAqIEBjbGFzc1xuICogQGV4dGVuZHMgQWJzdHJhY3RGaWx0ZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBUaWx0U2hpZnRZRmlsdGVyKCkge1xuICAgIEFic3RyYWN0RmlsdGVyLmNhbGwodGhpcyk7XG5cbiAgICAvLyBzZXQgdGhlIHVuaWZvcm1zXG4gICAgdGhpcy51bmlmb3JtcyA9IHtcbiAgICAgICAgYmx1cjogICAgICAgICAgIHsgdHlwZTogJzFmJywgdmFsdWU6IDEwMCB9LFxuICAgICAgICBncmFkaWVudEJsdXI6ICAgeyB0eXBlOiAnMWYnLCB2YWx1ZTogNjAwIH0sXG4gICAgICAgIHN0YXJ0OiAgICAgICAgICB7IHR5cGU6ICcyZicsIHZhbHVlOiB7IHg6IDAsICAgIHk6IHdpbmRvdy5zY3JlZW5IZWlnaHQgLyAyIH0gfSxcbiAgICAgICAgZW5kOiAgICAgICAgICAgIHsgdHlwZTogJzJmJywgdmFsdWU6IHsgeDogNjAwLCAgeTogd2luZG93LnNjcmVlbkhlaWdodCAvIDIgfSB9LFxuICAgICAgICBkZWx0YTogICAgICAgICAgeyB0eXBlOiAnMmYnLCB2YWx1ZTogeyB4OiAzMCwgICB5OiAzMCB9IH0sXG4gICAgICAgIHRleFNpemU6ICAgICAgICB7IHR5cGU6ICcyZicsIHZhbHVlOiB7IHg6IHdpbmRvdy5zY3JlZW5XaWR0aCwgeTogd2luZG93LnNjcmVlbkhlaWdodCB9IH1cbiAgICB9O1xuXG4gICAgdGhpcy51cGRhdGVEZWx0YSgpO1xuXG4gICAgdGhpcy5mcmFnbWVudFNyYyA9IFtcbiAgICAgICAgJ3ByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OycsXG5cbiAgICAgICAgJ3ZhcnlpbmcgdmVjMiB2VGV4dHVyZUNvb3JkOycsXG5cbiAgICAgICAgJ3VuaWZvcm0gc2FtcGxlcjJEIHVTYW1wbGVyOycsXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IGJsdXI7JyxcbiAgICAgICAgJ3VuaWZvcm0gZmxvYXQgZ3JhZGllbnRCbHVyOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzIgc3RhcnQ7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBlbmQ7JyxcbiAgICAgICAgJ3VuaWZvcm0gdmVjMiBkZWx0YTsnLFxuICAgICAgICAndW5pZm9ybSB2ZWMyIHRleFNpemU7JyxcblxuICAgICAgICAnZmxvYXQgcmFuZG9tKHZlYzMgc2NhbGUsIGZsb2F0IHNlZWQpIHsnLFxuICAgICAgICAnICAgcmV0dXJuIGZyYWN0KHNpbihkb3QoZ2xfRnJhZ0Nvb3JkLnh5eiArIHNlZWQsIHNjYWxlKSkgKiA0Mzc1OC41NDUzICsgc2VlZCk7JyxcbiAgICAgICAgJ30nLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICAgdmVjNCBjb2xvciA9IHZlYzQoMC4wKTsnLFxuICAgICAgICAnICAgIGZsb2F0IHRvdGFsID0gMC4wOycsXG5cbiAgICAgICAgJyAgICBmbG9hdCBvZmZzZXQgPSByYW5kb20odmVjMygxMi45ODk4LCA3OC4yMzMsIDE1MS43MTgyKSwgMC4wKTsnLFxuICAgICAgICAnICAgIHZlYzIgbm9ybWFsID0gbm9ybWFsaXplKHZlYzIoc3RhcnQueSAtIGVuZC55LCBlbmQueCAtIHN0YXJ0LngpKTsnLFxuICAgICAgICAnICAgIGZsb2F0IHJhZGl1cyA9IHNtb290aHN0ZXAoMC4wLCAxLjAsIGFicyhkb3QodlRleHR1cmVDb29yZCAqIHRleFNpemUgLSBzdGFydCwgbm9ybWFsKSkgLyBncmFkaWVudEJsdXIpICogYmx1cjsnLFxuXG4gICAgICAgICcgICAgZm9yIChmbG9hdCB0ID0gLTMwLjA7IHQgPD0gMzAuMDsgdCsrKSB7JyxcbiAgICAgICAgJyAgICAgICAgZmxvYXQgcGVyY2VudCA9ICh0ICsgb2Zmc2V0IC0gMC41KSAvIDMwLjA7JyxcbiAgICAgICAgJyAgICAgICAgZmxvYXQgd2VpZ2h0ID0gMS4wIC0gYWJzKHBlcmNlbnQpOycsXG4gICAgICAgICcgICAgICAgIHZlYzQgc2FtcGxlID0gdGV4dHVyZTJEKHVTYW1wbGVyLCB2VGV4dHVyZUNvb3JkICsgZGVsdGEgLyB0ZXhTaXplICogcGVyY2VudCAqIHJhZGl1cyk7JyxcbiAgICAgICAgJyAgICAgICAgc2FtcGxlLnJnYiAqPSBzYW1wbGUuYTsnLFxuICAgICAgICAnICAgICAgICBjb2xvciArPSBzYW1wbGUgKiB3ZWlnaHQ7JyxcbiAgICAgICAgJyAgICAgICAgdG90YWwgKz0gd2VpZ2h0OycsXG4gICAgICAgICcgICAgfScsXG5cbiAgICAgICAgJyAgICBnbF9GcmFnQ29sb3IgPSBjb2xvciAvIHRvdGFsOycsXG4gICAgICAgICcgICAgZ2xfRnJhZ0NvbG9yLnJnYiAvPSBnbF9GcmFnQ29sb3IuYSArIDAuMDAwMDE7JyxcbiAgICAgICAgJ30nXG4gICAgXTtcbn1cblxuVGlsdFNoaWZ0WUZpbHRlci5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKEFic3RyYWN0RmlsdGVyLnByb3RvdHlwZSk7XG5UaWx0U2hpZnRZRmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFRpbHRTaGlmdFlGaWx0ZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFRpbHRTaGlmdFlGaWx0ZXI7XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgZmlsdGVyIGRlbHRhIHZhbHVlcy5cbiAqXG4gKi9cblRpbHRTaGlmdFlGaWx0ZXIucHJvdG90eXBlLnVwZGF0ZURlbHRhID0gZnVuY3Rpb24gKCl7XG4gICAgdmFyIGR4ID0gdGhpcy51bmlmb3Jtcy5lbmQudmFsdWUueCAtIHRoaXMudW5pZm9ybXMuc3RhcnQudmFsdWUueDtcbiAgICB2YXIgZHkgPSB0aGlzLnVuaWZvcm1zLmVuZC52YWx1ZS55IC0gdGhpcy51bmlmb3Jtcy5zdGFydC52YWx1ZS55O1xuICAgIHZhciBkID0gTWF0aC5zcXJ0KGR4ICogZHggKyBkeSAqIGR5KTtcbiAgICB0aGlzLnVuaWZvcm1zLmRlbHRhLnZhbHVlLnggPSAtZHkgLyBkO1xuICAgIHRoaXMudW5pZm9ybXMuZGVsdGEudmFsdWUueSA9IGR4IC8gZDtcbn07XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKFRpbHRTaGlmdFlGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhlIHN0cmVuZ3RoIG9mIHRoZSBibHVyLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUaWx0U2hpZnRZRmlsdGVyI1xuICAgICAqL1xuICAgIGJsdXI6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5ibHVyLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5ibHVyLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIHN0cmVuZ3RoIG9mIHRoZSBncmFkaWVudCBibHVyLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUaWx0U2hpZnRZRmlsdGVyI1xuICAgICAqL1xuICAgIGdyYWRpZW50Qmx1cjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmdyYWRpZW50Qmx1ci52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuZ3JhZGllbnRCbHVyLnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhlIFkgdmFsdWUgdG8gc3RhcnQgdGhlIGVmZmVjdCBhdC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgVGlsdFNoaWZ0WUZpbHRlciNcbiAgICAgKi9cbiAgICBzdGFydDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLnN0YXJ0LnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5zdGFydC52YWx1ZSA9IHZhbHVlO1xuICAgICAgICAgICAgdGhpcy51cGRhdGVEZWx0YSgpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoZSBZIHZhbHVlIHRvIGVuZCB0aGUgZWZmZWN0IGF0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUaWx0U2hpZnRZRmlsdGVyI1xuICAgICAqL1xuICAgIGVuZDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmVuZC52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMuZW5kLnZhbHVlID0gdmFsdWU7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZURlbHRhKCk7XG4gICAgICAgIH1cbiAgICB9XG59KTtcbiIsInZhciBBYnN0cmFjdEZpbHRlciA9IHJlcXVpcmUoJy4vQWJzdHJhY3RGaWx0ZXInKTtcblxuLyoqXG4gKiBUaGlzIGZpbHRlciBhcHBsaWVzIGEgdHdpc3QgZWZmZWN0IG1ha2luZyBkaXNwbGF5IG9iamVjdHMgYXBwZWFyIHR3aXN0ZWQgaW4gdGhlIGdpdmVuIGRpcmVjdGlvbi5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIEFic3RyYWN0RmlsdGVyXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xuZnVuY3Rpb24gVHdpc3RGaWx0ZXIoKSB7XG4gICAgQWJzdHJhY3RGaWx0ZXIuY2FsbCh0aGlzKTtcblxuICAgIC8vIHNldCB0aGUgdW5pZm9ybXNcbiAgICB0aGlzLnVuaWZvcm1zID0ge1xuICAgICAgICByYWRpdXM6ICAgICB7IHR5cGU6ICcxZicsIHZhbHVlOiAwLjV9LFxuICAgICAgICBhbmdsZTogICAgICB7IHR5cGU6ICcxZicsIHZhbHVlOiA1fSxcbiAgICAgICAgb2Zmc2V0OiAgICAgeyB0eXBlOiAnMmYnLCB2YWx1ZTogeyB4OiAwLjUsIHk6IDAuNSB9IH1cbiAgICB9O1xuXG4gICAgdGhpcy5mcmFnbWVudFNyYyA9IFtcbiAgICAgICAgJ3ByZWNpc2lvbiBtZWRpdW1wIGZsb2F0OycsXG5cbiAgICAgICAgJ3ZhcnlpbmcgdmVjMiB2VGV4dHVyZUNvb3JkOycsXG4gICAgICAgICd2YXJ5aW5nIHZlYzQgdkNvbG9yOycsXG5cbiAgICAgICAgJ3VuaWZvcm0gZmxvYXQgcmFkaXVzOycsXG4gICAgICAgICd1bmlmb3JtIGZsb2F0IGFuZ2xlOycsXG4gICAgICAgICd1bmlmb3JtIHZlYzIgb2Zmc2V0OycsXG4gICAgICAgICd1bmlmb3JtIHNhbXBsZXIyRCB1U2FtcGxlcjsnLFxuXG4gICAgICAgICd2b2lkIG1haW4odm9pZCkgeycsXG4gICAgICAgICcgICB2ZWMyIGNvb3JkID0gdlRleHR1cmVDb29yZCAtIG9mZnNldDsnLFxuICAgICAgICAnICAgZmxvYXQgZGlzdGFuY2UgPSBsZW5ndGgoY29vcmQpOycsXG5cbiAgICAgICAgJyAgIGlmIChkaXN0YW5jZSA8IHJhZGl1cykgeycsXG4gICAgICAgICcgICAgICAgZmxvYXQgcmF0aW8gPSAocmFkaXVzIC0gZGlzdGFuY2UpIC8gcmFkaXVzOycsXG4gICAgICAgICcgICAgICAgZmxvYXQgYW5nbGVNb2QgPSByYXRpbyAqIHJhdGlvICogYW5nbGU7JyxcbiAgICAgICAgJyAgICAgICBmbG9hdCBzID0gc2luKGFuZ2xlTW9kKTsnLFxuICAgICAgICAnICAgICAgIGZsb2F0IGMgPSBjb3MoYW5nbGVNb2QpOycsXG4gICAgICAgICcgICAgICAgY29vcmQgPSB2ZWMyKGNvb3JkLnggKiBjIC0gY29vcmQueSAqIHMsIGNvb3JkLnggKiBzICsgY29vcmQueSAqIGMpOycsXG4gICAgICAgICcgICB9JyxcblxuICAgICAgICAnICAgZ2xfRnJhZ0NvbG9yID0gdGV4dHVyZTJEKHVTYW1wbGVyLCBjb29yZCtvZmZzZXQpOycsXG4gICAgICAgICd9J1xuICAgIF07XG59XG5cblR3aXN0RmlsdGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoQWJzdHJhY3RGaWx0ZXIucHJvdG90eXBlKTtcblR3aXN0RmlsdGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFR3aXN0RmlsdGVyO1xubW9kdWxlLmV4cG9ydHMgPSBUd2lzdEZpbHRlcjtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoVHdpc3RGaWx0ZXIucHJvdG90eXBlLCB7XG4gICAgLyoqXG4gICAgICogVGhpcyBwb2ludCBkZXNjcmliZXMgdGhlIHRoZSBvZmZzZXQgb2YgdGhlIHR3aXN0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7UG9pbnR9XG4gICAgICogQG1lbWJlcm9mIFR3aXN0RmlsdGVyI1xuICAgICAqL1xuICAgIG9mZnNldDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLm9mZnNldC52YWx1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudW5pZm9ybXMub2Zmc2V0LnZhbHVlID0gdmFsdWU7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVGhpcyByYWRpdXMgb2YgdGhlIHR3aXN0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUd2lzdEZpbHRlciNcbiAgICAgKi9cbiAgICByYWRpdXM6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51bmlmb3Jtcy5yYWRpdXMudmFsdWU7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnVuaWZvcm1zLnJhZGl1cy52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoaXMgYW5nbGUgb2YgdGhlIHR3aXN0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUd2lzdEZpbHRlciNcbiAgICAgKi9cbiAgICBhbmdsZToge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVuaWZvcm1zLmFuZ2xlLnZhbHVlO1xuICAgICAgICB9LFxuICAgICAgICBzZXQ6IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgdGhpcy51bmlmb3Jtcy5hbmdsZS52YWx1ZSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG4iLCIvKipcbiAqIEBmaWxlICAgICAgICBNYWluIGV4cG9ydCBvZiB0aGUgUElYSSBmaWx0ZXJzIGxpYnJhcnlcbiAqIEBhdXRob3IgICAgICBNYXQgR3JvdmVzIDxtYXRAZ29vZGJveWRpZ2l0YWwuY29tPlxuICogQGNvcHlyaWdodCAgIDIwMTMtMjAxNSBHb29kQm95RGlnaXRhbFxuICogQGxpY2Vuc2UgICAgIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vR29vZEJveURpZ2l0YWwvcGl4aS5qcy9ibG9iL21hc3Rlci9MSUNFTlNFfE1JVCBMaWNlbnNlfVxuICovXG5cbi8qKlxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEFic3RyYWN0RmlsdGVyOiAgICAgcmVxdWlyZSgnLi9BYnN0cmFjdEZpbHRlcicpLFxuICAgIEFscGhhTWFza0ZpbHRlcjogICAgcmVxdWlyZSgnLi9BbHBoYU1hc2tGaWx0ZXInKSxcbiAgICBBc2NpaUZpbHRlcjogICAgICAgIHJlcXVpcmUoJy4vQXNjaWlGaWx0ZXInKSxcbiAgICBCbHVyRmlsdGVyOiAgICAgICAgIHJlcXVpcmUoJy4vQmx1ckZpbHRlcicpLFxuICAgIEJsdXJYRmlsdGVyOiAgICAgICAgcmVxdWlyZSgnLi9CbHVyWEZpbHRlcicpLFxuICAgIEJsdXJZRmlsdGVyOiAgICAgICAgcmVxdWlyZSgnLi9CbHVyWUZpbHRlcicpLFxuICAgIENvbG9yTWF0cml4RmlsdGVyOiAgcmVxdWlyZSgnLi9Db2xvck1hdHJpeEZpbHRlcicpLFxuICAgIENvbG9yU3RlcEZpbHRlcjogICAgcmVxdWlyZSgnLi9Db2xvclN0ZXBGaWx0ZXInKSxcbiAgICBDb252b2x1dGlvbkZpbHRlcjogIHJlcXVpcmUoJy4vQ29udm9sdXRpb25GaWx0ZXInKSxcbiAgICBDcm9zc0hhdGNoRmlsdGVyOiAgIHJlcXVpcmUoJy4vQ3Jvc3NIYXRjaEZpbHRlcicpLFxuICAgIERpc3BsYWNlbWVudEZpbHRlcjogcmVxdWlyZSgnLi9EaXNwbGFjZW1lbnRGaWx0ZXInKSxcbiAgICBEb3RTY3JlZW5GaWx0ZXI6ICAgIHJlcXVpcmUoJy4vRG90U2NyZWVuRmlsdGVyJyksXG4gICAgRmlsdGVyQmxvY2s6ICAgICAgICByZXF1aXJlKCcuL0ZpbHRlckJsb2NrJyksXG4gICAgR3JheUZpbHRlcjogICAgICAgICByZXF1aXJlKCcuL0dyYXlGaWx0ZXInKSxcbiAgICBJbnZlcnRGaWx0ZXI6ICAgICAgIHJlcXVpcmUoJy4vSW52ZXJ0RmlsdGVyJyksXG4gICAgTm9pc2VGaWx0ZXI6ICAgICAgICByZXF1aXJlKCcuL05vaXNlRmlsdGVyJyksXG4gICAgTm9ybWFsTWFwRmlsdGVyOiAgICByZXF1aXJlKCcuL05vcm1hbE1hcEZpbHRlcicpLFxuICAgIFBpeGVsYXRlRmlsdGVyOiAgICAgcmVxdWlyZSgnLi9QaXhlbGF0ZUZpbHRlcicpLFxuICAgIFJHQlNwbGl0RmlsdGVyOiAgICAgcmVxdWlyZSgnLi9SR0JTcGxpdEZpbHRlcicpLFxuICAgIFNlcGlhRmlsdGVyOiAgICAgICAgcmVxdWlyZSgnLi9TZXBpYUZpbHRlcicpLFxuICAgIFNtYXJ0Qmx1ckZpbHRlcjogICAgcmVxdWlyZSgnLi9TbWFydEJsdXJGaWx0ZXInKSxcbiAgICBUaWx0U2hpZnRGaWx0ZXI6ICAgIHJlcXVpcmUoJy4vVGlsdFNoaWZ0RmlsdGVyJyksXG4gICAgVGlsdFNoaWZ0WEZpbHRlcjogICByZXF1aXJlKCcuL1RpbHRTaGlmdFhGaWx0ZXInKSxcbiAgICBUaWx0U2hpZnRZRmlsdGVyOiAgIHJlcXVpcmUoJy4vVGlsdFNoaWZ0WUZpbHRlcicpLFxuICAgIFR3aXN0RmlsdGVyOiAgICAgICAgcmVxdWlyZSgnLi9Ud2lzdEZpbHRlcicpXG59O1xuIiwidmFyIGNvcmUgPSByZXF1aXJlKCcuLi9jb3JlJyk7XG5cbi8qKlxuICogSG9sZHMgYWxsIGluZm9ybWF0aW9uIHJlbGF0ZWQgdG8gYW4gSW50ZXJhY3Rpb24gZXZlbnRcbiAqXG4gKiBAY2xhc3NcbiAqIEBuYW1lc3BhY2UgUElYSVxuICovXG5mdW5jdGlvbiBJbnRlcmFjdGlvbkRhdGEoKSB7XG4gICAgLyoqXG4gICAgICogVGhpcyBwb2ludCBzdG9yZXMgdGhlIGdsb2JhbCBjb29yZHMgb2Ygd2hlcmUgdGhlIHRvdWNoL21vdXNlIGV2ZW50IGhhcHBlbmVkXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKi9cbiAgICB0aGlzLmdsb2JhbCA9IG5ldyBjb3JlLm1hdGguUG9pbnQoKTtcblxuICAgIC8qKlxuICAgICAqIFRoZSB0YXJnZXQgU3ByaXRlIHRoYXQgd2FzIGludGVyYWN0ZWQgd2l0aFxuICAgICAqXG4gICAgICogQG1lbWJlciB7U3ByaXRlfVxuICAgICAqL1xuICAgIHRoaXMudGFyZ2V0ID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqIFdoZW4gcGFzc2VkIHRvIGFuIGV2ZW50IGhhbmRsZXIsIHRoaXMgd2lsbCBiZSB0aGUgb3JpZ2luYWwgRE9NIEV2ZW50IHRoYXQgd2FzIGNhcHR1cmVkXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtFdmVudH1cbiAgICAgKi9cbiAgICB0aGlzLm9yaWdpbmFsRXZlbnQgPSBudWxsO1xufVxuXG5JbnRlcmFjdGlvbkRhdGEucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gSW50ZXJhY3Rpb25EYXRhO1xubW9kdWxlLmV4cG9ydHMgPSBJbnRlcmFjdGlvbkRhdGE7XG5cbi8qKlxuICogVGhpcyB3aWxsIHJldHVybiB0aGUgbG9jYWwgY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBkaXNwbGF5T2JqZWN0IGZvciB0aGlzIEludGVyYWN0aW9uRGF0YVxuICpcbiAqIEBwYXJhbSBkaXNwbGF5T2JqZWN0IHtEaXNwbGF5T2JqZWN0fSBUaGUgRGlzcGxheU9iamVjdCB0aGF0IHlvdSB3b3VsZCBsaWtlIHRoZSBsb2NhbCBjb29yZHMgb2ZmXG4gKiBAcGFyYW0gW3BvaW50XSB7UG9pbnR9IEEgUG9pbnQgb2JqZWN0IGluIHdoaWNoIHRvIHN0b3JlIHRoZSB2YWx1ZSwgb3B0aW9uYWwgKG90aGVyd2lzZSB3aWxsIGNyZWF0ZSBhIG5ldyBwb2ludClcbiAqIEByZXR1cm4ge1BvaW50fSBBIHBvaW50IGNvbnRhaW5pbmcgdGhlIGNvb3JkaW5hdGVzIG9mIHRoZSBJbnRlcmFjdGlvbkRhdGEgcG9zaXRpb24gcmVsYXRpdmUgdG8gdGhlIERpc3BsYXlPYmplY3RcbiAqL1xuSW50ZXJhY3Rpb25EYXRhLnByb3RvdHlwZS5nZXRMb2NhbFBvc2l0aW9uID0gZnVuY3Rpb24gKGRpc3BsYXlPYmplY3QsIHBvaW50KSB7XG4gICAgdmFyIHdvcmxkVHJhbnNmb3JtID0gZGlzcGxheU9iamVjdC53b3JsZFRyYW5zZm9ybTtcbiAgICB2YXIgZ2xvYmFsID0gdGhpcy5nbG9iYWw7XG5cbiAgICAvLyBkbyBhIGNoZWVreSB0cmFuc2Zvcm0gdG8gZ2V0IHRoZSBtb3VzZSBjb29yZHM7XG4gICAgdmFyIGEwMCA9IHdvcmxkVHJhbnNmb3JtLmEsIGEwMSA9IHdvcmxkVHJhbnNmb3JtLmMsIGEwMiA9IHdvcmxkVHJhbnNmb3JtLnR4LFxuICAgICAgICBhMTAgPSB3b3JsZFRyYW5zZm9ybS5iLCBhMTEgPSB3b3JsZFRyYW5zZm9ybS5kLCBhMTIgPSB3b3JsZFRyYW5zZm9ybS50eSxcbiAgICAgICAgaWQgPSAxIC8gKGEwMCAqIGExMSArIGEwMSAqIC1hMTApO1xuXG4gICAgcG9pbnQgPSBwb2ludCB8fCBuZXcgY29yZS5tYXRoLlBvaW50KCk7XG5cbiAgICBwb2ludC54ID0gYTExICogaWQgKiBnbG9iYWwueCArIC1hMDEgKiBpZCAqIGdsb2JhbC55ICsgKGExMiAqIGEwMSAtIGEwMiAqIGExMSkgKiBpZDtcbiAgICBwb2ludC55ID0gYTAwICogaWQgKiBnbG9iYWwueSArIC1hMTAgKiBpZCAqIGdsb2JhbC54ICsgKC1hMTIgKiBhMDAgKyBhMDIgKiBhMTApICogaWQ7XG5cbiAgICAvLyBzZXQgdGhlIG1vdXNlIGNvb3Jkcy4uLlxuICAgIHJldHVybiBwb2ludDtcbn07XG4iLCJ2YXIgY29yZSA9IHJlcXVpcmUoJy4uL2NvcmUnKSxcbiAgICBJbnRlcmFjdGlvbkRhdGEgPSByZXF1aXJlKCcuL0ludGVyYWN0aW9uRGF0YScpO1xuXG4vLyBUT0RPOiBPYnZpb3VzbHkgcmV3cml0ZSB0aGlzLi4uXG52YXIgSU5URVJBQ1RJT05fRlJFUVVFTkNZID0gMzA7XG52YXIgQVVUT19QUkVWRU5UX0RFRkFVTFQgPSB0cnVlO1xuXG4vKipcbiAqIFRoZSBpbnRlcmFjdGlvbiBtYW5hZ2VyIGRlYWxzIHdpdGggbW91c2UgYW5kIHRvdWNoIGV2ZW50cy4gQW55IERpc3BsYXlPYmplY3QgY2FuIGJlIGludGVyYWN0aXZlXG4gKiBpZiBpdHMgaW50ZXJhY3RpdmUgcGFyYW1ldGVyIGlzIHNldCB0byB0cnVlXG4gKiBUaGlzIG1hbmFnZXIgYWxzbyBzdXBwb3J0cyBtdWx0aXRvdWNoLlxuICpcbiAqIEBjbGFzc1xuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gc3RhZ2Uge1N0YWdlfSBUaGUgc3RhZ2UgdG8gaGFuZGxlIGludGVyYWN0aW9uc1xuICovXG5mdW5jdGlvbiBJbnRlcmFjdGlvbk1hbmFnZXIoc3RhZ2UpIHtcbiAgICAvKipcbiAgICAgKiBBIHJlZmVyZW5jZSB0byB0aGUgc3RhZ2VcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1N0YWdlfVxuICAgICAqL1xuICAgIHRoaXMuc3RhZ2UgPSBzdGFnZTtcblxuICAgIC8qKlxuICAgICAqIFRoZSBtb3VzZSBkYXRhXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtJbnRlcmFjdGlvbkRhdGF9XG4gICAgICovXG4gICAgdGhpcy5tb3VzZSA9IG5ldyBJbnRlcmFjdGlvbkRhdGEoKTtcblxuICAgIC8qKlxuICAgICAqIEFuIG9iamVjdCB0aGF0IHN0b3JlcyBjdXJyZW50IHRvdWNoZXMgKEludGVyYWN0aW9uRGF0YSkgYnkgaWQgcmVmZXJlbmNlXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtvYmplY3R9XG4gICAgICovXG4gICAgdGhpcy50b3VjaGVzID0ge307XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtQb2ludH1cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMudGVtcFBvaW50ID0gbmV3IGNvcmUubWF0aC5Qb2ludCgpO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAZGVmYXVsdFxuICAgICAqL1xuICAgIHRoaXMubW91c2VvdmVyRW5hYmxlZCA9IHRydWU7XG5cbiAgICAvKipcbiAgICAgKiBUaW55IGxpdHRsZSBpbnRlcmFjdGl2ZURhdGEgcG9vbCAhXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtBcnJheX1cbiAgICAgKi9cbiAgICB0aGlzLnBvb2wgPSBbXTtcblxuICAgIC8qKlxuICAgICAqIEFuIGFycmF5IGNvbnRhaW5pbmcgYWxsIHRoZSBpdGVyYXRpdmUgaXRlbXMgZnJvbSB0aGUgb3VyIGludGVyYWN0aXZlIHRyZWVcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0FycmF5fVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zID0gW107XG5cbiAgICAvKipcbiAgICAgKiBUaGUgRE9NIGVsZW1lbnQgdG8gYmluZCB0by5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge0hUTUxFbGVtZW50fVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQgPSBudWxsO1xuXG4gICAgLyoqXG4gICAgICogSGF2ZSBldmVudHMgYmVlbiBhdHRhY2hlZCB0byB0aGUgZG9tIGVsZW1lbnQ/XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5ldmVudHNBZGRlZCA9IGZhbHNlO1xuXG4gICAgLy90aGlzIHdpbGwgbWFrZSBpdCBzbyB0aGF0IHlvdSBkb24ndCBoYXZlIHRvIGNhbGwgYmluZCBhbGwgdGhlIHRpbWVcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge0Z1bmN0aW9ufVxuICAgICAqL1xuICAgIHRoaXMub25Nb3VzZU1vdmUgPSB0aGlzLm9uTW91c2VNb3ZlLmJpbmQoIHRoaXMgKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge0Z1bmN0aW9ufVxuICAgICAqL1xuICAgIHRoaXMub25Nb3VzZURvd24gPSB0aGlzLm9uTW91c2VEb3duLmJpbmQodGhpcyk7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtGdW5jdGlvbn1cbiAgICAgKi9cbiAgICB0aGlzLm9uTW91c2VPdXQgPSB0aGlzLm9uTW91c2VPdXQuYmluZCh0aGlzKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge0Z1bmN0aW9ufVxuICAgICAqL1xuICAgIHRoaXMub25Nb3VzZVVwID0gdGhpcy5vbk1vdXNlVXAuYmluZCh0aGlzKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge0Z1bmN0aW9ufVxuICAgICAqL1xuICAgIHRoaXMub25Ub3VjaFN0YXJ0ID0gdGhpcy5vblRvdWNoU3RhcnQuYmluZCh0aGlzKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge0Z1bmN0aW9ufVxuICAgICAqL1xuICAgIHRoaXMub25Ub3VjaEVuZCA9IHRoaXMub25Ub3VjaEVuZC5iaW5kKHRoaXMpO1xuXG4gICAgLyoqXG4gICAgICogQG1lbWJlciB7RnVuY3Rpb259XG4gICAgICovXG4gICAgdGhpcy5vblRvdWNoTW92ZSA9IHRoaXMub25Ub3VjaE1vdmUuYmluZCh0aGlzKTtcblxuICAgIC8qKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKi9cbiAgICB0aGlzLmxhc3QgPSAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGNzcyBzdHlsZSBvZiB0aGUgY3Vyc29yIHRoYXQgaXMgYmVpbmcgdXNlZFxuICAgICAqIEBtZW1iZXIge3N0cmluZ31cbiAgICAgKi9cbiAgICB0aGlzLmN1cnJlbnRDdXJzb3JTdHlsZSA9ICdpbmhlcml0JztcblxuICAgIC8qKlxuICAgICAqIElzIHNldCB0byB0cnVlIHdoZW4gdGhlIG1vdXNlIGlzIG1vdmVkIG91dCBvZiB0aGUgY2FudmFzXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLm1vdXNlT3V0ID0gZmFsc2U7XG5cbiAgICAvKipcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICovXG4gICAgdGhpcy5yZXNvbHV0aW9uID0gMTtcblxuICAgIC8vIHVzZWQgZm9yIGhpdCB0ZXN0aW5nXG4gICAgdGhpcy5fdGVtcFBvaW50ID0gbmV3IGNvcmUubWF0aC5Qb2ludCgpO1xufVxuXG5JbnRlcmFjdGlvbk1hbmFnZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gSW50ZXJhY3Rpb25NYW5hZ2VyO1xubW9kdWxlLmV4cG9ydHMgPSBJbnRlcmFjdGlvbk1hbmFnZXI7XG5cbi8qKlxuICogQ29sbGVjdHMgYW4gaW50ZXJhY3RpdmUgc3ByaXRlIHJlY3Vyc2l2ZWx5IHRvIGhhdmUgdGhlaXIgaW50ZXJhY3Rpb25zIG1hbmFnZWRcbiAqXG4gKiBAcGFyYW0gZGlzcGxheU9iamVjdCB7RGlzcGxheU9iamVjdH0gdGhlIGRpc3BsYXlPYmplY3QgdG8gY29sbGVjdFxuICogQHBhcmFtIGlQYXJlbnQge0Rpc3BsYXlPYmplY3R9IHRoZSBkaXNwbGF5IG9iamVjdCdzIHBhcmVudFxuICogQHByaXZhdGVcbiAqL1xuSW50ZXJhY3Rpb25NYW5hZ2VyLnByb3RvdHlwZS5jb2xsZWN0SW50ZXJhY3RpdmVTcHJpdGUgPSBmdW5jdGlvbiAoZGlzcGxheU9iamVjdCwgaVBhcmVudCkge1xuICAgIHZhciBjaGlsZHJlbiA9IGRpc3BsYXlPYmplY3QuY2hpbGRyZW47XG4gICAgdmFyIGxlbmd0aCA9IGNoaWxkcmVuLmxlbmd0aDtcblxuICAgIC8vIG1ha2UgYW4gaW50ZXJhY3Rpb24gdHJlZS4uLiB7aXRlbS5fX2ludGVyYWN0aXZlUGFyZW50fVxuICAgIGZvciAodmFyIGkgPSBsZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgICB2YXIgY2hpbGQgPSBjaGlsZHJlbltpXTtcblxuICAgICAgICAvLyBwdXNoIGFsbCBpbnRlcmFjdGl2ZSBiaXRzXG4gICAgICAgIGlmIChjaGlsZC5faW50ZXJhY3RpdmUpIHtcbiAgICAgICAgICAgIGlQYXJlbnQuaW50ZXJhY3RpdmVDaGlsZHJlbiA9IHRydWU7XG4gICAgICAgICAgICAvL2NoaWxkLl9faVBhcmVudCA9IGlQYXJlbnQ7XG4gICAgICAgICAgICB0aGlzLmludGVyYWN0aXZlSXRlbXMucHVzaChjaGlsZCk7XG5cbiAgICAgICAgICAgIGlmIChjaGlsZC5jaGlsZHJlbi5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jb2xsZWN0SW50ZXJhY3RpdmVTcHJpdGUoY2hpbGQsIGNoaWxkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNoaWxkLl9faVBhcmVudCA9IG51bGw7XG4gICAgICAgICAgICBpZiAoY2hpbGQuY2hpbGRyZW4ubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHRoaXMuY29sbGVjdEludGVyYWN0aXZlU3ByaXRlKGNoaWxkLCBpUGFyZW50KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgfVxufTtcblxuLyoqXG4gKiBTZXRzIHRoZSBET00gZWxlbWVudCB3aGljaCB3aWxsIHJlY2VpdmUgbW91c2UvdG91Y2ggZXZlbnRzLiBUaGlzIGlzIHVzZWZ1bCBmb3Igd2hlbiB5b3UgaGF2ZVxuICogb3RoZXIgRE9NIGVsZW1lbnRzIG9uIHRvcCBvZiB0aGUgcmVuZGVyZXJzIENhbnZhcyBlbGVtZW50LiBXaXRoIHRoaXMgeW91J2xsIGJlIGJhbGUgdG8gZGVsZXRlZ2F0ZVxuICogYW5vdGhlciBET00gZWxlbWVudCB0byByZWNlaXZlIHRob3NlIGV2ZW50cy5cbiAqXG4gKiBAcGFyYW0gZWxlbWVudCB7SFRNTEVsZW1lbnR9IHRoZSBET00gZWxlbWVudCB3aGljaCB3aWxsIHJlY2VpdmUgbW91c2UgYW5kIHRvdWNoIGV2ZW50cy5cbiAqIEBwYXJhbSBbcmVzb2x1dGlvbj0xXSB7bnVtYmVyfSBUSGUgcmVzb2x1dGlvbiBvZiB0aGUgbmV3IGVsZW1lbnQgKHJlbGF0aXZlIHRvIHRoZSBjYW52YXMpLlxuICogQHByaXZhdGVcbiAqL1xuSW50ZXJhY3Rpb25NYW5hZ2VyLnByb3RvdHlwZS5zZXRUYXJnZXRFbGVtZW50ID0gZnVuY3Rpb24gKGVsZW1lbnQsIHJlc29sdXRpb24pIHtcbiAgICB0aGlzLnJlbW92ZUV2ZW50cygpO1xuXG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQgPSBlbGVtZW50O1xuXG4gICAgdGhpcy5yZXNvbHV0aW9uID0gcmVzb2x1dGlvbiB8fCAxO1xuXG4gICAgdGhpcy5hZGRFdmVudHMoKTtcbn07XG5cbi8qKlxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUuYWRkRXZlbnRzID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICghdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh3aW5kb3cubmF2aWdhdG9yLm1zUG9pbnRlckVuYWJsZWQpIHtcbiAgICAgICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQuc3R5bGVbJy1tcy1jb250ZW50LXpvb21pbmcnXSA9ICdub25lJztcbiAgICAgICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQuc3R5bGVbJy1tcy10b3VjaC1hY3Rpb24nXSA9ICdub25lJztcbiAgICB9XG5cbiAgICB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZW1vdmUnLCAgICB0aGlzLm9uTW91c2VNb3ZlLCB0cnVlKTtcbiAgICB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZWRvd24nLCAgICB0aGlzLm9uTW91c2VEb3duLCB0cnVlKTtcbiAgICB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdtb3VzZW91dCcsICAgICB0aGlzLm9uTW91c2VPdXQsIHRydWUpO1xuXG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigndG91Y2hzdGFydCcsICAgdGhpcy5vblRvdWNoU3RhcnQsIHRydWUpO1xuICAgIHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoJ3RvdWNoZW5kJywgICAgIHRoaXMub25Ub3VjaEVuZCwgdHJ1ZSk7XG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcigndG91Y2htb3ZlJywgICAgdGhpcy5vblRvdWNoTW92ZSwgdHJ1ZSk7XG5cbiAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbW91c2V1cCcsICB0aGlzLm9uTW91c2VVcCwgdHJ1ZSk7XG5cbiAgICB0aGlzLmV2ZW50c0FkZGVkID0gdHJ1ZTtcbn07XG5cbi8qKlxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUucmVtb3ZlRXZlbnRzID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICghdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh3aW5kb3cubmF2aWdhdG9yLm1zUG9pbnRlckVuYWJsZWQpIHtcbiAgICAgICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQuc3R5bGVbJy1tcy1jb250ZW50LXpvb21pbmcnXSA9ICcnO1xuICAgICAgICB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5zdHlsZVsnLW1zLXRvdWNoLWFjdGlvbiddID0gJyc7XG4gICAgfVxuXG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vtb3ZlJywgdGhpcy5vbk1vdXNlTW92ZSwgdHJ1ZSk7XG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2Vkb3duJywgdGhpcy5vbk1vdXNlRG93biwgdHJ1ZSk7XG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcignbW91c2VvdXQnLCAgdGhpcy5vbk1vdXNlT3V0LCB0cnVlKTtcblxuICAgIHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ3RvdWNoc3RhcnQnLCB0aGlzLm9uVG91Y2hTdGFydCwgdHJ1ZSk7XG4gICAgdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcigndG91Y2hlbmQnLCAgdGhpcy5vblRvdWNoRW5kLCB0cnVlKTtcbiAgICB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCd0b3VjaG1vdmUnLCB0aGlzLm9uVG91Y2hNb3ZlLCB0cnVlKTtcblxuICAgIHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50ID0gbnVsbDtcblxuICAgIHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCdtb3VzZXVwJywgIHRoaXMub25Nb3VzZVVwLCB0cnVlKTtcblxuICAgIHRoaXMuZXZlbnRzQWRkZWQgPSBmYWxzZTtcbn07XG5cbi8qKlxuICogdXBkYXRlcyB0aGUgc3RhdGUgb2YgaW50ZXJhY3RpdmUgb2JqZWN0c1xuICpcbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUudXBkYXRlID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICghdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIGZyZXF1ZW5jeSBvZiAzMGZwcz8/XG4gICAgdmFyIG5vdyA9IERhdGUubm93KCk7XG4gICAgdmFyIGRpZmYgPSBub3cgLSB0aGlzLmxhc3Q7XG4gICAgZGlmZiA9IChkaWZmICogSU5URVJBQ1RJT05fRlJFUVVFTkNZICkgLyAxMDAwO1xuICAgIGlmIChkaWZmIDwgMSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5sYXN0ID0gbm93O1xuXG4gICAgdmFyIGkgPSAwO1xuXG4gICAgLy8gb2suLiBzbyBtb3VzZSBldmVudHM/P1xuICAgIC8vIHllcyBmb3Igbm93IDopXG4gICAgLy8gT1BUSU1JU0UgLSBob3cgb2Z0ZW4gdG8gY2hlY2s/P1xuICAgIGlmICh0aGlzLmRpcnR5KSB7XG4gICAgICAgIHRoaXMucmVidWlsZEludGVyYWN0aXZlR3JhcGgoKTtcbiAgICB9XG5cbiAgICAvLyBsb29wIHRocm91Z2ggaW50ZXJhY3RpdmUgb2JqZWN0cyFcbiAgICB2YXIgbGVuZ3RoID0gdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zLmxlbmd0aDtcbiAgICB2YXIgY3Vyc29yID0gJ2luaGVyaXQnO1xuICAgIHZhciBvdmVyID0gZmFsc2U7XG5cbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGl0ZW0gPSB0aGlzLmludGVyYWN0aXZlSXRlbXNbaV07XG5cbiAgICAgICAgLy8gT1BUSU1JU0FUSU9OIC0gb25seSBjYWxjdWxhdGUgZXZlcnkgdGltZSBpZiB0aGUgbW91c2Vtb3ZlIGZ1bmN0aW9uIGV4aXN0cy4uXG4gICAgICAgIC8vIE9LIHNvLi4gZG9lcyB0aGUgb2JqZWN0IGhhdmUgYW55IG90aGVyIGludGVyYWN0aXZlIGZ1bmN0aW9ucz9cbiAgICAgICAgLy8gaGl0LXRlc3QgdGhlIGNsaXAhXG4gICAgICAgLy8gaWYgKGl0ZW0ubW91c2VvdmVyIHx8IGl0ZW0ubW91c2VvdXQgfHwgaXRlbS5idXR0b25Nb2RlKVxuICAgICAgIC8vIHtcbiAgICAgICAgLy8gb2sgc28gdGhlcmUgYXJlIHNvbWUgZnVuY3Rpb25zIHNvIGxldHMgaGl0IHRlc3QgaXQuLlxuICAgICAgICBpdGVtLl9faGl0ID0gdGhpcy5oaXRUZXN0KGl0ZW0sIHRoaXMubW91c2UpO1xuICAgICAgICB0aGlzLm1vdXNlLnRhcmdldCA9IGl0ZW07XG4gICAgICAgIC8vIG9rIHNvIGRlYWwgd2l0aCBpbnRlcmFjdGlvbnMuLlxuICAgICAgICAvLyBsb29rcyBsaWtlIHRoZXJlIHdhcyBhIGhpdCFcbiAgICAgICAgaWYgKGl0ZW0uX19oaXQgJiYgIW92ZXIpIHtcbiAgICAgICAgICAgIGlmIChpdGVtLmJ1dHRvbk1vZGUpIHtcbiAgICAgICAgICAgICAgICBjdXJzb3IgPSBpdGVtLmRlZmF1bHRDdXJzb3I7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghaXRlbS5pbnRlcmFjdGl2ZUNoaWxkcmVuKSB7XG4gICAgICAgICAgICAgICAgb3ZlciA9IHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghaXRlbS5fX2lzT3Zlcikge1xuICAgICAgICAgICAgICAgIGlmIChpdGVtLm1vdXNlb3Zlcikge1xuICAgICAgICAgICAgICAgICAgICBpdGVtLm1vdXNlb3ZlciAodGhpcy5tb3VzZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGl0ZW0uX19pc092ZXIgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgaWYgKGl0ZW0uX19pc092ZXIpIHtcbiAgICAgICAgICAgICAgICAvLyByb2xsIG91dCFcbiAgICAgICAgICAgICAgICBpZiAoaXRlbS5tb3VzZW91dCkge1xuICAgICAgICAgICAgICAgICAgICBpdGVtLm1vdXNlb3V0ICh0aGlzLm1vdXNlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaXRlbS5fX2lzT3ZlciA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuY3VycmVudEN1cnNvclN0eWxlICE9PSBjdXJzb3IpIHtcbiAgICAgICAgdGhpcy5jdXJyZW50Q3Vyc29yU3R5bGUgPSBjdXJzb3I7XG4gICAgICAgIHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LnN0eWxlLmN1cnNvciA9IGN1cnNvcjtcbiAgICB9XG59O1xuXG4vKipcbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUucmVidWlsZEludGVyYWN0aXZlR3JhcGggPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5kaXJ0eSA9IGZhbHNlO1xuXG4gICAgdmFyIGxlbiA9IHRoaXMuaW50ZXJhY3RpdmVJdGVtcy5sZW5ndGg7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG4gICAgICAgIHRoaXMuaW50ZXJhY3RpdmVJdGVtc1tpXS5pbnRlcmFjdGl2ZUNoaWxkcmVuID0gZmFsc2U7XG4gICAgfVxuXG4gICAgdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zLmxlbmd0aCA9IDA7XG5cbiAgICBpZiAodGhpcy5zdGFnZS5pbnRlcmFjdGl2ZSkge1xuICAgICAgICB0aGlzLmludGVyYWN0aXZlSXRlbXMucHVzaCh0aGlzLnN0YWdlKTtcbiAgICB9XG5cbiAgICAvLyBHbyB0aHJvdWdoIGFuZCBjb2xsZWN0IGFsbCB0aGUgb2JqZWN0cyB0aGF0IGFyZSBpbnRlcmFjdGl2ZS4uXG4gICAgdGhpcy5jb2xsZWN0SW50ZXJhY3RpdmVTcHJpdGUodGhpcy5zdGFnZSwgdGhpcy5zdGFnZSk7XG59O1xuXG4vKipcbiAqIElzIGNhbGxlZCB3aGVuIHRoZSBtb3VzZSBtb3ZlcyBhY3Jvc3MgdGhlIHJlbmRlcmVyIGVsZW1lbnRcbiAqXG4gKiBAcGFyYW0gZXZlbnQge0V2ZW50fSBUaGUgRE9NIGV2ZW50IG9mIHRoZSBtb3VzZSBtb3ZpbmdcbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUub25Nb3VzZU1vdmUgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnJlYnVpbGRJbnRlcmFjdGl2ZUdyYXBoKCk7XG4gICAgfVxuXG4gICAgdGhpcy5tb3VzZS5vcmlnaW5hbEV2ZW50ID0gZXZlbnQ7XG5cbiAgICAvLyBUT0RPIG9wdGltaXplIGJ5IG5vdCBjaGVjayBFVkVSWSBUSU1FISBtYXliZSBoYWxmIGFzIG9mdGVuPyAvL1xuICAgIHZhciByZWN0ID0gdGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cbiAgICB0aGlzLm1vdXNlLmdsb2JhbC54ID0gKGV2ZW50LmNsaWVudFggLSByZWN0LmxlZnQpICogKHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LndpZHRoIC8gcmVjdC53aWR0aCkgLyB0aGlzLnJlc29sdXRpb247XG4gICAgdGhpcy5tb3VzZS5nbG9iYWwueSA9IChldmVudC5jbGllbnRZIC0gcmVjdC50b3ApICogKCB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5oZWlnaHQgLyByZWN0LmhlaWdodCkgLyB0aGlzLnJlc29sdXRpb247XG5cbiAgICB2YXIgbGVuZ3RoID0gdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zLmxlbmd0aDtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGl0ZW0gPSB0aGlzLmludGVyYWN0aXZlSXRlbXNbaV07XG5cbiAgICAgICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24hXG4gICAgICAgIGlmIChpdGVtLm1vdXNlbW92ZSkge1xuICAgICAgICAgICAgaXRlbS5tb3VzZW1vdmUodGhpcy5tb3VzZSk7XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4vKipcbiAqIElzIGNhbGxlZCB3aGVuIHRoZSBtb3VzZSBidXR0b24gaXMgcHJlc3NlZCBkb3duIG9uIHRoZSByZW5kZXJlciBlbGVtZW50XG4gKlxuICogQHBhcmFtIGV2ZW50IHtFdmVudH0gVGhlIERPTSBldmVudCBvZiBhIG1vdXNlIGJ1dHRvbiBiZWluZyBwcmVzc2VkIGRvd25cbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUub25Nb3VzZURvd24gPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnJlYnVpbGRJbnRlcmFjdGl2ZUdyYXBoKCk7XG4gICAgfVxuXG4gICAgdGhpcy5tb3VzZS5vcmlnaW5hbEV2ZW50ID0gZXZlbnQ7XG5cbiAgICBpZiAoQVVUT19QUkVWRU5UX0RFRkFVTFQpIHtcbiAgICAgICAgdGhpcy5tb3VzZS5vcmlnaW5hbEV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuXG4gICAgLy8gbG9vcCB0aHJvdWdoIGludGVyYWN0aW9uIHRyZWUuLi5cbiAgICAvLyBoaXQgdGVzdCBlYWNoIGl0ZW0hIC0+XG4gICAgLy8gZ2V0IGludGVyYWN0aXZlIGl0ZW1zIHVuZGVyIHBvaW50Pz9cbiAgICAvL3N0YWdlLl9faVxuICAgIHZhciBsZW5ndGggPSB0aGlzLmludGVyYWN0aXZlSXRlbXMubGVuZ3RoO1xuXG4gICAgdmFyIGUgPSB0aGlzLm1vdXNlLm9yaWdpbmFsRXZlbnQ7XG4gICAgdmFyIGlzUmlnaHRCdXR0b24gPSBlLmJ1dHRvbiA9PT0gMiB8fCBlLndoaWNoID09PSAzO1xuICAgIHZhciBkb3duRnVuY3Rpb24gPSBpc1JpZ2h0QnV0dG9uID8gJ3JpZ2h0ZG93bicgOiAnbW91c2Vkb3duJztcbiAgICB2YXIgY2xpY2tGdW5jdGlvbiA9IGlzUmlnaHRCdXR0b24gPyAncmlnaHRjbGljaycgOiAnY2xpY2snO1xuICAgIHZhciBidXR0b25Jc0Rvd24gPSBpc1JpZ2h0QnV0dG9uID8gJ19fcmlnaHRJc0Rvd24nIDogJ19fbW91c2VJc0Rvd24nO1xuICAgIHZhciBpc0Rvd24gPSBpc1JpZ2h0QnV0dG9uID8gJ19faXNSaWdodERvd24nIDogJ19faXNEb3duJztcblxuICAgIC8vIHdoaWxlXG4gICAgLy8gaGl0IHRlc3RcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBpdGVtID0gdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zW2ldO1xuXG4gICAgICAgIGlmIChpdGVtW2Rvd25GdW5jdGlvbl0gfHwgaXRlbVtjbGlja0Z1bmN0aW9uXSkge1xuICAgICAgICAgICAgaXRlbVtidXR0b25Jc0Rvd25dID0gdHJ1ZTtcbiAgICAgICAgICAgIGl0ZW0uX19oaXQgPSB0aGlzLmhpdFRlc3QoaXRlbSwgdGhpcy5tb3VzZSk7XG5cbiAgICAgICAgICAgIGlmIChpdGVtLl9faGl0KSB7XG4gICAgICAgICAgICAgICAgLy9jYWxsIHRoZSBmdW5jdGlvbiFcbiAgICAgICAgICAgICAgICBpZiAoaXRlbVtkb3duRnVuY3Rpb25dKSB7XG4gICAgICAgICAgICAgICAgICAgIGl0ZW1bZG93bkZ1bmN0aW9uXSh0aGlzLm1vdXNlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaXRlbVtpc0Rvd25dID0gdHJ1ZTtcblxuICAgICAgICAgICAgICAgIC8vIGp1c3QgdGhlIG9uZSFcbiAgICAgICAgICAgICAgICBpZiAoIWl0ZW0uaW50ZXJhY3RpdmVDaGlsZHJlbikge1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4vKipcbiAqIElzIGNhbGxlZCB3aGVuIHRoZSBtb3VzZSBpcyBtb3ZlZCBvdXQgb2YgdGhlIHJlbmRlcmVyIGVsZW1lbnRcbiAqXG4gKiBAcGFyYW0gZXZlbnQge0V2ZW50fSBUaGUgRE9NIGV2ZW50IG9mIGEgbW91c2UgYmVpbmcgbW92ZWQgb3V0XG4gKiBAcHJpdmF0ZVxuICovXG5JbnRlcmFjdGlvbk1hbmFnZXIucHJvdG90eXBlLm9uTW91c2VPdXQgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnJlYnVpbGRJbnRlcmFjdGl2ZUdyYXBoKCk7XG4gICAgfVxuXG4gICAgdGhpcy5tb3VzZS5vcmlnaW5hbEV2ZW50ID0gZXZlbnQ7XG5cbiAgICB2YXIgbGVuZ3RoID0gdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zLmxlbmd0aDtcblxuICAgIHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LnN0eWxlLmN1cnNvciA9ICdpbmhlcml0JztcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGl0ZW0gPSB0aGlzLmludGVyYWN0aXZlSXRlbXNbaV07XG4gICAgICAgIGlmIChpdGVtLl9faXNPdmVyKSB7XG4gICAgICAgICAgICB0aGlzLm1vdXNlLnRhcmdldCA9IGl0ZW07XG4gICAgICAgICAgICBpZiAoaXRlbS5tb3VzZW91dCkge1xuICAgICAgICAgICAgICAgIGl0ZW0ubW91c2VvdXQodGhpcy5tb3VzZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpdGVtLl9faXNPdmVyID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLm1vdXNlT3V0ID0gdHJ1ZTtcblxuICAgIC8vIG1vdmUgdGhlIG1vdXNlIHRvIGFuIGltcG9zc2libGUgcG9zaXRpb25cbiAgICB0aGlzLm1vdXNlLmdsb2JhbC54ID0gLTEwMDAwO1xuICAgIHRoaXMubW91c2UuZ2xvYmFsLnkgPSAtMTAwMDA7XG59O1xuXG4vKipcbiAqIElzIGNhbGxlZCB3aGVuIHRoZSBtb3VzZSBidXR0b24gaXMgcmVsZWFzZWQgb24gdGhlIHJlbmRlcmVyIGVsZW1lbnRcbiAqXG4gKiBAcGFyYW0gZXZlbnQge0V2ZW50fSBUaGUgRE9NIGV2ZW50IG9mIGEgbW91c2UgYnV0dG9uIGJlaW5nIHJlbGVhc2VkXG4gKiBAcHJpdmF0ZVxuICovXG5JbnRlcmFjdGlvbk1hbmFnZXIucHJvdG90eXBlLm9uTW91c2VVcCA9IGZ1bmN0aW9uIChldmVudCkge1xuICAgIGlmICh0aGlzLmRpcnR5KSB7XG4gICAgICAgIHRoaXMucmVidWlsZEludGVyYWN0aXZlR3JhcGgoKTtcbiAgICB9XG5cbiAgICB0aGlzLm1vdXNlLm9yaWdpbmFsRXZlbnQgPSBldmVudDtcblxuICAgIHZhciBsZW5ndGggPSB0aGlzLmludGVyYWN0aXZlSXRlbXMubGVuZ3RoO1xuICAgIHZhciB1cCA9IGZhbHNlO1xuXG4gICAgdmFyIGUgPSB0aGlzLm1vdXNlLm9yaWdpbmFsRXZlbnQ7XG4gICAgdmFyIGlzUmlnaHRCdXR0b24gPSBlLmJ1dHRvbiA9PT0gMiB8fCBlLndoaWNoID09PSAzO1xuXG4gICAgdmFyIHVwRnVuY3Rpb24gPSBpc1JpZ2h0QnV0dG9uID8gJ3JpZ2h0dXAnIDogJ21vdXNldXAnO1xuICAgIHZhciBjbGlja0Z1bmN0aW9uID0gaXNSaWdodEJ1dHRvbiA/ICdyaWdodGNsaWNrJyA6ICdjbGljayc7XG4gICAgdmFyIHVwT3V0c2lkZUZ1bmN0aW9uID0gaXNSaWdodEJ1dHRvbiA/ICdyaWdodHVwb3V0c2lkZScgOiAnbW91c2V1cG91dHNpZGUnO1xuICAgIHZhciBpc0Rvd24gPSBpc1JpZ2h0QnV0dG9uID8gJ19faXNSaWdodERvd24nIDogJ19faXNEb3duJztcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGl0ZW0gPSB0aGlzLmludGVyYWN0aXZlSXRlbXNbaV07XG5cbiAgICAgICAgaWYgKGl0ZW1bY2xpY2tGdW5jdGlvbl0gfHwgaXRlbVt1cEZ1bmN0aW9uXSB8fCBpdGVtW3VwT3V0c2lkZUZ1bmN0aW9uXSkge1xuICAgICAgICAgICAgaXRlbS5fX2hpdCA9IHRoaXMuaGl0VGVzdChpdGVtLCB0aGlzLm1vdXNlKTtcblxuICAgICAgICAgICAgaWYgKGl0ZW0uX19oaXQgJiYgIXVwKSB7XG4gICAgICAgICAgICAgICAgLy9jYWxsIHRoZSBmdW5jdGlvbiFcbiAgICAgICAgICAgICAgICBpZiAoaXRlbVt1cEZ1bmN0aW9uXSkge1xuICAgICAgICAgICAgICAgICAgICBpdGVtW3VwRnVuY3Rpb25dKHRoaXMubW91c2UpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoaXRlbVtpc0Rvd25dKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpdGVtW2NsaWNrRnVuY3Rpb25dKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpdGVtW2NsaWNrRnVuY3Rpb25dKHRoaXMubW91c2UpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKCFpdGVtLmludGVyYWN0aXZlQ2hpbGRyZW4pIHtcbiAgICAgICAgICAgICAgICAgICAgdXAgPSB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmIChpdGVtW2lzRG93bl0pIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGl0ZW1bdXBPdXRzaWRlRnVuY3Rpb25dKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpdGVtW3VwT3V0c2lkZUZ1bmN0aW9uXSh0aGlzLm1vdXNlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaXRlbVtpc0Rvd25dID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4vKipcbiAqIFRlc3RzIGlmIHRoZSBjdXJyZW50IG1vdXNlIGNvb3JkaW5hdGVzIGhpdCBhIHNwcml0ZVxuICpcbiAqIEBwYXJhbSBpdGVtIHtEaXNwbGF5T2JqZWN0fSBUaGUgZGlzcGxheU9iamVjdCB0byB0ZXN0IGZvciBhIGhpdFxuICogQHBhcmFtIGludGVyYWN0aW9uRGF0YSB7SW50ZXJhY3Rpb25EYXRhfSBUaGUgaW50ZXJhY3Rpb25EYXRhIG9iamVjdCB0byB1cGRhdGUgaW4gdGhlIGNhc2UgdGhlcmUgaXMgYSBoaXRcbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUuaGl0VGVzdCA9IGZ1bmN0aW9uIChpdGVtLCBpbnRlcmFjdGlvbkRhdGEpIHtcbiAgICB2YXIgZ2xvYmFsID0gaW50ZXJhY3Rpb25EYXRhLmdsb2JhbDtcblxuICAgIGlmICghaXRlbS53b3JsZFZpc2libGUpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIG1hcCB0aGUgZ2xvYmFsIHBvaW50IHRvIGxvY2FsIHNwYWNlLlxuICAgIGl0ZW0ud29ybGRUcmFuc2Zvcm0uYXBwbHlJbnZlcnNlKGdsb2JhbCwgIHRoaXMuX3RlbXBQb2ludCk7XG5cbiAgICB2YXIgeCA9IHRoaXMuX3RlbXBQb2ludC54LFxuICAgICAgICB5ID0gdGhpcy5fdGVtcFBvaW50LnksXG4gICAgICAgIGk7XG5cbiAgICBpbnRlcmFjdGlvbkRhdGEudGFyZ2V0ID0gaXRlbTtcblxuICAgIC8vYSBzcHJpdGUgb3IgZGlzcGxheSBvYmplY3Qgd2l0aCBhIGhpdCBhcmVhIGRlZmluZWRcbiAgICBpZiAoaXRlbS5oaXRBcmVhICYmIGl0ZW0uaGl0QXJlYS5jb250YWlucykge1xuICAgICAgICByZXR1cm4gaXRlbS5oaXRBcmVhLmNvbnRhaW5zKHgsIHkpO1xuICAgIH1cbiAgICAvLyBhIHNwcml0ZSB3aXRoIG5vIGhpdGFyZWEgZGVmaW5lZFxuICAgIGVsc2UgaWYgKGl0ZW0gaW5zdGFuY2VvZiBjb3JlLlNwcml0ZSkge1xuICAgICAgICB2YXIgd2lkdGggPSBpdGVtLnRleHR1cmUuZnJhbWUud2lkdGg7XG4gICAgICAgIHZhciBoZWlnaHQgPSBpdGVtLnRleHR1cmUuZnJhbWUuaGVpZ2h0O1xuICAgICAgICB2YXIgeDEgPSAtd2lkdGggKiBpdGVtLmFuY2hvci54O1xuICAgICAgICB2YXIgeTE7XG5cbiAgICAgICAgaWYgKHggPiB4MSAmJiB4IDwgeDEgKyB3aWR0aCkge1xuICAgICAgICAgICAgeTEgPSAtaGVpZ2h0ICogaXRlbS5hbmNob3IueTtcblxuICAgICAgICAgICAgaWYgKHkgPiB5MSAmJiB5IDwgeTEgKyBoZWlnaHQpIHtcbiAgICAgICAgICAgICAgICAvLyBzZXQgdGhlIHRhcmdldCBwcm9wZXJ0eSBpZiBhIGhpdCBpcyB0cnVlIVxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIGVsc2UgaWYgKGl0ZW0gaW5zdGFuY2VvZiBjb3JlLkdyYXBoaWNzKSB7XG4gICAgICAgIHZhciBncmFwaGljc0RhdGEgPSBpdGVtLmdyYXBoaWNzRGF0YTtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGdyYXBoaWNzRGF0YS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIGRhdGEgPSBncmFwaGljc0RhdGFbaV07XG5cbiAgICAgICAgICAgIGlmICghZGF0YS5maWxsKSB7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIG9ubHkgZGVhbCB3aXRoIGZpbGxzLi5cbiAgICAgICAgICAgIGlmIChkYXRhLnNoYXBlKSB7XG4gICAgICAgICAgICAgICAgaWYgKGRhdGEuc2hhcGUuY29udGFpbnMoeCwgeSkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy9pbnRlcmFjdGlvbkRhdGEudGFyZ2V0ID0gaXRlbTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgdmFyIGxlbmd0aCA9IGl0ZW0uY2hpbGRyZW4ubGVuZ3RoO1xuXG4gICAgZm9yIChpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciB0ZW1wSXRlbSA9IGl0ZW0uY2hpbGRyZW5baV07XG4gICAgICAgIHZhciBoaXQgPSB0aGlzLmhpdFRlc3QodGVtcEl0ZW0sIGludGVyYWN0aW9uRGF0YSk7XG4gICAgICAgIGlmIChoaXQpIHtcbiAgICAgICAgICAgIC8vIGhtbS4uIFRPRE8gU0VUIENPUlJFQ1QgVEFSR0VUP1xuICAgICAgICAgICAgaW50ZXJhY3Rpb25EYXRhLnRhcmdldCA9IGl0ZW07XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59O1xuXG4vKipcbiAqIElzIGNhbGxlZCB3aGVuIGEgdG91Y2ggaXMgbW92ZWQgYWNyb3NzIHRoZSByZW5kZXJlciBlbGVtZW50XG4gKlxuICogQHBhcmFtIGV2ZW50IHtFdmVudH0gVGhlIERPTSBldmVudCBvZiBhIHRvdWNoIG1vdmluZyBhY3Jvc3MgdGhlIHJlbmRlcmVyIHZpZXdcbiAqIEBwcml2YXRlXG4gKi9cbkludGVyYWN0aW9uTWFuYWdlci5wcm90b3R5cGUub25Ub3VjaE1vdmUgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnJlYnVpbGRJbnRlcmFjdGl2ZUdyYXBoKCk7XG4gICAgfVxuXG4gICAgdmFyIHJlY3QgPSB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICB2YXIgY2hhbmdlZFRvdWNoZXMgPSBldmVudC5jaGFuZ2VkVG91Y2hlcztcbiAgICB2YXIgdG91Y2hEYXRhO1xuICAgIHZhciBpID0gMDtcblxuICAgIGZvciAoaSA9IDA7IGkgPCBjaGFuZ2VkVG91Y2hlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgdG91Y2hFdmVudCA9IGNoYW5nZWRUb3VjaGVzW2ldO1xuICAgICAgICB0b3VjaERhdGEgPSB0aGlzLnRvdWNoZXNbdG91Y2hFdmVudC5pZGVudGlmaWVyXTtcbiAgICAgICAgdG91Y2hEYXRhLm9yaWdpbmFsRXZlbnQgPSBldmVudDtcblxuICAgICAgICAvLyB1cGRhdGUgdGhlIHRvdWNoIHBvc2l0aW9uXG4gICAgICAgIHRvdWNoRGF0YS5nbG9iYWwueCA9ICggKHRvdWNoRXZlbnQuY2xpZW50WCAtIHJlY3QubGVmdCkgKiAodGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQud2lkdGggLyByZWN0LndpZHRoKSApIC8gdGhpcy5yZXNvbHV0aW9uO1xuICAgICAgICB0b3VjaERhdGEuZ2xvYmFsLnkgPSAoICh0b3VjaEV2ZW50LmNsaWVudFkgLSByZWN0LnRvcCkgICogKHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LmhlaWdodCAvIHJlY3QuaGVpZ2h0KSApICAvIHRoaXMucmVzb2x1dGlvbjtcbiAgICAgICAgaWYgKG5hdmlnYXRvci5pc0NvY29vbkpTICYmICFyZWN0LmxlZnQgJiYgIXJlY3QudG9wICYmICFldmVudC50YXJnZXQuc3R5bGUud2lkdGggJiYgIWV2ZW50LnRhcmdldC5zdHlsZS5oZWlnaHQpIHtcbiAgICAgICAgICAgIC8vU3VwcG9ydCBmb3IgQ29jb29uSlMgZnVsbHNjcmVlbiBzY2FsZSBtb2Rlc1xuICAgICAgICAgICAgdG91Y2hEYXRhLmdsb2JhbC54ID0gdG91Y2hFdmVudC5jbGllbnRYO1xuICAgICAgICAgICAgdG91Y2hEYXRhLmdsb2JhbC55ID0gdG91Y2hFdmVudC5jbGllbnRZO1xuICAgICAgICB9XG5cbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCB0aGlzLmludGVyYWN0aXZlSXRlbXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgIHZhciBpdGVtID0gdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zW2pdO1xuICAgICAgICAgICAgaWYgKGl0ZW0udG91Y2htb3ZlICYmIGl0ZW0uX190b3VjaERhdGEgJiYgaXRlbS5fX3RvdWNoRGF0YVt0b3VjaEV2ZW50LmlkZW50aWZpZXJdKSB7XG4gICAgICAgICAgICAgICAgaXRlbS50b3VjaG1vdmUodG91Y2hEYXRhKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn07XG5cbi8qKlxuICogSXMgY2FsbGVkIHdoZW4gYSB0b3VjaCBpcyBzdGFydGVkIG9uIHRoZSByZW5kZXJlciBlbGVtZW50XG4gKlxuICogQHBhcmFtIGV2ZW50IHtFdmVudH0gVGhlIERPTSBldmVudCBvZiBhIHRvdWNoIHN0YXJ0aW5nIG9uIHRoZSByZW5kZXJlciB2aWV3XG4gKiBAcHJpdmF0ZVxuICovXG5JbnRlcmFjdGlvbk1hbmFnZXIucHJvdG90eXBlLm9uVG91Y2hTdGFydCA9IGZ1bmN0aW9uIChldmVudCkge1xuICAgIGlmICh0aGlzLmRpcnR5KSB7XG4gICAgICAgIHRoaXMucmVidWlsZEludGVyYWN0aXZlR3JhcGgoKTtcbiAgICB9XG5cbiAgICB2YXIgcmVjdCA9IHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXG4gICAgaWYgKEFVVE9fUFJFVkVOVF9ERUZBVUxUKSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuXG4gICAgdmFyIGNoYW5nZWRUb3VjaGVzID0gZXZlbnQuY2hhbmdlZFRvdWNoZXM7XG4gICAgZm9yICh2YXIgaT0wOyBpIDwgY2hhbmdlZFRvdWNoZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIHRvdWNoRXZlbnQgPSBjaGFuZ2VkVG91Y2hlc1tpXTtcblxuICAgICAgICB2YXIgdG91Y2hEYXRhID0gdGhpcy5wb29sLnBvcCgpO1xuICAgICAgICBpZiAoIXRvdWNoRGF0YSkge1xuICAgICAgICAgICAgdG91Y2hEYXRhID0gbmV3IEludGVyYWN0aW9uRGF0YSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdG91Y2hEYXRhLm9yaWdpbmFsRXZlbnQgPSBldmVudDtcblxuICAgICAgICB0aGlzLnRvdWNoZXNbdG91Y2hFdmVudC5pZGVudGlmaWVyXSA9IHRvdWNoRGF0YTtcbiAgICAgICAgdG91Y2hEYXRhLmdsb2JhbC54ID0gKCAodG91Y2hFdmVudC5jbGllbnRYIC0gcmVjdC5sZWZ0KSAqICh0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC53aWR0aCAvIHJlY3Qud2lkdGgpICkgLyB0aGlzLnJlc29sdXRpb247XG4gICAgICAgIHRvdWNoRGF0YS5nbG9iYWwueSA9ICggKHRvdWNoRXZlbnQuY2xpZW50WSAtIHJlY3QudG9wKSAgKiAodGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQuaGVpZ2h0IC8gcmVjdC5oZWlnaHQpICkgLyB0aGlzLnJlc29sdXRpb247XG4gICAgICAgIGlmIChuYXZpZ2F0b3IuaXNDb2Nvb25KUyAmJiAhcmVjdC5sZWZ0ICYmICFyZWN0LnRvcCAmJiAhZXZlbnQudGFyZ2V0LnN0eWxlLndpZHRoICYmICFldmVudC50YXJnZXQuc3R5bGUuaGVpZ2h0KSB7XG4gICAgICAgICAgICAvL1N1cHBvcnQgZm9yIENvY29vbkpTIGZ1bGxzY3JlZW4gc2NhbGUgbW9kZXNcbiAgICAgICAgICAgIHRvdWNoRGF0YS5nbG9iYWwueCA9IHRvdWNoRXZlbnQuY2xpZW50WDtcbiAgICAgICAgICAgIHRvdWNoRGF0YS5nbG9iYWwueSA9IHRvdWNoRXZlbnQuY2xpZW50WTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBsZW5ndGggPSB0aGlzLmludGVyYWN0aXZlSXRlbXMubGVuZ3RoO1xuXG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgbGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgIHZhciBpdGVtID0gdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zW2pdO1xuXG4gICAgICAgICAgICBpZiAoaXRlbS50b3VjaHN0YXJ0IHx8IGl0ZW0udGFwKSB7XG4gICAgICAgICAgICAgICAgaXRlbS5fX2hpdCA9IHRoaXMuaGl0VGVzdChpdGVtLCB0b3VjaERhdGEpO1xuXG4gICAgICAgICAgICAgICAgaWYgKGl0ZW0uX19oaXQpIHtcbiAgICAgICAgICAgICAgICAgICAgLy9jYWxsIHRoZSBmdW5jdGlvbiFcbiAgICAgICAgICAgICAgICAgICAgaWYgKGl0ZW0udG91Y2hzdGFydCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaXRlbS50b3VjaHN0YXJ0KHRvdWNoRGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBpdGVtLl9faXNEb3duID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgaXRlbS5fX3RvdWNoRGF0YSA9IGl0ZW0uX190b3VjaERhdGEgfHwge307XG4gICAgICAgICAgICAgICAgICAgIGl0ZW0uX190b3VjaERhdGFbdG91Y2hFdmVudC5pZGVudGlmaWVyXSA9IHRvdWNoRGF0YTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoIWl0ZW0uaW50ZXJhY3RpdmVDaGlsZHJlbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4vKipcbiAqIElzIGNhbGxlZCB3aGVuIGEgdG91Y2ggaXMgZW5kZWQgb24gdGhlIHJlbmRlcmVyIGVsZW1lbnRcbiAqXG4gKiBAcGFyYW0gZXZlbnQge0V2ZW50fSBUaGUgRE9NIGV2ZW50IG9mIGEgdG91Y2ggZW5kaW5nIG9uIHRoZSByZW5kZXJlciB2aWV3XG4gKiBAcHJpdmF0ZVxuICovXG5JbnRlcmFjdGlvbk1hbmFnZXIucHJvdG90eXBlLm9uVG91Y2hFbmQgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnJlYnVpbGRJbnRlcmFjdGl2ZUdyYXBoKCk7XG4gICAgfVxuXG4gICAgdmFyIHJlY3QgPSB0aGlzLmludGVyYWN0aW9uRE9NRWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICB2YXIgY2hhbmdlZFRvdWNoZXMgPSBldmVudC5jaGFuZ2VkVG91Y2hlcztcblxuICAgIGZvciAodmFyIGk9MDsgaSA8IGNoYW5nZWRUb3VjaGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciB0b3VjaEV2ZW50ID0gY2hhbmdlZFRvdWNoZXNbaV07XG4gICAgICAgIHZhciB0b3VjaERhdGEgPSB0aGlzLnRvdWNoZXNbdG91Y2hFdmVudC5pZGVudGlmaWVyXTtcbiAgICAgICAgdmFyIHVwID0gZmFsc2U7XG4gICAgICAgIHRvdWNoRGF0YS5nbG9iYWwueCA9ICggKHRvdWNoRXZlbnQuY2xpZW50WCAtIHJlY3QubGVmdCkgKiAodGhpcy5pbnRlcmFjdGlvbkRPTUVsZW1lbnQud2lkdGggLyByZWN0LndpZHRoKSApIC8gdGhpcy5yZXNvbHV0aW9uO1xuICAgICAgICB0b3VjaERhdGEuZ2xvYmFsLnkgPSAoICh0b3VjaEV2ZW50LmNsaWVudFkgLSByZWN0LnRvcCkgICogKHRoaXMuaW50ZXJhY3Rpb25ET01FbGVtZW50LmhlaWdodCAvIHJlY3QuaGVpZ2h0KSApIC8gdGhpcy5yZXNvbHV0aW9uO1xuICAgICAgICBpZiAobmF2aWdhdG9yLmlzQ29jb29uSlMgJiYgIXJlY3QubGVmdCAmJiAhcmVjdC50b3AgJiYgIWV2ZW50LnRhcmdldC5zdHlsZS53aWR0aCAmJiAhZXZlbnQudGFyZ2V0LnN0eWxlLmhlaWdodCkge1xuICAgICAgICAgICAgLy9TdXBwb3J0IGZvciBDb2Nvb25KUyBmdWxsc2NyZWVuIHNjYWxlIG1vZGVzXG4gICAgICAgICAgICB0b3VjaERhdGEuZ2xvYmFsLnggPSB0b3VjaEV2ZW50LmNsaWVudFg7XG4gICAgICAgICAgICB0b3VjaERhdGEuZ2xvYmFsLnkgPSB0b3VjaEV2ZW50LmNsaWVudFk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgbGVuZ3RoID0gdGhpcy5pbnRlcmFjdGl2ZUl0ZW1zLmxlbmd0aDtcbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBsZW5ndGg7IGorKykge1xuICAgICAgICAgICAgdmFyIGl0ZW0gPSB0aGlzLmludGVyYWN0aXZlSXRlbXNbal07XG5cbiAgICAgICAgICAgIGlmIChpdGVtLl9fdG91Y2hEYXRhICYmIGl0ZW0uX190b3VjaERhdGFbdG91Y2hFdmVudC5pZGVudGlmaWVyXSkge1xuXG4gICAgICAgICAgICAgICAgaXRlbS5fX2hpdCA9IHRoaXMuaGl0VGVzdChpdGVtLCBpdGVtLl9fdG91Y2hEYXRhW3RvdWNoRXZlbnQuaWRlbnRpZmllcl0pO1xuXG4gICAgICAgICAgICAgICAgLy8gc28gdGhpcyBvbmUgV0FTIGRvd24uLi5cbiAgICAgICAgICAgICAgICB0b3VjaERhdGEub3JpZ2luYWxFdmVudCA9IGV2ZW50O1xuICAgICAgICAgICAgICAgIC8vIGhpdFRlc3Q/P1xuXG4gICAgICAgICAgICAgICAgaWYgKGl0ZW0udG91Y2hlbmQgfHwgaXRlbS50YXApIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGl0ZW0uX19oaXQgJiYgIXVwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXRlbS50b3VjaGVuZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGl0ZW0udG91Y2hlbmQodG91Y2hEYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpdGVtLl9faXNEb3duICYmIGl0ZW0udGFwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaXRlbS50YXAodG91Y2hEYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghaXRlbS5pbnRlcmFjdGl2ZUNoaWxkcmVuKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdXAgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGl0ZW0uX19pc0Rvd24gJiYgaXRlbS50b3VjaGVuZG91dHNpZGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpdGVtLnRvdWNoZW5kb3V0c2lkZSh0b3VjaERhdGEpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgaXRlbS5fX2lzRG93biA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGl0ZW0uX190b3VjaERhdGFbdG91Y2hFdmVudC5pZGVudGlmaWVyXSA9IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gcmVtb3ZlIHRoZSB0b3VjaC4uXG4gICAgICAgIHRoaXMucG9vbC5wdXNoKHRvdWNoRGF0YSk7XG4gICAgICAgIHRoaXMudG91Y2hlc1t0b3VjaEV2ZW50LmlkZW50aWZpZXJdID0gbnVsbDtcbiAgICB9XG59O1xuIiwiLyoqXG4gKiBAZmlsZSAgICAgICAgTWFpbiBleHBvcnQgb2YgdGhlIFBJWEkgaW50ZXJhY3Rpb25zIGxpYnJhcnlcbiAqIEBhdXRob3IgICAgICBNYXQgR3JvdmVzIDxtYXRAZ29vZGJveWRpZ2l0YWwuY29tPlxuICogQGNvcHlyaWdodCAgIDIwMTMtMjAxNSBHb29kQm95RGlnaXRhbFxuICogQGxpY2Vuc2UgICAgIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vR29vZEJveURpZ2l0YWwvcGl4aS5qcy9ibG9iL21hc3Rlci9MSUNFTlNFfE1JVCBMaWNlbnNlfVxuICovXG5cbi8qKlxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEludGVyYWN0aW9uRGF0YTogICAgcmVxdWlyZSgnLi9JbnRlcmFjdGlvbkRhdGEnKSxcbiAgICBJbnRlcmFjdGlvbk1hbmFnZXI6IHJlcXVpcmUoJy4vSW50ZXJhY3Rpb25NYW5hZ2VyJylcbn07XG4iLCJ2YXIgY29yZSA9IHJlcXVpcmUoJy4uL2NvcmUnKSxcbiAgICBJbWFnZUxvYWRlciA9IHJlcXVpcmUoJy4vSW1hZ2VMb2FkZXInKTtcblxuLyoqXG4gKiBUaGUgYXRsYXMgZmlsZSBsb2FkZXIgaXMgdXNlZCB0byBsb2FkIGluIFRleHR1cmUgQXRsYXMgZGF0YSBhbmQgcGFyc2UgaXQuIFdoZW4gbG9hZGVkIHRoaXMgY2xhc3Mgd2lsbCBkaXNwYXRjaCBhICdsb2FkZWQnIGV2ZW50LiBJZiBsb2FkaW5nIGZhaWxzIHRoaXMgY2xhc3Mgd2lsbCBkaXNwYXRjaCBhbiAnZXJyb3InIGV2ZW50LlxuICpcbiAqIFRvIGdlbmVyYXRlIHRoZSBkYXRhIHlvdSBjYW4gdXNlIGh0dHA6Ly93d3cuY29kZWFuZHdlYi5jb20vdGV4dHVyZXBhY2tlciBhbmQgcHVibGlzaCBpbiB0aGUgJ0pTT04nIGZvcm1hdC5cbiAqXG4gKiBJdCBpcyBoaWdobHkgcmVjb21tZW5kZWQgdG8gdXNlIHRleHR1cmUgYXRsYXNlcyAoYWxzbyBrbm93IGFzICdzcHJpdGUgc2hlZXRzJykgYXMgaXQgYWxsb3dlZCBzcHJpdGVzIHRvIGJlIGJhdGNoZWQgYW5kIGRyYXduIHRvZ2V0aGVyIGZvciBoaWdobHkgaW5jcmVhc2VkIHJlbmRlcmluZyBzcGVlZC5cbiAqIE9uY2UgdGhlIGRhdGEgaGFzIGJlZW4gbG9hZGVkIHRoZSBmcmFtZXMgYXJlIHN0b3JlZCBpbiB0aGUgUElYSSB0ZXh0dXJlIGNhY2hlIGFuZCBjYW4gYmUgYWNjZXNzZWQgdGhvdWdoIFRleHR1cmUuZnJvbUZyYW1lSWQoKSBhbmQgU3ByaXRlLmZyb21GcmFtZUlkKClcbiAqXG4gKiBAY2xhc3NcbiAqIEBtaXhlcyBldmVudFRhcmdldFxuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gdXJsIHtTdHJpbmd9IFRoZSB1cmwgb2YgdGhlIEpTT04gZmlsZVxuICogQHBhcmFtIGNyb3Nzb3JpZ2luIHtib29sZWFufSBXaGV0aGVyIHJlcXVlc3RzIHNob3VsZCBiZSB0cmVhdGVkIGFzIGNyb3Nzb3JpZ2luXG4gKi9cbmZ1bmN0aW9uIEF0bGFzTG9hZGVyKHVybCwgY3Jvc3NvcmlnaW4pIHtcbiAgICB0aGlzLnVybCA9IHVybDtcbiAgICB0aGlzLmJhc2VVcmwgPSB1cmwucmVwbGFjZSgvW15cXC9dKiQvLCAnJyk7XG4gICAgdGhpcy5jcm9zc29yaWdpbiA9IGNyb3Nzb3JpZ2luO1xuICAgIHRoaXMubG9hZGVkID0gZmFsc2U7XG59XG5cbkF0bGFzTG9hZGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEF0bGFzTG9hZGVyO1xubW9kdWxlLmV4cG9ydHMgPSBBdGxhc0xvYWRlcjtcblxuY29yZS51dGlscy5ldmVudFRhcmdldC5taXhpbihBdGxhc0xvYWRlci5wcm90b3R5cGUpO1xuXG4gLyoqXG4gKiBTdGFydHMgbG9hZGluZyB0aGUgSlNPTiBmaWxlXG4gKlxuICovXG5BdGxhc0xvYWRlci5wcm90b3R5cGUubG9hZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmFqYXhSZXF1ZXN0ID0gbmV3IGNvcmUudXRpbHMuQWpheFJlcXVlc3QoKTtcbiAgICB0aGlzLmFqYXhSZXF1ZXN0Lm9ucmVhZHlzdGF0ZWNoYW5nZSA9IHRoaXMub25BdGxhc0xvYWRlZC5iaW5kKHRoaXMpO1xuXG4gICAgdGhpcy5hamF4UmVxdWVzdC5vcGVuKCdHRVQnLCB0aGlzLnVybCwgdHJ1ZSk7XG5cbiAgICBpZiAodGhpcy5hamF4UmVxdWVzdC5vdmVycmlkZU1pbWVUeXBlKSB7XG4gICAgICAgIHRoaXMuYWpheFJlcXVlc3Qub3ZlcnJpZGVNaW1lVHlwZSgnYXBwbGljYXRpb24vanNvbicpO1xuICAgIH1cblxuICAgIHRoaXMuYWpheFJlcXVlc3Quc2VuZChudWxsKTtcbn07XG5cbi8qKlxuICogSW52b2tlZCB3aGVuIHRoZSBBdGxhcyBoYXMgZnVsbHkgbG9hZGVkLiBQYXJzZXMgdGhlIEpTT04gYW5kIGJ1aWxkcyB0aGUgdGV4dHVyZSBmcmFtZXMuXG4gKlxuICogQHByaXZhdGVcbiAqL1xuQXRsYXNMb2FkZXIucHJvdG90eXBlLm9uQXRsYXNMb2FkZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHRoaXMuYWpheFJlcXVlc3QucmVhZHlTdGF0ZSA9PT0gNCkge1xuICAgICAgICBpZiAodGhpcy5hamF4UmVxdWVzdC5zdGF0dXMgPT09IDIwMCB8fCB3aW5kb3cubG9jYXRpb24uaHJlZi5pbmRleE9mKCdodHRwJykgPT09IC0xKSB7XG4gICAgICAgICAgICB0aGlzLmF0bGFzID0ge1xuICAgICAgICAgICAgICAgIG1ldGEgOiB7XG4gICAgICAgICAgICAgICAgICAgIGltYWdlIDogW11cbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGZyYW1lcyA6IFtdXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHRoaXMuYWpheFJlcXVlc3QucmVzcG9uc2VUZXh0LnNwbGl0KC9cXHI/XFxuLyk7XG4gICAgICAgICAgICB2YXIgbGluZUNvdW50ID0gLTM7XG5cbiAgICAgICAgICAgIHZhciBjdXJyZW50SW1hZ2VJZCA9IDA7XG4gICAgICAgICAgICB2YXIgY3VycmVudEZyYW1lID0gbnVsbDtcbiAgICAgICAgICAgIHZhciBuYW1lSW5OZXh0TGluZSA9IGZhbHNlO1xuXG4gICAgICAgICAgICB2YXIgaSA9IDAsXG4gICAgICAgICAgICAgICAgaiA9IDAsXG4gICAgICAgICAgICAgICAgc2VsZk9uTG9hZGVkID0gdGhpcy5vbkxvYWRlZC5iaW5kKHRoaXMpO1xuXG4gICAgICAgICAgICAvLyBwYXJzZXIgd2l0aG91dCByb3RhdGlvbiBzdXBwb3J0IHlldCFcbiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCByZXN1bHQubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICByZXN1bHRbaV0gPSByZXN1bHRbaV0ucmVwbGFjZSgvXlxccyt8XFxzKyQvZywgJycpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHJlc3VsdFtpXSA9PT0gJycpIHtcbiAgICAgICAgICAgICAgICAgICAgbmFtZUluTmV4dExpbmUgPSBpKzE7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHJlc3VsdFtpXS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChuYW1lSW5OZXh0TGluZSA9PT0gaSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5hdGxhcy5tZXRhLmltYWdlLnB1c2gocmVzdWx0W2ldKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRJbWFnZUlkID0gdGhpcy5hdGxhcy5tZXRhLmltYWdlLmxlbmd0aCAtIDE7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmF0bGFzLmZyYW1lcy5wdXNoKHt9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxpbmVDb3VudCA9IC0zO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGxpbmVDb3VudCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChsaW5lQ291bnQgJSA3ID09PSAxKSB7IC8vIGZyYW1lIG5hbWVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoY3VycmVudEZyYW1lICE9IG51bGwpIHsgLy9qc2hpbnQgaWdub3JlOmxpbmVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5hdGxhcy5mcmFtZXNbY3VycmVudEltYWdlSWRdW2N1cnJlbnRGcmFtZS5uYW1lXSA9IGN1cnJlbnRGcmFtZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VycmVudEZyYW1lID0geyBuYW1lOiByZXN1bHRbaV0sIGZyYW1lIDoge30gfTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHRleHQgPSByZXN1bHRbaV0uc3BsaXQoJyAnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobGluZUNvdW50ICUgNyA9PT0gMykgeyAvLyBwb3NpdGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50RnJhbWUuZnJhbWUueCA9IE51bWJlcih0ZXh0WzFdLnJlcGxhY2UoJywnLCAnJykpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50RnJhbWUuZnJhbWUueSA9IE51bWJlcih0ZXh0WzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGxpbmVDb3VudCAlIDcgPT09IDQpIHsgLy8gc2l6ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50RnJhbWUuZnJhbWUudyA9IE51bWJlcih0ZXh0WzFdLnJlcGxhY2UoJywnLCAnJykpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50RnJhbWUuZnJhbWUuaCA9IE51bWJlcih0ZXh0WzJdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGxpbmVDb3VudCAlIDcgPT09IDUpIHsgLy8gcmVhbCBzaXplXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciByZWFsU2l6ZSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggOiAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA6IDAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3IDogTnVtYmVyKHRleHRbMV0ucmVwbGFjZSgnLCcsICcnKSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoIDogTnVtYmVyKHRleHRbMl0pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJlYWxTaXplLncgPiBjdXJyZW50RnJhbWUuZnJhbWUudyB8fCByZWFsU2l6ZS5oID4gY3VycmVudEZyYW1lLmZyYW1lLmgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRGcmFtZS50cmltbWVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRGcmFtZS5yZWFsU2l6ZSA9IHJlYWxTaXplO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VycmVudEZyYW1lLnRyaW1tZWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBsaW5lQ291bnQrKztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChjdXJyZW50RnJhbWUgIT0gbnVsbCkgeyAvL2pzaGludCBpZ25vcmU6bGluZVxuICAgICAgICAgICAgICAgIHRoaXMuYXRsYXMuZnJhbWVzW2N1cnJlbnRJbWFnZUlkXVtjdXJyZW50RnJhbWUubmFtZV0gPSBjdXJyZW50RnJhbWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0aGlzLmF0bGFzLm1ldGEuaW1hZ2UubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHRoaXMuaW1hZ2VzID0gW107XG4gICAgICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IHRoaXMuYXRsYXMubWV0YS5pbWFnZS5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgICAgICAvLyBzcHJpdGUgc2hlZXRcbiAgICAgICAgICAgICAgICAgICAgdmFyIHRleHR1cmVVcmwgPSB0aGlzLmJhc2VVcmwgKyB0aGlzLmF0bGFzLm1ldGEuaW1hZ2Vbal07XG4gICAgICAgICAgICAgICAgICAgIHZhciBmcmFtZURhdGEgPSB0aGlzLmF0bGFzLmZyYW1lc1tqXTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5pbWFnZXMucHVzaChuZXcgSW1hZ2VMb2FkZXIodGV4dHVyZVVybCwgdGhpcy5jcm9zc29yaWdpbikpO1xuXG4gICAgICAgICAgICAgICAgICAgIGZvciAoaSBpbiBmcmFtZURhdGEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciByZWN0ID0gZnJhbWVEYXRhW2ldLmZyYW1lO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJlY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3JlLnV0aWxzLlRleHR1cmVDYWNoZVtpXSA9IG5ldyBjb3JlLlRleHR1cmUodGhpcy5pbWFnZXNbal0udGV4dHVyZS5iYXNlVGV4dHVyZSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4OiByZWN0LngsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk6IHJlY3QueSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGg6IHJlY3QudyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVpZ2h0OiByZWN0LmhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZnJhbWVEYXRhW2ldLnRyaW1tZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29yZS51dGlscy5UZXh0dXJlQ2FjaGVbaV0ucmVhbFNpemUgPSBmcmFtZURhdGFbaV0ucmVhbFNpemU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRyaW0gaW4gcGl4aSBub3Qgc3VwcG9ydGVkIHlldCwgdG9kbyB1cGRhdGUgdHJpbSBwcm9wZXJ0aWVzIGlmIGl0IGlzIGRvbmUgLi4uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmUudXRpbHMuVGV4dHVyZUNhY2hlW2ldLnRyaW0ueCA9IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcmUudXRpbHMuVGV4dHVyZUNhY2hlW2ldLnRyaW0ueSA9IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdGhpcy5jdXJyZW50SW1hZ2VJZCA9IDA7XG4gICAgICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IHRoaXMuaW1hZ2VzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaW1hZ2VzW2pdLm9uKCdsb2FkZWQnLCBzZWxmT25Mb2FkZWQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLmltYWdlc1t0aGlzLmN1cnJlbnRJbWFnZUlkXS5sb2FkKCk7XG5cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5vbkxvYWRlZCgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLm9uRXJyb3IoKTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cbi8qKlxuICogSW52b2tlZCB3aGVuIGpzb24gZmlsZSBoYXMgbG9hZGVkLlxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkF0bGFzTG9hZGVyLnByb3RvdHlwZS5vbkxvYWRlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5pbWFnZXMubGVuZ3RoIC0gMSA+IHRoaXMuY3VycmVudEltYWdlSWQpIHtcbiAgICAgICAgdGhpcy5jdXJyZW50SW1hZ2VJZCsrO1xuICAgICAgICB0aGlzLmltYWdlc1t0aGlzLmN1cnJlbnRJbWFnZUlkXS5sb2FkKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5sb2FkZWQgPSB0cnVlO1xuICAgICAgICB0aGlzLmVtaXQoJ2xvYWRlZCcsIHsgY29udGVudDogdGhpcyB9KTtcbiAgICB9XG59O1xuXG4vKipcbiAqIEludm9rZWQgd2hlbiBhbiBlcnJvciBvY2N1cnMuXG4gKlxuICogQHByaXZhdGVcbiAqL1xuQXRsYXNMb2FkZXIucHJvdG90eXBlLm9uRXJyb3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5lbWl0KCdlcnJvcicsIHsgY29udGVudDogdGhpcyB9KTtcbn07XG4iLCJ2YXIgY29yZSA9IHJlcXVpcmUoJy4uL2NvcmUnKSxcbiAgICBJbWFnZUxvYWRlciA9IHJlcXVpcmUoJy4vSW1hZ2VMb2FkZXInKTtcblxuLyoqXG4gKiBUaGUgeG1sIGxvYWRlciBpcyB1c2VkIHRvIGxvYWQgaW4gWE1MIGJpdG1hcCBmb250IGRhdGEgKCd4bWwnIG9yICdmbnQnKVxuICogVG8gZ2VuZXJhdGUgdGhlIGRhdGEgeW91IGNhbiB1c2UgaHR0cDovL3d3dy5hbmdlbGNvZGUuY29tL3Byb2R1Y3RzL2JtZm9udC9cbiAqIFRoaXMgbG9hZGVyIHdpbGwgYWxzbyBsb2FkIHRoZSBpbWFnZSBmaWxlIGFzIHRoZSBkYXRhLlxuICogV2hlbiBsb2FkZWQgdGhpcyBjbGFzcyB3aWxsIGRpc3BhdGNoIGEgJ2xvYWRlZCcgZXZlbnRcbiAqXG4gKiBAY2xhc3NcbiAqIEBtaXhlcyBldmVudFRhcmdldFxuICogQG5hbWVzcGFjZSBQSVhJXG4gKiBAcGFyYW0gdXJsIHtTdHJpbmd9IFRoZSB1cmwgb2YgdGhlIHNwcml0ZSBzaGVldCBKU09OIGZpbGVcbiAqIEBwYXJhbSBjcm9zc29yaWdpbiB7Ym9vbGVhbn0gV2hldGhlciByZXF1ZXN0cyBzaG91bGQgYmUgdHJlYXRlZCBhcyBjcm9zc29yaWdpblxuICovXG5mdW5jdGlvbiBCaXRtYXBGb250TG9hZGVyKHVybCwgY3Jvc3NvcmlnaW4pIHtcbiAgICAvKipcbiAgICAgKiBUaGUgdXJsIG9mIHRoZSBiaXRtYXAgZm9udCBkYXRhXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtTdHJpbmd9XG4gICAgICovXG4gICAgdGhpcy51cmwgPSB1cmw7XG5cbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRoZSByZXF1ZXN0cyBzaG91bGQgYmUgdHJlYXRlZCBhcyBjcm9zcyBvcmlnaW5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5jcm9zc29yaWdpbiA9IGNyb3Nzb3JpZ2luO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGJhc2UgdXJsIG9mIHRoZSBiaXRtYXAgZm9udCBkYXRhXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtTdHJpbmd9XG4gICAgICogQHJlYWRPbmx5XG4gICAgICovXG4gICAgdGhpcy5iYXNlVXJsID0gdXJsLnJlcGxhY2UoL1teXFwvXSokLywgJycpO1xuXG4gICAgLyoqXG4gICAgICogVGhlIHRleHR1cmUgb2YgdGhlIGJpdG1hcCBmb250XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtUZXh0dXJlfVxuICAgICAqL1xuICAgIHRoaXMudGV4dHVyZSA9IG51bGw7XG59XG5cbi8vIGNvbnN0cnVjdG9yXG5CaXRtYXBGb250TG9hZGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEJpdG1hcEZvbnRMb2FkZXI7XG5tb2R1bGUuZXhwb3J0cyA9IEJpdG1hcEZvbnRMb2FkZXI7XG5cbmNvcmUudXRpbHMuZXZlbnRUYXJnZXQubWl4aW4oQml0bWFwRm9udExvYWRlci5wcm90b3R5cGUpO1xuXG4vKipcbiAqIExvYWRzIHRoZSBYTUwgZm9udCBkYXRhXG4gKlxuICovXG5CaXRtYXBGb250TG9hZGVyLnByb3RvdHlwZS5sb2FkID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuYWpheFJlcXVlc3QgPSBuZXcgY29yZS51dGlscy5BamF4UmVxdWVzdCgpO1xuICAgIHRoaXMuYWpheFJlcXVlc3Qub25yZWFkeXN0YXRlY2hhbmdlID0gdGhpcy5vblhNTExvYWRlZC5iaW5kKHRoaXMpO1xuXG4gICAgdGhpcy5hamF4UmVxdWVzdC5vcGVuKCdHRVQnLCB0aGlzLnVybCwgdHJ1ZSk7XG5cbiAgICBpZiAodGhpcy5hamF4UmVxdWVzdC5vdmVycmlkZU1pbWVUeXBlKSB7XG4gICAgICAgIHRoaXMuYWpheFJlcXVlc3Qub3ZlcnJpZGVNaW1lVHlwZSgnYXBwbGljYXRpb24veG1sJyk7XG4gICAgfVxuXG4gICAgdGhpcy5hamF4UmVxdWVzdC5zZW5kKG51bGwpO1xufTtcblxuLyoqXG4gKiBJbnZva2VkIHdoZW4gdGhlIFhNTCBmaWxlIGlzIGxvYWRlZCwgcGFyc2VzIHRoZSBkYXRhLlxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkJpdG1hcEZvbnRMb2FkZXIucHJvdG90eXBlLm9uWE1MTG9hZGVkID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICh0aGlzLmFqYXhSZXF1ZXN0LnJlYWR5U3RhdGUgPT09IDQpIHtcbiAgICAgICAgaWYgKHRoaXMuYWpheFJlcXVlc3Quc3RhdHVzID09PSAyMDAgfHwgd2luZG93LmxvY2F0aW9uLnByb3RvY29sLmluZGV4T2YoJ2h0dHAnKSA9PT0gLTEpIHtcbiAgICAgICAgICAgIHZhciByZXNwb25zZVhNTCA9IHRoaXMuYWpheFJlcXVlc3QucmVzcG9uc2VYTUw7XG4gICAgICAgICAgICBpZiAoIXJlc3BvbnNlWE1MIHx8IC9NU0lFIDkvaS50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpIHx8IG5hdmlnYXRvci5pc0NvY29vbkpTKSB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZih3aW5kb3cuRE9NUGFyc2VyKSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZG9tcGFyc2VyID0gbmV3IERPTVBhcnNlcigpO1xuICAgICAgICAgICAgICAgICAgICByZXNwb25zZVhNTCA9IGRvbXBhcnNlci5wYXJzZUZyb21TdHJpbmcodGhpcy5hamF4UmVxdWVzdC5yZXNwb25zZVRleHQsICd0ZXh0L3htbCcpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkaXYgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICAgICAgICAgICAgICAgICAgZGl2LmlubmVySFRNTCA9IHRoaXMuYWpheFJlcXVlc3QucmVzcG9uc2VUZXh0O1xuICAgICAgICAgICAgICAgICAgICByZXNwb25zZVhNTCA9IGRpdjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciB0ZXh0dXJlVXJsID0gdGhpcy5iYXNlVXJsICsgcmVzcG9uc2VYTUwuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3BhZ2UnKVswXS5nZXRBdHRyaWJ1dGUoJ2ZpbGUnKTtcbiAgICAgICAgICAgIHZhciBpbWFnZSA9IG5ldyBJbWFnZUxvYWRlcih0ZXh0dXJlVXJsLCB0aGlzLmNyb3Nzb3JpZ2luKTtcbiAgICAgICAgICAgIHRoaXMudGV4dHVyZSA9IGltYWdlLnRleHR1cmUuYmFzZVRleHR1cmU7XG5cbiAgICAgICAgICAgIHZhciBkYXRhID0ge307XG4gICAgICAgICAgICB2YXIgaW5mbyA9IHJlc3BvbnNlWE1MLmdldEVsZW1lbnRzQnlUYWdOYW1lKCdpbmZvJylbMF07XG4gICAgICAgICAgICB2YXIgY29tbW9uID0gcmVzcG9uc2VYTUwuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2NvbW1vbicpWzBdO1xuICAgICAgICAgICAgZGF0YS5mb250ID0gaW5mby5nZXRBdHRyaWJ1dGUoJ2ZhY2UnKTtcbiAgICAgICAgICAgIGRhdGEuc2l6ZSA9IHBhcnNlSW50KGluZm8uZ2V0QXR0cmlidXRlKCdzaXplJyksIDEwKTtcbiAgICAgICAgICAgIGRhdGEubGluZUhlaWdodCA9IHBhcnNlSW50KGNvbW1vbi5nZXRBdHRyaWJ1dGUoJ2xpbmVIZWlnaHQnKSwgMTApO1xuICAgICAgICAgICAgZGF0YS5jaGFycyA9IHt9O1xuXG4gICAgICAgICAgICAvL3BhcnNlIGxldHRlcnNcbiAgICAgICAgICAgIHZhciBsZXR0ZXJzID0gcmVzcG9uc2VYTUwuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2NoYXInKTtcblxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZXR0ZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNoYXJDb2RlID0gcGFyc2VJbnQobGV0dGVyc1tpXS5nZXRBdHRyaWJ1dGUoJ2lkJyksIDEwKTtcblxuICAgICAgICAgICAgICAgIHZhciB0ZXh0dXJlUmVjdCA9IG5ldyBjb3JlLm1hdGguUmVjdGFuZ2xlKFxuICAgICAgICAgICAgICAgICAgICBwYXJzZUludChsZXR0ZXJzW2ldLmdldEF0dHJpYnV0ZSgneCcpLCAxMCksXG4gICAgICAgICAgICAgICAgICAgIHBhcnNlSW50KGxldHRlcnNbaV0uZ2V0QXR0cmlidXRlKCd5JyksIDEwKSxcbiAgICAgICAgICAgICAgICAgICAgcGFyc2VJbnQobGV0dGVyc1tpXS5nZXRBdHRyaWJ1dGUoJ3dpZHRoJyksIDEwKSxcbiAgICAgICAgICAgICAgICAgICAgcGFyc2VJbnQobGV0dGVyc1tpXS5nZXRBdHRyaWJ1dGUoJ2hlaWdodCcpLCAxMClcbiAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgZGF0YS5jaGFyc1tjaGFyQ29kZV0gPSB7XG4gICAgICAgICAgICAgICAgICAgIHhPZmZzZXQ6IHBhcnNlSW50KGxldHRlcnNbaV0uZ2V0QXR0cmlidXRlKCd4b2Zmc2V0JyksIDEwKSxcbiAgICAgICAgICAgICAgICAgICAgeU9mZnNldDogcGFyc2VJbnQobGV0dGVyc1tpXS5nZXRBdHRyaWJ1dGUoJ3lvZmZzZXQnKSwgMTApLFxuICAgICAgICAgICAgICAgICAgICB4QWR2YW5jZTogcGFyc2VJbnQobGV0dGVyc1tpXS5nZXRBdHRyaWJ1dGUoJ3hhZHZhbmNlJyksIDEwKSxcbiAgICAgICAgICAgICAgICAgICAga2VybmluZzoge30sXG4gICAgICAgICAgICAgICAgICAgIHRleHR1cmU6IGNvcmUudXRpbHMuVGV4dHVyZUNhY2hlW2NoYXJDb2RlXSA9IG5ldyBjb3JlLlRleHR1cmUodGhpcy50ZXh0dXJlLCB0ZXh0dXJlUmVjdClcblxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vcGFyc2Uga2VybmluZ3NcbiAgICAgICAgICAgIHZhciBrZXJuaW5ncyA9IHJlc3BvbnNlWE1MLmdldEVsZW1lbnRzQnlUYWdOYW1lKCdrZXJuaW5nJyk7XG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwga2VybmluZ3MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgZmlyc3QgPSBwYXJzZUludChrZXJuaW5nc1tpXS5nZXRBdHRyaWJ1dGUoJ2ZpcnN0JyksIDEwKTtcbiAgICAgICAgICAgICAgICB2YXIgc2Vjb25kID0gcGFyc2VJbnQoa2VybmluZ3NbaV0uZ2V0QXR0cmlidXRlKCdzZWNvbmQnKSwgMTApO1xuICAgICAgICAgICAgICAgIHZhciBhbW91bnQgPSBwYXJzZUludChrZXJuaW5nc1tpXS5nZXRBdHRyaWJ1dGUoJ2Ftb3VudCcpLCAxMCk7XG5cbiAgICAgICAgICAgICAgICBkYXRhLmNoYXJzW3NlY29uZF0ua2VybmluZ1tmaXJzdF0gPSBhbW91bnQ7XG5cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29yZS5CaXRtYXBUZXh0LmZvbnRzW2RhdGEuZm9udF0gPSBkYXRhO1xuXG4gICAgICAgICAgICBpbWFnZS5hZGRFdmVudExpc3RlbmVyKCdsb2FkZWQnLCB0aGlzLm9uTG9hZGVkLmJpbmQodGhpcykpO1xuICAgICAgICAgICAgaW1hZ2UubG9hZCgpO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuLyoqXG4gKiBJbnZva2VkIHdoZW4gYWxsIGZpbGVzIGFyZSBsb2FkZWQgKHhtbC9mbnQgYW5kIHRleHR1cmUpXG4gKlxuICogQHByaXZhdGVcbiAqL1xuQml0bWFwRm9udExvYWRlci5wcm90b3R5cGUub25Mb2FkZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5lbWl0KCdsb2FkZWQnLCB7IGNvbnRlbnQ6IHRoaXMgfSk7XG59O1xuIiwidmFyIGNvcmUgPSByZXF1aXJlKCcuLi9jb3JlJyk7XG5cbi8qKlxuICogVGhlIGltYWdlIGxvYWRlciBjbGFzcyBpcyByZXNwb25zaWJsZSBmb3IgbG9hZGluZyBpbWFnZXMgZmlsZSBmb3JtYXRzICgnanBlZycsICdqcGcnLCAncG5nJyBhbmQgJ2dpZicpXG4gKiBPbmNlIHRoZSBpbWFnZSBoYXMgYmVlbiBsb2FkZWQgaXQgaXMgc3RvcmVkIGluIHRoZSBQSVhJIHRleHR1cmUgY2FjaGUgYW5kIGNhbiBiZSBhY2Nlc3NlZCB0aG91Z2ggVGV4dHVyZS5mcm9tRnJhbWUoKSBhbmQgU3ByaXRlLmZyb21GcmFtZSgpXG4gKiBXaGVuIGxvYWRlZCB0aGlzIGNsYXNzIHdpbGwgZGlzcGF0Y2ggYSAnbG9hZGVkJyBldmVudFxuICpcbiAqIEBjbGFzc1xuICogQG1peGVzIGV2ZW50VGFyZ2V0XG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSB1cmwge1N0cmluZ30gVGhlIHVybCBvZiB0aGUgaW1hZ2VcbiAqIEBwYXJhbSBjcm9zc29yaWdpbiB7Ym9vbGVhbn0gV2hldGhlciByZXF1ZXN0cyBzaG91bGQgYmUgdHJlYXRlZCBhcyBjcm9zc29yaWdpblxuICovXG5mdW5jdGlvbiBJbWFnZUxvYWRlcih1cmwsIGNyb3Nzb3JpZ2luKSB7XG4gICAgLyoqXG4gICAgICogVGhlIHRleHR1cmUgYmVpbmcgbG9hZGVkXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtUZXh0dXJlfVxuICAgICAqL1xuICAgIHRoaXMudGV4dHVyZSA9IGNvcmUuVGV4dHVyZS5mcm9tSW1hZ2UodXJsLCBjcm9zc29yaWdpbik7XG5cbiAgICAvKipcbiAgICAgKiBpZiB0aGUgaW1hZ2UgaXMgbG9hZGVkIHdpdGggbG9hZEZyYW1lZFNwcml0ZVNoZWV0XG4gICAgICogZnJhbWVzIHdpbGwgY29udGFpbiB0aGUgc3ByaXRlIHNoZWV0IGZyYW1lc1xuICAgICAqXG4gICAgICogQG1lbWJlciB7QXJyYXl9XG4gICAgICogQHJlYWRPbmx5XG4gICAgICovXG4gICAgdGhpcy5mcmFtZXMgPSBbXTtcbn1cblxuLy8gY29uc3RydWN0b3JcbkltYWdlTG9hZGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEltYWdlTG9hZGVyO1xubW9kdWxlLmV4cG9ydHMgPSBJbWFnZUxvYWRlcjtcblxuY29yZS51dGlscy5ldmVudFRhcmdldC5taXhpbihJbWFnZUxvYWRlci5wcm90b3R5cGUpO1xuXG4vKipcbiAqIExvYWRzIGltYWdlIG9yIHRha2VzIGl0IGZyb20gY2FjaGVcbiAqXG4gKi9cbkltYWdlTG9hZGVyLnByb3RvdHlwZS5sb2FkID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICghdGhpcy50ZXh0dXJlLmJhc2VUZXh0dXJlLmhhc0xvYWRlZCkge1xuICAgICAgICB0aGlzLnRleHR1cmUuYmFzZVRleHR1cmUub24oJ2xvYWRlZCcsIHRoaXMub25Mb2FkZWQuYmluZCh0aGlzKSk7XG4gICAgICAgIHRoaXMudGV4dHVyZS5iYXNlVGV4dHVyZS5vbignZXJyb3InLCB0aGlzLm9uRXJyb3IuYmluZCh0aGlzKSk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLm9uTG9hZGVkKCk7XG4gICAgfVxufTtcblxuLyoqXG4gKiBJbnZva2VkIHdoZW4gaW1hZ2UgZmlsZSBpcyBsb2FkZWQgb3IgaXQgaXMgYWxyZWFkeSBjYWNoZWQgYW5kIHJlYWR5IHRvIHVzZVxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkltYWdlTG9hZGVyLnByb3RvdHlwZS5vbkxvYWRlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmVtaXQoJ2xvYWRlZCcsIHsgY29udGVudDogdGhpcyB9KTtcbn07XG5cbi8qKlxuICogSW52b2tlZCB3aGVuIGltYWdlIGZpbGUgZmFpbGVkIGxvYWRpbmdcbiAqXG4gKiBAbWV0aG9kIG9uRXJyb3JcbiAqIEBwcml2YXRlXG4gKi9cbkltYWdlTG9hZGVyLnByb3RvdHlwZS5vbkVycm9yID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZW1pdCgnZXJyb3InLCB7IGNvbnRlbnQ6IHRoaXMgfSk7XG59O1xuXG4vKipcbiAqIExvYWRzIGltYWdlIGFuZCBzcGxpdCBpdCB0byB1bmlmb3JtIHNpemVkIGZyYW1lc1xuICpcbiAqIEBwYXJhbSBmcmFtZVdpZHRoIHtudW1iZXJ9IHdpZHRoIG9mIGVhY2ggZnJhbWVcbiAqIEBwYXJhbSBmcmFtZUhlaWdodCB7bnVtYmVyfSBoZWlnaHQgb2YgZWFjaCBmcmFtZVxuICogQHBhcmFtIHRleHR1cmVOYW1lIHtTdHJpbmd9IGlmIGdpdmVuLCB0aGUgZnJhbWVzIHdpbGwgYmUgY2FjaGVkIGluIDx0ZXh0dXJlTmFtZT4tPG9yZD4gZm9ybWF0XG4gKi9cbkltYWdlTG9hZGVyLnByb3RvdHlwZS5sb2FkRnJhbWVkU3ByaXRlU2hlZXQgPSBmdW5jdGlvbiAoZnJhbWVXaWR0aCwgZnJhbWVIZWlnaHQsIHRleHR1cmVOYW1lKSB7XG4gICAgdGhpcy5mcmFtZXMgPSBbXTtcblxuICAgIHZhciBjb2xzID0gTWF0aC5mbG9vcih0aGlzLnRleHR1cmUud2lkdGggLyBmcmFtZVdpZHRoKTtcbiAgICB2YXIgcm93cyA9IE1hdGguZmxvb3IodGhpcy50ZXh0dXJlLmhlaWdodCAvIGZyYW1lSGVpZ2h0KTtcblxuICAgIHZhciBpPTA7XG4gICAgZm9yICh2YXIgeSA9IDA7IHkgPCByb3dzOyArK3kpIHtcbiAgICAgICAgZm9yICh2YXIgeCA9IDA7IHggPCBjb2xzOyArK3gsICsraSkge1xuICAgICAgICAgICAgdmFyIHRleHR1cmUgPSBuZXcgY29yZS5UZXh0dXJlKFxuICAgICAgICAgICAgICAgIHRoaXMudGV4dHVyZS5iYXNlVGV4dHVyZSxcbiAgICAgICAgICAgICAgICBuZXcgY29yZS5tYXRoLlJlY3RhbmdsZShcbiAgICAgICAgICAgICAgICAgICAgeCAqIGZyYW1lV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgIHkgKiBmcmFtZUhlaWdodCxcbiAgICAgICAgICAgICAgICAgICAgZnJhbWVXaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgZnJhbWVIZWlnaHRcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICApO1xuXG4gICAgICAgICAgICB0aGlzLmZyYW1lcy5wdXNoKHRleHR1cmUpO1xuXG4gICAgICAgICAgICBpZiAodGV4dHVyZU5hbWUpIHtcbiAgICAgICAgICAgICAgICBjb3JlLnV0aWxzLlRleHR1cmVDYWNoZVt0ZXh0dXJlTmFtZSArICctJyArIGldID0gdGV4dHVyZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuXHR0aGlzLmxvYWQoKTtcbn07XG4iLCJ2YXIgY29yZSA9IHJlcXVpcmUoJy4uL2NvcmUnKSxcbiAgICBzcGluZSA9IHJlcXVpcmUoJy4uL3NwaW5lL1NwaW5lUnVudGltZScpLFxuICAgIEltYWdlTG9hZGVyID0gcmVxdWlyZSgnLi9JbWFnZUxvYWRlcicpLFxuICAgIFNwaW5lVGV4dHVyZUxvYWRlciA9IHJlcXVpcmUoJy4vU3BpbmVUZXh0dXJlTG9hZGVyJyk7XG5cbi8qKlxuICogVGhlIGpzb24gZmlsZSBsb2FkZXIgaXMgdXNlZCB0byBsb2FkIGluIEpTT04gZGF0YSBhbmQgcGFyc2UgaXRcbiAqIFdoZW4gbG9hZGVkIHRoaXMgY2xhc3Mgd2lsbCBkaXNwYXRjaCBhICdsb2FkZWQnIGV2ZW50XG4gKiBJZiBsb2FkaW5nIGZhaWxzIHRoaXMgY2xhc3Mgd2lsbCBkaXNwYXRjaCBhbiAnZXJyb3InIGV2ZW50XG4gKlxuICogQGNsYXNzXG4gKiBAbWl4ZXMgZXZlbnRUYXJnZXRcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHVybCB7U3RyaW5nfSBUaGUgdXJsIG9mIHRoZSBKU09OIGZpbGVcbiAqIEBwYXJhbSBjcm9zc29yaWdpbiB7Ym9vbGVhbn0gV2hldGhlciByZXF1ZXN0cyBzaG91bGQgYmUgdHJlYXRlZCBhcyBjcm9zc29yaWdpblxuICovXG5mdW5jdGlvbiBKc29uTG9hZGVyKHVybCwgY3Jvc3NvcmlnaW4pIHtcbiAgICAvKipcbiAgICAgKiBUaGUgdXJsIG9mIHRoZSBiaXRtYXAgZm9udCBkYXRhXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtTdHJpbmd9XG4gICAgICovXG4gICAgdGhpcy51cmwgPSB1cmw7XG5cbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRoZSByZXF1ZXN0cyBzaG91bGQgYmUgdHJlYXRlZCBhcyBjcm9zcyBvcmlnaW5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge2Jvb2xlYW59XG4gICAgICovXG4gICAgdGhpcy5jcm9zc29yaWdpbiA9IGNyb3Nzb3JpZ2luO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGJhc2UgdXJsIG9mIHRoZSBiaXRtYXAgZm9udCBkYXRhXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtTdHJpbmd9XG4gICAgICogQHJlYWRPbmx5XG4gICAgICovXG4gICAgdGhpcy5iYXNlVXJsID0gdXJsLnJlcGxhY2UoL1teXFwvXSokLywgJycpO1xuXG4gICAgLyoqXG4gICAgICogV2hldGhlciB0aGUgZGF0YSBoYXMgbG9hZGVkIHlldFxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAcmVhZE9ubHlcbiAgICAgKi9cbiAgICAgdGhpcy5sb2FkZWQgPSBmYWxzZTtcbn1cblxuLy8gY29uc3RydWN0b3Jcbkpzb25Mb2FkZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gSnNvbkxvYWRlcjtcbm1vZHVsZS5leHBvcnRzID0gSnNvbkxvYWRlcjtcblxuY29yZS51dGlscy5ldmVudFRhcmdldC5taXhpbihKc29uTG9hZGVyLnByb3RvdHlwZSk7XG5cbi8qKlxuICogTG9hZHMgdGhlIEpTT04gZGF0YVxuICpcbiAqL1xuSnNvbkxvYWRlci5wcm90b3R5cGUubG9hZCA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAod2luZG93LlhEb21haW5SZXF1ZXN0ICYmIHRoaXMuY3Jvc3NvcmlnaW4pIHtcbiAgICAgICAgdGhpcy5hamF4UmVxdWVzdCA9IG5ldyB3aW5kb3cuWERvbWFpblJlcXVlc3QoKTtcblxuICAgICAgICAvLyBYRG9tYWluUmVxdWVzdCBoYXMgYSBmZXcgcXVpcmtzLiBPY2Nhc2lvbmFsbHkgaXQgd2lsbCBhYm9ydCByZXF1ZXN0c1xuICAgICAgICAvLyBBIHdheSB0byBhdm9pZCB0aGlzIGlzIHRvIG1ha2Ugc3VyZSBBTEwgY2FsbGJhY2tzIGFyZSBzZXQgZXZlbiBpZiBub3QgdXNlZFxuICAgICAgICAvLyBNb3JlIGluZm8gaGVyZTogaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8xNTc4Njk2Ni94ZG9tYWlucmVxdWVzdC1hYm9ydHMtcG9zdC1vbi1pZS05XG4gICAgICAgIHRoaXMuYWpheFJlcXVlc3QudGltZW91dCA9IDMwMDA7XG5cbiAgICAgICAgdGhpcy5hamF4UmVxdWVzdC5vbmVycm9yID0gdGhpcy5vbkVycm9yLmJpbmQodGhpcyk7XG4gICAgICAgIHRoaXMuYWpheFJlcXVlc3Qub250aW1lb3V0ID0gdGhpcy5vbkVycm9yLmJpbmQodGhpcyk7XG5cbiAgICAgICAgdGhpcy5hamF4UmVxdWVzdC5vbnByb2dyZXNzID0gZnVuY3Rpb24gKCkge307XG5cbiAgICAgICAgdGhpcy5hamF4UmVxdWVzdC5vbmxvYWQgPSB0aGlzLm9uSlNPTkxvYWRlZC5iaW5kKHRoaXMpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgaWYgKHdpbmRvdy5YTUxIdHRwUmVxdWVzdCkge1xuICAgICAgICAgICAgdGhpcy5hamF4UmVxdWVzdCA9IG5ldyB3aW5kb3cuWE1MSHR0cFJlcXVlc3QoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuYWpheFJlcXVlc3QgPSBuZXcgd2luZG93LkFjdGl2ZVhPYmplY3QoJ01pY3Jvc29mdC5YTUxIVFRQJyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmFqYXhSZXF1ZXN0Lm9ucmVhZHlzdGF0ZWNoYW5nZSA9IHRoaXMub25SZWFkeVN0YXRlQ2hhbmdlZC5iaW5kKHRoaXMpO1xuICAgIH1cblxuICAgIHRoaXMuYWpheFJlcXVlc3Qub3BlbignR0VUJyx0aGlzLnVybCx0cnVlKTtcblxuICAgIHRoaXMuYWpheFJlcXVlc3Quc2VuZCgpO1xufTtcblxuLyoqXG4gKiBCcmlkZ2UgZnVuY3Rpb24gdG8gYmUgYWJsZSB0byB1c2UgdGhlIG1vcmUgcmVsaWFibGUgb25yZWFkeXN0YXRlY2hhbmdlIGluIFhNTEh0dHBSZXF1ZXN0LlxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkpzb25Mb2FkZXIucHJvdG90eXBlLm9uUmVhZHlTdGF0ZUNoYW5nZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHRoaXMuYWpheFJlcXVlc3QucmVhZHlTdGF0ZSA9PT0gNCAmJiAodGhpcy5hamF4UmVxdWVzdC5zdGF0dXMgPT09IDIwMCB8fCB3aW5kb3cubG9jYXRpb24uaHJlZi5pbmRleE9mKCdodHRwJykgPT09IC0xKSkge1xuICAgICAgICB0aGlzLm9uSlNPTkxvYWRlZCgpO1xuICAgIH1cbn07XG5cbi8qKlxuICogSW52b2tlIHdoZW4gSlNPTiBmaWxlIGlzIGxvYWRlZFxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkpzb25Mb2FkZXIucHJvdG90eXBlLm9uSlNPTkxvYWRlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoIXRoaXMuYWpheFJlcXVlc3QucmVzcG9uc2VUZXh0KSB7XG4gICAgICAgIHRoaXMub25FcnJvcigpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5qc29uID0gSlNPTi5wYXJzZSh0aGlzLmFqYXhSZXF1ZXN0LnJlc3BvbnNlVGV4dCk7XG5cbiAgICBpZiAodGhpcy5qc29uLmZyYW1lcykge1xuICAgICAgICAvLyBzcHJpdGUgc2hlZXRcbiAgICAgICAgdmFyIHRleHR1cmVVcmwgPSB0aGlzLmJhc2VVcmwgKyB0aGlzLmpzb24ubWV0YS5pbWFnZTtcbiAgICAgICAgdmFyIGltYWdlID0gbmV3IEltYWdlTG9hZGVyKHRleHR1cmVVcmwsIHRoaXMuY3Jvc3NvcmlnaW4pO1xuICAgICAgICB2YXIgZnJhbWVEYXRhID0gdGhpcy5qc29uLmZyYW1lcztcblxuICAgICAgICB0aGlzLnRleHR1cmUgPSBpbWFnZS50ZXh0dXJlLmJhc2VUZXh0dXJlO1xuICAgICAgICBpbWFnZS5hZGRFdmVudExpc3RlbmVyKCdsb2FkZWQnLCB0aGlzLm9uTG9hZGVkLmJpbmQodGhpcykpO1xuICAgICAgICBpbWFnZS5hZGRFdmVudExpc3RlbmVyKCdlcnJvcicsIHRoaXMub25FcnJvci5iaW5kKHRoaXMpKTtcblxuICAgICAgICBmb3IgKHZhciBpIGluIGZyYW1lRGF0YSkge1xuICAgICAgICAgICAgdmFyIHJlY3QgPSBmcmFtZURhdGFbaV0uZnJhbWU7XG5cbiAgICAgICAgICAgIGlmIChyZWN0KSB7XG4gICAgICAgICAgICAgICAgdmFyIHRleHR1cmVTaXplID0gbmV3IGNvcmUubWF0aC5SZWN0YW5nbGUocmVjdC54LCByZWN0LnksIHJlY3QudywgcmVjdC5oKTtcbiAgICAgICAgICAgICAgICB2YXIgY3JvcCA9IHRleHR1cmVTaXplLmNsb25lKCk7XG4gICAgICAgICAgICAgICAgdmFyIHRyaW0gPSBudWxsO1xuXG4gICAgICAgICAgICAgICAgLy8gIENoZWNrIHRvIHNlZSBpZiB0aGUgc3ByaXRlIGlzIHRyaW1tZWRcbiAgICAgICAgICAgICAgICBpZiAoZnJhbWVEYXRhW2ldLnRyaW1tZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGFjdHVhbFNpemUgPSBmcmFtZURhdGFbaV0uc291cmNlU2l6ZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHJlYWxTaXplID0gZnJhbWVEYXRhW2ldLnNwcml0ZVNvdXJjZVNpemU7XG4gICAgICAgICAgICAgICAgICAgIHRyaW0gPSBuZXcgY29yZS5tYXRoLlJlY3RhbmdsZShyZWFsU2l6ZS54LCByZWFsU2l6ZS55LCBhY3R1YWxTaXplLncsIGFjdHVhbFNpemUuaCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvcmUudXRpbHMuVGV4dHVyZUNhY2hlW2ldID0gbmV3IGNvcmUuVGV4dHVyZSh0aGlzLnRleHR1cmUsIHRleHR1cmVTaXplLCBjcm9wLCB0cmltKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGltYWdlLmxvYWQoKTtcblxuICAgIH1cbiAgICBlbHNlIGlmICh0aGlzLmpzb24uYm9uZXMpIHtcblx0XHQvLyBjaGVjayBpZiB0aGUganNvbiB3YXMgbG9hZGVkIGJlZm9yZVxuXHRcdGlmIChjb3JlLnV0aWxzLkFuaW1DYWNoZVt0aGlzLnVybF0pIHtcblx0XHRcdHRoaXMub25Mb2FkZWQoKTtcblx0XHR9XG5cdFx0ZWxzZSB7XG5cdFx0XHQvKipcbiAgICAgICAgICAgICAqIHVzZSBhIGJpdCBvZiBoYWNrZXJ5IHRvIGxvYWQgdGhlIGF0bGFzIGZpbGUsIGhlcmUgd2UgYXNzdW1lIHRoYXQgdGhlIC5qc29uLCAuYXRsYXMgYW5kIC5wbmcgZmlsZXNcblx0XHRcdCAqIHRoYXQgY29ycmVzcG9uZCB0byB0aGUgc3BpbmUgZmlsZSBhcmUgaW4gdGhlIHNhbWUgYmFzZSBVUkwgYW5kIHRoYXQgdGhlIC5qc29uIGFuZCAuYXRsYXMgZmlsZXNcblx0XHRcdCAqIGhhdmUgdGhlIHNhbWUgbmFtZVxuXHRcdFx0ICovXG5cdFx0XHR2YXIgYXRsYXNQYXRoID0gdGhpcy51cmwuc3Vic3RyKDAsIHRoaXMudXJsLmxhc3RJbmRleE9mKCcuJykpICsgJy5hdGxhcyc7XG5cdFx0XHR2YXIgYXRsYXNMb2FkZXIgPSBuZXcgSnNvbkxvYWRlcihhdGxhc1BhdGgsIHRoaXMuY3Jvc3NvcmlnaW4pO1xuXHRcdFx0Ly8gc2F2ZSBhIGNvcHkgb2YgdGhlIGN1cnJlbnQgb2JqZWN0IGZvciBmdXR1cmUgcmVmZXJlbmNlIC8vXG5cdFx0XHR2YXIgb3JpZ2luYWxMb2FkZXIgPSB0aGlzO1xuXHRcdFx0Ly8gYmVmb3JlIGxvYWRpbmcgdGhlIGZpbGUsIHJlcGxhY2UgdGhlIFwib25KU09OTG9hZGVkXCIgZnVuY3Rpb24gZm9yIG91ciBvd24gLy9cblx0XHRcdGF0bGFzTG9hZGVyLm9uSlNPTkxvYWRlZCA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0Ly8gYXQgdGhpcyBwb2ludCBcInRoaXNcIiBwb2ludHMgYXQgdGhlIGF0bGFzTG9hZGVyIChKc29uTG9hZGVyKSBpbnN0YW5jZSAvL1xuXHRcdFx0XHRpZiAoIXRoaXMuYWpheFJlcXVlc3QucmVzcG9uc2VUZXh0KSB7XG5cdFx0XHRcdFx0dGhpcy5vbkVycm9yKCk7IC8vIEZJWE1FOiBobW0sIHRoaXMgaXMgZnVubnkgYmVjYXVzZSB3ZSBhcmUgbm90IHJlc3BvbmRpbmcgdG8gZXJyb3JzIHlldFxuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXHRcdFx0XHQvLyBjcmVhdGUgYSBuZXcgaW5zdGFuY2Ugb2YgYSBzcGluZSB0ZXh0dXJlIGxvYWRlciBmb3IgdGhpcyBzcGluZSBvYmplY3QgLy9cblx0XHRcdFx0dmFyIHRleHR1cmVMb2FkZXIgPSBuZXcgU3BpbmVUZXh0dXJlTG9hZGVyKHRoaXMudXJsLnN1YnN0cmluZygwLCB0aGlzLnVybC5sYXN0SW5kZXhPZignLycpKSk7XG5cdFx0XHRcdC8vIGNyZWF0ZSBhIHNwaW5lIGF0bGFzIHVzaW5nIHRoZSBsb2FkZWQgdGV4dCBhbmQgYSBzcGluZSB0ZXh0dXJlIGxvYWRlciBpbnN0YW5jZSAvL1xuXHRcdFx0XHR2YXIgc3BpbmVBdGxhcyA9IG5ldyBzcGluZS5BdGxhcyh0aGlzLmFqYXhSZXF1ZXN0LnJlc3BvbnNlVGV4dCwgdGV4dHVyZUxvYWRlcik7XG5cdFx0XHRcdC8vIG5vdyB3ZSB1c2UgYW4gYXRsYXMgYXR0YWNobWVudCBsb2FkZXIgLy9cblx0XHRcdFx0dmFyIGF0dGFjaG1lbnRMb2FkZXIgPSBuZXcgc3BpbmUuQXRsYXNBdHRhY2htZW50TG9hZGVyKHNwaW5lQXRsYXMpO1xuXHRcdFx0XHQvLyBzcGluZSBhbmltYXRpb25cblx0XHRcdFx0dmFyIHNwaW5lSnNvblBhcnNlciA9IG5ldyBzcGluZS5Ta2VsZXRvbkpzb24oYXR0YWNobWVudExvYWRlcik7XG5cdFx0XHRcdHZhciBza2VsZXRvbkRhdGEgPSBzcGluZUpzb25QYXJzZXIucmVhZFNrZWxldG9uRGF0YShvcmlnaW5hbExvYWRlci5qc29uKTtcblx0XHRcdFx0Y29yZS51dGlscy5BbmltQ2FjaGVbb3JpZ2luYWxMb2FkZXIudXJsXSA9IHNrZWxldG9uRGF0YTtcblx0XHRcdFx0b3JpZ2luYWxMb2FkZXIuc3BpbmUgPSBza2VsZXRvbkRhdGE7XG5cdFx0XHRcdG9yaWdpbmFsTG9hZGVyLnNwaW5lQXRsYXMgPSBzcGluZUF0bGFzO1xuXHRcdFx0XHRvcmlnaW5hbExvYWRlci5zcGluZUF0bGFzTG9hZGVyID0gYXRsYXNMb2FkZXI7XG5cdFx0XHRcdC8vIHdhaXQgZm9yIHRleHR1cmVzIHRvIGZpbmlzaCBsb2FkaW5nIGlmIG5lZWRlZFxuXHRcdFx0XHRpZiAodGV4dHVyZUxvYWRlci5sb2FkaW5nQ291bnQgPiAwKSB7XG5cdFx0XHRcdFx0dGV4dHVyZUxvYWRlci5hZGRFdmVudExpc3RlbmVyKCdsb2FkZWRCYXNlVGV4dHVyZScsIGZ1bmN0aW9uIChldnQpe1xuXHRcdFx0XHRcdFx0aWYgKGV2dC5jb250ZW50LmNvbnRlbnQubG9hZGluZ0NvdW50IDw9IDApIHtcblx0XHRcdFx0XHRcdFx0b3JpZ2luYWxMb2FkZXIub25Mb2FkZWQoKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRvcmlnaW5hbExvYWRlci5vbkxvYWRlZCgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9O1xuXHRcdFx0Ly8gc3RhcnQgdGhlIGxvYWRpbmcgLy9cblx0XHRcdGF0bGFzTG9hZGVyLmxvYWQoKTtcblx0XHR9XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLm9uTG9hZGVkKCk7XG4gICAgfVxufTtcblxuLyoqXG4gKiBJbnZva2Ugd2hlbiBqc29uIGZpbGUgbG9hZGVkXG4gKlxuICogQHByaXZhdGVcbiAqL1xuSnNvbkxvYWRlci5wcm90b3R5cGUub25Mb2FkZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5sb2FkZWQgPSB0cnVlO1xuICAgIHRoaXMuZGlzcGF0Y2hFdmVudCh7XG4gICAgICAgIHR5cGU6ICdsb2FkZWQnLFxuICAgICAgICBjb250ZW50OiB0aGlzXG4gICAgfSk7XG59O1xuXG4vKipcbiAqIEludm9rZSB3aGVuIGVycm9yIG9jY3VyZWRcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5Kc29uTG9hZGVyLnByb3RvdHlwZS5vbkVycm9yID0gZnVuY3Rpb24gKCkge1xuXG4gICAgdGhpcy5kaXNwYXRjaEV2ZW50KHtcbiAgICAgICAgdHlwZTogJ2Vycm9yJyxcbiAgICAgICAgY29udGVudDogdGhpc1xuICAgIH0pO1xufTtcbiIsInZhciBjb3JlID0gcmVxdWlyZSgnLi4vY29yZScpLFxuICAgIEpzb25Mb2FkZXIgPSByZXF1aXJlKCcuL0pzb25Mb2FkZXInKTtcblxuLyoqXG4gKiBAYXV0aG9yIE1hdCBHcm92ZXMgaHR0cDovL21hdGdyb3Zlcy5jb20vIEBEb29ybWF0MjNcbiAqIGJhc2VkIG9uIHBpeGkgaW1wYWN0IHNwaW5lIGltcGxlbWVudGF0aW9uIG1hZGUgYnkgRWVtZWxpIEtlbG9rb3JwaSAoQGVrZWxva29ycGkpIGh0dHBzOi8vZ2l0aHViLmNvbS9la2Vsb2tvcnBpXG4gKlxuICogQXdlc29tZSBKUyBydW4gdGltZSBwcm92aWRlZCBieSBFc290ZXJpY1NvZnR3YXJlXG4gKiBodHRwczovL2dpdGh1Yi5jb20vRXNvdGVyaWNTb2Z0d2FyZS9zcGluZS1ydW50aW1lc1xuICpcbiAqL1xuXG4vKipcbiAqIFRoZSBTcGluZSBsb2FkZXIgaXMgdXNlZCB0byBsb2FkIGluIEpTT04gc3BpbmUgZGF0YVxuICogVG8gZ2VuZXJhdGUgdGhlIGRhdGEgeW91IG5lZWQgdG8gdXNlIGh0dHA6Ly9lc290ZXJpY3NvZnR3YXJlLmNvbS8gYW5kIGV4cG9ydCBpbiB0aGUgXCJKU09OXCIgZm9ybWF0XG4gKiBEdWUgdG8gYSBjbGFzaCBvZiBuYW1lcyAgWW91IHdpbGwgbmVlZCB0byBjaGFuZ2UgdGhlIGV4dGVuc2lvbiBvZiB0aGUgc3BpbmUgZmlsZSBmcm9tICouanNvbiB0byAqLmFuaW0gZm9yIGl0IHRvIGxvYWRcbiAqIFNlZSBleGFtcGxlIDEyIChodHRwOi8vd3d3Lmdvb2Rib3lkaWdpdGFsLmNvbS9waXhpanMvZXhhbXBsZXMvMTIvKSB0byBzZWUgYSB3b3JraW5nIGV4YW1wbGUgYW5kIGNoZWNrIG91dCB0aGUgc291cmNlXG4gKiBZb3Ugd2lsbCBuZWVkIHRvIGdlbmVyYXRlIGEgc3ByaXRlIHNoZWV0IHRvIGFjY29tcGFueSB0aGUgc3BpbmUgZGF0YVxuICogV2hlbiBsb2FkZWQgdGhpcyBjbGFzcyB3aWxsIGRpc3BhdGNoIGEgXCJsb2FkZWRcIiBldmVudFxuICpcbiAqIEBjbGFzc1xuICogQG1peGVzIGV2ZW50VGFyZ2V0XG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSB1cmwge1N0cmluZ30gVGhlIHVybCBvZiB0aGUgSlNPTiBmaWxlXG4gKiBAcGFyYW0gY3Jvc3NvcmlnaW4ge2Jvb2xlYW59IFdoZXRoZXIgcmVxdWVzdHMgc2hvdWxkIGJlIHRyZWF0ZWQgYXMgY3Jvc3NvcmlnaW5cbiAqL1xuZnVuY3Rpb24gU3BpbmVMb2FkZXIodXJsLCBjcm9zc29yaWdpbikge1xuICAgIC8qKlxuICAgICAqIFRoZSB1cmwgb2YgdGhlIGJpdG1hcCBmb250IGRhdGFcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1N0cmluZ31cbiAgICAgKi9cbiAgICB0aGlzLnVybCA9IHVybDtcblxuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgdGhlIHJlcXVlc3RzIHNob3VsZCBiZSB0cmVhdGVkIGFzIGNyb3NzIG9yaWdpblxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLmNyb3Nzb3JpZ2luID0gY3Jvc3NvcmlnaW47XG5cbiAgICAvKipcbiAgICAgKiBXaGV0aGVyIHRoZSBkYXRhIGhhcyBsb2FkZWQgeWV0XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtib29sZWFufVxuICAgICAqIEByZWFkT25seVxuICAgICAqL1xuICAgIHRoaXMubG9hZGVkID0gZmFsc2U7XG59XG5cblNwaW5lTG9hZGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFNwaW5lTG9hZGVyO1xubW9kdWxlLmV4cG9ydHMgPSBTcGluZUxvYWRlcjtcblxuY29yZS51dGlscy5ldmVudFRhcmdldC5taXhpbihTcGluZUxvYWRlci5wcm90b3R5cGUpO1xuXG4vKipcbiAqIExvYWRzIHRoZSBKU09OIGRhdGFcbiAqXG4gKi9cblNwaW5lTG9hZGVyLnByb3RvdHlwZS5sb2FkID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBzY29wZSA9IHRoaXM7XG4gICAgdmFyIGpzb25Mb2FkZXIgPSBuZXcgSnNvbkxvYWRlcih0aGlzLnVybCwgdGhpcy5jcm9zc29yaWdpbik7XG5cbiAgICBqc29uTG9hZGVyLm9uKCdsb2FkZWQnLCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgc2NvcGUuanNvbiA9IGV2ZW50LmRhdGEuY29udGVudC5qc29uO1xuICAgICAgICBzY29wZS5vbkxvYWRlZCgpO1xuICAgIH0pO1xuXG4gICAganNvbkxvYWRlci5sb2FkKCk7XG59O1xuXG4vKipcbiAqIEludm9rZWQgd2hlbiBKU09OIGZpbGUgaXMgbG9hZGVkLlxuICpcbiAqIEBwcml2YXRlXG4gKi9cblNwaW5lTG9hZGVyLnByb3RvdHlwZS5vbkxvYWRlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmxvYWRlZCA9IHRydWU7XG4gICAgdGhpcy5lbWl0KCdsb2FkZWQnLCB7IGNvbnRlbnQ6IHRoaXMgfSk7XG59O1xuIiwidmFyIGNvcmUgPSByZXF1aXJlKCcuLi9jb3JlJyk7XG5cbi8qKlxuICogU3VwcG9ydGluZyBjbGFzcyB0byBsb2FkIGltYWdlcyBmcm9tIHNwaW5lIGF0bGFzZXMgYXMgcGVyIHNwaW5lIHNwZWMuXG4gKlxuICogQGNsYXNzXG4gKiBAbWl4ZXMgZXZlbnRUYXJnZXRcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIGJhc2VQYXRoIHtzdHJpbmd9IFRoYSBiYXNlIHBhdGggd2hlcmUgdG8gbG9vayBmb3IgdGhlIGltYWdlcyB0byBiZSBsb2FkZWRcbiAqIEBwYXJhbSBjcm9zc29yaWdpbiB7Ym9vbGVhbn0gV2hldGhlciByZXF1ZXN0cyBzaG91bGQgYmUgdHJlYXRlZCBhcyBjcm9zc29yaWdpblxuICovXG5mdW5jdGlvbiBTcGluZVRleHR1cmVMb2FkZXIoYmFzZVBhdGgsIGNyb3Nzb3JpZ2luKSB7XG4gICAgdGhpcy5iYXNlUGF0aCA9IGJhc2VQYXRoO1xuICAgIHRoaXMuY3Jvc3NvcmlnaW4gPSBjcm9zc29yaWdpbjtcbiAgICB0aGlzLmxvYWRpbmdDb3VudCA9IDA7XG59XG5cblNwaW5lVGV4dHVyZUxvYWRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBTcGluZVRleHR1cmVMb2FkZXI7XG5tb2R1bGUuZXhwb3J0cyA9IFNwaW5lVGV4dHVyZUxvYWRlcjtcblxuY29yZS51dGlscy5ldmVudFRhcmdldC5taXhpbihTcGluZVRleHR1cmVMb2FkZXIucHJvdG90eXBlKTtcblxuLyoqXG4gKiBTdGFydHMgbG9hZGluZyBhIGJhc2UgdGV4dHVyZSBhcyBwZXIgc3BpbmUgc3BlY2lmaWNhdGlvblxuICpcbiAqIEBwYXJhbSBwYWdlIHtzcGluZS5BdGxhc1BhZ2V9IEF0bGFzIHBhZ2UgdG8gd2hpY2ggdGV4dHVyZSBiZWxvbmdzXG4gKiBAcGFyYW0gZmlsZSB7c3RyaW5nfSBUaGUgZmlsZSB0byBsb2FkLCB0aGlzIGlzIGp1c3QgdGhlIGZpbGUgcGF0aCByZWxhdGl2ZSB0byB0aGUgYmFzZSBwYXRoIGNvbmZpZ3VyZWQgaW4gdGhlIGNvbnN0cnVjdG9yXG4gKi9cblNwaW5lVGV4dHVyZUxvYWRlci5wcm90b3R5cGUubG9hZCA9IGZ1bmN0aW9uIChwYWdlLCBmaWxlKSB7XG4gICAgcGFnZS5yZW5kZXJlck9iamVjdCA9IGNvcmUuQmFzZVRleHR1cmUuZnJvbUltYWdlKHRoaXMuYmFzZVBhdGggKyAnLycgKyBmaWxlLCB0aGlzLmNyb3Nzb3JpZ2luKTtcbiAgICBpZiAoIXBhZ2UucmVuZGVyZXJPYmplY3QuaGFzTG9hZGVkKSB7XG4gICAgICAgIHZhciBzY29wZSA9IHRoaXM7XG4gICAgICAgICsrc2NvcGUubG9hZGluZ0NvdW50O1xuICAgICAgICBwYWdlLnJlbmRlcmVyT2JqZWN0LmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWRlZCcsIGZ1bmN0aW9uICgpe1xuICAgICAgICAgICAgLS1zY29wZS5sb2FkaW5nQ291bnQ7XG4gICAgICAgICAgICBzY29wZS5kaXNwYXRjaEV2ZW50KHtcbiAgICAgICAgICAgICAgICB0eXBlOiAnbG9hZGVkQmFzZVRleHR1cmUnLFxuICAgICAgICAgICAgICAgIGNvbnRlbnQ6IHNjb3BlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfVxufTtcblxuLyoqXG4gKiBVbmxvYWRzIGEgcHJldmlvdXNseSBsb2FkZWQgdGV4dHVyZSBhcyBwZXIgc3BpbmUgc3BlY2lmaWNhdGlvblxuICpcbiAqIEBwYXJhbSB0ZXh0dXJlIHtCYXNlVGV4dHVyZX0gVGV4dHVyZSBvYmplY3QgdG8gZGVzdHJveVxuICovXG5TcGluZVRleHR1cmVMb2FkZXIucHJvdG90eXBlLnVubG9hZCA9IGZ1bmN0aW9uICh0ZXh0dXJlKSB7XG4gICAgdGV4dHVyZS5kZXN0cm95KHRydWUpO1xufTtcbiIsInZhciBjb3JlID0gcmVxdWlyZSgnLi4vY29yZScpLFxuICAgIEpzb25Mb2FkZXIgPSByZXF1aXJlKCcuL0pzb25Mb2FkZXInKTtcblxuLyoqXG4gKiBUaGUgc3ByaXRlIHNoZWV0IGxvYWRlciBpcyB1c2VkIHRvIGxvYWQgaW4gSlNPTiBzcHJpdGUgc2hlZXQgZGF0YVxuICogVG8gZ2VuZXJhdGUgdGhlIGRhdGEgeW91IGNhbiB1c2UgaHR0cDovL3d3dy5jb2RlYW5kd2ViLmNvbS90ZXh0dXJlcGFja2VyIGFuZCBwdWJsaXNoIGluIHRoZSAnSlNPTicgZm9ybWF0XG4gKiBUaGVyZSBpcyBhIGZyZWUgdmVyc2lvbiBzbyB0aGF0cyBuaWNlLCBhbHRob3VnaCB0aGUgcGFpZCB2ZXJzaW9uIGlzIGdyZWF0IHZhbHVlIGZvciBtb25leS5cbiAqIEl0IGlzIGhpZ2hseSByZWNvbW1lbmRlZCB0byB1c2UgU3ByaXRlIHNoZWV0cyAoYWxzbyBrbm93IGFzIGEgJ3RleHR1cmUgYXRsYXMnKSBhcyBpdCBtZWFucyBzcHJpdGVzIGNhbiBiZSBiYXRjaGVkIGFuZCBkcmF3biB0b2dldGhlciBmb3IgaGlnaGx5IGluY3JlYXNlZCByZW5kZXJpbmcgc3BlZWQuXG4gKiBPbmNlIHRoZSBkYXRhIGhhcyBiZWVuIGxvYWRlZCB0aGUgZnJhbWVzIGFyZSBzdG9yZWQgaW4gdGhlIFBJWEkgdGV4dHVyZSBjYWNoZSBhbmQgY2FuIGJlIGFjY2Vzc2VkIHRob3VnaCBUZXh0dXJlLmZyb21GcmFtZUlkKCkgYW5kIFNwcml0ZS5mcm9tRnJhbWVJZCgpXG4gKiBUaGlzIGxvYWRlciB3aWxsIGxvYWQgdGhlIGltYWdlIGZpbGUgdGhhdCB0aGUgU3ByaXRlc2hlZXQgcG9pbnRzIHRvIGFzIHdlbGwgYXMgdGhlIGRhdGEuXG4gKiBXaGVuIGxvYWRlZCB0aGlzIGNsYXNzIHdpbGwgZGlzcGF0Y2ggYSAnbG9hZGVkJyBldmVudFxuICpcbiAqIEBjbGFzc1xuICogQG1peGVzIGV2ZW50VGFyZ2V0XG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqIEBwYXJhbSB1cmwge1N0cmluZ30gVGhlIHVybCBvZiB0aGUgc3ByaXRlIHNoZWV0IEpTT04gZmlsZVxuICogQHBhcmFtIGNyb3Nzb3JpZ2luIHtib29sZWFufSBXaGV0aGVyIHJlcXVlc3RzIHNob3VsZCBiZSB0cmVhdGVkIGFzIGNyb3Nzb3JpZ2luXG4gKi9cbmZ1bmN0aW9uIFNwcml0ZVNoZWV0TG9hZGVyKHVybCwgY3Jvc3NvcmlnaW4pIHtcblxuICAgIC8qKlxuICAgICAqIFRoZSB1cmwgb2YgdGhlIGF0bGFzIGRhdGFcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1N0cmluZ31cbiAgICAgKi9cbiAgICB0aGlzLnVybCA9IHVybDtcblxuICAgIC8qKlxuICAgICAqIFdoZXRoZXIgdGhlIHJlcXVlc3RzIHNob3VsZCBiZSB0cmVhdGVkIGFzIGNyb3NzIG9yaWdpblxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLmNyb3Nzb3JpZ2luID0gY3Jvc3NvcmlnaW47XG5cbiAgICAvKipcbiAgICAgKiBUaGUgYmFzZSB1cmwgb2YgdGhlIGJpdG1hcCBmb250IGRhdGFcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1N0cmluZ31cbiAgICAgKiBAcmVhZE9ubHlcbiAgICAgKi9cbiAgICB0aGlzLmJhc2VVcmwgPSB1cmwucmVwbGFjZSgvW15cXC9dKiQvLCAnJyk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgdGV4dHVyZSBiZWluZyBsb2FkZWRcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge1RleHR1cmV9XG4gICAgICovXG4gICAgdGhpcy50ZXh0dXJlID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqIFRoZSBmcmFtZXMgb2YgdGhlIHNwcml0ZSBzaGVldFxuICAgICAqXG4gICAgICogQG1lbWJlciB7b2JqZWN0fVxuICAgICAqL1xuICAgIHRoaXMuZnJhbWVzID0ge307XG59XG5cbi8vIGNvbnN0cnVjdG9yXG5TcHJpdGVTaGVldExvYWRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBTcHJpdGVTaGVldExvYWRlcjtcbm1vZHVsZS5leHBvcnRzID0gU3ByaXRlU2hlZXRMb2FkZXI7XG5cbmNvcmUudXRpbHMuZXZlbnRUYXJnZXQubWl4aW4oU3ByaXRlU2hlZXRMb2FkZXIucHJvdG90eXBlKTtcblxuLyoqXG4gKiBUaGlzIHdpbGwgYmVnaW4gbG9hZGluZyB0aGUgSlNPTiBmaWxlXG4gKlxuICovXG5TcHJpdGVTaGVldExvYWRlci5wcm90b3R5cGUubG9hZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgc2NvcGUgPSB0aGlzO1xuICAgIHZhciBqc29uTG9hZGVyID0gbmV3IEpzb25Mb2FkZXIodGhpcy51cmwsIHRoaXMuY3Jvc3NvcmlnaW4pO1xuXG4gICAganNvbkxvYWRlci5vbignbG9hZGVkJywgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIHNjb3BlLmpzb24gPSBldmVudC5kYXRhLmNvbnRlbnQuanNvbjtcbiAgICAgICAgc2NvcGUub25Mb2FkZWQoKTtcbiAgICB9KTtcblxuICAgIGpzb25Mb2FkZXIubG9hZCgpO1xufTtcblxuLyoqXG4gKiBJbnZva2Ugd2hlbiBhbGwgZmlsZXMgYXJlIGxvYWRlZCAoanNvbiBhbmQgdGV4dHVyZSlcbiAqXG4gKiBAcHJpdmF0ZVxuICovXG5TcHJpdGVTaGVldExvYWRlci5wcm90b3R5cGUub25Mb2FkZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5lbWl0KCdsb2FkZWQnLCB7XG4gICAgICAgIGNvbnRlbnQ6IHRoaXNcbiAgICB9KTtcbn07XG4iLCIvKipcbiAqIEBmaWxlICAgICAgICBNYWluIGV4cG9ydCBvZiB0aGUgUElYSSBsb2FkZXJzIGxpYnJhcnlcbiAqIEBhdXRob3IgICAgICBNYXQgR3JvdmVzIDxtYXRAZ29vZGJveWRpZ2l0YWwuY29tPlxuICogQGNvcHlyaWdodCAgIDIwMTMtMjAxNSBHb29kQm95RGlnaXRhbFxuICogQGxpY2Vuc2UgICAgIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vR29vZEJveURpZ2l0YWwvcGl4aS5qcy9ibG9iL21hc3Rlci9MSUNFTlNFfE1JVCBMaWNlbnNlfVxuICovXG5cbi8qKlxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIEF0bGFzTG9hZGVyOiAgICAgICAgcmVxdWlyZSgnLi9BdGxhc0xvYWRlcicpLFxuICAgIEJpdG1hcEZvbnRMb2FkZXI6ICAgcmVxdWlyZSgnLi9CaXRtYXBGb250TG9hZGVyJyksXG4gICAgSW1hZ2VMb2FkZXI6ICAgICAgICByZXF1aXJlKCcuL0ltYWdlTG9hZGVyJyksXG4gICAgSnNvbkxvYWRlcjogICAgICAgICByZXF1aXJlKCcuL0pzb25Mb2FkZXInKSxcbiAgICBTcGluZUxvYWRlcjogICAgICAgIHJlcXVpcmUoJy4vU3BpbmVMb2FkZXInKSxcbiAgICBTcHJpdGVTaGVldExvYWRlcjogIHJlcXVpcmUoJy4vU3ByaXRlU2hlZXRMb2FkZXInKVxufTtcbiIsInZhciBjb3JlID0gcmVxdWlyZSgnLi4vY29yZScpLFxuICAgIHNwaW5lID0gcmVxdWlyZSgnLi9TcGluZVJ1bnRpbWUnKTtcblxuLyogRXNvdGVyaWMgU29mdHdhcmUgU1BJTkUgd3JhcHBlciBmb3IgcGl4aS5qcyAqL1xuXG5zcGluZS5Cb25lLnlEb3duID0gdHJ1ZTtcblxuLyoqXG4gKiBBIGNsYXNzIHRoYXQgZW5hYmxlcyB0aGUgeW91IHRvIGltcG9ydCBhbmQgcnVuIHlvdXIgc3BpbmUgYW5pbWF0aW9ucyBpbiBwaXhpLlxuICogU3BpbmUgYW5pbWF0aW9uIGRhdGEgbmVlZHMgdG8gYmUgbG9hZGVkIHVzaW5nIHRoZSBBc3NldExvYWRlciBvciBTcGluZUxvYWRlciBiZWZvcmUgaXQgY2FuIGJlIHVzZWQgYnkgdGhpcyBjbGFzc1xuICogU2VlIGV4YW1wbGUgMTIgKGh0dHA6Ly93d3cuZ29vZGJveWRpZ2l0YWwuY29tL3BpeGlqcy9leGFtcGxlcy8xMi8pIHRvIHNlZSBhIHdvcmtpbmcgZXhhbXBsZSBhbmQgY2hlY2sgb3V0IHRoZSBzb3VyY2VcbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIERpc3BsYXlPYmplY3RDb250YWluZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHVybCB7c3RyaW5nfSBUaGUgdXJsIG9mIHRoZSBzcGluZSBhbmltIGZpbGUgdG8gYmUgdXNlZFxuICovXG5mdW5jdGlvbiBTcGluZSh1cmwpIHtcbiAgICBjb3JlLkRpc3BsYXlPYmplY3RDb250YWluZXIuY2FsbCh0aGlzKTtcblxuICAgIHRoaXMuc3BpbmVEYXRhID0gY29yZS51dGlscy5BbmltQ2FjaGVbdXJsXTtcblxuICAgIGlmICghdGhpcy5zcGluZURhdGEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdTcGluZSBkYXRhIG11c3QgYmUgcHJlbG9hZGVkIHVzaW5nIFNwaW5lTG9hZGVyIG9yIEFzc2V0TG9hZGVyOiAnICsgdXJsKTtcbiAgICB9XG5cbiAgICB0aGlzLnNrZWxldG9uID0gbmV3IHNwaW5lLlNrZWxldG9uKHRoaXMuc3BpbmVEYXRhKTtcbiAgICB0aGlzLnNrZWxldG9uLnVwZGF0ZVdvcmxkVHJhbnNmb3JtKCk7XG5cbiAgICB0aGlzLnN0YXRlRGF0YSA9IG5ldyBzcGluZS5BbmltYXRpb25TdGF0ZURhdGEodGhpcy5zcGluZURhdGEpO1xuICAgIHRoaXMuc3RhdGUgPSBuZXcgc3BpbmUuQW5pbWF0aW9uU3RhdGUodGhpcy5zdGF0ZURhdGEpO1xuXG4gICAgdGhpcy5zbG90Q29udGFpbmVycyA9IFtdO1xuXG4gICAgZm9yICh2YXIgaSA9IDAsIG4gPSB0aGlzLnNrZWxldG9uLmRyYXdPcmRlci5sZW5ndGg7IGkgPCBuOyBpKyspIHtcbiAgICAgICAgdmFyIHNsb3QgPSB0aGlzLnNrZWxldG9uLmRyYXdPcmRlcltpXTtcbiAgICAgICAgdmFyIGF0dGFjaG1lbnQgPSBzbG90LmF0dGFjaG1lbnQ7XG4gICAgICAgIHZhciBzbG90Q29udGFpbmVyID0gbmV3IGNvcmUuRGlzcGxheU9iamVjdENvbnRhaW5lcigpO1xuICAgICAgICB0aGlzLnNsb3RDb250YWluZXJzLnB1c2goc2xvdENvbnRhaW5lcik7XG4gICAgICAgIHRoaXMuYWRkQ2hpbGQoc2xvdENvbnRhaW5lcik7XG5cbiAgICAgICAgaWYgKGF0dGFjaG1lbnQgaW5zdGFuY2VvZiBzcGluZS5SZWdpb25BdHRhY2htZW50KSB7XG4gICAgICAgICAgICB2YXIgc3ByaXRlTmFtZSA9IGF0dGFjaG1lbnQucmVuZGVyZXJPYmplY3QubmFtZTtcbiAgICAgICAgICAgIHZhciBzcHJpdGUgPSB0aGlzLmNyZWF0ZVNwcml0ZShzbG90LCBhdHRhY2htZW50KTtcbiAgICAgICAgICAgIHNsb3QuY3VycmVudFNwcml0ZSA9IHNwcml0ZTtcbiAgICAgICAgICAgIHNsb3QuY3VycmVudFNwcml0ZU5hbWUgPSBzcHJpdGVOYW1lO1xuICAgICAgICAgICAgc2xvdENvbnRhaW5lci5hZGRDaGlsZChzcHJpdGUpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGF0dGFjaG1lbnQgaW5zdGFuY2VvZiBzcGluZS5NZXNoQXR0YWNobWVudCkge1xuICAgICAgICAgICAgdmFyIG1lc2ggPSB0aGlzLmNyZWF0ZU1lc2goc2xvdCwgYXR0YWNobWVudCk7XG4gICAgICAgICAgICBzbG90LmN1cnJlbnRNZXNoID0gbWVzaDtcbiAgICAgICAgICAgIHNsb3QuY3VycmVudE1lc2hOYW1lID0gYXR0YWNobWVudC5uYW1lO1xuICAgICAgICAgICAgc2xvdENvbnRhaW5lci5hZGRDaGlsZChtZXNoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICB9XG5cbiAgICB0aGlzLmF1dG9VcGRhdGUgPSB0cnVlO1xufVxuXG5TcGluZS5wcm90b3R5cGUgPSBPYmplY3QuY3JlYXRlKGNvcmUuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUpO1xuU3BpbmUucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gU3BpbmU7XG5tb2R1bGUuZXhwb3J0cyA9IFNwaW5lO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydGllcyhTcGluZS5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBJZiB0aGlzIGZsYWcgaXMgc2V0IHRvIHRydWUsIHRoZSBzcGluZSBhbmltYXRpb24gd2lsbCBiZSBhdXRvdXBkYXRlZCBldmVyeSB0aW1lXG4gICAgICogdGhlIG9iamVjdCBpZCBkcmF3bi4gVGhlIGRvd24gc2lkZSBvZiB0aGlzIGFwcHJvYWNoIGlzIHRoYXQgdGhlIGRlbHRhIHRpbWUgaXNcbiAgICAgKiBhdXRvbWF0aWNhbGx5IGNhbGN1bGF0ZWQgYW5kIHlvdSBjb3VsZCBtaXNzIG91dCBvbiBjb29sIGVmZmVjdHMgbGlrZSBzbG93IG1vdGlvbixcbiAgICAgKiBwYXVzZSwgc2tpcCBhaGVhZCBhbmQgdGhlIHNvcnRzLiBNb3N0IG9mIHRoZXNlIGVmZmVjdHMgY2FuIGJlIGFjaGlldmVkIGV2ZW4gd2l0aFxuICAgICAqIGF1dG91cGRhdGUgZW5hYmxlZCBidXQgYXJlIGhhcmRlciB0byBhY2hpZXZlLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKiBAbWVtYmVyb2YgU3BpbmUjXG4gICAgICogQGRlZmF1bHQgdHJ1ZVxuICAgICAqL1xuICAgIGF1dG9VcGRhdGU6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gKHRoaXMudXBkYXRlVHJhbnNmb3JtID09PSBTcGluZS5wcm90b3R5cGUuYXV0b1VwZGF0ZVRyYW5zZm9ybSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlVHJhbnNmb3JtID0gdmFsdWUgPyBTcGluZS5wcm90b3R5cGUuYXV0b1VwZGF0ZVRyYW5zZm9ybSA6IGNvcmUuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUudXBkYXRlVHJhbnNmb3JtO1xuICAgICAgICB9XG4gICAgfVxufSk7XG5cbi8qKlxuICogVXBkYXRlIHRoZSBzcGluZSBza2VsZXRvbiBhbmQgaXRzIGFuaW1hdGlvbnMgYnkgZGVsdGEgdGltZSAoZHQpXG4gKlxuICogQHBhcmFtIGR0IHtudW1iZXJ9IERlbHRhIHRpbWUuIFRpbWUgYnkgd2hpY2ggdGhlIGFuaW1hdGlvbiBzaG91bGQgYmUgdXBkYXRlZFxuICovXG5TcGluZS5wcm90b3R5cGUudXBkYXRlID0gZnVuY3Rpb24gKGR0KSB7XG4gICAgdGhpcy5zdGF0ZS51cGRhdGUoZHQpO1xuICAgIHRoaXMuc3RhdGUuYXBwbHkodGhpcy5za2VsZXRvbik7XG4gICAgdGhpcy5za2VsZXRvbi51cGRhdGVXb3JsZFRyYW5zZm9ybSgpO1xuXG4gICAgdmFyIGRyYXdPcmRlciA9IHRoaXMuc2tlbGV0b24uZHJhd09yZGVyO1xuICAgIGZvciAodmFyIGkgPSAwLCBuID0gZHJhd09yZGVyLmxlbmd0aDsgaSA8IG47IGkrKykge1xuICAgICAgICB2YXIgc2xvdCA9IGRyYXdPcmRlcltpXTtcbiAgICAgICAgdmFyIGF0dGFjaG1lbnQgPSBzbG90LmF0dGFjaG1lbnQ7XG4gICAgICAgIHZhciBzbG90Q29udGFpbmVyID0gdGhpcy5zbG90Q29udGFpbmVyc1tpXTtcblxuICAgICAgICBpZiAoIWF0dGFjaG1lbnQpIHtcbiAgICAgICAgICAgIHNsb3RDb250YWluZXIudmlzaWJsZSA9IGZhbHNlO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgdHlwZSA9IGF0dGFjaG1lbnQudHlwZTtcbiAgICAgICAgaWYgKHR5cGUgPT09IHNwaW5lLkF0dGFjaG1lbnRUeXBlLnJlZ2lvbikge1xuICAgICAgICAgICAgaWYgKGF0dGFjaG1lbnQucmVuZGVyZXJPYmplY3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXNsb3QuY3VycmVudFNwcml0ZU5hbWUgfHwgc2xvdC5jdXJyZW50U3ByaXRlTmFtZSAhPT0gYXR0YWNobWVudC5yZW5kZXJlck9iamVjdC5uYW1lKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBzcHJpdGVOYW1lID0gYXR0YWNobWVudC5yZW5kZXJlck9iamVjdC5uYW1lO1xuICAgICAgICAgICAgICAgICAgICBpZiAoc2xvdC5jdXJyZW50U3ByaXRlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNsb3QuY3VycmVudFNwcml0ZS52aXNpYmxlID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgc2xvdC5zcHJpdGVzID0gc2xvdC5zcHJpdGVzIHx8IHt9O1xuICAgICAgICAgICAgICAgICAgICBpZiAoc2xvdC5zcHJpdGVzW3Nwcml0ZU5hbWVdICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNsb3Quc3ByaXRlc1tzcHJpdGVOYW1lXS52aXNpYmxlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBzcHJpdGUgPSB0aGlzLmNyZWF0ZVNwcml0ZShzbG90LCBhdHRhY2htZW50KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNsb3RDb250YWluZXIuYWRkQ2hpbGQoc3ByaXRlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBzbG90LmN1cnJlbnRTcHJpdGUgPSBzbG90LnNwcml0ZXNbc3ByaXRlTmFtZV07XG4gICAgICAgICAgICAgICAgICAgIHNsb3QuY3VycmVudFNwcml0ZU5hbWUgPSBzcHJpdGVOYW1lO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGJvbmUgPSBzbG90LmJvbmU7XG5cbiAgICAgICAgICAgIHNsb3RDb250YWluZXIucG9zaXRpb24ueCA9IGJvbmUud29ybGRYICsgYXR0YWNobWVudC54ICogYm9uZS5tMDAgKyBhdHRhY2htZW50LnkgKiBib25lLm0wMTtcbiAgICAgICAgICAgIHNsb3RDb250YWluZXIucG9zaXRpb24ueSA9IGJvbmUud29ybGRZICsgYXR0YWNobWVudC54ICogYm9uZS5tMTAgKyBhdHRhY2htZW50LnkgKiBib25lLm0xMTtcbiAgICAgICAgICAgIHNsb3RDb250YWluZXIuc2NhbGUueCA9IGJvbmUud29ybGRTY2FsZVg7XG4gICAgICAgICAgICBzbG90Q29udGFpbmVyLnNjYWxlLnkgPSBib25lLndvcmxkU2NhbGVZO1xuXG4gICAgICAgICAgICBzbG90Q29udGFpbmVyLnJvdGF0aW9uID0gLShzbG90LmJvbmUud29ybGRSb3RhdGlvbiAqIHNwaW5lLmRlZ1JhZCk7XG5cbiAgICAgICAgICAgIHNsb3QuY3VycmVudFNwcml0ZS50aW50ID0gY29yZS51dGlscy5yZ2IyaGV4KFtzbG90LnIsc2xvdC5nLHNsb3QuYl0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHR5cGUgPT09IHNwaW5lLkF0dGFjaG1lbnRUeXBlLnNraW5uZWRtZXNoKSB7XG4gICAgICAgICAgICBpZiAoIXNsb3QuY3VycmVudE1lc2hOYW1lIHx8IHNsb3QuY3VycmVudE1lc2hOYW1lICE9PSBhdHRhY2htZW50Lm5hbWUpIHtcbiAgICAgICAgICAgICAgICB2YXIgbWVzaE5hbWUgPSBhdHRhY2htZW50Lm5hbWU7XG4gICAgICAgICAgICAgICAgaWYgKHNsb3QuY3VycmVudE1lc2ggIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgICBzbG90LmN1cnJlbnRNZXNoLnZpc2libGUgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBzbG90Lm1lc2hlcyA9IHNsb3QubWVzaGVzIHx8IHt9O1xuXG4gICAgICAgICAgICAgICAgaWYgKHNsb3QubWVzaGVzW21lc2hOYW1lXSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHNsb3QubWVzaGVzW21lc2hOYW1lXS52aXNpYmxlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBtZXNoID0gdGhpcy5jcmVhdGVNZXNoKHNsb3QsIGF0dGFjaG1lbnQpO1xuICAgICAgICAgICAgICAgICAgICBzbG90Q29udGFpbmVyLmFkZENoaWxkKG1lc2gpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHNsb3QuY3VycmVudE1lc2ggPSBzbG90Lm1lc2hlc1ttZXNoTmFtZV07XG4gICAgICAgICAgICAgICAgc2xvdC5jdXJyZW50TWVzaE5hbWUgPSBtZXNoTmFtZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgYXR0YWNobWVudC5jb21wdXRlV29ybGRWZXJ0aWNlcyhzbG90LmJvbmUuc2tlbGV0b24ueCwgc2xvdC5ib25lLnNrZWxldG9uLnksIHNsb3QsIHNsb3QuY3VycmVudE1lc2gudmVydGljZXMpO1xuXG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBzbG90Q29udGFpbmVyLnZpc2libGUgPSBmYWxzZTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIHNsb3RDb250YWluZXIudmlzaWJsZSA9IHRydWU7XG5cbiAgICAgICAgc2xvdENvbnRhaW5lci5hbHBoYSA9IHNsb3QuYTtcbiAgICB9XG59O1xuXG4vKipcbiAqIFdoZW4gYXV0b3VwZGF0ZSBpcyBzZXQgdG8geWVzIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCBhcyBwaXhpJ3MgdXBkYXRlVHJhbnNmb3JtIGZ1bmN0aW9uXG4gKlxuICogQHByaXZhdGVcbiAqL1xuU3BpbmUucHJvdG90eXBlLmF1dG9VcGRhdGVUcmFuc2Zvcm0gPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5sYXN0VGltZSA9IHRoaXMubGFzdFRpbWUgfHwgRGF0ZS5ub3coKTtcbiAgICB2YXIgdGltZURlbHRhID0gKERhdGUubm93KCkgLSB0aGlzLmxhc3RUaW1lKSAqIDAuMDAxO1xuICAgIHRoaXMubGFzdFRpbWUgPSBEYXRlLm5vdygpO1xuXG4gICAgdGhpcy51cGRhdGUodGltZURlbHRhKTtcblxuICAgIGNvcmUuRGlzcGxheU9iamVjdENvbnRhaW5lci5wcm90b3R5cGUudXBkYXRlVHJhbnNmb3JtLmNhbGwodGhpcyk7XG59O1xuXG4vKipcbiAqIENyZWF0ZSBhIG5ldyBzcHJpdGUgdG8gYmUgdXNlZCB3aXRoIHNwaW5lLlJlZ2lvbkF0dGFjaG1lbnRcbiAqXG4gKiBAcGFyYW0gc2xvdCB7c3BpbmUuU2xvdH0gVGhlIHNsb3QgdG8gd2hpY2ggdGhlIGF0dGFjaG1lbnQgaXMgcGFyZW50ZWRcbiAqIEBwYXJhbSBhdHRhY2htZW50IHtzcGluZS5SZWdpb25BdHRhY2htZW50fSBUaGUgYXR0YWNobWVudCB0aGF0IHRoZSBzcHJpdGUgd2lsbCByZXByZXNlbnRcbiAqIEBwcml2YXRlXG4gKi9cblNwaW5lLnByb3RvdHlwZS5jcmVhdGVTcHJpdGUgPSBmdW5jdGlvbiAoc2xvdCwgYXR0YWNobWVudCkge1xuICAgIHZhciBkZXNjcmlwdG9yID0gYXR0YWNobWVudC5yZW5kZXJlck9iamVjdDtcbiAgICB2YXIgYmFzZVRleHR1cmUgPSBkZXNjcmlwdG9yLnBhZ2UucmVuZGVyZXJPYmplY3Q7XG4gICAgdmFyIHNwcml0ZVJlY3QgPSBuZXcgY29yZS5tYXRoLlJlY3RhbmdsZShkZXNjcmlwdG9yLngsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRvci55LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0b3Iucm90YXRlID8gZGVzY3JpcHRvci5oZWlnaHQgOiBkZXNjcmlwdG9yLndpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlc2NyaXB0b3Iucm90YXRlID8gZGVzY3JpcHRvci53aWR0aCA6IGRlc2NyaXB0b3IuaGVpZ2h0KTtcbiAgICB2YXIgc3ByaXRlVGV4dHVyZSA9IG5ldyBjb3JlLlRleHR1cmUoYmFzZVRleHR1cmUsIHNwcml0ZVJlY3QpO1xuICAgIHZhciBzcHJpdGUgPSBuZXcgY29yZS5TcHJpdGUoc3ByaXRlVGV4dHVyZSk7XG5cbiAgICB2YXIgYmFzZVJvdGF0aW9uID0gZGVzY3JpcHRvci5yb3RhdGUgPyBNYXRoLlBJICogMC41IDogMC4wO1xuICAgIHNwcml0ZS5zY2FsZS5zZXQoZGVzY3JpcHRvci53aWR0aCAvIGRlc2NyaXB0b3Iub3JpZ2luYWxXaWR0aCwgZGVzY3JpcHRvci5oZWlnaHQgLyBkZXNjcmlwdG9yLm9yaWdpbmFsSGVpZ2h0KTtcbiAgICBzcHJpdGUucm90YXRpb24gPSBiYXNlUm90YXRpb24gLSAoYXR0YWNobWVudC5yb3RhdGlvbiAqIHNwaW5lLmRlZ1JhZCk7XG4gICAgc3ByaXRlLmFuY2hvci54ID0gc3ByaXRlLmFuY2hvci55ID0gMC41O1xuXG4gICAgc2xvdC5zcHJpdGVzID0gc2xvdC5zcHJpdGVzIHx8IHt9O1xuICAgIHNsb3Quc3ByaXRlc1tkZXNjcmlwdG9yLm5hbWVdID0gc3ByaXRlO1xuICAgIHJldHVybiBzcHJpdGU7XG59O1xuXG4vKipcbiAqXG4gKiBAcGFyYW0gc2xvdCB7c3BpbmUuU2xvdH0gVGhlIHNsb3QgdG8gd2hpY2ggdGhlIGF0dGFjaG1lbnQgaXMgcGFyZW50ZWRcbiAqIEBwYXJhbSBhdHRhY2htZW50IHtzcGluZS5SZWdpb25BdHRhY2htZW50fSBUaGUgYXR0YWNobWVudCB0aGF0IHRoZSBzcHJpdGUgd2lsbCByZXByZXNlbnRcbiAqIEBwcml2YXRlXG4gKi9cblNwaW5lLnByb3RvdHlwZS5jcmVhdGVNZXNoID0gZnVuY3Rpb24gKHNsb3QsIGF0dGFjaG1lbnQpIHtcbiAgICB2YXIgZGVzY3JpcHRvciA9IGF0dGFjaG1lbnQucmVuZGVyZXJPYmplY3Q7XG4gICAgdmFyIGJhc2VUZXh0dXJlID0gZGVzY3JpcHRvci5wYWdlLnJlbmRlcmVyT2JqZWN0O1xuICAgIHZhciB0ZXh0dXJlID0gbmV3IGNvcmUuVGV4dHVyZShiYXNlVGV4dHVyZSk7XG5cbiAgICB2YXIgc3RyaXAgPSBuZXcgY29yZS5TdHJpcCh0ZXh0dXJlKTtcbiAgICBzdHJpcC5kcmF3TW9kZSA9IGNvcmUuU3RyaXAuRHJhd01vZGVzLlRSSUFOR0xFUztcbiAgICBzdHJpcC5jYW52YXNQYWRkaW5nID0gMS41O1xuXG4gICAgc3RyaXAudmVydGljZXMgPSBuZXcgRmxvYXQzMkFycmF5KGF0dGFjaG1lbnQudXZzLmxlbmd0aCk7XG4gICAgc3RyaXAudXZzID0gYXR0YWNobWVudC51dnM7XG4gICAgc3RyaXAuaW5kaWNlcyA9IGF0dGFjaG1lbnQudHJpYW5nbGVzO1xuXG4gICAgc2xvdC5tZXNoZXMgPSBzbG90Lm1lc2hlcyB8fCB7fTtcbiAgICBzbG90Lm1lc2hlc1thdHRhY2htZW50Lm5hbWVdID0gc3RyaXA7XG5cbiAgICByZXR1cm4gc3RyaXA7XG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuICogU3BpbmUgUnVudGltZXMgU29mdHdhcmUgTGljZW5zZVxuICogVmVyc2lvbiAyLjFcbiAqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTMsIEVzb3RlcmljIFNvZnR3YXJlXG4gKiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuICpcbiAqIFlvdSBhcmUgZ3JhbnRlZCBhIHBlcnBldHVhbCwgbm9uLWV4Y2x1c2l2ZSwgbm9uLXN1YmxpY2Vuc2FibGUgYW5kXG4gKiBub24tdHJhbnNmZXJhYmxlIGxpY2Vuc2UgdG8gaW5zdGFsbCwgZXhlY3V0ZSBhbmQgcGVyZm9ybSB0aGUgU3BpbmUgUnVudGltZXNcbiAqIFNvZnR3YXJlICh0aGUgXCJTb2Z0d2FyZVwiKSBzb2xlbHkgZm9yIGludGVybmFsIHVzZS4gV2l0aG91dCB0aGUgd3JpdHRlblxuICogcGVybWlzc2lvbiBvZiBFc290ZXJpYyBTb2Z0d2FyZSAodHlwaWNhbGx5IGdyYW50ZWQgYnkgbGljZW5zaW5nIFNwaW5lKSwgeW91XG4gKiBtYXkgbm90IChhKSBtb2RpZnksIHRyYW5zbGF0ZSwgYWRhcHQgb3Igb3RoZXJ3aXNlIGNyZWF0ZSBkZXJpdmF0aXZlIHdvcmtzLFxuICogaW1wcm92ZW1lbnRzIG9mIHRoZSBTb2Z0d2FyZSBvciBkZXZlbG9wIG5ldyBhcHBsaWNhdGlvbnMgdXNpbmcgdGhlIFNvZnR3YXJlXG4gKiBvciAoYikgcmVtb3ZlLCBkZWxldGUsIGFsdGVyIG9yIG9ic2N1cmUgYW55IHRyYWRlbWFya3Mgb3IgYW55IGNvcHlyaWdodCxcbiAqIHRyYWRlbWFyaywgcGF0ZW50IG9yIG90aGVyIGludGVsbGVjdHVhbCBwcm9wZXJ0eSBvciBwcm9wcmlldGFyeSByaWdodHNcbiAqIG5vdGljZXMgb24gb3IgaW4gdGhlIFNvZnR3YXJlLCBpbmNsdWRpbmcgYW55IGNvcHkgdGhlcmVvZi4gUmVkaXN0cmlidXRpb25zXG4gKiBpbiBiaW5hcnkgb3Igc291cmNlIGZvcm0gbXVzdCBpbmNsdWRlIHRoaXMgbGljZW5zZSBhbmQgdGVybXMuXG4gKlxuICogVEhJUyBTT0ZUV0FSRSBJUyBQUk9WSURFRCBCWSBFU09URVJJQyBTT0ZUV0FSRSBcIkFTIElTXCIgQU5EIEFOWSBFWFBSRVNTIE9SXG4gKiBJTVBMSUVEIFdBUlJBTlRJRVMsIElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBUSEUgSU1QTElFRCBXQVJSQU5USUVTIE9GXG4gKiBNRVJDSEFOVEFCSUxJVFkgQU5EIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFSRSBESVNDTEFJTUVELiBJTiBOT1xuICogRVZFTlQgU0hBTEwgRVNPVEVSSUMgU09GVEFSRSBCRSBMSUFCTEUgRk9SIEFOWSBESVJFQ1QsIElORElSRUNULCBJTkNJREVOVEFMLFxuICogU1BFQ0lBTCwgRVhFTVBMQVJZLCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMgKElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLFxuICogUFJPQ1VSRU1FTlQgT0YgU1VCU1RJVFVURSBHT09EUyBPUiBTRVJWSUNFUzsgTE9TUyBPRiBVU0UsIERBVEEsIE9SIFBST0ZJVFM7XG4gKiBPUiBCVVNJTkVTUyBJTlRFUlJVUFRJT04pIEhPV0VWRVIgQ0FVU0VEIEFORCBPTiBBTlkgVEhFT1JZIE9GIExJQUJJTElUWSxcbiAqIFdIRVRIRVIgSU4gQ09OVFJBQ1QsIFNUUklDVCBMSUFCSUxJVFksIE9SIFRPUlQgKElOQ0xVRElORyBORUdMSUdFTkNFIE9SXG4gKiBPVEhFUldJU0UpIEFSSVNJTkcgSU4gQU5ZIFdBWSBPVVQgT0YgVEhFIFVTRSBPRiBUSElTIFNPRlRXQVJFLCBFVkVOIElGXG4gKiBBRFZJU0VEIE9GIFRIRSBQT1NTSUJJTElUWSBPRiBTVUNIIERBTUFHRS5cbiAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxudmFyIHNwaW5lID0gbW9kdWxlLmV4cG9ydHMgPSB7XG5cdHJhZERlZzogMTgwIC8gTWF0aC5QSSxcblx0ZGVnUmFkOiBNYXRoLlBJIC8gMTgwLFxuXHR0ZW1wOiBbXSxcbiAgICBGbG9hdDMyQXJyYXk6ICh0eXBlb2YoRmxvYXQzMkFycmF5KSA9PT0gJ3VuZGVmaW5lZCcpID8gQXJyYXkgOiBGbG9hdDMyQXJyYXksXG4gICAgVWludDE2QXJyYXk6ICh0eXBlb2YoVWludDE2QXJyYXkpID09PSAndW5kZWZpbmVkJykgPyBBcnJheSA6IFVpbnQxNkFycmF5XG59O1xuXG5zcGluZS5Cb25lRGF0YSA9IGZ1bmN0aW9uIChuYW1lLCBwYXJlbnQpIHtcblx0dGhpcy5uYW1lID0gbmFtZTtcblx0dGhpcy5wYXJlbnQgPSBwYXJlbnQ7XG59O1xuc3BpbmUuQm9uZURhdGEucHJvdG90eXBlID0ge1xuXHRsZW5ndGg6IDAsXG5cdHg6IDAsIHk6IDAsXG5cdHJvdGF0aW9uOiAwLFxuXHRzY2FsZVg6IDEsIHNjYWxlWTogMSxcblx0aW5oZXJpdFNjYWxlOiB0cnVlLFxuXHRpbmhlcml0Um90YXRpb246IHRydWUsXG5cdGZsaXBYOiBmYWxzZSwgZmxpcFk6IGZhbHNlXG59O1xuXG5zcGluZS5TbG90RGF0YSA9IGZ1bmN0aW9uIChuYW1lLCBib25lRGF0YSkge1xuXHR0aGlzLm5hbWUgPSBuYW1lO1xuXHR0aGlzLmJvbmVEYXRhID0gYm9uZURhdGE7XG59O1xuc3BpbmUuU2xvdERhdGEucHJvdG90eXBlID0ge1xuXHRyOiAxLCBnOiAxLCBiOiAxLCBhOiAxLFxuXHRhdHRhY2htZW50TmFtZTogbnVsbCxcblx0YWRkaXRpdmVCbGVuZGluZzogZmFsc2Vcbn07XG5cbnNwaW5lLklrQ29uc3RyYWludERhdGEgPSBmdW5jdGlvbiAobmFtZSkge1xuXHR0aGlzLm5hbWUgPSBuYW1lO1xuXHR0aGlzLmJvbmVzID0gW107XG59O1xuc3BpbmUuSWtDb25zdHJhaW50RGF0YS5wcm90b3R5cGUgPSB7XG5cdHRhcmdldDogbnVsbCxcblx0YmVuZERpcmVjdGlvbjogMSxcblx0bWl4OiAxXG59O1xuXG5zcGluZS5Cb25lID0gZnVuY3Rpb24gKGJvbmVEYXRhLCBza2VsZXRvbiwgcGFyZW50KSB7XG5cdHRoaXMuZGF0YSA9IGJvbmVEYXRhO1xuXHR0aGlzLnNrZWxldG9uID0gc2tlbGV0b247XG5cdHRoaXMucGFyZW50ID0gcGFyZW50O1xuXHR0aGlzLnNldFRvU2V0dXBQb3NlKCk7XG59O1xuc3BpbmUuQm9uZS55RG93biA9IGZhbHNlO1xuc3BpbmUuQm9uZS5wcm90b3R5cGUgPSB7XG5cdHg6IDAsIHk6IDAsXG5cdHJvdGF0aW9uOiAwLCByb3RhdGlvbklLOiAwLFxuXHRzY2FsZVg6IDEsIHNjYWxlWTogMSxcblx0ZmxpcFg6IGZhbHNlLCBmbGlwWTogZmFsc2UsXG5cdG0wMDogMCwgbTAxOiAwLCB3b3JsZFg6IDAsIC8vIGEgYiB4XG5cdG0xMDogMCwgbTExOiAwLCB3b3JsZFk6IDAsIC8vIGMgZCB5XG5cdHdvcmxkUm90YXRpb246IDAsXG5cdHdvcmxkU2NhbGVYOiAxLCB3b3JsZFNjYWxlWTogMSxcblx0d29ybGRGbGlwWDogZmFsc2UsIHdvcmxkRmxpcFk6IGZhbHNlLFxuXHR1cGRhdGVXb3JsZFRyYW5zZm9ybTogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBwYXJlbnQgPSB0aGlzLnBhcmVudDtcblx0XHRpZiAocGFyZW50KSB7XG5cdFx0XHR0aGlzLndvcmxkWCA9IHRoaXMueCAqIHBhcmVudC5tMDAgKyB0aGlzLnkgKiBwYXJlbnQubTAxICsgcGFyZW50LndvcmxkWDtcblx0XHRcdHRoaXMud29ybGRZID0gdGhpcy54ICogcGFyZW50Lm0xMCArIHRoaXMueSAqIHBhcmVudC5tMTEgKyBwYXJlbnQud29ybGRZO1xuXHRcdFx0aWYgKHRoaXMuZGF0YS5pbmhlcml0U2NhbGUpIHtcblx0XHRcdFx0dGhpcy53b3JsZFNjYWxlWCA9IHBhcmVudC53b3JsZFNjYWxlWCAqIHRoaXMuc2NhbGVYO1xuXHRcdFx0XHR0aGlzLndvcmxkU2NhbGVZID0gcGFyZW50LndvcmxkU2NhbGVZICogdGhpcy5zY2FsZVk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzLndvcmxkU2NhbGVYID0gdGhpcy5zY2FsZVg7XG5cdFx0XHRcdHRoaXMud29ybGRTY2FsZVkgPSB0aGlzLnNjYWxlWTtcblx0XHRcdH1cblx0XHRcdHRoaXMud29ybGRSb3RhdGlvbiA9IHRoaXMuZGF0YS5pbmhlcml0Um90YXRpb24gPyAocGFyZW50LndvcmxkUm90YXRpb24gKyB0aGlzLnJvdGF0aW9uSUspIDogdGhpcy5yb3RhdGlvbklLO1xuXHRcdFx0dGhpcy53b3JsZEZsaXBYID0gcGFyZW50LndvcmxkRmxpcFggIT0gdGhpcy5mbGlwWDtcblx0XHRcdHRoaXMud29ybGRGbGlwWSA9IHBhcmVudC53b3JsZEZsaXBZICE9IHRoaXMuZmxpcFk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHZhciBza2VsZXRvbkZsaXBYID0gdGhpcy5za2VsZXRvbi5mbGlwWCwgc2tlbGV0b25GbGlwWSA9IHRoaXMuc2tlbGV0b24uZmxpcFk7XG5cdFx0XHR0aGlzLndvcmxkWCA9IHNrZWxldG9uRmxpcFggPyAtdGhpcy54IDogdGhpcy54O1xuXHRcdFx0dGhpcy53b3JsZFkgPSAoc2tlbGV0b25GbGlwWSAhPSBzcGluZS5Cb25lLnlEb3duKSA/IC10aGlzLnkgOiB0aGlzLnk7XG5cdFx0XHR0aGlzLndvcmxkU2NhbGVYID0gdGhpcy5zY2FsZVg7XG5cdFx0XHR0aGlzLndvcmxkU2NhbGVZID0gdGhpcy5zY2FsZVk7XG5cdFx0XHR0aGlzLndvcmxkUm90YXRpb24gPSB0aGlzLnJvdGF0aW9uSUs7XG5cdFx0XHR0aGlzLndvcmxkRmxpcFggPSBza2VsZXRvbkZsaXBYICE9IHRoaXMuZmxpcFg7XG5cdFx0XHR0aGlzLndvcmxkRmxpcFkgPSBza2VsZXRvbkZsaXBZICE9IHRoaXMuZmxpcFk7XG5cdFx0fVxuXHRcdHZhciByYWRpYW5zID0gdGhpcy53b3JsZFJvdGF0aW9uICogc3BpbmUuZGVnUmFkO1xuXHRcdHZhciBjb3MgPSBNYXRoLmNvcyhyYWRpYW5zKTtcblx0XHR2YXIgc2luID0gTWF0aC5zaW4ocmFkaWFucyk7XG5cdFx0aWYgKHRoaXMud29ybGRGbGlwWCkge1xuXHRcdFx0dGhpcy5tMDAgPSAtY29zICogdGhpcy53b3JsZFNjYWxlWDtcblx0XHRcdHRoaXMubTAxID0gc2luICogdGhpcy53b3JsZFNjYWxlWTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5tMDAgPSBjb3MgKiB0aGlzLndvcmxkU2NhbGVYO1xuXHRcdFx0dGhpcy5tMDEgPSAtc2luICogdGhpcy53b3JsZFNjYWxlWTtcblx0XHR9XG5cdFx0aWYgKHRoaXMud29ybGRGbGlwWSAhPSBzcGluZS5Cb25lLnlEb3duKSB7XG5cdFx0XHR0aGlzLm0xMCA9IC1zaW4gKiB0aGlzLndvcmxkU2NhbGVYO1xuXHRcdFx0dGhpcy5tMTEgPSAtY29zICogdGhpcy53b3JsZFNjYWxlWTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5tMTAgPSBzaW4gKiB0aGlzLndvcmxkU2NhbGVYO1xuXHRcdFx0dGhpcy5tMTEgPSBjb3MgKiB0aGlzLndvcmxkU2NhbGVZO1xuXHRcdH1cblx0fSxcblx0c2V0VG9TZXR1cFBvc2U6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgZGF0YSA9IHRoaXMuZGF0YTtcblx0XHR0aGlzLnggPSBkYXRhLng7XG5cdFx0dGhpcy55ID0gZGF0YS55O1xuXHRcdHRoaXMucm90YXRpb24gPSBkYXRhLnJvdGF0aW9uO1xuXHRcdHRoaXMucm90YXRpb25JSyA9IHRoaXMucm90YXRpb247XG5cdFx0dGhpcy5zY2FsZVggPSBkYXRhLnNjYWxlWDtcblx0XHR0aGlzLnNjYWxlWSA9IGRhdGEuc2NhbGVZO1xuXHRcdHRoaXMuZmxpcFggPSBkYXRhLmZsaXBYO1xuXHRcdHRoaXMuZmxpcFkgPSBkYXRhLmZsaXBZO1xuXHR9LFxuXHR3b3JsZFRvTG9jYWw6IGZ1bmN0aW9uICh3b3JsZCkge1xuXHRcdHZhciBkeCA9IHdvcmxkWzBdIC0gdGhpcy53b3JsZFgsIGR5ID0gd29ybGRbMV0gLSB0aGlzLndvcmxkWTtcblx0XHR2YXIgbTAwID0gdGhpcy5tMDAsIG0xMCA9IHRoaXMubTEwLCBtMDEgPSB0aGlzLm0wMSwgbTExID0gdGhpcy5tMTE7XG5cdFx0aWYgKHRoaXMud29ybGRGbGlwWCAhPSAodGhpcy53b3JsZEZsaXBZICE9IHNwaW5lLkJvbmUueURvd24pKSB7XG5cdFx0XHRtMDAgPSAtbTAwO1xuXHRcdFx0bTExID0gLW0xMTtcblx0XHR9XG5cdFx0dmFyIGludkRldCA9IDEgLyAobTAwICogbTExIC0gbTAxICogbTEwKTtcblx0XHR3b3JsZFswXSA9IGR4ICogbTAwICogaW52RGV0IC0gZHkgKiBtMDEgKiBpbnZEZXQ7XG5cdFx0d29ybGRbMV0gPSBkeSAqIG0xMSAqIGludkRldCAtIGR4ICogbTEwICogaW52RGV0O1xuXHR9LFxuXHRsb2NhbFRvV29ybGQ6IGZ1bmN0aW9uIChsb2NhbCkge1xuXHRcdHZhciBsb2NhbFggPSBsb2NhbFswXSwgbG9jYWxZID0gbG9jYWxbMV07XG5cdFx0bG9jYWxbMF0gPSBsb2NhbFggKiB0aGlzLm0wMCArIGxvY2FsWSAqIHRoaXMubTAxICsgdGhpcy53b3JsZFg7XG5cdFx0bG9jYWxbMV0gPSBsb2NhbFggKiB0aGlzLm0xMCArIGxvY2FsWSAqIHRoaXMubTExICsgdGhpcy53b3JsZFk7XG5cdH1cbn07XG5cbnNwaW5lLlNsb3QgPSBmdW5jdGlvbiAoc2xvdERhdGEsIGJvbmUpIHtcblx0dGhpcy5kYXRhID0gc2xvdERhdGE7XG5cdHRoaXMuYm9uZSA9IGJvbmU7XG5cdHRoaXMuc2V0VG9TZXR1cFBvc2UoKTtcbn07XG5zcGluZS5TbG90LnByb3RvdHlwZSA9IHtcblx0cjogMSwgZzogMSwgYjogMSwgYTogMSxcblx0X2F0dGFjaG1lbnRUaW1lOiAwLFxuXHRhdHRhY2htZW50OiBudWxsLFxuXHRhdHRhY2htZW50VmVydGljZXM6IFtdLFxuXHRzZXRBdHRhY2htZW50OiBmdW5jdGlvbiAoYXR0YWNobWVudCkge1xuXHRcdHRoaXMuYXR0YWNobWVudCA9IGF0dGFjaG1lbnQ7XG5cdFx0dGhpcy5fYXR0YWNobWVudFRpbWUgPSB0aGlzLmJvbmUuc2tlbGV0b24udGltZTtcblx0XHR0aGlzLmF0dGFjaG1lbnRWZXJ0aWNlcy5sZW5ndGggPSAwO1xuXHR9LFxuXHRzZXRBdHRhY2htZW50VGltZTogZnVuY3Rpb24gKHRpbWUpIHtcblx0XHR0aGlzLl9hdHRhY2htZW50VGltZSA9IHRoaXMuYm9uZS5za2VsZXRvbi50aW1lIC0gdGltZTtcblx0fSxcblx0Z2V0QXR0YWNobWVudFRpbWU6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5ib25lLnNrZWxldG9uLnRpbWUgLSB0aGlzLl9hdHRhY2htZW50VGltZTtcblx0fSxcblx0c2V0VG9TZXR1cFBvc2U6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgZGF0YSA9IHRoaXMuZGF0YTtcblx0XHR0aGlzLnIgPSBkYXRhLnI7XG5cdFx0dGhpcy5nID0gZGF0YS5nO1xuXHRcdHRoaXMuYiA9IGRhdGEuYjtcblx0XHR0aGlzLmEgPSBkYXRhLmE7XG5cblx0XHR2YXIgc2xvdERhdGFzID0gdGhpcy5ib25lLnNrZWxldG9uLmRhdGEuc2xvdHM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBzbG90RGF0YXMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRpZiAoc2xvdERhdGFzW2ldID09IGRhdGEpIHtcblx0XHRcdFx0dGhpcy5zZXRBdHRhY2htZW50KCFkYXRhLmF0dGFjaG1lbnROYW1lID8gbnVsbCA6IHRoaXMuYm9uZS5za2VsZXRvbi5nZXRBdHRhY2htZW50QnlTbG90SW5kZXgoaSwgZGF0YS5hdHRhY2htZW50TmFtZSkpO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdH1cblx0XHR9XG5cdH1cbn07XG5cbnNwaW5lLklrQ29uc3RyYWludCA9IGZ1bmN0aW9uIChkYXRhLCBza2VsZXRvbikge1xuXHR0aGlzLmRhdGEgPSBkYXRhO1xuXHR0aGlzLm1peCA9IGRhdGEubWl4O1xuXHR0aGlzLmJlbmREaXJlY3Rpb24gPSBkYXRhLmJlbmREaXJlY3Rpb247XG5cblx0dGhpcy5ib25lcyA9IFtdO1xuXHRmb3IgKHZhciBpID0gMCwgbiA9IGRhdGEuYm9uZXMubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdHRoaXMuYm9uZXMucHVzaChza2VsZXRvbi5maW5kQm9uZShkYXRhLmJvbmVzW2ldLm5hbWUpKTtcblx0dGhpcy50YXJnZXQgPSBza2VsZXRvbi5maW5kQm9uZShkYXRhLnRhcmdldC5uYW1lKTtcbn07XG5zcGluZS5Ja0NvbnN0cmFpbnQucHJvdG90eXBlID0ge1xuXHRhcHBseTogZnVuY3Rpb24gKCkge1xuXHRcdHZhciB0YXJnZXQgPSB0aGlzLnRhcmdldDtcblx0XHR2YXIgYm9uZXMgPSB0aGlzLmJvbmVzO1xuXHRcdHN3aXRjaCAoYm9uZXMubGVuZ3RoKSB7XG5cdFx0Y2FzZSAxOlxuXHRcdFx0c3BpbmUuSWtDb25zdHJhaW50LmFwcGx5MShib25lc1swXSwgdGFyZ2V0LndvcmxkWCwgdGFyZ2V0LndvcmxkWSwgdGhpcy5taXgpO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAyOlxuXHRcdFx0c3BpbmUuSWtDb25zdHJhaW50LmFwcGx5Mihib25lc1swXSwgYm9uZXNbMV0sIHRhcmdldC53b3JsZFgsIHRhcmdldC53b3JsZFksIHRoaXMuYmVuZERpcmVjdGlvbiwgdGhpcy5taXgpO1xuXHRcdFx0YnJlYWs7XG5cdFx0fVxuXHR9XG59O1xuLyoqIEFkanVzdHMgdGhlIGJvbmUgcm90YXRpb24gc28gdGhlIHRpcCBpcyBhcyBjbG9zZSB0byB0aGUgdGFyZ2V0IHBvc2l0aW9uIGFzIHBvc3NpYmxlLiBUaGUgdGFyZ2V0IGlzIHNwZWNpZmllZCBpbiB0aGUgd29ybGRcbiAqIGNvb3JkaW5hdGUgc3lzdGVtLiAqL1xuc3BpbmUuSWtDb25zdHJhaW50LmFwcGx5MSA9IGZ1bmN0aW9uIChib25lLCB0YXJnZXRYLCB0YXJnZXRZLCBhbHBoYSkge1xuXHR2YXIgcGFyZW50Um90YXRpb24gPSAoIWJvbmUuZGF0YS5pbmhlcml0Um90YXRpb24gfHwgIWJvbmUucGFyZW50KSA/IDAgOiBib25lLnBhcmVudC53b3JsZFJvdGF0aW9uO1xuXHR2YXIgcm90YXRpb24gPSBib25lLnJvdGF0aW9uO1xuXHR2YXIgcm90YXRpb25JSyA9IE1hdGguYXRhbjIodGFyZ2V0WSAtIGJvbmUud29ybGRZLCB0YXJnZXRYIC0gYm9uZS53b3JsZFgpICogc3BpbmUucmFkRGVnIC0gcGFyZW50Um90YXRpb247XG5cdGJvbmUucm90YXRpb25JSyA9IHJvdGF0aW9uICsgKHJvdGF0aW9uSUsgLSByb3RhdGlvbikgKiBhbHBoYTtcbn07XG4vKiogQWRqdXN0cyB0aGUgcGFyZW50IGFuZCBjaGlsZCBib25lIHJvdGF0aW9ucyBzbyB0aGUgdGlwIG9mIHRoZSBjaGlsZCBpcyBhcyBjbG9zZSB0byB0aGUgdGFyZ2V0IHBvc2l0aW9uIGFzIHBvc3NpYmxlLiBUaGVcbiAqIHRhcmdldCBpcyBzcGVjaWZpZWQgaW4gdGhlIHdvcmxkIGNvb3JkaW5hdGUgc3lzdGVtLlxuICogQHBhcmFtIGNoaWxkIEFueSBkZXNjZW5kYW50IGJvbmUgb2YgdGhlIHBhcmVudC4gKi9cbnNwaW5lLklrQ29uc3RyYWludC5hcHBseTIgPSBmdW5jdGlvbiAocGFyZW50LCBjaGlsZCwgdGFyZ2V0WCwgdGFyZ2V0WSwgYmVuZERpcmVjdGlvbiwgYWxwaGEpIHtcblx0dmFyIGNoaWxkUm90YXRpb24gPSBjaGlsZC5yb3RhdGlvbiwgcGFyZW50Um90YXRpb24gPSBwYXJlbnQucm90YXRpb247XG5cdGlmICghYWxwaGEpIHtcblx0XHRjaGlsZC5yb3RhdGlvbklLID0gY2hpbGRSb3RhdGlvbjtcblx0XHRwYXJlbnQucm90YXRpb25JSyA9IHBhcmVudFJvdGF0aW9uO1xuXHRcdHJldHVybjtcblx0fVxuXHR2YXIgcG9zaXRpb25YLCBwb3NpdGlvblksIHRlbXBQb3NpdGlvbiA9IHNwaW5lLnRlbXA7XG5cdHZhciBwYXJlbnRQYXJlbnQgPSBwYXJlbnQucGFyZW50O1xuXHRpZiAocGFyZW50UGFyZW50KSB7XG5cdFx0dGVtcFBvc2l0aW9uWzBdID0gdGFyZ2V0WDtcblx0XHR0ZW1wUG9zaXRpb25bMV0gPSB0YXJnZXRZO1xuXHRcdHBhcmVudFBhcmVudC53b3JsZFRvTG9jYWwodGVtcFBvc2l0aW9uKTtcblx0XHR0YXJnZXRYID0gKHRlbXBQb3NpdGlvblswXSAtIHBhcmVudC54KSAqIHBhcmVudFBhcmVudC53b3JsZFNjYWxlWDtcblx0XHR0YXJnZXRZID0gKHRlbXBQb3NpdGlvblsxXSAtIHBhcmVudC55KSAqIHBhcmVudFBhcmVudC53b3JsZFNjYWxlWTtcblx0fSBlbHNlIHtcblx0XHR0YXJnZXRYIC09IHBhcmVudC54O1xuXHRcdHRhcmdldFkgLT0gcGFyZW50Lnk7XG5cdH1cblx0aWYgKGNoaWxkLnBhcmVudCA9PSBwYXJlbnQpIHtcblx0XHRwb3NpdGlvblggPSBjaGlsZC54O1xuXHRcdHBvc2l0aW9uWSA9IGNoaWxkLnk7XG5cdH0gZWxzZSB7XG5cdFx0dGVtcFBvc2l0aW9uWzBdID0gY2hpbGQueDtcblx0XHR0ZW1wUG9zaXRpb25bMV0gPSBjaGlsZC55O1xuXHRcdGNoaWxkLnBhcmVudC5sb2NhbFRvV29ybGQodGVtcFBvc2l0aW9uKTtcblx0XHRwYXJlbnQud29ybGRUb0xvY2FsKHRlbXBQb3NpdGlvbik7XG5cdFx0cG9zaXRpb25YID0gdGVtcFBvc2l0aW9uWzBdO1xuXHRcdHBvc2l0aW9uWSA9IHRlbXBQb3NpdGlvblsxXTtcblx0fVxuXHR2YXIgY2hpbGRYID0gcG9zaXRpb25YICogcGFyZW50LndvcmxkU2NhbGVYLCBjaGlsZFkgPSBwb3NpdGlvblkgKiBwYXJlbnQud29ybGRTY2FsZVk7XG5cdHZhciBvZmZzZXQgPSBNYXRoLmF0YW4yKGNoaWxkWSwgY2hpbGRYKTtcblx0dmFyIGxlbjEgPSBNYXRoLnNxcnQoY2hpbGRYICogY2hpbGRYICsgY2hpbGRZICogY2hpbGRZKSwgbGVuMiA9IGNoaWxkLmRhdGEubGVuZ3RoICogY2hpbGQud29ybGRTY2FsZVg7XG5cdC8vIEJhc2VkIG9uIGNvZGUgYnkgUnlhbiBKdWNrZXR0IHdpdGggcGVybWlzc2lvbjogQ29weXJpZ2h0IChjKSAyMDA4LTIwMDkgUnlhbiBKdWNrZXR0LCBodHRwOi8vd3d3LnJ5YW5qdWNrZXR0LmNvbS9cblx0dmFyIGNvc0Rlbm9tID0gMiAqIGxlbjEgKiBsZW4yO1xuXHRpZiAoY29zRGVub20gPCAwLjAwMDEpIHtcblx0XHRjaGlsZC5yb3RhdGlvbklLID0gY2hpbGRSb3RhdGlvbiArIChNYXRoLmF0YW4yKHRhcmdldFksIHRhcmdldFgpICogc3BpbmUucmFkRGVnIC0gcGFyZW50Um90YXRpb24gLSBjaGlsZFJvdGF0aW9uKSAqIGFscGhhO1xuXHRcdHJldHVybjtcblx0fVxuXHR2YXIgY29zID0gKHRhcmdldFggKiB0YXJnZXRYICsgdGFyZ2V0WSAqIHRhcmdldFkgLSBsZW4xICogbGVuMSAtIGxlbjIgKiBsZW4yKSAvIGNvc0Rlbm9tO1xuXHRpZiAoY29zIDwgLTEpXG5cdFx0Y29zID0gLTE7XG5cdGVsc2UgaWYgKGNvcyA+IDEpXG5cdFx0Y29zID0gMTtcblx0dmFyIGNoaWxkQW5nbGUgPSBNYXRoLmFjb3MoY29zKSAqIGJlbmREaXJlY3Rpb247XG5cdHZhciBhZGphY2VudCA9IGxlbjEgKyBsZW4yICogY29zLCBvcHBvc2l0ZSA9IGxlbjIgKiBNYXRoLnNpbihjaGlsZEFuZ2xlKTtcblx0dmFyIHBhcmVudEFuZ2xlID0gTWF0aC5hdGFuMih0YXJnZXRZICogYWRqYWNlbnQgLSB0YXJnZXRYICogb3Bwb3NpdGUsIHRhcmdldFggKiBhZGphY2VudCArIHRhcmdldFkgKiBvcHBvc2l0ZSk7XG5cdHZhciByb3RhdGlvbiA9IChwYXJlbnRBbmdsZSAtIG9mZnNldCkgKiBzcGluZS5yYWREZWcgLSBwYXJlbnRSb3RhdGlvbjtcblx0aWYgKHJvdGF0aW9uID4gMTgwKVxuXHRcdHJvdGF0aW9uIC09IDM2MDtcblx0ZWxzZSBpZiAocm90YXRpb24gPCAtMTgwKSAvL1xuXHRcdHJvdGF0aW9uICs9IDM2MDtcblx0cGFyZW50LnJvdGF0aW9uSUsgPSBwYXJlbnRSb3RhdGlvbiArIHJvdGF0aW9uICogYWxwaGE7XG5cdHJvdGF0aW9uID0gKGNoaWxkQW5nbGUgKyBvZmZzZXQpICogc3BpbmUucmFkRGVnIC0gY2hpbGRSb3RhdGlvbjtcblx0aWYgKHJvdGF0aW9uID4gMTgwKVxuXHRcdHJvdGF0aW9uIC09IDM2MDtcblx0ZWxzZSBpZiAocm90YXRpb24gPCAtMTgwKSAvL1xuXHRcdHJvdGF0aW9uICs9IDM2MDtcblx0Y2hpbGQucm90YXRpb25JSyA9IGNoaWxkUm90YXRpb24gKyAocm90YXRpb24gKyBwYXJlbnQud29ybGRSb3RhdGlvbiAtIGNoaWxkLnBhcmVudC53b3JsZFJvdGF0aW9uKSAqIGFscGhhO1xufTtcblxuc3BpbmUuU2tpbiA9IGZ1bmN0aW9uIChuYW1lKSB7XG5cdHRoaXMubmFtZSA9IG5hbWU7XG5cdHRoaXMuYXR0YWNobWVudHMgPSB7fTtcbn07XG5zcGluZS5Ta2luLnByb3RvdHlwZSA9IHtcblx0YWRkQXR0YWNobWVudDogZnVuY3Rpb24gKHNsb3RJbmRleCwgbmFtZSwgYXR0YWNobWVudCkge1xuXHRcdHRoaXMuYXR0YWNobWVudHNbc2xvdEluZGV4ICsgXCI6XCIgKyBuYW1lXSA9IGF0dGFjaG1lbnQ7XG5cdH0sXG5cdGdldEF0dGFjaG1lbnQ6IGZ1bmN0aW9uIChzbG90SW5kZXgsIG5hbWUpIHtcblx0XHRyZXR1cm4gdGhpcy5hdHRhY2htZW50c1tzbG90SW5kZXggKyBcIjpcIiArIG5hbWVdO1xuXHR9LFxuXHRfYXR0YWNoQWxsOiBmdW5jdGlvbiAoc2tlbGV0b24sIG9sZFNraW4pIHtcblx0XHRmb3IgKHZhciBrZXkgaW4gb2xkU2tpbi5hdHRhY2htZW50cykge1xuXHRcdFx0dmFyIGNvbG9uID0ga2V5LmluZGV4T2YoXCI6XCIpO1xuXHRcdFx0dmFyIHNsb3RJbmRleCA9IHBhcnNlSW50KGtleS5zdWJzdHJpbmcoMCwgY29sb24pKTtcblx0XHRcdHZhciBuYW1lID0ga2V5LnN1YnN0cmluZyhjb2xvbiArIDEpO1xuXHRcdFx0dmFyIHNsb3QgPSBza2VsZXRvbi5zbG90c1tzbG90SW5kZXhdO1xuXHRcdFx0aWYgKHNsb3QuYXR0YWNobWVudCAmJiBzbG90LmF0dGFjaG1lbnQubmFtZSA9PSBuYW1lKSB7XG5cdFx0XHRcdHZhciBhdHRhY2htZW50ID0gdGhpcy5nZXRBdHRhY2htZW50KHNsb3RJbmRleCwgbmFtZSk7XG5cdFx0XHRcdGlmIChhdHRhY2htZW50KSBzbG90LnNldEF0dGFjaG1lbnQoYXR0YWNobWVudCk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG59O1xuXG5zcGluZS5BbmltYXRpb24gPSBmdW5jdGlvbiAobmFtZSwgdGltZWxpbmVzLCBkdXJhdGlvbikge1xuXHR0aGlzLm5hbWUgPSBuYW1lO1xuXHR0aGlzLnRpbWVsaW5lcyA9IHRpbWVsaW5lcztcblx0dGhpcy5kdXJhdGlvbiA9IGR1cmF0aW9uO1xufTtcbnNwaW5lLkFuaW1hdGlvbi5wcm90b3R5cGUgPSB7XG5cdGFwcGx5OiBmdW5jdGlvbiAoc2tlbGV0b24sIGxhc3RUaW1lLCB0aW1lLCBsb29wLCBldmVudHMpIHtcblx0XHRpZiAobG9vcCAmJiB0aGlzLmR1cmF0aW9uICE9IDApIHtcblx0XHRcdHRpbWUgJT0gdGhpcy5kdXJhdGlvbjtcblx0XHRcdGxhc3RUaW1lICU9IHRoaXMuZHVyYXRpb247XG5cdFx0fVxuXHRcdHZhciB0aW1lbGluZXMgPSB0aGlzLnRpbWVsaW5lcztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHRpbWVsaW5lcy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHR0aW1lbGluZXNbaV0uYXBwbHkoc2tlbGV0b24sIGxhc3RUaW1lLCB0aW1lLCBldmVudHMsIDEpO1xuXHR9LFxuXHRtaXg6IGZ1bmN0aW9uIChza2VsZXRvbiwgbGFzdFRpbWUsIHRpbWUsIGxvb3AsIGV2ZW50cywgYWxwaGEpIHtcblx0XHRpZiAobG9vcCAmJiB0aGlzLmR1cmF0aW9uICE9IDApIHtcblx0XHRcdHRpbWUgJT0gdGhpcy5kdXJhdGlvbjtcblx0XHRcdGxhc3RUaW1lICU9IHRoaXMuZHVyYXRpb247XG5cdFx0fVxuXHRcdHZhciB0aW1lbGluZXMgPSB0aGlzLnRpbWVsaW5lcztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHRpbWVsaW5lcy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHR0aW1lbGluZXNbaV0uYXBwbHkoc2tlbGV0b24sIGxhc3RUaW1lLCB0aW1lLCBldmVudHMsIGFscGhhKTtcblx0fVxufTtcbnNwaW5lLkFuaW1hdGlvbi5iaW5hcnlTZWFyY2ggPSBmdW5jdGlvbiAodmFsdWVzLCB0YXJnZXQsIHN0ZXApIHtcblx0dmFyIGxvdyA9IDA7XG5cdHZhciBoaWdoID0gTWF0aC5mbG9vcih2YWx1ZXMubGVuZ3RoIC8gc3RlcCkgLSAyO1xuXHRpZiAoIWhpZ2gpIHJldHVybiBzdGVwO1xuXHR2YXIgY3VycmVudCA9IGhpZ2ggPj4+IDE7XG5cdHdoaWxlICh0cnVlKSB7XG5cdFx0aWYgKHZhbHVlc1soY3VycmVudCArIDEpICogc3RlcF0gPD0gdGFyZ2V0KVxuXHRcdFx0bG93ID0gY3VycmVudCArIDE7XG5cdFx0ZWxzZVxuXHRcdFx0aGlnaCA9IGN1cnJlbnQ7XG5cdFx0aWYgKGxvdyA9PSBoaWdoKSByZXR1cm4gKGxvdyArIDEpICogc3RlcDtcblx0XHRjdXJyZW50ID0gKGxvdyArIGhpZ2gpID4+PiAxO1xuXHR9XG59O1xuc3BpbmUuQW5pbWF0aW9uLmJpbmFyeVNlYXJjaDEgPSBmdW5jdGlvbiAodmFsdWVzLCB0YXJnZXQpIHtcblx0dmFyIGxvdyA9IDA7XG5cdHZhciBoaWdoID0gdmFsdWVzLmxlbmd0aCAtIDI7XG5cdGlmICghaGlnaCkgcmV0dXJuIDE7XG5cdHZhciBjdXJyZW50ID0gaGlnaCA+Pj4gMTtcblx0d2hpbGUgKHRydWUpIHtcblx0XHRpZiAodmFsdWVzW2N1cnJlbnQgKyAxXSA8PSB0YXJnZXQpXG5cdFx0XHRsb3cgPSBjdXJyZW50ICsgMTtcblx0XHRlbHNlXG5cdFx0XHRoaWdoID0gY3VycmVudDtcblx0XHRpZiAobG93ID09IGhpZ2gpIHJldHVybiBsb3cgKyAxO1xuXHRcdGN1cnJlbnQgPSAobG93ICsgaGlnaCkgPj4+IDE7XG5cdH1cbn07XG5zcGluZS5BbmltYXRpb24ubGluZWFyU2VhcmNoID0gZnVuY3Rpb24gKHZhbHVlcywgdGFyZ2V0LCBzdGVwKSB7XG5cdGZvciAodmFyIGkgPSAwLCBsYXN0ID0gdmFsdWVzLmxlbmd0aCAtIHN0ZXA7IGkgPD0gbGFzdDsgaSArPSBzdGVwKVxuXHRcdGlmICh2YWx1ZXNbaV0gPiB0YXJnZXQpIHJldHVybiBpO1xuXHRyZXR1cm4gLTE7XG59O1xuXG5zcGluZS5DdXJ2ZXMgPSBmdW5jdGlvbiAoZnJhbWVDb3VudCkge1xuXHR0aGlzLmN1cnZlcyA9IFtdOyAvLyB0eXBlLCB4LCB5LCAuLi5cblx0Ly90aGlzLmN1cnZlcy5sZW5ndGggPSAoZnJhbWVDb3VudCAtIDEpICogMTkvKkJFWklFUl9TSVpFKi87XG59O1xuc3BpbmUuQ3VydmVzLnByb3RvdHlwZSA9IHtcblx0c2V0TGluZWFyOiBmdW5jdGlvbiAoZnJhbWVJbmRleCkge1xuXHRcdHRoaXMuY3VydmVzW2ZyYW1lSW5kZXggKiAxOS8qQkVaSUVSX1NJWkUqL10gPSAwLypMSU5FQVIqLztcblx0fSxcblx0c2V0U3RlcHBlZDogZnVuY3Rpb24gKGZyYW1lSW5kZXgpIHtcblx0XHR0aGlzLmN1cnZlc1tmcmFtZUluZGV4ICogMTkvKkJFWklFUl9TSVpFKi9dID0gMS8qU1RFUFBFRCovO1xuXHR9LFxuXHQvKiogU2V0cyB0aGUgY29udHJvbCBoYW5kbGUgcG9zaXRpb25zIGZvciBhbiBpbnRlcnBvbGF0aW9uIGJlemllciBjdXJ2ZSB1c2VkIHRvIHRyYW5zaXRpb24gZnJvbSB0aGlzIGtleWZyYW1lIHRvIHRoZSBuZXh0LlxuXHQgKiBjeDEgYW5kIGN4MiBhcmUgZnJvbSAwIHRvIDEsIHJlcHJlc2VudGluZyB0aGUgcGVyY2VudCBvZiB0aW1lIGJldHdlZW4gdGhlIHR3byBrZXlmcmFtZXMuIGN5MSBhbmQgY3kyIGFyZSB0aGUgcGVyY2VudCBvZlxuXHQgKiB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBrZXlmcmFtZSdzIHZhbHVlcy4gKi9cblx0c2V0Q3VydmU6IGZ1bmN0aW9uIChmcmFtZUluZGV4LCBjeDEsIGN5MSwgY3gyLCBjeTIpIHtcblx0XHR2YXIgc3ViZGl2MSA9IDEgLyAxMC8qQkVaSUVSX1NFR01FTlRTKi8sIHN1YmRpdjIgPSBzdWJkaXYxICogc3ViZGl2MSwgc3ViZGl2MyA9IHN1YmRpdjIgKiBzdWJkaXYxO1xuXHRcdHZhciBwcmUxID0gMyAqIHN1YmRpdjEsIHByZTIgPSAzICogc3ViZGl2MiwgcHJlNCA9IDYgKiBzdWJkaXYyLCBwcmU1ID0gNiAqIHN1YmRpdjM7XG5cdFx0dmFyIHRtcDF4ID0gLWN4MSAqIDIgKyBjeDIsIHRtcDF5ID0gLWN5MSAqIDIgKyBjeTIsIHRtcDJ4ID0gKGN4MSAtIGN4MikgKiAzICsgMSwgdG1wMnkgPSAoY3kxIC0gY3kyKSAqIDMgKyAxO1xuXHRcdHZhciBkZnggPSBjeDEgKiBwcmUxICsgdG1wMXggKiBwcmUyICsgdG1wMnggKiBzdWJkaXYzLCBkZnkgPSBjeTEgKiBwcmUxICsgdG1wMXkgKiBwcmUyICsgdG1wMnkgKiBzdWJkaXYzO1xuXHRcdHZhciBkZGZ4ID0gdG1wMXggKiBwcmU0ICsgdG1wMnggKiBwcmU1LCBkZGZ5ID0gdG1wMXkgKiBwcmU0ICsgdG1wMnkgKiBwcmU1O1xuXHRcdHZhciBkZGRmeCA9IHRtcDJ4ICogcHJlNSwgZGRkZnkgPSB0bXAyeSAqIHByZTU7XG5cblx0XHR2YXIgaSA9IGZyYW1lSW5kZXggKiAxOS8qQkVaSUVSX1NJWkUqLztcblx0XHR2YXIgY3VydmVzID0gdGhpcy5jdXJ2ZXM7XG5cdFx0Y3VydmVzW2krK10gPSAyLypCRVpJRVIqLztcblxuXHRcdHZhciB4ID0gZGZ4LCB5ID0gZGZ5O1xuXHRcdGZvciAodmFyIG4gPSBpICsgMTkvKkJFWklFUl9TSVpFKi8gLSAxOyBpIDwgbjsgaSArPSAyKSB7XG5cdFx0XHRjdXJ2ZXNbaV0gPSB4O1xuXHRcdFx0Y3VydmVzW2kgKyAxXSA9IHk7XG5cdFx0XHRkZnggKz0gZGRmeDtcblx0XHRcdGRmeSArPSBkZGZ5O1xuXHRcdFx0ZGRmeCArPSBkZGRmeDtcblx0XHRcdGRkZnkgKz0gZGRkZnk7XG5cdFx0XHR4ICs9IGRmeDtcblx0XHRcdHkgKz0gZGZ5O1xuXHRcdH1cblx0fSxcblx0Z2V0Q3VydmVQZXJjZW50OiBmdW5jdGlvbiAoZnJhbWVJbmRleCwgcGVyY2VudCkge1xuXHRcdHBlcmNlbnQgPSBwZXJjZW50IDwgMCA/IDAgOiAocGVyY2VudCA+IDEgPyAxIDogcGVyY2VudCk7XG5cdFx0dmFyIGN1cnZlcyA9IHRoaXMuY3VydmVzO1xuXHRcdHZhciBpID0gZnJhbWVJbmRleCAqIDE5LypCRVpJRVJfU0laRSovO1xuXHRcdHZhciB0eXBlID0gY3VydmVzW2ldO1xuXHRcdGlmICh0eXBlID09PSAwLypMSU5FQVIqLykgcmV0dXJuIHBlcmNlbnQ7XG5cdFx0aWYgKHR5cGUgPT0gMS8qU1RFUFBFRCovKSByZXR1cm4gMDtcblx0XHRpKys7XG5cdFx0dmFyIHggPSAwO1xuXHRcdGZvciAodmFyIHN0YXJ0ID0gaSwgbiA9IGkgKyAxOS8qQkVaSUVSX1NJWkUqLyAtIDE7IGkgPCBuOyBpICs9IDIpIHtcblx0XHRcdHggPSBjdXJ2ZXNbaV07XG5cdFx0XHRpZiAoeCA+PSBwZXJjZW50KSB7XG5cdFx0XHRcdHZhciBwcmV2WCwgcHJldlk7XG5cdFx0XHRcdGlmIChpID09IHN0YXJ0KSB7XG5cdFx0XHRcdFx0cHJldlggPSAwO1xuXHRcdFx0XHRcdHByZXZZID0gMDtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRwcmV2WCA9IGN1cnZlc1tpIC0gMl07XG5cdFx0XHRcdFx0cHJldlkgPSBjdXJ2ZXNbaSAtIDFdO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBwcmV2WSArIChjdXJ2ZXNbaSArIDFdIC0gcHJldlkpICogKHBlcmNlbnQgLSBwcmV2WCkgLyAoeCAtIHByZXZYKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0dmFyIHkgPSBjdXJ2ZXNbaSAtIDFdO1xuXHRcdHJldHVybiB5ICsgKDEgLSB5KSAqIChwZXJjZW50IC0geCkgLyAoMSAtIHgpOyAvLyBMYXN0IHBvaW50IGlzIDEsMS5cblx0fVxufTtcblxuc3BpbmUuUm90YXRlVGltZWxpbmUgPSBmdW5jdGlvbiAoZnJhbWVDb3VudCkge1xuXHR0aGlzLmN1cnZlcyA9IG5ldyBzcGluZS5DdXJ2ZXMoZnJhbWVDb3VudCk7XG5cdHRoaXMuZnJhbWVzID0gW107IC8vIHRpbWUsIGFuZ2xlLCAuLi5cblx0dGhpcy5mcmFtZXMubGVuZ3RoID0gZnJhbWVDb3VudCAqIDI7XG59O1xuc3BpbmUuUm90YXRlVGltZWxpbmUucHJvdG90eXBlID0ge1xuXHRib25lSW5kZXg6IDAsXG5cdGdldEZyYW1lQ291bnQ6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5mcmFtZXMubGVuZ3RoIC8gMjtcblx0fSxcblx0c2V0RnJhbWU6IGZ1bmN0aW9uIChmcmFtZUluZGV4LCB0aW1lLCBhbmdsZSkge1xuXHRcdGZyYW1lSW5kZXggKj0gMjtcblx0XHR0aGlzLmZyYW1lc1tmcmFtZUluZGV4XSA9IHRpbWU7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleCArIDFdID0gYW5nbGU7XG5cdH0sXG5cdGFwcGx5OiBmdW5jdGlvbiAoc2tlbGV0b24sIGxhc3RUaW1lLCB0aW1lLCBmaXJlZEV2ZW50cywgYWxwaGEpIHtcblx0XHR2YXIgZnJhbWVzID0gdGhpcy5mcmFtZXM7XG5cdFx0aWYgKHRpbWUgPCBmcmFtZXNbMF0pIHJldHVybjsgLy8gVGltZSBpcyBiZWZvcmUgZmlyc3QgZnJhbWUuXG5cblx0XHR2YXIgYm9uZSA9IHNrZWxldG9uLmJvbmVzW3RoaXMuYm9uZUluZGV4XTtcblxuXHRcdGlmICh0aW1lID49IGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMl0pIHsgLy8gVGltZSBpcyBhZnRlciBsYXN0IGZyYW1lLlxuXHRcdFx0dmFyIGFtb3VudCA9IGJvbmUuZGF0YS5yb3RhdGlvbiArIGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMV0gLSBib25lLnJvdGF0aW9uO1xuXHRcdFx0d2hpbGUgKGFtb3VudCA+IDE4MClcblx0XHRcdFx0YW1vdW50IC09IDM2MDtcblx0XHRcdHdoaWxlIChhbW91bnQgPCAtMTgwKVxuXHRcdFx0XHRhbW91bnQgKz0gMzYwO1xuXHRcdFx0Ym9uZS5yb3RhdGlvbiArPSBhbW91bnQgKiBhbHBoYTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBJbnRlcnBvbGF0ZSBiZXR3ZWVuIHRoZSBwcmV2aW91cyBmcmFtZSBhbmQgdGhlIGN1cnJlbnQgZnJhbWUuXG5cdFx0dmFyIGZyYW1lSW5kZXggPSBzcGluZS5BbmltYXRpb24uYmluYXJ5U2VhcmNoKGZyYW1lcywgdGltZSwgMik7XG5cdFx0dmFyIHByZXZGcmFtZVZhbHVlID0gZnJhbWVzW2ZyYW1lSW5kZXggLSAxXTtcblx0XHR2YXIgZnJhbWVUaW1lID0gZnJhbWVzW2ZyYW1lSW5kZXhdO1xuXHRcdHZhciBwZXJjZW50ID0gMSAtICh0aW1lIC0gZnJhbWVUaW1lKSAvIChmcmFtZXNbZnJhbWVJbmRleCAtIDIvKlBSRVZfRlJBTUVfVElNRSovXSAtIGZyYW1lVGltZSk7XG5cdFx0cGVyY2VudCA9IHRoaXMuY3VydmVzLmdldEN1cnZlUGVyY2VudChmcmFtZUluZGV4IC8gMiAtIDEsIHBlcmNlbnQpO1xuXG5cdFx0dmFyIGFtb3VudCA9IGZyYW1lc1tmcmFtZUluZGV4ICsgMS8qRlJBTUVfVkFMVUUqL10gLSBwcmV2RnJhbWVWYWx1ZTtcblx0XHR3aGlsZSAoYW1vdW50ID4gMTgwKVxuXHRcdFx0YW1vdW50IC09IDM2MDtcblx0XHR3aGlsZSAoYW1vdW50IDwgLTE4MClcblx0XHRcdGFtb3VudCArPSAzNjA7XG5cdFx0YW1vdW50ID0gYm9uZS5kYXRhLnJvdGF0aW9uICsgKHByZXZGcmFtZVZhbHVlICsgYW1vdW50ICogcGVyY2VudCkgLSBib25lLnJvdGF0aW9uO1xuXHRcdHdoaWxlIChhbW91bnQgPiAxODApXG5cdFx0XHRhbW91bnQgLT0gMzYwO1xuXHRcdHdoaWxlIChhbW91bnQgPCAtMTgwKVxuXHRcdFx0YW1vdW50ICs9IDM2MDtcblx0XHRib25lLnJvdGF0aW9uICs9IGFtb3VudCAqIGFscGhhO1xuXHR9XG59O1xuXG5zcGluZS5UcmFuc2xhdGVUaW1lbGluZSA9IGZ1bmN0aW9uIChmcmFtZUNvdW50KSB7XG5cdHRoaXMuY3VydmVzID0gbmV3IHNwaW5lLkN1cnZlcyhmcmFtZUNvdW50KTtcblx0dGhpcy5mcmFtZXMgPSBbXTsgLy8gdGltZSwgeCwgeSwgLi4uXG5cdHRoaXMuZnJhbWVzLmxlbmd0aCA9IGZyYW1lQ291bnQgKiAzO1xufTtcbnNwaW5lLlRyYW5zbGF0ZVRpbWVsaW5lLnByb3RvdHlwZSA9IHtcblx0Ym9uZUluZGV4OiAwLFxuXHRnZXRGcmFtZUNvdW50OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZnJhbWVzLmxlbmd0aCAvIDM7XG5cdH0sXG5cdHNldEZyYW1lOiBmdW5jdGlvbiAoZnJhbWVJbmRleCwgdGltZSwgeCwgeSkge1xuXHRcdGZyYW1lSW5kZXggKj0gMztcblx0XHR0aGlzLmZyYW1lc1tmcmFtZUluZGV4XSA9IHRpbWU7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleCArIDFdID0geDtcblx0XHR0aGlzLmZyYW1lc1tmcmFtZUluZGV4ICsgMl0gPSB5O1xuXHR9LFxuXHRhcHBseTogZnVuY3Rpb24gKHNrZWxldG9uLCBsYXN0VGltZSwgdGltZSwgZmlyZWRFdmVudHMsIGFscGhhKSB7XG5cdFx0dmFyIGZyYW1lcyA9IHRoaXMuZnJhbWVzO1xuXHRcdGlmICh0aW1lIDwgZnJhbWVzWzBdKSByZXR1cm47IC8vIFRpbWUgaXMgYmVmb3JlIGZpcnN0IGZyYW1lLlxuXG5cdFx0dmFyIGJvbmUgPSBza2VsZXRvbi5ib25lc1t0aGlzLmJvbmVJbmRleF07XG5cblx0XHRpZiAodGltZSA+PSBmcmFtZXNbZnJhbWVzLmxlbmd0aCAtIDNdKSB7IC8vIFRpbWUgaXMgYWZ0ZXIgbGFzdCBmcmFtZS5cblx0XHRcdGJvbmUueCArPSAoYm9uZS5kYXRhLnggKyBmcmFtZXNbZnJhbWVzLmxlbmd0aCAtIDJdIC0gYm9uZS54KSAqIGFscGhhO1xuXHRcdFx0Ym9uZS55ICs9IChib25lLmRhdGEueSArIGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMV0gLSBib25lLnkpICogYWxwaGE7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gSW50ZXJwb2xhdGUgYmV0d2VlbiB0aGUgcHJldmlvdXMgZnJhbWUgYW5kIHRoZSBjdXJyZW50IGZyYW1lLlxuXHRcdHZhciBmcmFtZUluZGV4ID0gc3BpbmUuQW5pbWF0aW9uLmJpbmFyeVNlYXJjaChmcmFtZXMsIHRpbWUsIDMpO1xuXHRcdHZhciBwcmV2RnJhbWVYID0gZnJhbWVzW2ZyYW1lSW5kZXggLSAyXTtcblx0XHR2YXIgcHJldkZyYW1lWSA9IGZyYW1lc1tmcmFtZUluZGV4IC0gMV07XG5cdFx0dmFyIGZyYW1lVGltZSA9IGZyYW1lc1tmcmFtZUluZGV4XTtcblx0XHR2YXIgcGVyY2VudCA9IDEgLSAodGltZSAtIGZyYW1lVGltZSkgLyAoZnJhbWVzW2ZyYW1lSW5kZXggKyAtMy8qUFJFVl9GUkFNRV9USU1FKi9dIC0gZnJhbWVUaW1lKTtcblx0XHRwZXJjZW50ID0gdGhpcy5jdXJ2ZXMuZ2V0Q3VydmVQZXJjZW50KGZyYW1lSW5kZXggLyAzIC0gMSwgcGVyY2VudCk7XG5cblx0XHRib25lLnggKz0gKGJvbmUuZGF0YS54ICsgcHJldkZyYW1lWCArIChmcmFtZXNbZnJhbWVJbmRleCArIDEvKkZSQU1FX1gqL10gLSBwcmV2RnJhbWVYKSAqIHBlcmNlbnQgLSBib25lLngpICogYWxwaGE7XG5cdFx0Ym9uZS55ICs9IChib25lLmRhdGEueSArIHByZXZGcmFtZVkgKyAoZnJhbWVzW2ZyYW1lSW5kZXggKyAyLypGUkFNRV9ZKi9dIC0gcHJldkZyYW1lWSkgKiBwZXJjZW50IC0gYm9uZS55KSAqIGFscGhhO1xuXHR9XG59O1xuXG5zcGluZS5TY2FsZVRpbWVsaW5lID0gZnVuY3Rpb24gKGZyYW1lQ291bnQpIHtcblx0dGhpcy5jdXJ2ZXMgPSBuZXcgc3BpbmUuQ3VydmVzKGZyYW1lQ291bnQpO1xuXHR0aGlzLmZyYW1lcyA9IFtdOyAvLyB0aW1lLCB4LCB5LCAuLi5cblx0dGhpcy5mcmFtZXMubGVuZ3RoID0gZnJhbWVDb3VudCAqIDM7XG59O1xuc3BpbmUuU2NhbGVUaW1lbGluZS5wcm90b3R5cGUgPSB7XG5cdGJvbmVJbmRleDogMCxcblx0Z2V0RnJhbWVDb3VudDogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLmZyYW1lcy5sZW5ndGggLyAzO1xuXHR9LFxuXHRzZXRGcmFtZTogZnVuY3Rpb24gKGZyYW1lSW5kZXgsIHRpbWUsIHgsIHkpIHtcblx0XHRmcmFtZUluZGV4ICo9IDM7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleF0gPSB0aW1lO1xuXHRcdHRoaXMuZnJhbWVzW2ZyYW1lSW5kZXggKyAxXSA9IHg7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleCArIDJdID0geTtcblx0fSxcblx0YXBwbHk6IGZ1bmN0aW9uIChza2VsZXRvbiwgbGFzdFRpbWUsIHRpbWUsIGZpcmVkRXZlbnRzLCBhbHBoYSkge1xuXHRcdHZhciBmcmFtZXMgPSB0aGlzLmZyYW1lcztcblx0XHRpZiAodGltZSA8IGZyYW1lc1swXSkgcmV0dXJuOyAvLyBUaW1lIGlzIGJlZm9yZSBmaXJzdCBmcmFtZS5cblxuXHRcdHZhciBib25lID0gc2tlbGV0b24uYm9uZXNbdGhpcy5ib25lSW5kZXhdO1xuXG5cdFx0aWYgKHRpbWUgPj0gZnJhbWVzW2ZyYW1lcy5sZW5ndGggLSAzXSkgeyAvLyBUaW1lIGlzIGFmdGVyIGxhc3QgZnJhbWUuXG5cdFx0XHRib25lLnNjYWxlWCArPSAoYm9uZS5kYXRhLnNjYWxlWCAqIGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMl0gLSBib25lLnNjYWxlWCkgKiBhbHBoYTtcblx0XHRcdGJvbmUuc2NhbGVZICs9IChib25lLmRhdGEuc2NhbGVZICogZnJhbWVzW2ZyYW1lcy5sZW5ndGggLSAxXSAtIGJvbmUuc2NhbGVZKSAqIGFscGhhO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIEludGVycG9sYXRlIGJldHdlZW4gdGhlIHByZXZpb3VzIGZyYW1lIGFuZCB0aGUgY3VycmVudCBmcmFtZS5cblx0XHR2YXIgZnJhbWVJbmRleCA9IHNwaW5lLkFuaW1hdGlvbi5iaW5hcnlTZWFyY2goZnJhbWVzLCB0aW1lLCAzKTtcblx0XHR2YXIgcHJldkZyYW1lWCA9IGZyYW1lc1tmcmFtZUluZGV4IC0gMl07XG5cdFx0dmFyIHByZXZGcmFtZVkgPSBmcmFtZXNbZnJhbWVJbmRleCAtIDFdO1xuXHRcdHZhciBmcmFtZVRpbWUgPSBmcmFtZXNbZnJhbWVJbmRleF07XG5cdFx0dmFyIHBlcmNlbnQgPSAxIC0gKHRpbWUgLSBmcmFtZVRpbWUpIC8gKGZyYW1lc1tmcmFtZUluZGV4ICsgLTMvKlBSRVZfRlJBTUVfVElNRSovXSAtIGZyYW1lVGltZSk7XG5cdFx0cGVyY2VudCA9IHRoaXMuY3VydmVzLmdldEN1cnZlUGVyY2VudChmcmFtZUluZGV4IC8gMyAtIDEsIHBlcmNlbnQpO1xuXG5cdFx0Ym9uZS5zY2FsZVggKz0gKGJvbmUuZGF0YS5zY2FsZVggKiAocHJldkZyYW1lWCArIChmcmFtZXNbZnJhbWVJbmRleCArIDEvKkZSQU1FX1gqL10gLSBwcmV2RnJhbWVYKSAqIHBlcmNlbnQpIC0gYm9uZS5zY2FsZVgpICogYWxwaGE7XG5cdFx0Ym9uZS5zY2FsZVkgKz0gKGJvbmUuZGF0YS5zY2FsZVkgKiAocHJldkZyYW1lWSArIChmcmFtZXNbZnJhbWVJbmRleCArIDIvKkZSQU1FX1kqL10gLSBwcmV2RnJhbWVZKSAqIHBlcmNlbnQpIC0gYm9uZS5zY2FsZVkpICogYWxwaGE7XG5cdH1cbn07XG5cbnNwaW5lLkNvbG9yVGltZWxpbmUgPSBmdW5jdGlvbiAoZnJhbWVDb3VudCkge1xuXHR0aGlzLmN1cnZlcyA9IG5ldyBzcGluZS5DdXJ2ZXMoZnJhbWVDb3VudCk7XG5cdHRoaXMuZnJhbWVzID0gW107IC8vIHRpbWUsIHIsIGcsIGIsIGEsIC4uLlxuXHR0aGlzLmZyYW1lcy5sZW5ndGggPSBmcmFtZUNvdW50ICogNTtcbn07XG5zcGluZS5Db2xvclRpbWVsaW5lLnByb3RvdHlwZSA9IHtcblx0c2xvdEluZGV4OiAwLFxuXHRnZXRGcmFtZUNvdW50OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZnJhbWVzLmxlbmd0aCAvIDU7XG5cdH0sXG5cdHNldEZyYW1lOiBmdW5jdGlvbiAoZnJhbWVJbmRleCwgdGltZSwgciwgZywgYiwgYSkge1xuXHRcdGZyYW1lSW5kZXggKj0gNTtcblx0XHR0aGlzLmZyYW1lc1tmcmFtZUluZGV4XSA9IHRpbWU7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleCArIDFdID0gcjtcblx0XHR0aGlzLmZyYW1lc1tmcmFtZUluZGV4ICsgMl0gPSBnO1xuXHRcdHRoaXMuZnJhbWVzW2ZyYW1lSW5kZXggKyAzXSA9IGI7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleCArIDRdID0gYTtcblx0fSxcblx0YXBwbHk6IGZ1bmN0aW9uIChza2VsZXRvbiwgbGFzdFRpbWUsIHRpbWUsIGZpcmVkRXZlbnRzLCBhbHBoYSkge1xuXHRcdHZhciBmcmFtZXMgPSB0aGlzLmZyYW1lcztcblx0XHRpZiAodGltZSA8IGZyYW1lc1swXSkgcmV0dXJuOyAvLyBUaW1lIGlzIGJlZm9yZSBmaXJzdCBmcmFtZS5cblxuXHRcdHZhciByLCBnLCBiLCBhO1xuXHRcdGlmICh0aW1lID49IGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gNV0pIHtcblx0XHRcdC8vIFRpbWUgaXMgYWZ0ZXIgbGFzdCBmcmFtZS5cblx0XHRcdHZhciBpID0gZnJhbWVzLmxlbmd0aCAtIDE7XG5cdFx0XHRyID0gZnJhbWVzW2kgLSAzXTtcblx0XHRcdGcgPSBmcmFtZXNbaSAtIDJdO1xuXHRcdFx0YiA9IGZyYW1lc1tpIC0gMV07XG5cdFx0XHRhID0gZnJhbWVzW2ldO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBJbnRlcnBvbGF0ZSBiZXR3ZWVuIHRoZSBwcmV2aW91cyBmcmFtZSBhbmQgdGhlIGN1cnJlbnQgZnJhbWUuXG5cdFx0XHR2YXIgZnJhbWVJbmRleCA9IHNwaW5lLkFuaW1hdGlvbi5iaW5hcnlTZWFyY2goZnJhbWVzLCB0aW1lLCA1KTtcblx0XHRcdHZhciBwcmV2RnJhbWVSID0gZnJhbWVzW2ZyYW1lSW5kZXggLSA0XTtcblx0XHRcdHZhciBwcmV2RnJhbWVHID0gZnJhbWVzW2ZyYW1lSW5kZXggLSAzXTtcblx0XHRcdHZhciBwcmV2RnJhbWVCID0gZnJhbWVzW2ZyYW1lSW5kZXggLSAyXTtcblx0XHRcdHZhciBwcmV2RnJhbWVBID0gZnJhbWVzW2ZyYW1lSW5kZXggLSAxXTtcblx0XHRcdHZhciBmcmFtZVRpbWUgPSBmcmFtZXNbZnJhbWVJbmRleF07XG5cdFx0XHR2YXIgcGVyY2VudCA9IDEgLSAodGltZSAtIGZyYW1lVGltZSkgLyAoZnJhbWVzW2ZyYW1lSW5kZXggLSA1LypQUkVWX0ZSQU1FX1RJTUUqL10gLSBmcmFtZVRpbWUpO1xuXHRcdFx0cGVyY2VudCA9IHRoaXMuY3VydmVzLmdldEN1cnZlUGVyY2VudChmcmFtZUluZGV4IC8gNSAtIDEsIHBlcmNlbnQpO1xuXG5cdFx0XHRyID0gcHJldkZyYW1lUiArIChmcmFtZXNbZnJhbWVJbmRleCArIDEvKkZSQU1FX1IqL10gLSBwcmV2RnJhbWVSKSAqIHBlcmNlbnQ7XG5cdFx0XHRnID0gcHJldkZyYW1lRyArIChmcmFtZXNbZnJhbWVJbmRleCArIDIvKkZSQU1FX0cqL10gLSBwcmV2RnJhbWVHKSAqIHBlcmNlbnQ7XG5cdFx0XHRiID0gcHJldkZyYW1lQiArIChmcmFtZXNbZnJhbWVJbmRleCArIDMvKkZSQU1FX0IqL10gLSBwcmV2RnJhbWVCKSAqIHBlcmNlbnQ7XG5cdFx0XHRhID0gcHJldkZyYW1lQSArIChmcmFtZXNbZnJhbWVJbmRleCArIDQvKkZSQU1FX0EqL10gLSBwcmV2RnJhbWVBKSAqIHBlcmNlbnQ7XG5cdFx0fVxuXHRcdHZhciBzbG90ID0gc2tlbGV0b24uc2xvdHNbdGhpcy5zbG90SW5kZXhdO1xuXHRcdGlmIChhbHBoYSA8IDEpIHtcblx0XHRcdHNsb3QuciArPSAociAtIHNsb3QucikgKiBhbHBoYTtcblx0XHRcdHNsb3QuZyArPSAoZyAtIHNsb3QuZykgKiBhbHBoYTtcblx0XHRcdHNsb3QuYiArPSAoYiAtIHNsb3QuYikgKiBhbHBoYTtcblx0XHRcdHNsb3QuYSArPSAoYSAtIHNsb3QuYSkgKiBhbHBoYTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0c2xvdC5yID0gcjtcblx0XHRcdHNsb3QuZyA9IGc7XG5cdFx0XHRzbG90LmIgPSBiO1xuXHRcdFx0c2xvdC5hID0gYTtcblx0XHR9XG5cdH1cbn07XG5cbnNwaW5lLkF0dGFjaG1lbnRUaW1lbGluZSA9IGZ1bmN0aW9uIChmcmFtZUNvdW50KSB7XG5cdHRoaXMuY3VydmVzID0gbmV3IHNwaW5lLkN1cnZlcyhmcmFtZUNvdW50KTtcblx0dGhpcy5mcmFtZXMgPSBbXTsgLy8gdGltZSwgLi4uXG5cdHRoaXMuZnJhbWVzLmxlbmd0aCA9IGZyYW1lQ291bnQ7XG5cdHRoaXMuYXR0YWNobWVudE5hbWVzID0gW107XG5cdHRoaXMuYXR0YWNobWVudE5hbWVzLmxlbmd0aCA9IGZyYW1lQ291bnQ7XG59O1xuc3BpbmUuQXR0YWNobWVudFRpbWVsaW5lLnByb3RvdHlwZSA9IHtcblx0c2xvdEluZGV4OiAwLFxuXHRnZXRGcmFtZUNvdW50OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZnJhbWVzLmxlbmd0aDtcblx0fSxcblx0c2V0RnJhbWU6IGZ1bmN0aW9uIChmcmFtZUluZGV4LCB0aW1lLCBhdHRhY2htZW50TmFtZSkge1xuXHRcdHRoaXMuZnJhbWVzW2ZyYW1lSW5kZXhdID0gdGltZTtcblx0XHR0aGlzLmF0dGFjaG1lbnROYW1lc1tmcmFtZUluZGV4XSA9IGF0dGFjaG1lbnROYW1lO1xuXHR9LFxuXHRhcHBseTogZnVuY3Rpb24gKHNrZWxldG9uLCBsYXN0VGltZSwgdGltZSwgZmlyZWRFdmVudHMsIGFscGhhKSB7XG5cdFx0dmFyIGZyYW1lcyA9IHRoaXMuZnJhbWVzO1xuXHRcdGlmICh0aW1lIDwgZnJhbWVzWzBdKSB7XG5cdFx0XHRpZiAobGFzdFRpbWUgPiB0aW1lKSB0aGlzLmFwcGx5KHNrZWxldG9uLCBsYXN0VGltZSwgTnVtYmVyLk1BWF9WQUxVRSwgbnVsbCwgMCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fSBlbHNlIGlmIChsYXN0VGltZSA+IHRpbWUpIC8vXG5cdFx0XHRsYXN0VGltZSA9IC0xO1xuXG5cdFx0dmFyIGZyYW1lSW5kZXggPSB0aW1lID49IGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMV0gPyBmcmFtZXMubGVuZ3RoIC0gMSA6IHNwaW5lLkFuaW1hdGlvbi5iaW5hcnlTZWFyY2gxKGZyYW1lcywgdGltZSkgLSAxO1xuXHRcdGlmIChmcmFtZXNbZnJhbWVJbmRleF0gPCBsYXN0VGltZSkgcmV0dXJuO1xuXG5cdFx0dmFyIGF0dGFjaG1lbnROYW1lID0gdGhpcy5hdHRhY2htZW50TmFtZXNbZnJhbWVJbmRleF07XG5cdFx0c2tlbGV0b24uc2xvdHNbdGhpcy5zbG90SW5kZXhdLnNldEF0dGFjaG1lbnQoXG5cdFx0XHQhYXR0YWNobWVudE5hbWUgPyBudWxsIDogc2tlbGV0b24uZ2V0QXR0YWNobWVudEJ5U2xvdEluZGV4KHRoaXMuc2xvdEluZGV4LCBhdHRhY2htZW50TmFtZSkpO1xuXHR9XG59O1xuXG5zcGluZS5FdmVudFRpbWVsaW5lID0gZnVuY3Rpb24gKGZyYW1lQ291bnQpIHtcblx0dGhpcy5mcmFtZXMgPSBbXTsgLy8gdGltZSwgLi4uXG5cdHRoaXMuZnJhbWVzLmxlbmd0aCA9IGZyYW1lQ291bnQ7XG5cdHRoaXMuZXZlbnRzID0gW107XG5cdHRoaXMuZXZlbnRzLmxlbmd0aCA9IGZyYW1lQ291bnQ7XG59O1xuc3BpbmUuRXZlbnRUaW1lbGluZS5wcm90b3R5cGUgPSB7XG5cdGdldEZyYW1lQ291bnQ6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5mcmFtZXMubGVuZ3RoO1xuXHR9LFxuXHRzZXRGcmFtZTogZnVuY3Rpb24gKGZyYW1lSW5kZXgsIHRpbWUsIGV2ZW50KSB7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleF0gPSB0aW1lO1xuXHRcdHRoaXMuZXZlbnRzW2ZyYW1lSW5kZXhdID0gZXZlbnQ7XG5cdH0sXG5cdC8qKiBGaXJlcyBldmVudHMgZm9yIGZyYW1lcyA+IGxhc3RUaW1lIGFuZCA8PSB0aW1lLiAqL1xuXHRhcHBseTogZnVuY3Rpb24gKHNrZWxldG9uLCBsYXN0VGltZSwgdGltZSwgZmlyZWRFdmVudHMsIGFscGhhKSB7XG5cdFx0aWYgKCFmaXJlZEV2ZW50cykgcmV0dXJuO1xuXG5cdFx0dmFyIGZyYW1lcyA9IHRoaXMuZnJhbWVzO1xuXHRcdHZhciBmcmFtZUNvdW50ID0gZnJhbWVzLmxlbmd0aDtcblxuXHRcdGlmIChsYXN0VGltZSA+IHRpbWUpIHsgLy8gRmlyZSBldmVudHMgYWZ0ZXIgbGFzdCB0aW1lIGZvciBsb29wZWQgYW5pbWF0aW9ucy5cblx0XHRcdHRoaXMuYXBwbHkoc2tlbGV0b24sIGxhc3RUaW1lLCBOdW1iZXIuTUFYX1ZBTFVFLCBmaXJlZEV2ZW50cywgYWxwaGEpO1xuXHRcdFx0bGFzdFRpbWUgPSAtMTtcblx0XHR9IGVsc2UgaWYgKGxhc3RUaW1lID49IGZyYW1lc1tmcmFtZUNvdW50IC0gMV0pIC8vIExhc3QgdGltZSBpcyBhZnRlciBsYXN0IGZyYW1lLlxuXHRcdFx0cmV0dXJuO1xuXHRcdGlmICh0aW1lIDwgZnJhbWVzWzBdKSByZXR1cm47IC8vIFRpbWUgaXMgYmVmb3JlIGZpcnN0IGZyYW1lLlxuXG5cdFx0dmFyIGZyYW1lSW5kZXg7XG5cdFx0aWYgKGxhc3RUaW1lIDwgZnJhbWVzWzBdKVxuXHRcdFx0ZnJhbWVJbmRleCA9IDA7XG5cdFx0ZWxzZSB7XG5cdFx0XHRmcmFtZUluZGV4ID0gc3BpbmUuQW5pbWF0aW9uLmJpbmFyeVNlYXJjaDEoZnJhbWVzLCBsYXN0VGltZSk7XG5cdFx0XHR2YXIgZnJhbWUgPSBmcmFtZXNbZnJhbWVJbmRleF07XG5cdFx0XHR3aGlsZSAoZnJhbWVJbmRleCA+IDApIHsgLy8gRmlyZSBtdWx0aXBsZSBldmVudHMgd2l0aCB0aGUgc2FtZSBmcmFtZS5cblx0XHRcdFx0aWYgKGZyYW1lc1tmcmFtZUluZGV4IC0gMV0gIT0gZnJhbWUpIGJyZWFrO1xuXHRcdFx0XHRmcmFtZUluZGV4LS07XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHZhciBldmVudHMgPSB0aGlzLmV2ZW50cztcblx0XHRmb3IgKDsgZnJhbWVJbmRleCA8IGZyYW1lQ291bnQgJiYgdGltZSA+PSBmcmFtZXNbZnJhbWVJbmRleF07IGZyYW1lSW5kZXgrKylcblx0XHRcdGZpcmVkRXZlbnRzLnB1c2goZXZlbnRzW2ZyYW1lSW5kZXhdKTtcblx0fVxufTtcblxuc3BpbmUuRHJhd09yZGVyVGltZWxpbmUgPSBmdW5jdGlvbiAoZnJhbWVDb3VudCkge1xuXHR0aGlzLmZyYW1lcyA9IFtdOyAvLyB0aW1lLCAuLi5cblx0dGhpcy5mcmFtZXMubGVuZ3RoID0gZnJhbWVDb3VudDtcblx0dGhpcy5kcmF3T3JkZXJzID0gW107XG5cdHRoaXMuZHJhd09yZGVycy5sZW5ndGggPSBmcmFtZUNvdW50O1xufTtcbnNwaW5lLkRyYXdPcmRlclRpbWVsaW5lLnByb3RvdHlwZSA9IHtcblx0Z2V0RnJhbWVDb3VudDogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLmZyYW1lcy5sZW5ndGg7XG5cdH0sXG5cdHNldEZyYW1lOiBmdW5jdGlvbiAoZnJhbWVJbmRleCwgdGltZSwgZHJhd09yZGVyKSB7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleF0gPSB0aW1lO1xuXHRcdHRoaXMuZHJhd09yZGVyc1tmcmFtZUluZGV4XSA9IGRyYXdPcmRlcjtcblx0fSxcblx0YXBwbHk6IGZ1bmN0aW9uIChza2VsZXRvbiwgbGFzdFRpbWUsIHRpbWUsIGZpcmVkRXZlbnRzLCBhbHBoYSkge1xuXHRcdHZhciBmcmFtZXMgPSB0aGlzLmZyYW1lcztcblx0XHRpZiAodGltZSA8IGZyYW1lc1swXSkgcmV0dXJuOyAvLyBUaW1lIGlzIGJlZm9yZSBmaXJzdCBmcmFtZS5cblxuXHRcdHZhciBmcmFtZUluZGV4O1xuXHRcdGlmICh0aW1lID49IGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMV0pIC8vIFRpbWUgaXMgYWZ0ZXIgbGFzdCBmcmFtZS5cblx0XHRcdGZyYW1lSW5kZXggPSBmcmFtZXMubGVuZ3RoIC0gMTtcblx0XHRlbHNlXG5cdFx0XHRmcmFtZUluZGV4ID0gc3BpbmUuQW5pbWF0aW9uLmJpbmFyeVNlYXJjaDEoZnJhbWVzLCB0aW1lKSAtIDE7XG5cblx0XHR2YXIgZHJhd09yZGVyID0gc2tlbGV0b24uZHJhd09yZGVyO1xuXHRcdHZhciBzbG90cyA9IHNrZWxldG9uLnNsb3RzO1xuXHRcdHZhciBkcmF3T3JkZXJUb1NldHVwSW5kZXggPSB0aGlzLmRyYXdPcmRlcnNbZnJhbWVJbmRleF07XG5cdFx0aWYgKCFkcmF3T3JkZXJUb1NldHVwSW5kZXgpIHtcblx0XHRcdGZvciAodmFyIGkgPSAwLCBuID0gc2xvdHMubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0XHRkcmF3T3JkZXJbaV0gPSBzbG90c1tpXTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBkcmF3T3JkZXJUb1NldHVwSW5kZXgubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0XHRkcmF3T3JkZXJbaV0gPSBza2VsZXRvbi5zbG90c1tkcmF3T3JkZXJUb1NldHVwSW5kZXhbaV1dO1xuXHRcdH1cblxuXHR9XG59O1xuXG5zcGluZS5GZmRUaW1lbGluZSA9IGZ1bmN0aW9uIChmcmFtZUNvdW50KSB7XG5cdHRoaXMuY3VydmVzID0gbmV3IHNwaW5lLkN1cnZlcyhmcmFtZUNvdW50KTtcblx0dGhpcy5mcmFtZXMgPSBbXTtcblx0dGhpcy5mcmFtZXMubGVuZ3RoID0gZnJhbWVDb3VudDtcblx0dGhpcy5mcmFtZVZlcnRpY2VzID0gW107XG5cdHRoaXMuZnJhbWVWZXJ0aWNlcy5sZW5ndGggPSBmcmFtZUNvdW50O1xufTtcbnNwaW5lLkZmZFRpbWVsaW5lLnByb3RvdHlwZSA9IHtcblx0c2xvdEluZGV4OiAwLFxuXHRhdHRhY2htZW50OiAwLFxuXHRnZXRGcmFtZUNvdW50OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZnJhbWVzLmxlbmd0aDtcblx0fSxcblx0c2V0RnJhbWU6IGZ1bmN0aW9uIChmcmFtZUluZGV4LCB0aW1lLCB2ZXJ0aWNlcykge1xuXHRcdHRoaXMuZnJhbWVzW2ZyYW1lSW5kZXhdID0gdGltZTtcblx0XHR0aGlzLmZyYW1lVmVydGljZXNbZnJhbWVJbmRleF0gPSB2ZXJ0aWNlcztcblx0fSxcblx0YXBwbHk6IGZ1bmN0aW9uIChza2VsZXRvbiwgbGFzdFRpbWUsIHRpbWUsIGZpcmVkRXZlbnRzLCBhbHBoYSkge1xuXHRcdHZhciBzbG90ID0gc2tlbGV0b24uc2xvdHNbdGhpcy5zbG90SW5kZXhdO1xuXHRcdGlmIChzbG90LmF0dGFjaG1lbnQgIT0gdGhpcy5hdHRhY2htZW50KSByZXR1cm47XG5cblx0XHR2YXIgZnJhbWVzID0gdGhpcy5mcmFtZXM7XG5cdFx0aWYgKHRpbWUgPCBmcmFtZXNbMF0pIHJldHVybjsgLy8gVGltZSBpcyBiZWZvcmUgZmlyc3QgZnJhbWUuXG5cblx0XHR2YXIgZnJhbWVWZXJ0aWNlcyA9IHRoaXMuZnJhbWVWZXJ0aWNlcztcblx0XHR2YXIgdmVydGV4Q291bnQgPSBmcmFtZVZlcnRpY2VzWzBdLmxlbmd0aDtcblxuXHRcdHZhciB2ZXJ0aWNlcyA9IHNsb3QuYXR0YWNobWVudFZlcnRpY2VzO1xuXHRcdGlmICh2ZXJ0aWNlcy5sZW5ndGggIT0gdmVydGV4Q291bnQpIGFscGhhID0gMTtcblx0XHR2ZXJ0aWNlcy5sZW5ndGggPSB2ZXJ0ZXhDb3VudDtcblxuXHRcdGlmICh0aW1lID49IGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMV0pIHsgLy8gVGltZSBpcyBhZnRlciBsYXN0IGZyYW1lLlxuXHRcdFx0dmFyIGxhc3RWZXJ0aWNlcyA9IGZyYW1lVmVydGljZXNbZnJhbWVzLmxlbmd0aCAtIDFdO1xuXHRcdFx0aWYgKGFscGhhIDwgMSkge1xuXHRcdFx0XHRmb3IgKHZhciBpID0gMDsgaSA8IHZlcnRleENvdW50OyBpKyspXG5cdFx0XHRcdFx0dmVydGljZXNbaV0gKz0gKGxhc3RWZXJ0aWNlc1tpXSAtIHZlcnRpY2VzW2ldKSAqIGFscGhhO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCB2ZXJ0ZXhDb3VudDsgaSsrKVxuXHRcdFx0XHRcdHZlcnRpY2VzW2ldID0gbGFzdFZlcnRpY2VzW2ldO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIEludGVycG9sYXRlIGJldHdlZW4gdGhlIHByZXZpb3VzIGZyYW1lIGFuZCB0aGUgY3VycmVudCBmcmFtZS5cblx0XHR2YXIgZnJhbWVJbmRleCA9IHNwaW5lLkFuaW1hdGlvbi5iaW5hcnlTZWFyY2gxKGZyYW1lcywgdGltZSk7XG5cdFx0dmFyIGZyYW1lVGltZSA9IGZyYW1lc1tmcmFtZUluZGV4XTtcblx0XHR2YXIgcGVyY2VudCA9IDEgLSAodGltZSAtIGZyYW1lVGltZSkgLyAoZnJhbWVzW2ZyYW1lSW5kZXggLSAxXSAtIGZyYW1lVGltZSk7XG5cdFx0cGVyY2VudCA9IHRoaXMuY3VydmVzLmdldEN1cnZlUGVyY2VudChmcmFtZUluZGV4IC0gMSwgcGVyY2VudCA8IDAgPyAwIDogKHBlcmNlbnQgPiAxID8gMSA6IHBlcmNlbnQpKTtcblxuXHRcdHZhciBwcmV2VmVydGljZXMgPSBmcmFtZVZlcnRpY2VzW2ZyYW1lSW5kZXggLSAxXTtcblx0XHR2YXIgbmV4dFZlcnRpY2VzID0gZnJhbWVWZXJ0aWNlc1tmcmFtZUluZGV4XTtcblxuXHRcdGlmIChhbHBoYSA8IDEpIHtcblx0XHRcdGZvciAodmFyIGkgPSAwOyBpIDwgdmVydGV4Q291bnQ7IGkrKykge1xuXHRcdFx0XHR2YXIgcHJldiA9IHByZXZWZXJ0aWNlc1tpXTtcblx0XHRcdFx0dmVydGljZXNbaV0gKz0gKHByZXYgKyAobmV4dFZlcnRpY2VzW2ldIC0gcHJldikgKiBwZXJjZW50IC0gdmVydGljZXNbaV0pICogYWxwaGE7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdGZvciAodmFyIGkgPSAwOyBpIDwgdmVydGV4Q291bnQ7IGkrKykge1xuXHRcdFx0XHR2YXIgcHJldiA9IHByZXZWZXJ0aWNlc1tpXTtcblx0XHRcdFx0dmVydGljZXNbaV0gPSBwcmV2ICsgKG5leHRWZXJ0aWNlc1tpXSAtIHByZXYpICogcGVyY2VudDtcblx0XHRcdH1cblx0XHR9XG5cdH1cbn07XG5cbnNwaW5lLklrQ29uc3RyYWludFRpbWVsaW5lID0gZnVuY3Rpb24gKGZyYW1lQ291bnQpIHtcblx0dGhpcy5jdXJ2ZXMgPSBuZXcgc3BpbmUuQ3VydmVzKGZyYW1lQ291bnQpO1xuXHR0aGlzLmZyYW1lcyA9IFtdOyAvLyB0aW1lLCBtaXgsIGJlbmREaXJlY3Rpb24sIC4uLlxuXHR0aGlzLmZyYW1lcy5sZW5ndGggPSBmcmFtZUNvdW50ICogMztcbn07XG5zcGluZS5Ja0NvbnN0cmFpbnRUaW1lbGluZS5wcm90b3R5cGUgPSB7XG5cdGlrQ29uc3RyYWludEluZGV4OiAwLFxuXHRnZXRGcmFtZUNvdW50OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuZnJhbWVzLmxlbmd0aCAvIDM7XG5cdH0sXG5cdHNldEZyYW1lOiBmdW5jdGlvbiAoZnJhbWVJbmRleCwgdGltZSwgbWl4LCBiZW5kRGlyZWN0aW9uKSB7XG5cdFx0ZnJhbWVJbmRleCAqPSAzO1xuXHRcdHRoaXMuZnJhbWVzW2ZyYW1lSW5kZXhdID0gdGltZTtcblx0XHR0aGlzLmZyYW1lc1tmcmFtZUluZGV4ICsgMV0gPSBtaXg7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleCArIDJdID0gYmVuZERpcmVjdGlvbjtcblx0fSxcblx0YXBwbHk6IGZ1bmN0aW9uIChza2VsZXRvbiwgbGFzdFRpbWUsIHRpbWUsIGZpcmVkRXZlbnRzLCBhbHBoYSkge1xuXHRcdHZhciBmcmFtZXMgPSB0aGlzLmZyYW1lcztcblx0XHRpZiAodGltZSA8IGZyYW1lc1swXSkgcmV0dXJuOyAvLyBUaW1lIGlzIGJlZm9yZSBmaXJzdCBmcmFtZS5cblxuXHRcdHZhciBpa0NvbnN0cmFpbnQgPSBza2VsZXRvbi5pa0NvbnN0cmFpbnRzW3RoaXMuaWtDb25zdHJhaW50SW5kZXhdO1xuXG5cdFx0aWYgKHRpbWUgPj0gZnJhbWVzW2ZyYW1lcy5sZW5ndGggLSAzXSkgeyAvLyBUaW1lIGlzIGFmdGVyIGxhc3QgZnJhbWUuXG5cdFx0XHRpa0NvbnN0cmFpbnQubWl4ICs9IChmcmFtZXNbZnJhbWVzLmxlbmd0aCAtIDJdIC0gaWtDb25zdHJhaW50Lm1peCkgKiBhbHBoYTtcblx0XHRcdGlrQ29uc3RyYWludC5iZW5kRGlyZWN0aW9uID0gZnJhbWVzW2ZyYW1lcy5sZW5ndGggLSAxXTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBJbnRlcnBvbGF0ZSBiZXR3ZWVuIHRoZSBwcmV2aW91cyBmcmFtZSBhbmQgdGhlIGN1cnJlbnQgZnJhbWUuXG5cdFx0dmFyIGZyYW1lSW5kZXggPSBzcGluZS5BbmltYXRpb24uYmluYXJ5U2VhcmNoKGZyYW1lcywgdGltZSwgMyk7XG5cdFx0dmFyIHByZXZGcmFtZU1peCA9IGZyYW1lc1tmcmFtZUluZGV4ICsgLTIvKlBSRVZfRlJBTUVfTUlYKi9dO1xuXHRcdHZhciBmcmFtZVRpbWUgPSBmcmFtZXNbZnJhbWVJbmRleF07XG5cdFx0dmFyIHBlcmNlbnQgPSAxIC0gKHRpbWUgLSBmcmFtZVRpbWUpIC8gKGZyYW1lc1tmcmFtZUluZGV4ICsgLTMvKlBSRVZfRlJBTUVfVElNRSovXSAtIGZyYW1lVGltZSk7XG5cdFx0cGVyY2VudCA9IHRoaXMuY3VydmVzLmdldEN1cnZlUGVyY2VudChmcmFtZUluZGV4IC8gMyAtIDEsIHBlcmNlbnQpO1xuXG5cdFx0dmFyIG1peCA9IHByZXZGcmFtZU1peCArIChmcmFtZXNbZnJhbWVJbmRleCArIDEvKkZSQU1FX01JWCovXSAtIHByZXZGcmFtZU1peCkgKiBwZXJjZW50O1xuXHRcdGlrQ29uc3RyYWludC5taXggKz0gKG1peCAtIGlrQ29uc3RyYWludC5taXgpICogYWxwaGE7XG5cdFx0aWtDb25zdHJhaW50LmJlbmREaXJlY3Rpb24gPSBmcmFtZXNbZnJhbWVJbmRleCArIC0xLypQUkVWX0ZSQU1FX0JFTkRfRElSRUNUSU9OKi9dO1xuXHR9XG59O1xuXG5zcGluZS5GbGlwWFRpbWVsaW5lID0gZnVuY3Rpb24gKGZyYW1lQ291bnQpIHtcblx0dGhpcy5jdXJ2ZXMgPSBuZXcgc3BpbmUuQ3VydmVzKGZyYW1lQ291bnQpO1xuXHR0aGlzLmZyYW1lcyA9IFtdOyAvLyB0aW1lLCBmbGlwLCAuLi5cblx0dGhpcy5mcmFtZXMubGVuZ3RoID0gZnJhbWVDb3VudCAqIDI7XG59O1xuc3BpbmUuRmxpcFhUaW1lbGluZS5wcm90b3R5cGUgPSB7XG5cdGJvbmVJbmRleDogMCxcblx0Z2V0RnJhbWVDb3VudDogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLmZyYW1lcy5sZW5ndGggLyAyO1xuXHR9LFxuXHRzZXRGcmFtZTogZnVuY3Rpb24gKGZyYW1lSW5kZXgsIHRpbWUsIGZsaXApIHtcblx0XHRmcmFtZUluZGV4ICo9IDI7XG5cdFx0dGhpcy5mcmFtZXNbZnJhbWVJbmRleF0gPSB0aW1lO1xuXHRcdHRoaXMuZnJhbWVzW2ZyYW1lSW5kZXggKyAxXSA9IGZsaXAgPyAxIDogMDtcblx0fSxcblx0YXBwbHk6IGZ1bmN0aW9uIChza2VsZXRvbiwgbGFzdFRpbWUsIHRpbWUsIGZpcmVkRXZlbnRzLCBhbHBoYSkge1xuXHRcdHZhciBmcmFtZXMgPSB0aGlzLmZyYW1lcztcblx0XHRpZiAodGltZSA8IGZyYW1lc1swXSkge1xuXHRcdFx0aWYgKGxhc3RUaW1lID4gdGltZSkgdGhpcy5hcHBseShza2VsZXRvbiwgbGFzdFRpbWUsIE51bWJlci5NQVhfVkFMVUUsIG51bGwsIDApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH0gZWxzZSBpZiAobGFzdFRpbWUgPiB0aW1lKSAvL1xuXHRcdFx0bGFzdFRpbWUgPSAtMTtcblx0XHR2YXIgZnJhbWVJbmRleCA9ICh0aW1lID49IGZyYW1lc1tmcmFtZXMubGVuZ3RoIC0gMl0gPyBmcmFtZXMubGVuZ3RoIDogc3BpbmUuQW5pbWF0aW9uLmJpbmFyeVNlYXJjaChmcmFtZXMsIHRpbWUsIDIpKSAtIDI7XG5cdFx0aWYgKGZyYW1lc1tmcmFtZUluZGV4XSA8IGxhc3RUaW1lKSByZXR1cm47XG5cdFx0c2tlbGV0b24uYm9uZXNbYm9uZUluZGV4XS5mbGlwWCA9IGZyYW1lc1tmcmFtZUluZGV4ICsgMV0gIT0gMDtcblx0fVxufTtcblxuc3BpbmUuRmxpcFlUaW1lbGluZSA9IGZ1bmN0aW9uIChmcmFtZUNvdW50KSB7XG5cdHRoaXMuY3VydmVzID0gbmV3IHNwaW5lLkN1cnZlcyhmcmFtZUNvdW50KTtcblx0dGhpcy5mcmFtZXMgPSBbXTsgLy8gdGltZSwgZmxpcCwgLi4uXG5cdHRoaXMuZnJhbWVzLmxlbmd0aCA9IGZyYW1lQ291bnQgKiAyO1xufTtcbnNwaW5lLkZsaXBZVGltZWxpbmUucHJvdG90eXBlID0ge1xuXHRib25lSW5kZXg6IDAsXG5cdGdldEZyYW1lQ291bnQ6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5mcmFtZXMubGVuZ3RoIC8gMjtcblx0fSxcblx0c2V0RnJhbWU6IGZ1bmN0aW9uIChmcmFtZUluZGV4LCB0aW1lLCBmbGlwKSB7XG5cdFx0ZnJhbWVJbmRleCAqPSAyO1xuXHRcdHRoaXMuZnJhbWVzW2ZyYW1lSW5kZXhdID0gdGltZTtcblx0XHR0aGlzLmZyYW1lc1tmcmFtZUluZGV4ICsgMV0gPSBmbGlwID8gMSA6IDA7XG5cdH0sXG5cdGFwcGx5OiBmdW5jdGlvbiAoc2tlbGV0b24sIGxhc3RUaW1lLCB0aW1lLCBmaXJlZEV2ZW50cywgYWxwaGEpIHtcblx0XHR2YXIgZnJhbWVzID0gdGhpcy5mcmFtZXM7XG5cdFx0aWYgKHRpbWUgPCBmcmFtZXNbMF0pIHtcblx0XHRcdGlmIChsYXN0VGltZSA+IHRpbWUpIHRoaXMuYXBwbHkoc2tlbGV0b24sIGxhc3RUaW1lLCBOdW1iZXIuTUFYX1ZBTFVFLCBudWxsLCAwKTtcblx0XHRcdHJldHVybjtcblx0XHR9IGVsc2UgaWYgKGxhc3RUaW1lID4gdGltZSkgLy9cblx0XHRcdGxhc3RUaW1lID0gLTE7XG5cdFx0dmFyIGZyYW1lSW5kZXggPSAodGltZSA+PSBmcmFtZXNbZnJhbWVzLmxlbmd0aCAtIDJdID8gZnJhbWVzLmxlbmd0aCA6IHNwaW5lLkFuaW1hdGlvbi5iaW5hcnlTZWFyY2goZnJhbWVzLCB0aW1lLCAyKSkgLSAyO1xuXHRcdGlmIChmcmFtZXNbZnJhbWVJbmRleF0gPCBsYXN0VGltZSkgcmV0dXJuO1xuXHRcdHNrZWxldG9uLmJvbmVzW2JvbmVJbmRleF0uZmxpcFkgPSBmcmFtZXNbZnJhbWVJbmRleCArIDFdICE9IDA7XG5cdH1cbn07XG5cbnNwaW5lLlNrZWxldG9uRGF0YSA9IGZ1bmN0aW9uICgpIHtcblx0dGhpcy5ib25lcyA9IFtdO1xuXHR0aGlzLnNsb3RzID0gW107XG5cdHRoaXMuc2tpbnMgPSBbXTtcblx0dGhpcy5ldmVudHMgPSBbXTtcblx0dGhpcy5hbmltYXRpb25zID0gW107XG5cdHRoaXMuaWtDb25zdHJhaW50cyA9IFtdO1xufTtcbnNwaW5lLlNrZWxldG9uRGF0YS5wcm90b3R5cGUgPSB7XG5cdG5hbWU6IG51bGwsXG5cdGRlZmF1bHRTa2luOiBudWxsLFxuXHR3aWR0aDogMCwgaGVpZ2h0OiAwLFxuXHR2ZXJzaW9uOiBudWxsLCBoYXNoOiBudWxsLFxuXHQvKiogQHJldHVybiBNYXkgYmUgbnVsbC4gKi9cblx0ZmluZEJvbmU6IGZ1bmN0aW9uIChib25lTmFtZSkge1xuXHRcdHZhciBib25lcyA9IHRoaXMuYm9uZXM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBib25lcy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRpZiAoYm9uZXNbaV0ubmFtZSA9PSBib25lTmFtZSkgcmV0dXJuIGJvbmVzW2ldO1xuXHRcdHJldHVybiBudWxsO1xuXHR9LFxuXHQvKiogQHJldHVybiAtMSBpZiB0aGUgYm9uZSB3YXMgbm90IGZvdW5kLiAqL1xuXHRmaW5kQm9uZUluZGV4OiBmdW5jdGlvbiAoYm9uZU5hbWUpIHtcblx0XHR2YXIgYm9uZXMgPSB0aGlzLmJvbmVzO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gYm9uZXMubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0aWYgKGJvbmVzW2ldLm5hbWUgPT0gYm9uZU5hbWUpIHJldHVybiBpO1xuXHRcdHJldHVybiAtMTtcblx0fSxcblx0LyoqIEByZXR1cm4gTWF5IGJlIG51bGwuICovXG5cdGZpbmRTbG90OiBmdW5jdGlvbiAoc2xvdE5hbWUpIHtcblx0XHR2YXIgc2xvdHMgPSB0aGlzLnNsb3RzO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gc2xvdHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRpZiAoc2xvdHNbaV0ubmFtZSA9PSBzbG90TmFtZSkgcmV0dXJuIHNsb3RbaV07XG5cdFx0fVxuXHRcdHJldHVybiBudWxsO1xuXHR9LFxuXHQvKiogQHJldHVybiAtMSBpZiB0aGUgYm9uZSB3YXMgbm90IGZvdW5kLiAqL1xuXHRmaW5kU2xvdEluZGV4OiBmdW5jdGlvbiAoc2xvdE5hbWUpIHtcblx0XHR2YXIgc2xvdHMgPSB0aGlzLnNsb3RzO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gc2xvdHMubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0aWYgKHNsb3RzW2ldLm5hbWUgPT0gc2xvdE5hbWUpIHJldHVybiBpO1xuXHRcdHJldHVybiAtMTtcblx0fSxcblx0LyoqIEByZXR1cm4gTWF5IGJlIG51bGwuICovXG5cdGZpbmRTa2luOiBmdW5jdGlvbiAoc2tpbk5hbWUpIHtcblx0XHR2YXIgc2tpbnMgPSB0aGlzLnNraW5zO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gc2tpbnMubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0aWYgKHNraW5zW2ldLm5hbWUgPT0gc2tpbk5hbWUpIHJldHVybiBza2luc1tpXTtcblx0XHRyZXR1cm4gbnVsbDtcblx0fSxcblx0LyoqIEByZXR1cm4gTWF5IGJlIG51bGwuICovXG5cdGZpbmRFdmVudDogZnVuY3Rpb24gKGV2ZW50TmFtZSkge1xuXHRcdHZhciBldmVudHMgPSB0aGlzLmV2ZW50cztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IGV2ZW50cy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRpZiAoZXZlbnRzW2ldLm5hbWUgPT0gZXZlbnROYW1lKSByZXR1cm4gZXZlbnRzW2ldO1xuXHRcdHJldHVybiBudWxsO1xuXHR9LFxuXHQvKiogQHJldHVybiBNYXkgYmUgbnVsbC4gKi9cblx0ZmluZEFuaW1hdGlvbjogZnVuY3Rpb24gKGFuaW1hdGlvbk5hbWUpIHtcblx0XHR2YXIgYW5pbWF0aW9ucyA9IHRoaXMuYW5pbWF0aW9ucztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IGFuaW1hdGlvbnMubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0aWYgKGFuaW1hdGlvbnNbaV0ubmFtZSA9PSBhbmltYXRpb25OYW1lKSByZXR1cm4gYW5pbWF0aW9uc1tpXTtcblx0XHRyZXR1cm4gbnVsbDtcblx0fSxcblx0LyoqIEByZXR1cm4gTWF5IGJlIG51bGwuICovXG5cdGZpbmRJa0NvbnN0cmFpbnQ6IGZ1bmN0aW9uIChpa0NvbnN0cmFpbnROYW1lKSB7XG5cdFx0dmFyIGlrQ29uc3RyYWludHMgPSB0aGlzLmlrQ29uc3RyYWludHM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBpa0NvbnN0cmFpbnRzLmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdGlmIChpa0NvbnN0cmFpbnRzW2ldLm5hbWUgPT0gaWtDb25zdHJhaW50TmFtZSkgcmV0dXJuIGlrQ29uc3RyYWludHNbaV07XG5cdFx0cmV0dXJuIG51bGw7XG5cdH1cbn07XG5cbnNwaW5lLlNrZWxldG9uID0gZnVuY3Rpb24gKHNrZWxldG9uRGF0YSkge1xuXHR0aGlzLmRhdGEgPSBza2VsZXRvbkRhdGE7XG5cblx0dGhpcy5ib25lcyA9IFtdO1xuXHRmb3IgKHZhciBpID0gMCwgbiA9IHNrZWxldG9uRGF0YS5ib25lcy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcblx0XHR2YXIgYm9uZURhdGEgPSBza2VsZXRvbkRhdGEuYm9uZXNbaV07XG5cdFx0dmFyIHBhcmVudCA9ICFib25lRGF0YS5wYXJlbnQgPyBudWxsIDogdGhpcy5ib25lc1tza2VsZXRvbkRhdGEuYm9uZXMuaW5kZXhPZihib25lRGF0YS5wYXJlbnQpXTtcblx0XHR0aGlzLmJvbmVzLnB1c2gobmV3IHNwaW5lLkJvbmUoYm9uZURhdGEsIHRoaXMsIHBhcmVudCkpO1xuXHR9XG5cblx0dGhpcy5zbG90cyA9IFtdO1xuXHR0aGlzLmRyYXdPcmRlciA9IFtdO1xuXHRmb3IgKHZhciBpID0gMCwgbiA9IHNrZWxldG9uRGF0YS5zbG90cy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcblx0XHR2YXIgc2xvdERhdGEgPSBza2VsZXRvbkRhdGEuc2xvdHNbaV07XG5cdFx0dmFyIGJvbmUgPSB0aGlzLmJvbmVzW3NrZWxldG9uRGF0YS5ib25lcy5pbmRleE9mKHNsb3REYXRhLmJvbmVEYXRhKV07XG5cdFx0dmFyIHNsb3QgPSBuZXcgc3BpbmUuU2xvdChzbG90RGF0YSwgYm9uZSk7XG5cdFx0dGhpcy5zbG90cy5wdXNoKHNsb3QpO1xuXHRcdHRoaXMuZHJhd09yZGVyLnB1c2goc2xvdCk7XG5cdH1cblxuXHR0aGlzLmlrQ29uc3RyYWludHMgPSBbXTtcblx0Zm9yICh2YXIgaSA9IDAsIG4gPSBza2VsZXRvbkRhdGEuaWtDb25zdHJhaW50cy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0dGhpcy5pa0NvbnN0cmFpbnRzLnB1c2gobmV3IHNwaW5lLklrQ29uc3RyYWludChza2VsZXRvbkRhdGEuaWtDb25zdHJhaW50c1tpXSwgdGhpcykpO1xuXG5cdHRoaXMuYm9uZUNhY2hlID0gW107XG5cdHRoaXMudXBkYXRlQ2FjaGUoKTtcbn07XG5zcGluZS5Ta2VsZXRvbi5wcm90b3R5cGUgPSB7XG5cdHg6IDAsIHk6IDAsXG5cdHNraW46IG51bGwsXG5cdHI6IDEsIGc6IDEsIGI6IDEsIGE6IDEsXG5cdHRpbWU6IDAsXG5cdGZsaXBYOiBmYWxzZSwgZmxpcFk6IGZhbHNlLFxuXHQvKiogQ2FjaGVzIGluZm9ybWF0aW9uIGFib3V0IGJvbmVzIGFuZCBJSyBjb25zdHJhaW50cy4gTXVzdCBiZSBjYWxsZWQgaWYgYm9uZXMgb3IgSUsgY29uc3RyYWludHMgYXJlIGFkZGVkIG9yIHJlbW92ZWQuICovXG5cdHVwZGF0ZUNhY2hlOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGlrQ29uc3RyYWludHMgPSB0aGlzLmlrQ29uc3RyYWludHM7XG5cdFx0dmFyIGlrQ29uc3RyYWludHNDb3VudCA9IGlrQ29uc3RyYWludHMubGVuZ3RoO1xuXG5cdFx0dmFyIGFycmF5Q291bnQgPSBpa0NvbnN0cmFpbnRzQ291bnQgKyAxO1xuXHRcdHZhciBib25lQ2FjaGUgPSB0aGlzLmJvbmVDYWNoZTtcblx0XHRpZiAoYm9uZUNhY2hlLmxlbmd0aCA+IGFycmF5Q291bnQpIGJvbmVDYWNoZS5sZW5ndGggPSBhcnJheUNvdW50O1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gYm9uZUNhY2hlLmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdGJvbmVDYWNoZVtpXS5sZW5ndGggPSAwO1xuXHRcdHdoaWxlIChib25lQ2FjaGUubGVuZ3RoIDwgYXJyYXlDb3VudClcblx0XHRcdGJvbmVDYWNoZVtib25lQ2FjaGUubGVuZ3RoXSA9IFtdO1xuXG5cdFx0dmFyIG5vbklrQm9uZXMgPSBib25lQ2FjaGVbMF07XG5cdFx0dmFyIGJvbmVzID0gdGhpcy5ib25lcztcblxuXHRcdG91dGVyOlxuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gYm9uZXMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHR2YXIgYm9uZSA9IGJvbmVzW2ldO1xuXHRcdFx0dmFyIGN1cnJlbnQgPSBib25lO1xuXHRcdFx0ZG8ge1xuXHRcdFx0XHRmb3IgKHZhciBpaSA9IDA7IGlpIDwgaWtDb25zdHJhaW50c0NvdW50OyBpaSsrKSB7XG5cdFx0XHRcdFx0dmFyIGlrQ29uc3RyYWludCA9IGlrQ29uc3RyYWludHNbaWldO1xuXHRcdFx0XHRcdHZhciBwYXJlbnQgPSBpa0NvbnN0cmFpbnQuYm9uZXNbMF07XG5cdFx0XHRcdFx0dmFyIGNoaWxkPSBpa0NvbnN0cmFpbnQuYm9uZXNbaWtDb25zdHJhaW50LmJvbmVzLmxlbmd0aCAtIDFdO1xuXHRcdFx0XHRcdHdoaWxlICh0cnVlKSB7XG5cdFx0XHRcdFx0XHRpZiAoY3VycmVudCA9PSBjaGlsZCkge1xuXHRcdFx0XHRcdFx0XHRib25lQ2FjaGVbaWldLnB1c2goYm9uZSk7XG5cdFx0XHRcdFx0XHRcdGJvbmVDYWNoZVtpaSArIDFdLnB1c2goYm9uZSk7XG5cdFx0XHRcdFx0XHRcdGNvbnRpbnVlIG91dGVyO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aWYgKGNoaWxkID09IHBhcmVudCkgYnJlYWs7XG5cdFx0XHRcdFx0XHRjaGlsZCA9IGNoaWxkLnBhcmVudDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0Y3VycmVudCA9IGN1cnJlbnQucGFyZW50O1xuXHRcdFx0fSB3aGlsZSAoY3VycmVudCk7XG5cdFx0XHRub25Ja0JvbmVzW25vbklrQm9uZXMubGVuZ3RoXSA9IGJvbmU7XG5cdFx0fVxuXHR9LFxuXHQvKiogVXBkYXRlcyB0aGUgd29ybGQgdHJhbnNmb3JtIGZvciBlYWNoIGJvbmUuICovXG5cdHVwZGF0ZVdvcmxkVHJhbnNmb3JtOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGJvbmVzID0gdGhpcy5ib25lcztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IGJvbmVzLmxlbmd0aDsgaSA8IG47IGkrKykge1xuXHRcdFx0dmFyIGJvbmUgPSBib25lc1tpXTtcblx0XHRcdGJvbmUucm90YXRpb25JSyA9IGJvbmUucm90YXRpb247XG5cdFx0fVxuXHRcdHZhciBpID0gMCwgbGFzdCA9IHRoaXMuYm9uZUNhY2hlLmxlbmd0aCAtIDE7XG5cdFx0d2hpbGUgKHRydWUpIHtcblx0XHRcdHZhciBjYWNoZUJvbmVzID0gdGhpcy5ib25lQ2FjaGVbaV07XG5cdFx0XHRmb3IgKHZhciBpaSA9IDAsIG5uID0gY2FjaGVCb25lcy5sZW5ndGg7IGlpIDwgbm47IGlpKyspXG5cdFx0XHRcdGNhY2hlQm9uZXNbaWldLnVwZGF0ZVdvcmxkVHJhbnNmb3JtKCk7XG5cdFx0XHRpZiAoaSA9PSBsYXN0KSBicmVhaztcblx0XHRcdHRoaXMuaWtDb25zdHJhaW50c1tpXS5hcHBseSgpO1xuXHRcdFx0aSsrO1xuXHRcdH1cblx0fSxcblx0LyoqIFNldHMgdGhlIGJvbmVzIGFuZCBzbG90cyB0byB0aGVpciBzZXR1cCBwb3NlIHZhbHVlcy4gKi9cblx0c2V0VG9TZXR1cFBvc2U6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLnNldEJvbmVzVG9TZXR1cFBvc2UoKTtcblx0XHR0aGlzLnNldFNsb3RzVG9TZXR1cFBvc2UoKTtcblx0fSxcblx0c2V0Qm9uZXNUb1NldHVwUG9zZTogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBib25lcyA9IHRoaXMuYm9uZXM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBib25lcy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRib25lc1tpXS5zZXRUb1NldHVwUG9zZSgpO1xuXG5cdFx0dmFyIGlrQ29uc3RyYWludHMgPSB0aGlzLmlrQ29uc3RyYWludHM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBpa0NvbnN0cmFpbnRzLmxlbmd0aDsgaSA8IG47IGkrKykge1xuXHRcdFx0dmFyIGlrQ29uc3RyYWludCA9IGlrQ29uc3RyYWludHNbaV07XG5cdFx0XHRpa0NvbnN0cmFpbnQuYmVuZERpcmVjdGlvbiA9IGlrQ29uc3RyYWludC5kYXRhLmJlbmREaXJlY3Rpb247XG5cdFx0XHRpa0NvbnN0cmFpbnQubWl4ID0gaWtDb25zdHJhaW50LmRhdGEubWl4O1xuXHRcdH1cblx0fSxcblx0c2V0U2xvdHNUb1NldHVwUG9zZTogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBzbG90cyA9IHRoaXMuc2xvdHM7XG5cdFx0dmFyIGRyYXdPcmRlciA9IHRoaXMuZHJhd09yZGVyO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gc2xvdHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRkcmF3T3JkZXJbaV0gPSBzbG90c1tpXTtcblx0XHRcdHNsb3RzW2ldLnNldFRvU2V0dXBQb3NlKGkpO1xuXHRcdH1cblx0fSxcblx0LyoqIEByZXR1cm4gTWF5IHJldHVybiBudWxsLiAqL1xuXHRnZXRSb290Qm9uZTogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLmJvbmVzLmxlbmd0aCA/IHRoaXMuYm9uZXNbMF0gOiBudWxsO1xuXHR9LFxuXHQvKiogQHJldHVybiBNYXkgYmUgbnVsbC4gKi9cblx0ZmluZEJvbmU6IGZ1bmN0aW9uIChib25lTmFtZSkge1xuXHRcdHZhciBib25lcyA9IHRoaXMuYm9uZXM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBib25lcy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRpZiAoYm9uZXNbaV0uZGF0YS5uYW1lID09IGJvbmVOYW1lKSByZXR1cm4gYm9uZXNbaV07XG5cdFx0cmV0dXJuIG51bGw7XG5cdH0sXG5cdC8qKiBAcmV0dXJuIC0xIGlmIHRoZSBib25lIHdhcyBub3QgZm91bmQuICovXG5cdGZpbmRCb25lSW5kZXg6IGZ1bmN0aW9uIChib25lTmFtZSkge1xuXHRcdHZhciBib25lcyA9IHRoaXMuYm9uZXM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBib25lcy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRpZiAoYm9uZXNbaV0uZGF0YS5uYW1lID09IGJvbmVOYW1lKSByZXR1cm4gaTtcblx0XHRyZXR1cm4gLTE7XG5cdH0sXG5cdC8qKiBAcmV0dXJuIE1heSBiZSBudWxsLiAqL1xuXHRmaW5kU2xvdDogZnVuY3Rpb24gKHNsb3ROYW1lKSB7XG5cdFx0dmFyIHNsb3RzID0gdGhpcy5zbG90cztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHNsb3RzLmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdGlmIChzbG90c1tpXS5kYXRhLm5hbWUgPT0gc2xvdE5hbWUpIHJldHVybiBzbG90c1tpXTtcblx0XHRyZXR1cm4gbnVsbDtcblx0fSxcblx0LyoqIEByZXR1cm4gLTEgaWYgdGhlIGJvbmUgd2FzIG5vdCBmb3VuZC4gKi9cblx0ZmluZFNsb3RJbmRleDogZnVuY3Rpb24gKHNsb3ROYW1lKSB7XG5cdFx0dmFyIHNsb3RzID0gdGhpcy5zbG90cztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHNsb3RzLmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdGlmIChzbG90c1tpXS5kYXRhLm5hbWUgPT0gc2xvdE5hbWUpIHJldHVybiBpO1xuXHRcdHJldHVybiAtMTtcblx0fSxcblx0c2V0U2tpbkJ5TmFtZTogZnVuY3Rpb24gKHNraW5OYW1lKSB7XG5cdFx0dmFyIHNraW4gPSB0aGlzLmRhdGEuZmluZFNraW4oc2tpbk5hbWUpO1xuXHRcdGlmICghc2tpbikgdGhyb3cgXCJTa2luIG5vdCBmb3VuZDogXCIgKyBza2luTmFtZTtcblx0XHR0aGlzLnNldFNraW4oc2tpbik7XG5cdH0sXG5cdC8qKiBTZXRzIHRoZSBza2luIHVzZWQgdG8gbG9vayB1cCBhdHRhY2htZW50cyBiZWZvcmUgbG9va2luZyBpbiB0aGUge0BsaW5rIFNrZWxldG9uRGF0YSNnZXREZWZhdWx0U2tpbigpIGRlZmF1bHQgc2tpbn0uXG5cdCAqIEF0dGFjaG1lbnRzIGZyb20gdGhlIG5ldyBza2luIGFyZSBhdHRhY2hlZCBpZiB0aGUgY29ycmVzcG9uZGluZyBhdHRhY2htZW50IGZyb20gdGhlIG9sZCBza2luIHdhcyBhdHRhY2hlZC4gSWYgdGhlcmUgd2FzXG5cdCAqIG5vIG9sZCBza2luLCBlYWNoIHNsb3QncyBzZXR1cCBtb2RlIGF0dGFjaG1lbnQgaXMgYXR0YWNoZWQgZnJvbSB0aGUgbmV3IHNraW4uXG5cdCAqIEBwYXJhbSBuZXdTa2luIE1heSBiZSBudWxsLiAqL1xuXHRzZXRTa2luOiBmdW5jdGlvbiAobmV3U2tpbikge1xuXHRcdGlmIChuZXdTa2luKSB7XG5cdFx0XHRpZiAodGhpcy5za2luKVxuXHRcdFx0XHRuZXdTa2luLl9hdHRhY2hBbGwodGhpcywgdGhpcy5za2luKTtcblx0XHRcdGVsc2Uge1xuXHRcdFx0XHR2YXIgc2xvdHMgPSB0aGlzLnNsb3RzO1xuXHRcdFx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHNsb3RzLmxlbmd0aDsgaSA8IG47IGkrKykge1xuXHRcdFx0XHRcdHZhciBzbG90ID0gc2xvdHNbaV07XG5cdFx0XHRcdFx0dmFyIG5hbWUgPSBzbG90LmRhdGEuYXR0YWNobWVudE5hbWU7XG5cdFx0XHRcdFx0aWYgKG5hbWUpIHtcblx0XHRcdFx0XHRcdHZhciBhdHRhY2htZW50ID0gbmV3U2tpbi5nZXRBdHRhY2htZW50KGksIG5hbWUpO1xuXHRcdFx0XHRcdFx0aWYgKGF0dGFjaG1lbnQpIHNsb3Quc2V0QXR0YWNobWVudChhdHRhY2htZW50KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdFx0dGhpcy5za2luID0gbmV3U2tpbjtcblx0fSxcblx0LyoqIEByZXR1cm4gTWF5IGJlIG51bGwuICovXG5cdGdldEF0dGFjaG1lbnRCeVNsb3ROYW1lOiBmdW5jdGlvbiAoc2xvdE5hbWUsIGF0dGFjaG1lbnROYW1lKSB7XG5cdFx0cmV0dXJuIHRoaXMuZ2V0QXR0YWNobWVudEJ5U2xvdEluZGV4KHRoaXMuZGF0YS5maW5kU2xvdEluZGV4KHNsb3ROYW1lKSwgYXR0YWNobWVudE5hbWUpO1xuXHR9LFxuXHQvKiogQHJldHVybiBNYXkgYmUgbnVsbC4gKi9cblx0Z2V0QXR0YWNobWVudEJ5U2xvdEluZGV4OiBmdW5jdGlvbiAoc2xvdEluZGV4LCBhdHRhY2htZW50TmFtZSkge1xuXHRcdGlmICh0aGlzLnNraW4pIHtcblx0XHRcdHZhciBhdHRhY2htZW50ID0gdGhpcy5za2luLmdldEF0dGFjaG1lbnQoc2xvdEluZGV4LCBhdHRhY2htZW50TmFtZSk7XG5cdFx0XHRpZiAoYXR0YWNobWVudCkgcmV0dXJuIGF0dGFjaG1lbnQ7XG5cdFx0fVxuXHRcdGlmICh0aGlzLmRhdGEuZGVmYXVsdFNraW4pIHJldHVybiB0aGlzLmRhdGEuZGVmYXVsdFNraW4uZ2V0QXR0YWNobWVudChzbG90SW5kZXgsIGF0dGFjaG1lbnROYW1lKTtcblx0XHRyZXR1cm4gbnVsbDtcblx0fSxcblx0LyoqIEBwYXJhbSBhdHRhY2htZW50TmFtZSBNYXkgYmUgbnVsbC4gKi9cblx0c2V0QXR0YWNobWVudDogZnVuY3Rpb24gKHNsb3ROYW1lLCBhdHRhY2htZW50TmFtZSkge1xuXHRcdHZhciBzbG90cyA9IHRoaXMuc2xvdHM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBzbG90cy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcblx0XHRcdHZhciBzbG90ID0gc2xvdHNbaV07XG5cdFx0XHRpZiAoc2xvdC5kYXRhLm5hbWUgPT0gc2xvdE5hbWUpIHtcblx0XHRcdFx0dmFyIGF0dGFjaG1lbnQgPSBudWxsO1xuXHRcdFx0XHRpZiAoYXR0YWNobWVudE5hbWUpIHtcblx0XHRcdFx0XHRhdHRhY2htZW50ID0gdGhpcy5nZXRBdHRhY2htZW50QnlTbG90SW5kZXgoaSwgYXR0YWNobWVudE5hbWUpO1xuXHRcdFx0XHRcdGlmICghYXR0YWNobWVudCkgdGhyb3cgXCJBdHRhY2htZW50IG5vdCBmb3VuZDogXCIgKyBhdHRhY2htZW50TmFtZSArIFwiLCBmb3Igc2xvdDogXCIgKyBzbG90TmFtZTtcblx0XHRcdFx0fVxuXHRcdFx0XHRzbG90LnNldEF0dGFjaG1lbnQoYXR0YWNobWVudCk7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblx0XHR9XG5cdFx0dGhyb3cgXCJTbG90IG5vdCBmb3VuZDogXCIgKyBzbG90TmFtZTtcblx0fSxcblx0LyoqIEByZXR1cm4gTWF5IGJlIG51bGwuICovXG5cdGZpbmRJa0NvbnN0cmFpbnQ6IGZ1bmN0aW9uIChpa0NvbnN0cmFpbnROYW1lKSB7XG5cdFx0dmFyIGlrQ29uc3RyYWludHMgPSB0aGlzLmlrQ29uc3RyYWludHM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBpa0NvbnN0cmFpbnRzLmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdGlmIChpa0NvbnN0cmFpbnRzW2ldLmRhdGEubmFtZSA9PSBpa0NvbnN0cmFpbnROYW1lKSByZXR1cm4gaWtDb25zdHJhaW50c1tpXTtcblx0XHRyZXR1cm4gbnVsbDtcblx0fSxcblx0dXBkYXRlOiBmdW5jdGlvbiAoZGVsdGEpIHtcblx0XHR0aGlzLnRpbWUgKz0gZGVsdGE7XG5cdH1cbn07XG5cbnNwaW5lLkV2ZW50RGF0YSA9IGZ1bmN0aW9uIChuYW1lKSB7XG5cdHRoaXMubmFtZSA9IG5hbWU7XG59O1xuc3BpbmUuRXZlbnREYXRhLnByb3RvdHlwZSA9IHtcblx0aW50VmFsdWU6IDAsXG5cdGZsb2F0VmFsdWU6IDAsXG5cdHN0cmluZ1ZhbHVlOiBudWxsXG59O1xuXG5zcGluZS5FdmVudCA9IGZ1bmN0aW9uIChkYXRhKSB7XG5cdHRoaXMuZGF0YSA9IGRhdGE7XG59O1xuc3BpbmUuRXZlbnQucHJvdG90eXBlID0ge1xuXHRpbnRWYWx1ZTogMCxcblx0ZmxvYXRWYWx1ZTogMCxcblx0c3RyaW5nVmFsdWU6IG51bGxcbn07XG5cbnNwaW5lLkF0dGFjaG1lbnRUeXBlID0ge1xuXHRyZWdpb246IDAsXG5cdGJvdW5kaW5nYm94OiAxLFxuXHRtZXNoOiAyLFxuXHRza2lubmVkbWVzaDogM1xufTtcblxuc3BpbmUuUmVnaW9uQXR0YWNobWVudCA9IGZ1bmN0aW9uIChuYW1lKSB7XG5cdHRoaXMubmFtZSA9IG5hbWU7XG5cdHRoaXMub2Zmc2V0ID0gW107XG5cdHRoaXMub2Zmc2V0Lmxlbmd0aCA9IDg7XG5cdHRoaXMudXZzID0gW107XG5cdHRoaXMudXZzLmxlbmd0aCA9IDg7XG59O1xuc3BpbmUuUmVnaW9uQXR0YWNobWVudC5wcm90b3R5cGUgPSB7XG5cdHR5cGU6IHNwaW5lLkF0dGFjaG1lbnRUeXBlLnJlZ2lvbixcblx0eDogMCwgeTogMCxcblx0cm90YXRpb246IDAsXG5cdHNjYWxlWDogMSwgc2NhbGVZOiAxLFxuXHR3aWR0aDogMCwgaGVpZ2h0OiAwLFxuXHRyOiAxLCBnOiAxLCBiOiAxLCBhOiAxLFxuXHRwYXRoOiBudWxsLFxuXHRyZW5kZXJlck9iamVjdDogbnVsbCxcblx0cmVnaW9uT2Zmc2V0WDogMCwgcmVnaW9uT2Zmc2V0WTogMCxcblx0cmVnaW9uV2lkdGg6IDAsIHJlZ2lvbkhlaWdodDogMCxcblx0cmVnaW9uT3JpZ2luYWxXaWR0aDogMCwgcmVnaW9uT3JpZ2luYWxIZWlnaHQ6IDAsXG5cdHNldFVWczogZnVuY3Rpb24gKHUsIHYsIHUyLCB2Miwgcm90YXRlKSB7XG5cdFx0dmFyIHV2cyA9IHRoaXMudXZzO1xuXHRcdGlmIChyb3RhdGUpIHtcblx0XHRcdHV2c1syLypYMiovXSA9IHU7XG5cdFx0XHR1dnNbMy8qWTIqL10gPSB2Mjtcblx0XHRcdHV2c1s0LypYMyovXSA9IHU7XG5cdFx0XHR1dnNbNS8qWTMqL10gPSB2O1xuXHRcdFx0dXZzWzYvKlg0Ki9dID0gdTI7XG5cdFx0XHR1dnNbNy8qWTQqL10gPSB2O1xuXHRcdFx0dXZzWzAvKlgxKi9dID0gdTI7XG5cdFx0XHR1dnNbMS8qWTEqL10gPSB2Mjtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dXZzWzAvKlgxKi9dID0gdTtcblx0XHRcdHV2c1sxLypZMSovXSA9IHYyO1xuXHRcdFx0dXZzWzIvKlgyKi9dID0gdTtcblx0XHRcdHV2c1szLypZMiovXSA9IHY7XG5cdFx0XHR1dnNbNC8qWDMqL10gPSB1Mjtcblx0XHRcdHV2c1s1LypZMyovXSA9IHY7XG5cdFx0XHR1dnNbNi8qWDQqL10gPSB1Mjtcblx0XHRcdHV2c1s3LypZNCovXSA9IHYyO1xuXHRcdH1cblx0fSxcblx0dXBkYXRlT2Zmc2V0OiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIHJlZ2lvblNjYWxlWCA9IHRoaXMud2lkdGggLyB0aGlzLnJlZ2lvbk9yaWdpbmFsV2lkdGggKiB0aGlzLnNjYWxlWDtcblx0XHR2YXIgcmVnaW9uU2NhbGVZID0gdGhpcy5oZWlnaHQgLyB0aGlzLnJlZ2lvbk9yaWdpbmFsSGVpZ2h0ICogdGhpcy5zY2FsZVk7XG5cdFx0dmFyIGxvY2FsWCA9IC10aGlzLndpZHRoIC8gMiAqIHRoaXMuc2NhbGVYICsgdGhpcy5yZWdpb25PZmZzZXRYICogcmVnaW9uU2NhbGVYO1xuXHRcdHZhciBsb2NhbFkgPSAtdGhpcy5oZWlnaHQgLyAyICogdGhpcy5zY2FsZVkgKyB0aGlzLnJlZ2lvbk9mZnNldFkgKiByZWdpb25TY2FsZVk7XG5cdFx0dmFyIGxvY2FsWDIgPSBsb2NhbFggKyB0aGlzLnJlZ2lvbldpZHRoICogcmVnaW9uU2NhbGVYO1xuXHRcdHZhciBsb2NhbFkyID0gbG9jYWxZICsgdGhpcy5yZWdpb25IZWlnaHQgKiByZWdpb25TY2FsZVk7XG5cdFx0dmFyIHJhZGlhbnMgPSB0aGlzLnJvdGF0aW9uICogc3BpbmUuZGVnUmFkO1xuXHRcdHZhciBjb3MgPSBNYXRoLmNvcyhyYWRpYW5zKTtcblx0XHR2YXIgc2luID0gTWF0aC5zaW4ocmFkaWFucyk7XG5cdFx0dmFyIGxvY2FsWENvcyA9IGxvY2FsWCAqIGNvcyArIHRoaXMueDtcblx0XHR2YXIgbG9jYWxYU2luID0gbG9jYWxYICogc2luO1xuXHRcdHZhciBsb2NhbFlDb3MgPSBsb2NhbFkgKiBjb3MgKyB0aGlzLnk7XG5cdFx0dmFyIGxvY2FsWVNpbiA9IGxvY2FsWSAqIHNpbjtcblx0XHR2YXIgbG9jYWxYMkNvcyA9IGxvY2FsWDIgKiBjb3MgKyB0aGlzLng7XG5cdFx0dmFyIGxvY2FsWDJTaW4gPSBsb2NhbFgyICogc2luO1xuXHRcdHZhciBsb2NhbFkyQ29zID0gbG9jYWxZMiAqIGNvcyArIHRoaXMueTtcblx0XHR2YXIgbG9jYWxZMlNpbiA9IGxvY2FsWTIgKiBzaW47XG5cdFx0dmFyIG9mZnNldCA9IHRoaXMub2Zmc2V0O1xuXHRcdG9mZnNldFswLypYMSovXSA9IGxvY2FsWENvcyAtIGxvY2FsWVNpbjtcblx0XHRvZmZzZXRbMS8qWTEqL10gPSBsb2NhbFlDb3MgKyBsb2NhbFhTaW47XG5cdFx0b2Zmc2V0WzIvKlgyKi9dID0gbG9jYWxYQ29zIC0gbG9jYWxZMlNpbjtcblx0XHRvZmZzZXRbMy8qWTIqL10gPSBsb2NhbFkyQ29zICsgbG9jYWxYU2luO1xuXHRcdG9mZnNldFs0LypYMyovXSA9IGxvY2FsWDJDb3MgLSBsb2NhbFkyU2luO1xuXHRcdG9mZnNldFs1LypZMyovXSA9IGxvY2FsWTJDb3MgKyBsb2NhbFgyU2luO1xuXHRcdG9mZnNldFs2LypYNCovXSA9IGxvY2FsWDJDb3MgLSBsb2NhbFlTaW47XG5cdFx0b2Zmc2V0WzcvKlk0Ki9dID0gbG9jYWxZQ29zICsgbG9jYWxYMlNpbjtcblx0fSxcblx0Y29tcHV0ZVZlcnRpY2VzOiBmdW5jdGlvbiAoeCwgeSwgYm9uZSwgdmVydGljZXMpIHtcblx0XHR4ICs9IGJvbmUud29ybGRYO1xuXHRcdHkgKz0gYm9uZS53b3JsZFk7XG5cdFx0dmFyIG0wMCA9IGJvbmUubTAwLCBtMDEgPSBib25lLm0wMSwgbTEwID0gYm9uZS5tMTAsIG0xMSA9IGJvbmUubTExO1xuXHRcdHZhciBvZmZzZXQgPSB0aGlzLm9mZnNldDtcblx0XHR2ZXJ0aWNlc1swLypYMSovXSA9IG9mZnNldFswLypYMSovXSAqIG0wMCArIG9mZnNldFsxLypZMSovXSAqIG0wMSArIHg7XG5cdFx0dmVydGljZXNbMS8qWTEqL10gPSBvZmZzZXRbMC8qWDEqL10gKiBtMTAgKyBvZmZzZXRbMS8qWTEqL10gKiBtMTEgKyB5O1xuXHRcdHZlcnRpY2VzWzIvKlgyKi9dID0gb2Zmc2V0WzIvKlgyKi9dICogbTAwICsgb2Zmc2V0WzMvKlkyKi9dICogbTAxICsgeDtcblx0XHR2ZXJ0aWNlc1szLypZMiovXSA9IG9mZnNldFsyLypYMiovXSAqIG0xMCArIG9mZnNldFszLypZMiovXSAqIG0xMSArIHk7XG5cdFx0dmVydGljZXNbNC8qWDMqL10gPSBvZmZzZXRbNC8qWDMqL10gKiBtMDAgKyBvZmZzZXRbNS8qWDMqL10gKiBtMDEgKyB4O1xuXHRcdHZlcnRpY2VzWzUvKlgzKi9dID0gb2Zmc2V0WzQvKlgzKi9dICogbTEwICsgb2Zmc2V0WzUvKlgzKi9dICogbTExICsgeTtcblx0XHR2ZXJ0aWNlc1s2LypYNCovXSA9IG9mZnNldFs2LypYNCovXSAqIG0wMCArIG9mZnNldFs3LypZNCovXSAqIG0wMSArIHg7XG5cdFx0dmVydGljZXNbNy8qWTQqL10gPSBvZmZzZXRbNi8qWDQqL10gKiBtMTAgKyBvZmZzZXRbNy8qWTQqL10gKiBtMTEgKyB5O1xuXHR9XG59O1xuXG5zcGluZS5NZXNoQXR0YWNobWVudCA9IGZ1bmN0aW9uIChuYW1lKSB7XG5cdHRoaXMubmFtZSA9IG5hbWU7XG59O1xuc3BpbmUuTWVzaEF0dGFjaG1lbnQucHJvdG90eXBlID0ge1xuXHR0eXBlOiBzcGluZS5BdHRhY2htZW50VHlwZS5tZXNoLFxuXHR2ZXJ0aWNlczogbnVsbCxcblx0dXZzOiBudWxsLFxuXHRyZWdpb25VVnM6IG51bGwsXG5cdHRyaWFuZ2xlczogbnVsbCxcblx0aHVsbExlbmd0aDogMCxcblx0cjogMSwgZzogMSwgYjogMSwgYTogMSxcblx0cGF0aDogbnVsbCxcblx0cmVuZGVyZXJPYmplY3Q6IG51bGwsXG5cdHJlZ2lvblU6IDAsIHJlZ2lvblY6IDAsIHJlZ2lvblUyOiAwLCByZWdpb25WMjogMCwgcmVnaW9uUm90YXRlOiBmYWxzZSxcblx0cmVnaW9uT2Zmc2V0WDogMCwgcmVnaW9uT2Zmc2V0WTogMCxcblx0cmVnaW9uV2lkdGg6IDAsIHJlZ2lvbkhlaWdodDogMCxcblx0cmVnaW9uT3JpZ2luYWxXaWR0aDogMCwgcmVnaW9uT3JpZ2luYWxIZWlnaHQ6IDAsXG5cdGVkZ2VzOiBudWxsLFxuXHR3aWR0aDogMCwgaGVpZ2h0OiAwLFxuXHR1cGRhdGVVVnM6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgd2lkdGggPSB0aGlzLnJlZ2lvblUyIC0gdGhpcy5yZWdpb25VLCBoZWlnaHQgPSB0aGlzLnJlZ2lvblYyIC0gdGhpcy5yZWdpb25WO1xuXHRcdHZhciBuID0gdGhpcy5yZWdpb25VVnMubGVuZ3RoO1xuXHRcdGlmICghdGhpcy51dnMgfHwgdGhpcy51dnMubGVuZ3RoICE9IG4pIHtcbiAgICAgICAgICAgIHRoaXMudXZzID0gbmV3IHNwaW5lLkZsb2F0MzJBcnJheShuKTtcblx0XHR9XG5cdFx0aWYgKHRoaXMucmVnaW9uUm90YXRlKSB7XG5cdFx0XHRmb3IgKHZhciBpID0gMDsgaSA8IG47IGkgKz0gMikge1xuICAgICAgICAgICAgICAgIHRoaXMudXZzW2ldID0gdGhpcy5yZWdpb25VICsgdGhpcy5yZWdpb25VVnNbaSArIDFdICogd2lkdGg7XG4gICAgICAgICAgICAgICAgdGhpcy51dnNbaSArIDFdID0gdGhpcy5yZWdpb25WICsgaGVpZ2h0IC0gdGhpcy5yZWdpb25VVnNbaV0gKiBoZWlnaHQ7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdGZvciAodmFyIGkgPSAwOyBpIDwgbjsgaSArPSAyKSB7XG4gICAgICAgICAgICAgICAgdGhpcy51dnNbaV0gPSB0aGlzLnJlZ2lvblUgKyB0aGlzLnJlZ2lvblVWc1tpXSAqIHdpZHRoO1xuICAgICAgICAgICAgICAgIHRoaXMudXZzW2kgKyAxXSA9IHRoaXMucmVnaW9uViArIHRoaXMucmVnaW9uVVZzW2kgKyAxXSAqIGhlaWdodDtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cdGNvbXB1dGVXb3JsZFZlcnRpY2VzOiBmdW5jdGlvbiAoeCwgeSwgc2xvdCwgd29ybGRWZXJ0aWNlcykge1xuXHRcdHZhciBib25lID0gc2xvdC5ib25lO1xuXHRcdHggKz0gYm9uZS53b3JsZFg7XG5cdFx0eSArPSBib25lLndvcmxkWTtcblx0XHR2YXIgbTAwID0gYm9uZS5tMDAsIG0wMSA9IGJvbmUubTAxLCBtMTAgPSBib25lLm0xMCwgbTExID0gYm9uZS5tMTE7XG5cdFx0dmFyIHZlcnRpY2VzID0gdGhpcy52ZXJ0aWNlcztcblx0XHR2YXIgdmVydGljZXNDb3VudCA9IHZlcnRpY2VzLmxlbmd0aDtcblx0XHRpZiAoc2xvdC5hdHRhY2htZW50VmVydGljZXMubGVuZ3RoID09IHZlcnRpY2VzQ291bnQpIHZlcnRpY2VzID0gc2xvdC5hdHRhY2htZW50VmVydGljZXM7XG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCB2ZXJ0aWNlc0NvdW50OyBpICs9IDIpIHtcblx0XHRcdHZhciB2eCA9IHZlcnRpY2VzW2ldO1xuXHRcdFx0dmFyIHZ5ID0gdmVydGljZXNbaSArIDFdO1xuXHRcdFx0d29ybGRWZXJ0aWNlc1tpXSA9IHZ4ICogbTAwICsgdnkgKiBtMDEgKyB4O1xuXHRcdFx0d29ybGRWZXJ0aWNlc1tpICsgMV0gPSB2eCAqIG0xMCArIHZ5ICogbTExICsgeTtcblx0XHR9XG5cdH1cbn07XG5cbnNwaW5lLlNraW5uZWRNZXNoQXR0YWNobWVudCA9IGZ1bmN0aW9uIChuYW1lKSB7XG5cdHRoaXMubmFtZSA9IG5hbWU7XG59O1xuc3BpbmUuU2tpbm5lZE1lc2hBdHRhY2htZW50LnByb3RvdHlwZSA9IHtcblx0dHlwZTogc3BpbmUuQXR0YWNobWVudFR5cGUuc2tpbm5lZG1lc2gsXG5cdGJvbmVzOiBudWxsLFxuXHR3ZWlnaHRzOiBudWxsLFxuXHR1dnM6IG51bGwsXG5cdHJlZ2lvblVWczogbnVsbCxcblx0dHJpYW5nbGVzOiBudWxsLFxuXHRodWxsTGVuZ3RoOiAwLFxuXHRyOiAxLCBnOiAxLCBiOiAxLCBhOiAxLFxuXHRwYXRoOiBudWxsLFxuXHRyZW5kZXJlck9iamVjdDogbnVsbCxcblx0cmVnaW9uVTogMCwgcmVnaW9uVjogMCwgcmVnaW9uVTI6IDAsIHJlZ2lvblYyOiAwLCByZWdpb25Sb3RhdGU6IGZhbHNlLFxuXHRyZWdpb25PZmZzZXRYOiAwLCByZWdpb25PZmZzZXRZOiAwLFxuXHRyZWdpb25XaWR0aDogMCwgcmVnaW9uSGVpZ2h0OiAwLFxuXHRyZWdpb25PcmlnaW5hbFdpZHRoOiAwLCByZWdpb25PcmlnaW5hbEhlaWdodDogMCxcblx0ZWRnZXM6IG51bGwsXG5cdHdpZHRoOiAwLCBoZWlnaHQ6IDAsXG5cdHVwZGF0ZVVWczogZnVuY3Rpb24gKHUsIHYsIHUyLCB2Miwgcm90YXRlKSB7XG5cdFx0dmFyIHdpZHRoID0gdGhpcy5yZWdpb25VMiAtIHRoaXMucmVnaW9uVSwgaGVpZ2h0ID0gdGhpcy5yZWdpb25WMiAtIHRoaXMucmVnaW9uVjtcblx0XHR2YXIgbiA9IHRoaXMucmVnaW9uVVZzLmxlbmd0aDtcblx0XHRpZiAoIXRoaXMudXZzIHx8IHRoaXMudXZzLmxlbmd0aCAhPSBuKSB7XG4gICAgICAgICAgICB0aGlzLnV2cyA9IG5ldyBzcGluZS5GbG9hdDMyQXJyYXkobik7XG5cdFx0fVxuXHRcdGlmICh0aGlzLnJlZ2lvblJvdGF0ZSkge1xuXHRcdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBuOyBpICs9IDIpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnV2c1tpXSA9IHRoaXMucmVnaW9uVSArIHRoaXMucmVnaW9uVVZzW2kgKyAxXSAqIHdpZHRoO1xuICAgICAgICAgICAgICAgIHRoaXMudXZzW2kgKyAxXSA9IHRoaXMucmVnaW9uViArIGhlaWdodCAtIHRoaXMucmVnaW9uVVZzW2ldICogaGVpZ2h0O1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHRmb3IgKHZhciBpID0gMDsgaSA8IG47IGkgKz0gMikge1xuICAgICAgICAgICAgICAgIHRoaXMudXZzW2ldID0gdGhpcy5yZWdpb25VICsgdGhpcy5yZWdpb25VVnNbaV0gKiB3aWR0aDtcbiAgICAgICAgICAgICAgICB0aGlzLnV2c1tpICsgMV0gPSB0aGlzLnJlZ2lvblYgKyB0aGlzLnJlZ2lvblVWc1tpICsgMV0gKiBoZWlnaHQ7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXHRjb21wdXRlV29ybGRWZXJ0aWNlczogZnVuY3Rpb24gKHgsIHksIHNsb3QsIHdvcmxkVmVydGljZXMpIHtcblx0XHR2YXIgc2tlbGV0b25Cb25lcyA9IHNsb3QuYm9uZS5za2VsZXRvbi5ib25lcztcblx0XHR2YXIgd2VpZ2h0cyA9IHRoaXMud2VpZ2h0cztcblx0XHR2YXIgYm9uZXMgPSB0aGlzLmJvbmVzO1xuXG5cdFx0dmFyIHcgPSAwLCB2ID0gMCwgYiA9IDAsIGYgPSAwLCBuID0gYm9uZXMubGVuZ3RoLCBubjtcblx0XHR2YXIgd3gsIHd5LCBib25lLCB2eCwgdnksIHdlaWdodDtcblx0XHRpZiAoIXNsb3QuYXR0YWNobWVudFZlcnRpY2VzLmxlbmd0aCkge1xuXHRcdFx0Zm9yICg7IHYgPCBuOyB3ICs9IDIpIHtcblx0XHRcdFx0d3ggPSAwO1xuXHRcdFx0XHR3eSA9IDA7XG5cdFx0XHRcdG5uID0gYm9uZXNbdisrXSArIHY7XG5cdFx0XHRcdGZvciAoOyB2IDwgbm47IHYrKywgYiArPSAzKSB7XG5cdFx0XHRcdFx0Ym9uZSA9IHNrZWxldG9uQm9uZXNbYm9uZXNbdl1dO1xuXHRcdFx0XHRcdHZ4ID0gd2VpZ2h0c1tiXTtcblx0XHRcdFx0XHR2eSA9IHdlaWdodHNbYiArIDFdO1xuXHRcdFx0XHRcdHdlaWdodCA9IHdlaWdodHNbYiArIDJdO1xuXHRcdFx0XHRcdHd4ICs9ICh2eCAqIGJvbmUubTAwICsgdnkgKiBib25lLm0wMSArIGJvbmUud29ybGRYKSAqIHdlaWdodDtcblx0XHRcdFx0XHR3eSArPSAodnggKiBib25lLm0xMCArIHZ5ICogYm9uZS5tMTEgKyBib25lLndvcmxkWSkgKiB3ZWlnaHQ7XG5cdFx0XHRcdH1cblx0XHRcdFx0d29ybGRWZXJ0aWNlc1t3XSA9IHd4ICsgeDtcblx0XHRcdFx0d29ybGRWZXJ0aWNlc1t3ICsgMV0gPSB3eSArIHk7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdHZhciBmZmQgPSBzbG90LmF0dGFjaG1lbnRWZXJ0aWNlcztcblx0XHRcdGZvciAoOyB2IDwgbjsgdyArPSAyKSB7XG5cdFx0XHRcdHd4ID0gMDtcblx0XHRcdFx0d3kgPSAwO1xuXHRcdFx0XHRubiA9IGJvbmVzW3YrK10gKyB2O1xuXHRcdFx0XHRmb3IgKDsgdiA8IG5uOyB2KyssIGIgKz0gMywgZiArPSAyKSB7XG5cdFx0XHRcdFx0Ym9uZSA9IHNrZWxldG9uQm9uZXNbYm9uZXNbdl1dO1xuXHRcdFx0XHRcdHZ4ID0gd2VpZ2h0c1tiXSArIGZmZFtmXTtcblx0XHRcdFx0XHR2eSA9IHdlaWdodHNbYiArIDFdICsgZmZkW2YgKyAxXTtcblx0XHRcdFx0XHR3ZWlnaHQgPSB3ZWlnaHRzW2IgKyAyXTtcblx0XHRcdFx0XHR3eCArPSAodnggKiBib25lLm0wMCArIHZ5ICogYm9uZS5tMDEgKyBib25lLndvcmxkWCkgKiB3ZWlnaHQ7XG5cdFx0XHRcdFx0d3kgKz0gKHZ4ICogYm9uZS5tMTAgKyB2eSAqIGJvbmUubTExICsgYm9uZS53b3JsZFkpICogd2VpZ2h0O1xuXHRcdFx0XHR9XG5cdFx0XHRcdHdvcmxkVmVydGljZXNbd10gPSB3eCArIHg7XG5cdFx0XHRcdHdvcmxkVmVydGljZXNbdyArIDFdID0gd3kgKyB5O1xuXHRcdFx0fVxuXHRcdH1cblx0fVxufTtcblxuc3BpbmUuQm91bmRpbmdCb3hBdHRhY2htZW50ID0gZnVuY3Rpb24gKG5hbWUpIHtcblx0dGhpcy5uYW1lID0gbmFtZTtcblx0dGhpcy52ZXJ0aWNlcyA9IFtdO1xufTtcbnNwaW5lLkJvdW5kaW5nQm94QXR0YWNobWVudC5wcm90b3R5cGUgPSB7XG5cdHR5cGU6IHNwaW5lLkF0dGFjaG1lbnRUeXBlLmJvdW5kaW5nYm94LFxuXHRjb21wdXRlV29ybGRWZXJ0aWNlczogZnVuY3Rpb24gKHgsIHksIGJvbmUsIHdvcmxkVmVydGljZXMpIHtcblx0XHR4ICs9IGJvbmUud29ybGRYO1xuXHRcdHkgKz0gYm9uZS53b3JsZFk7XG5cdFx0dmFyIG0wMCA9IGJvbmUubTAwLCBtMDEgPSBib25lLm0wMSwgbTEwID0gYm9uZS5tMTAsIG0xMSA9IGJvbmUubTExO1xuXHRcdHZhciB2ZXJ0aWNlcyA9IHRoaXMudmVydGljZXM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSB2ZXJ0aWNlcy5sZW5ndGg7IGkgPCBuOyBpICs9IDIpIHtcblx0XHRcdHZhciBweCA9IHZlcnRpY2VzW2ldO1xuXHRcdFx0dmFyIHB5ID0gdmVydGljZXNbaSArIDFdO1xuXHRcdFx0d29ybGRWZXJ0aWNlc1tpXSA9IHB4ICogbTAwICsgcHkgKiBtMDEgKyB4O1xuXHRcdFx0d29ybGRWZXJ0aWNlc1tpICsgMV0gPSBweCAqIG0xMCArIHB5ICogbTExICsgeTtcblx0XHR9XG5cdH1cbn07XG5cbnNwaW5lLkFuaW1hdGlvblN0YXRlRGF0YSA9IGZ1bmN0aW9uIChza2VsZXRvbkRhdGEpIHtcblx0dGhpcy5za2VsZXRvbkRhdGEgPSBza2VsZXRvbkRhdGE7XG5cdHRoaXMuYW5pbWF0aW9uVG9NaXhUaW1lID0ge307XG59O1xuc3BpbmUuQW5pbWF0aW9uU3RhdGVEYXRhLnByb3RvdHlwZSA9IHtcblx0ZGVmYXVsdE1peDogMCxcblx0c2V0TWl4QnlOYW1lOiBmdW5jdGlvbiAoZnJvbU5hbWUsIHRvTmFtZSwgZHVyYXRpb24pIHtcblx0XHR2YXIgZnJvbSA9IHRoaXMuc2tlbGV0b25EYXRhLmZpbmRBbmltYXRpb24oZnJvbU5hbWUpO1xuXHRcdGlmICghZnJvbSkgdGhyb3cgXCJBbmltYXRpb24gbm90IGZvdW5kOiBcIiArIGZyb21OYW1lO1xuXHRcdHZhciB0byA9IHRoaXMuc2tlbGV0b25EYXRhLmZpbmRBbmltYXRpb24odG9OYW1lKTtcblx0XHRpZiAoIXRvKSB0aHJvdyBcIkFuaW1hdGlvbiBub3QgZm91bmQ6IFwiICsgdG9OYW1lO1xuXHRcdHRoaXMuc2V0TWl4KGZyb20sIHRvLCBkdXJhdGlvbik7XG5cdH0sXG5cdHNldE1peDogZnVuY3Rpb24gKGZyb20sIHRvLCBkdXJhdGlvbikge1xuXHRcdHRoaXMuYW5pbWF0aW9uVG9NaXhUaW1lW2Zyb20ubmFtZSArIFwiOlwiICsgdG8ubmFtZV0gPSBkdXJhdGlvbjtcblx0fSxcblx0Z2V0TWl4OiBmdW5jdGlvbiAoZnJvbSwgdG8pIHtcblx0XHR2YXIga2V5ID0gZnJvbS5uYW1lICsgXCI6XCIgKyB0by5uYW1lO1xuXHRcdHJldHVybiB0aGlzLmFuaW1hdGlvblRvTWl4VGltZS5oYXNPd25Qcm9wZXJ0eShrZXkpID8gdGhpcy5hbmltYXRpb25Ub01peFRpbWVba2V5XSA6IHRoaXMuZGVmYXVsdE1peDtcblx0fVxufTtcblxuc3BpbmUuVHJhY2tFbnRyeSA9IGZ1bmN0aW9uICgpIHt9O1xuc3BpbmUuVHJhY2tFbnRyeS5wcm90b3R5cGUgPSB7XG5cdG5leHQ6IG51bGwsIHByZXZpb3VzOiBudWxsLFxuXHRhbmltYXRpb246IG51bGwsXG5cdGxvb3A6IGZhbHNlLFxuXHRkZWxheTogMCwgdGltZTogMCwgbGFzdFRpbWU6IC0xLCBlbmRUaW1lOiAwLFxuXHR0aW1lU2NhbGU6IDEsXG5cdG1peFRpbWU6IDAsIG1peER1cmF0aW9uOiAwLCBtaXg6IDEsXG5cdG9uU3RhcnQ6IG51bGwsIG9uRW5kOiBudWxsLCBvbkNvbXBsZXRlOiBudWxsLCBvbkV2ZW50OiBudWxsXG59O1xuXG5zcGluZS5BbmltYXRpb25TdGF0ZSA9IGZ1bmN0aW9uIChzdGF0ZURhdGEpIHtcblx0dGhpcy5kYXRhID0gc3RhdGVEYXRhO1xuXHR0aGlzLnRyYWNrcyA9IFtdO1xuXHR0aGlzLmV2ZW50cyA9IFtdO1xufTtcbnNwaW5lLkFuaW1hdGlvblN0YXRlLnByb3RvdHlwZSA9IHtcblx0b25TdGFydDogbnVsbCxcblx0b25FbmQ6IG51bGwsXG5cdG9uQ29tcGxldGU6IG51bGwsXG5cdG9uRXZlbnQ6IG51bGwsXG5cdHRpbWVTY2FsZTogMSxcblx0dXBkYXRlOiBmdW5jdGlvbiAoZGVsdGEpIHtcblx0XHRkZWx0YSAqPSB0aGlzLnRpbWVTY2FsZTtcblx0XHRmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMudHJhY2tzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHR2YXIgY3VycmVudCA9IHRoaXMudHJhY2tzW2ldO1xuXHRcdFx0aWYgKCFjdXJyZW50KSBjb250aW51ZTtcblxuXHRcdFx0Y3VycmVudC50aW1lICs9IGRlbHRhICogY3VycmVudC50aW1lU2NhbGU7XG5cdFx0XHRpZiAoY3VycmVudC5wcmV2aW91cykge1xuXHRcdFx0XHR2YXIgcHJldmlvdXNEZWx0YSA9IGRlbHRhICogY3VycmVudC5wcmV2aW91cy50aW1lU2NhbGU7XG5cdFx0XHRcdGN1cnJlbnQucHJldmlvdXMudGltZSArPSBwcmV2aW91c0RlbHRhO1xuXHRcdFx0XHRjdXJyZW50Lm1peFRpbWUgKz0gcHJldmlvdXNEZWx0YTtcblx0XHRcdH1cblxuXHRcdFx0dmFyIG5leHQgPSBjdXJyZW50Lm5leHQ7XG5cdFx0XHRpZiAobmV4dCkge1xuXHRcdFx0XHRuZXh0LnRpbWUgPSBjdXJyZW50Lmxhc3RUaW1lIC0gbmV4dC5kZWxheTtcblx0XHRcdFx0aWYgKG5leHQudGltZSA+PSAwKSB0aGlzLnNldEN1cnJlbnQoaSwgbmV4dCk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHQvLyBFbmQgbm9uLWxvb3BpbmcgYW5pbWF0aW9uIHdoZW4gaXQgcmVhY2hlcyBpdHMgZW5kIHRpbWUgYW5kIHRoZXJlIGlzIG5vIG5leHQgZW50cnkuXG5cdFx0XHRcdGlmICghY3VycmVudC5sb29wICYmIGN1cnJlbnQubGFzdFRpbWUgPj0gY3VycmVudC5lbmRUaW1lKSB0aGlzLmNsZWFyVHJhY2soaSk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXHRhcHBseTogZnVuY3Rpb24gKHNrZWxldG9uKSB7XG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnRyYWNrcy5sZW5ndGg7IGkrKykge1xuXHRcdFx0dmFyIGN1cnJlbnQgPSB0aGlzLnRyYWNrc1tpXTtcblx0XHRcdGlmICghY3VycmVudCkgY29udGludWU7XG5cblx0XHRcdHRoaXMuZXZlbnRzLmxlbmd0aCA9IDA7XG5cblx0XHRcdHZhciB0aW1lID0gY3VycmVudC50aW1lO1xuXHRcdFx0dmFyIGxhc3RUaW1lID0gY3VycmVudC5sYXN0VGltZTtcblx0XHRcdHZhciBlbmRUaW1lID0gY3VycmVudC5lbmRUaW1lO1xuXHRcdFx0dmFyIGxvb3AgPSBjdXJyZW50Lmxvb3A7XG5cdFx0XHRpZiAoIWxvb3AgJiYgdGltZSA+IGVuZFRpbWUpIHRpbWUgPSBlbmRUaW1lO1xuXG5cdFx0XHR2YXIgcHJldmlvdXMgPSBjdXJyZW50LnByZXZpb3VzO1xuXHRcdFx0aWYgKCFwcmV2aW91cykge1xuXHRcdFx0XHRpZiAoY3VycmVudC5taXggPT0gMSlcblx0XHRcdFx0XHRjdXJyZW50LmFuaW1hdGlvbi5hcHBseShza2VsZXRvbiwgY3VycmVudC5sYXN0VGltZSwgdGltZSwgbG9vcCwgdGhpcy5ldmVudHMpO1xuXHRcdFx0XHRlbHNlXG5cdFx0XHRcdFx0Y3VycmVudC5hbmltYXRpb24ubWl4KHNrZWxldG9uLCBjdXJyZW50Lmxhc3RUaW1lLCB0aW1lLCBsb29wLCB0aGlzLmV2ZW50cywgY3VycmVudC5taXgpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dmFyIHByZXZpb3VzVGltZSA9IHByZXZpb3VzLnRpbWU7XG5cdFx0XHRcdGlmICghcHJldmlvdXMubG9vcCAmJiBwcmV2aW91c1RpbWUgPiBwcmV2aW91cy5lbmRUaW1lKSBwcmV2aW91c1RpbWUgPSBwcmV2aW91cy5lbmRUaW1lO1xuXHRcdFx0XHRwcmV2aW91cy5hbmltYXRpb24uYXBwbHkoc2tlbGV0b24sIHByZXZpb3VzVGltZSwgcHJldmlvdXNUaW1lLCBwcmV2aW91cy5sb29wLCBudWxsKTtcblxuXHRcdFx0XHR2YXIgYWxwaGEgPSBjdXJyZW50Lm1peFRpbWUgLyBjdXJyZW50Lm1peER1cmF0aW9uICogY3VycmVudC5taXg7XG5cdFx0XHRcdGlmIChhbHBoYSA+PSAxKSB7XG5cdFx0XHRcdFx0YWxwaGEgPSAxO1xuXHRcdFx0XHRcdGN1cnJlbnQucHJldmlvdXMgPSBudWxsO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGN1cnJlbnQuYW5pbWF0aW9uLm1peChza2VsZXRvbiwgY3VycmVudC5sYXN0VGltZSwgdGltZSwgbG9vcCwgdGhpcy5ldmVudHMsIGFscGhhKTtcblx0XHRcdH1cblxuXHRcdFx0Zm9yICh2YXIgaWkgPSAwLCBubiA9IHRoaXMuZXZlbnRzLmxlbmd0aDsgaWkgPCBubjsgaWkrKykge1xuXHRcdFx0XHR2YXIgZXZlbnQgPSB0aGlzLmV2ZW50c1tpaV07XG5cdFx0XHRcdGlmIChjdXJyZW50Lm9uRXZlbnQpIGN1cnJlbnQub25FdmVudChpLCBldmVudCk7XG5cdFx0XHRcdGlmICh0aGlzLm9uRXZlbnQpIHRoaXMub25FdmVudChpLCBldmVudCk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIENoZWNrIGlmIGNvbXBsZXRlZCB0aGUgYW5pbWF0aW9uIG9yIGEgbG9vcCBpdGVyYXRpb24uXG5cdFx0XHRpZiAobG9vcCA/IChsYXN0VGltZSAlIGVuZFRpbWUgPiB0aW1lICUgZW5kVGltZSkgOiAobGFzdFRpbWUgPCBlbmRUaW1lICYmIHRpbWUgPj0gZW5kVGltZSkpIHtcblx0XHRcdFx0dmFyIGNvdW50ID0gTWF0aC5mbG9vcih0aW1lIC8gZW5kVGltZSk7XG5cdFx0XHRcdGlmIChjdXJyZW50Lm9uQ29tcGxldGUpIGN1cnJlbnQub25Db21wbGV0ZShpLCBjb3VudCk7XG5cdFx0XHRcdGlmICh0aGlzLm9uQ29tcGxldGUpIHRoaXMub25Db21wbGV0ZShpLCBjb3VudCk7XG5cdFx0XHR9XG5cblx0XHRcdGN1cnJlbnQubGFzdFRpbWUgPSBjdXJyZW50LnRpbWU7XG5cdFx0fVxuXHR9LFxuXHRjbGVhclRyYWNrczogZnVuY3Rpb24gKCkge1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gdGhpcy50cmFja3MubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0dGhpcy5jbGVhclRyYWNrKGkpO1xuXHRcdHRoaXMudHJhY2tzLmxlbmd0aCA9IDA7XG5cdH0sXG5cdGNsZWFyVHJhY2s6IGZ1bmN0aW9uICh0cmFja0luZGV4KSB7XG5cdFx0aWYgKHRyYWNrSW5kZXggPj0gdGhpcy50cmFja3MubGVuZ3RoKSByZXR1cm47XG5cdFx0dmFyIGN1cnJlbnQgPSB0aGlzLnRyYWNrc1t0cmFja0luZGV4XTtcblx0XHRpZiAoIWN1cnJlbnQpIHJldHVybjtcblxuXHRcdGlmIChjdXJyZW50Lm9uRW5kKSBjdXJyZW50Lm9uRW5kKHRyYWNrSW5kZXgpO1xuXHRcdGlmICh0aGlzLm9uRW5kKSB0aGlzLm9uRW5kKHRyYWNrSW5kZXgpO1xuXG5cdFx0dGhpcy50cmFja3NbdHJhY2tJbmRleF0gPSBudWxsO1xuXHR9LFxuXHRfZXhwYW5kVG9JbmRleDogZnVuY3Rpb24gKGluZGV4KSB7XG5cdFx0aWYgKGluZGV4IDwgdGhpcy50cmFja3MubGVuZ3RoKSByZXR1cm4gdGhpcy50cmFja3NbaW5kZXhdO1xuXHRcdHdoaWxlIChpbmRleCA+PSB0aGlzLnRyYWNrcy5sZW5ndGgpXG5cdFx0XHR0aGlzLnRyYWNrcy5wdXNoKG51bGwpO1xuXHRcdHJldHVybiBudWxsO1xuXHR9LFxuXHRzZXRDdXJyZW50OiBmdW5jdGlvbiAoaW5kZXgsIGVudHJ5KSB7XG5cdFx0dmFyIGN1cnJlbnQgPSB0aGlzLl9leHBhbmRUb0luZGV4KGluZGV4KTtcblx0XHRpZiAoY3VycmVudCkge1xuXHRcdFx0dmFyIHByZXZpb3VzID0gY3VycmVudC5wcmV2aW91cztcblx0XHRcdGN1cnJlbnQucHJldmlvdXMgPSBudWxsO1xuXG5cdFx0XHRpZiAoY3VycmVudC5vbkVuZCkgY3VycmVudC5vbkVuZChpbmRleCk7XG5cdFx0XHRpZiAodGhpcy5vbkVuZCkgdGhpcy5vbkVuZChpbmRleCk7XG5cblx0XHRcdGVudHJ5Lm1peER1cmF0aW9uID0gdGhpcy5kYXRhLmdldE1peChjdXJyZW50LmFuaW1hdGlvbiwgZW50cnkuYW5pbWF0aW9uKTtcblx0XHRcdGlmIChlbnRyeS5taXhEdXJhdGlvbiA+IDApIHtcblx0XHRcdFx0ZW50cnkubWl4VGltZSA9IDA7XG5cdFx0XHRcdC8vIElmIGEgbWl4IGlzIGluIHByb2dyZXNzLCBtaXggZnJvbSB0aGUgY2xvc2VzdCBhbmltYXRpb24uXG5cdFx0XHRcdGlmIChwcmV2aW91cyAmJiBjdXJyZW50Lm1peFRpbWUgLyBjdXJyZW50Lm1peER1cmF0aW9uIDwgMC41KVxuXHRcdFx0XHRcdGVudHJ5LnByZXZpb3VzID0gcHJldmlvdXM7XG5cdFx0XHRcdGVsc2Vcblx0XHRcdFx0XHRlbnRyeS5wcmV2aW91cyA9IGN1cnJlbnQ7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy50cmFja3NbaW5kZXhdID0gZW50cnk7XG5cblx0XHRpZiAoZW50cnkub25TdGFydCkgZW50cnkub25TdGFydChpbmRleCk7XG5cdFx0aWYgKHRoaXMub25TdGFydCkgdGhpcy5vblN0YXJ0KGluZGV4KTtcblx0fSxcblx0c2V0QW5pbWF0aW9uQnlOYW1lOiBmdW5jdGlvbiAodHJhY2tJbmRleCwgYW5pbWF0aW9uTmFtZSwgbG9vcCkge1xuXHRcdHZhciBhbmltYXRpb24gPSB0aGlzLmRhdGEuc2tlbGV0b25EYXRhLmZpbmRBbmltYXRpb24oYW5pbWF0aW9uTmFtZSk7XG5cdFx0aWYgKCFhbmltYXRpb24pIHRocm93IFwiQW5pbWF0aW9uIG5vdCBmb3VuZDogXCIgKyBhbmltYXRpb25OYW1lO1xuXHRcdHJldHVybiB0aGlzLnNldEFuaW1hdGlvbih0cmFja0luZGV4LCBhbmltYXRpb24sIGxvb3ApO1xuXHR9LFxuXHQvKiogU2V0IHRoZSBjdXJyZW50IGFuaW1hdGlvbi4gQW55IHF1ZXVlZCBhbmltYXRpb25zIGFyZSBjbGVhcmVkLiAqL1xuXHRzZXRBbmltYXRpb246IGZ1bmN0aW9uICh0cmFja0luZGV4LCBhbmltYXRpb24sIGxvb3ApIHtcblx0XHR2YXIgZW50cnkgPSBuZXcgc3BpbmUuVHJhY2tFbnRyeSgpO1xuXHRcdGVudHJ5LmFuaW1hdGlvbiA9IGFuaW1hdGlvbjtcblx0XHRlbnRyeS5sb29wID0gbG9vcDtcblx0XHRlbnRyeS5lbmRUaW1lID0gYW5pbWF0aW9uLmR1cmF0aW9uO1xuXHRcdHRoaXMuc2V0Q3VycmVudCh0cmFja0luZGV4LCBlbnRyeSk7XG5cdFx0cmV0dXJuIGVudHJ5O1xuXHR9LFxuXHRhZGRBbmltYXRpb25CeU5hbWU6IGZ1bmN0aW9uICh0cmFja0luZGV4LCBhbmltYXRpb25OYW1lLCBsb29wLCBkZWxheSkge1xuXHRcdHZhciBhbmltYXRpb24gPSB0aGlzLmRhdGEuc2tlbGV0b25EYXRhLmZpbmRBbmltYXRpb24oYW5pbWF0aW9uTmFtZSk7XG5cdFx0aWYgKCFhbmltYXRpb24pIHRocm93IFwiQW5pbWF0aW9uIG5vdCBmb3VuZDogXCIgKyBhbmltYXRpb25OYW1lO1xuXHRcdHJldHVybiB0aGlzLmFkZEFuaW1hdGlvbih0cmFja0luZGV4LCBhbmltYXRpb24sIGxvb3AsIGRlbGF5KTtcblx0fSxcblx0LyoqIEFkZHMgYW4gYW5pbWF0aW9uIHRvIGJlIHBsYXllZCBkZWxheSBzZWNvbmRzIGFmdGVyIHRoZSBjdXJyZW50IG9yIGxhc3QgcXVldWVkIGFuaW1hdGlvbi5cblx0ICogQHBhcmFtIGRlbGF5IE1heSBiZSA8PSAwIHRvIHVzZSBkdXJhdGlvbiBvZiBwcmV2aW91cyBhbmltYXRpb24gbWludXMgYW55IG1peCBkdXJhdGlvbiBwbHVzIHRoZSBuZWdhdGl2ZSBkZWxheS4gKi9cblx0YWRkQW5pbWF0aW9uOiBmdW5jdGlvbiAodHJhY2tJbmRleCwgYW5pbWF0aW9uLCBsb29wLCBkZWxheSkge1xuXHRcdHZhciBlbnRyeSA9IG5ldyBzcGluZS5UcmFja0VudHJ5KCk7XG5cdFx0ZW50cnkuYW5pbWF0aW9uID0gYW5pbWF0aW9uO1xuXHRcdGVudHJ5Lmxvb3AgPSBsb29wO1xuXHRcdGVudHJ5LmVuZFRpbWUgPSBhbmltYXRpb24uZHVyYXRpb247XG5cblx0XHR2YXIgbGFzdCA9IHRoaXMuX2V4cGFuZFRvSW5kZXgodHJhY2tJbmRleCk7XG5cdFx0aWYgKGxhc3QpIHtcblx0XHRcdHdoaWxlIChsYXN0Lm5leHQpXG5cdFx0XHRcdGxhc3QgPSBsYXN0Lm5leHQ7XG5cdFx0XHRsYXN0Lm5leHQgPSBlbnRyeTtcblx0XHR9IGVsc2Vcblx0XHRcdHRoaXMudHJhY2tzW3RyYWNrSW5kZXhdID0gZW50cnk7XG5cblx0XHRpZiAoZGVsYXkgPD0gMCkge1xuXHRcdFx0aWYgKGxhc3QpXG5cdFx0XHRcdGRlbGF5ICs9IGxhc3QuZW5kVGltZSAtIHRoaXMuZGF0YS5nZXRNaXgobGFzdC5hbmltYXRpb24sIGFuaW1hdGlvbik7XG5cdFx0XHRlbHNlXG5cdFx0XHRcdGRlbGF5ID0gMDtcblx0XHR9XG5cdFx0ZW50cnkuZGVsYXkgPSBkZWxheTtcblxuXHRcdHJldHVybiBlbnRyeTtcblx0fSxcblx0LyoqIE1heSBiZSBudWxsLiAqL1xuXHRnZXRDdXJyZW50OiBmdW5jdGlvbiAodHJhY2tJbmRleCkge1xuXHRcdGlmICh0cmFja0luZGV4ID49IHRoaXMudHJhY2tzLmxlbmd0aCkgcmV0dXJuIG51bGw7XG5cdFx0cmV0dXJuIHRoaXMudHJhY2tzW3RyYWNrSW5kZXhdO1xuXHR9XG59O1xuXG5zcGluZS5Ta2VsZXRvbkpzb24gPSBmdW5jdGlvbiAoYXR0YWNobWVudExvYWRlcikge1xuXHR0aGlzLmF0dGFjaG1lbnRMb2FkZXIgPSBhdHRhY2htZW50TG9hZGVyO1xufTtcbnNwaW5lLlNrZWxldG9uSnNvbi5wcm90b3R5cGUgPSB7XG5cdHNjYWxlOiAxLFxuXHRyZWFkU2tlbGV0b25EYXRhOiBmdW5jdGlvbiAocm9vdCwgbmFtZSkge1xuXHRcdHZhciBza2VsZXRvbkRhdGEgPSBuZXcgc3BpbmUuU2tlbGV0b25EYXRhKCk7XG5cdFx0c2tlbGV0b25EYXRhLm5hbWUgPSBuYW1lO1xuXG5cdFx0Ly8gU2tlbGV0b24uXG5cdFx0dmFyIHNrZWxldG9uTWFwID0gcm9vdFtcInNrZWxldG9uXCJdO1xuXHRcdGlmIChza2VsZXRvbk1hcCkge1xuXHRcdFx0c2tlbGV0b25EYXRhLmhhc2ggPSBza2VsZXRvbk1hcFtcImhhc2hcIl07XG5cdFx0XHRza2VsZXRvbkRhdGEudmVyc2lvbiA9IHNrZWxldG9uTWFwW1wic3BpbmVcIl07XG5cdFx0XHRza2VsZXRvbkRhdGEud2lkdGggPSBza2VsZXRvbk1hcFtcIndpZHRoXCJdIHx8IDA7XG5cdFx0XHRza2VsZXRvbkRhdGEuaGVpZ2h0ID0gc2tlbGV0b25NYXBbXCJoZWlnaHRcIl0gfHwgMDtcblx0XHR9XG5cblx0XHQvLyBCb25lcy5cblx0XHR2YXIgYm9uZXMgPSByb290W1wiYm9uZXNcIl07XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBib25lcy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcblx0XHRcdHZhciBib25lTWFwID0gYm9uZXNbaV07XG5cdFx0XHR2YXIgcGFyZW50ID0gbnVsbDtcblx0XHRcdGlmIChib25lTWFwW1wicGFyZW50XCJdKSB7XG5cdFx0XHRcdHBhcmVudCA9IHNrZWxldG9uRGF0YS5maW5kQm9uZShib25lTWFwW1wicGFyZW50XCJdKTtcblx0XHRcdFx0aWYgKCFwYXJlbnQpIHRocm93IFwiUGFyZW50IGJvbmUgbm90IGZvdW5kOiBcIiArIGJvbmVNYXBbXCJwYXJlbnRcIl07XG5cdFx0XHR9XG5cdFx0XHR2YXIgYm9uZURhdGEgPSBuZXcgc3BpbmUuQm9uZURhdGEoYm9uZU1hcFtcIm5hbWVcIl0sIHBhcmVudCk7XG5cdFx0XHRib25lRGF0YS5sZW5ndGggPSAoYm9uZU1hcFtcImxlbmd0aFwiXSB8fCAwKSAqIHRoaXMuc2NhbGU7XG5cdFx0XHRib25lRGF0YS54ID0gKGJvbmVNYXBbXCJ4XCJdIHx8IDApICogdGhpcy5zY2FsZTtcblx0XHRcdGJvbmVEYXRhLnkgPSAoYm9uZU1hcFtcInlcIl0gfHwgMCkgKiB0aGlzLnNjYWxlO1xuXHRcdFx0Ym9uZURhdGEucm90YXRpb24gPSAoYm9uZU1hcFtcInJvdGF0aW9uXCJdIHx8IDApO1xuXHRcdFx0Ym9uZURhdGEuc2NhbGVYID0gYm9uZU1hcC5oYXNPd25Qcm9wZXJ0eShcInNjYWxlWFwiKSA/IGJvbmVNYXBbXCJzY2FsZVhcIl0gOiAxO1xuXHRcdFx0Ym9uZURhdGEuc2NhbGVZID0gYm9uZU1hcC5oYXNPd25Qcm9wZXJ0eShcInNjYWxlWVwiKSA/IGJvbmVNYXBbXCJzY2FsZVlcIl0gOiAxO1xuXHRcdFx0Ym9uZURhdGEuaW5oZXJpdFNjYWxlID0gYm9uZU1hcC5oYXNPd25Qcm9wZXJ0eShcImluaGVyaXRTY2FsZVwiKSA/IGJvbmVNYXBbXCJpbmhlcml0U2NhbGVcIl0gOiB0cnVlO1xuXHRcdFx0Ym9uZURhdGEuaW5oZXJpdFJvdGF0aW9uID0gYm9uZU1hcC5oYXNPd25Qcm9wZXJ0eShcImluaGVyaXRSb3RhdGlvblwiKSA/IGJvbmVNYXBbXCJpbmhlcml0Um90YXRpb25cIl0gOiB0cnVlO1xuXHRcdFx0c2tlbGV0b25EYXRhLmJvbmVzLnB1c2goYm9uZURhdGEpO1xuXHRcdH1cblxuXHRcdC8vIElLIGNvbnN0cmFpbnRzLlxuXHRcdHZhciBpayA9IHJvb3RbXCJpa1wiXTtcblx0XHRpZiAoaWspIHtcblx0XHRcdGZvciAodmFyIGkgPSAwLCBuID0gaWsubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRcdHZhciBpa01hcCA9IGlrW2ldO1xuXHRcdFx0XHR2YXIgaWtDb25zdHJhaW50RGF0YSA9IG5ldyBzcGluZS5Ja0NvbnN0cmFpbnREYXRhKGlrTWFwW1wibmFtZVwiXSk7XG5cblx0XHRcdFx0dmFyIGJvbmVzID0gaWtNYXBbXCJib25lc1wiXTtcblx0XHRcdFx0Zm9yICh2YXIgaWkgPSAwLCBubiA9IGJvbmVzLmxlbmd0aDsgaWkgPCBubjsgaWkrKykge1xuXHRcdFx0XHRcdHZhciBib25lID0gc2tlbGV0b25EYXRhLmZpbmRCb25lKGJvbmVzW2lpXSk7XG5cdFx0XHRcdFx0aWYgKCFib25lKSB0aHJvdyBcIklLIGJvbmUgbm90IGZvdW5kOiBcIiArIGJvbmVzW2lpXTtcblx0XHRcdFx0XHRpa0NvbnN0cmFpbnREYXRhLmJvbmVzLnB1c2goYm9uZSk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpa0NvbnN0cmFpbnREYXRhLnRhcmdldCA9IHNrZWxldG9uRGF0YS5maW5kQm9uZShpa01hcFtcInRhcmdldFwiXSk7XG5cdFx0XHRcdGlmICghaWtDb25zdHJhaW50RGF0YS50YXJnZXQpIHRocm93IFwiVGFyZ2V0IGJvbmUgbm90IGZvdW5kOiBcIiArIGlrTWFwW1widGFyZ2V0XCJdO1xuXG5cdFx0XHRcdGlrQ29uc3RyYWludERhdGEuYmVuZERpcmVjdGlvbiA9ICghaWtNYXAuaGFzT3duUHJvcGVydHkoXCJiZW5kUG9zaXRpdmVcIikgfHwgaWtNYXBbXCJiZW5kUG9zaXRpdmVcIl0pID8gMSA6IC0xO1xuXHRcdFx0XHRpa0NvbnN0cmFpbnREYXRhLm1peCA9IGlrTWFwLmhhc093blByb3BlcnR5KFwibWl4XCIpID8gaWtNYXBbXCJtaXhcIl0gOiAxO1xuXG5cdFx0XHRcdHNrZWxldG9uRGF0YS5pa0NvbnN0cmFpbnRzLnB1c2goaWtDb25zdHJhaW50RGF0YSk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gU2xvdHMuXG5cdFx0dmFyIHNsb3RzID0gcm9vdFtcInNsb3RzXCJdO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gc2xvdHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHR2YXIgc2xvdE1hcCA9IHNsb3RzW2ldO1xuXHRcdFx0dmFyIGJvbmVEYXRhID0gc2tlbGV0b25EYXRhLmZpbmRCb25lKHNsb3RNYXBbXCJib25lXCJdKTtcblx0XHRcdGlmICghYm9uZURhdGEpIHRocm93IFwiU2xvdCBib25lIG5vdCBmb3VuZDogXCIgKyBzbG90TWFwW1wiYm9uZVwiXTtcblx0XHRcdHZhciBzbG90RGF0YSA9IG5ldyBzcGluZS5TbG90RGF0YShzbG90TWFwW1wibmFtZVwiXSwgYm9uZURhdGEpO1xuXG5cdFx0XHR2YXIgY29sb3IgPSBzbG90TWFwW1wiY29sb3JcIl07XG5cdFx0XHRpZiAoY29sb3IpIHtcblx0XHRcdFx0c2xvdERhdGEuciA9IHRoaXMudG9Db2xvcihjb2xvciwgMCk7XG5cdFx0XHRcdHNsb3REYXRhLmcgPSB0aGlzLnRvQ29sb3IoY29sb3IsIDEpO1xuXHRcdFx0XHRzbG90RGF0YS5iID0gdGhpcy50b0NvbG9yKGNvbG9yLCAyKTtcblx0XHRcdFx0c2xvdERhdGEuYSA9IHRoaXMudG9Db2xvcihjb2xvciwgMyk7XG5cdFx0XHR9XG5cblx0XHRcdHNsb3REYXRhLmF0dGFjaG1lbnROYW1lID0gc2xvdE1hcFtcImF0dGFjaG1lbnRcIl07XG5cdFx0XHRzbG90RGF0YS5hZGRpdGl2ZUJsZW5kaW5nID0gc2xvdE1hcFtcImFkZGl0aXZlXCJdICYmIHNsb3RNYXBbXCJhZGRpdGl2ZVwiXSA9PSBcInRydWVcIjtcblxuXHRcdFx0c2tlbGV0b25EYXRhLnNsb3RzLnB1c2goc2xvdERhdGEpO1xuXHRcdH1cblxuXHRcdC8vIFNraW5zLlxuXHRcdHZhciBza2lucyA9IHJvb3RbXCJza2luc1wiXTtcblx0XHRmb3IgKHZhciBza2luTmFtZSBpbiBza2lucykge1xuXHRcdFx0aWYgKCFza2lucy5oYXNPd25Qcm9wZXJ0eShza2luTmFtZSkpIGNvbnRpbnVlO1xuXHRcdFx0dmFyIHNraW5NYXAgPSBza2luc1tza2luTmFtZV07XG5cdFx0XHR2YXIgc2tpbiA9IG5ldyBzcGluZS5Ta2luKHNraW5OYW1lKTtcblx0XHRcdGZvciAodmFyIHNsb3ROYW1lIGluIHNraW5NYXApIHtcblx0XHRcdFx0aWYgKCFza2luTWFwLmhhc093blByb3BlcnR5KHNsb3ROYW1lKSkgY29udGludWU7XG5cdFx0XHRcdHZhciBzbG90SW5kZXggPSBza2VsZXRvbkRhdGEuZmluZFNsb3RJbmRleChzbG90TmFtZSk7XG5cdFx0XHRcdHZhciBzbG90RW50cnkgPSBza2luTWFwW3Nsb3ROYW1lXTtcblx0XHRcdFx0Zm9yICh2YXIgYXR0YWNobWVudE5hbWUgaW4gc2xvdEVudHJ5KSB7XG5cdFx0XHRcdFx0aWYgKCFzbG90RW50cnkuaGFzT3duUHJvcGVydHkoYXR0YWNobWVudE5hbWUpKSBjb250aW51ZTtcblx0XHRcdFx0XHR2YXIgYXR0YWNobWVudCA9IHRoaXMucmVhZEF0dGFjaG1lbnQoc2tpbiwgYXR0YWNobWVudE5hbWUsIHNsb3RFbnRyeVthdHRhY2htZW50TmFtZV0pO1xuXHRcdFx0XHRcdGlmIChhdHRhY2htZW50KSBza2luLmFkZEF0dGFjaG1lbnQoc2xvdEluZGV4LCBhdHRhY2htZW50TmFtZSwgYXR0YWNobWVudCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHNrZWxldG9uRGF0YS5za2lucy5wdXNoKHNraW4pO1xuXHRcdFx0aWYgKHNraW4ubmFtZSA9PSBcImRlZmF1bHRcIikgc2tlbGV0b25EYXRhLmRlZmF1bHRTa2luID0gc2tpbjtcblx0XHR9XG5cblx0XHQvLyBFdmVudHMuXG5cdFx0dmFyIGV2ZW50cyA9IHJvb3RbXCJldmVudHNcIl07XG5cdFx0Zm9yICh2YXIgZXZlbnROYW1lIGluIGV2ZW50cykge1xuXHRcdFx0aWYgKCFldmVudHMuaGFzT3duUHJvcGVydHkoZXZlbnROYW1lKSkgY29udGludWU7XG5cdFx0XHR2YXIgZXZlbnRNYXAgPSBldmVudHNbZXZlbnROYW1lXTtcblx0XHRcdHZhciBldmVudERhdGEgPSBuZXcgc3BpbmUuRXZlbnREYXRhKGV2ZW50TmFtZSk7XG5cdFx0XHRldmVudERhdGEuaW50VmFsdWUgPSBldmVudE1hcFtcImludFwiXSB8fCAwO1xuXHRcdFx0ZXZlbnREYXRhLmZsb2F0VmFsdWUgPSBldmVudE1hcFtcImZsb2F0XCJdIHx8IDA7XG5cdFx0XHRldmVudERhdGEuc3RyaW5nVmFsdWUgPSBldmVudE1hcFtcInN0cmluZ1wiXSB8fCBudWxsO1xuXHRcdFx0c2tlbGV0b25EYXRhLmV2ZW50cy5wdXNoKGV2ZW50RGF0YSk7XG5cdFx0fVxuXG5cdFx0Ly8gQW5pbWF0aW9ucy5cblx0XHR2YXIgYW5pbWF0aW9ucyA9IHJvb3RbXCJhbmltYXRpb25zXCJdO1xuXHRcdGZvciAodmFyIGFuaW1hdGlvbk5hbWUgaW4gYW5pbWF0aW9ucykge1xuXHRcdFx0aWYgKCFhbmltYXRpb25zLmhhc093blByb3BlcnR5KGFuaW1hdGlvbk5hbWUpKSBjb250aW51ZTtcblx0XHRcdHRoaXMucmVhZEFuaW1hdGlvbihhbmltYXRpb25OYW1lLCBhbmltYXRpb25zW2FuaW1hdGlvbk5hbWVdLCBza2VsZXRvbkRhdGEpO1xuXHRcdH1cblxuXHRcdHJldHVybiBza2VsZXRvbkRhdGE7XG5cdH0sXG5cdHJlYWRBdHRhY2htZW50OiBmdW5jdGlvbiAoc2tpbiwgbmFtZSwgbWFwKSB7XG5cdFx0bmFtZSA9IG1hcFtcIm5hbWVcIl0gfHwgbmFtZTtcblxuXHRcdHZhciB0eXBlID0gc3BpbmUuQXR0YWNobWVudFR5cGVbbWFwW1widHlwZVwiXSB8fCBcInJlZ2lvblwiXTtcblx0XHR2YXIgcGF0aCA9IG1hcFtcInBhdGhcIl0gfHwgbmFtZTtcblxuXHRcdHZhciBzY2FsZSA9IHRoaXMuc2NhbGU7XG5cdFx0aWYgKHR5cGUgPT0gc3BpbmUuQXR0YWNobWVudFR5cGUucmVnaW9uKSB7XG5cdFx0XHR2YXIgcmVnaW9uID0gdGhpcy5hdHRhY2htZW50TG9hZGVyLm5ld1JlZ2lvbkF0dGFjaG1lbnQoc2tpbiwgbmFtZSwgcGF0aCk7XG5cdFx0XHRpZiAoIXJlZ2lvbikgcmV0dXJuIG51bGw7XG5cdFx0XHRyZWdpb24ucGF0aCA9IHBhdGg7XG5cdFx0XHRyZWdpb24ueCA9IChtYXBbXCJ4XCJdIHx8IDApICogc2NhbGU7XG5cdFx0XHRyZWdpb24ueSA9IChtYXBbXCJ5XCJdIHx8IDApICogc2NhbGU7XG5cdFx0XHRyZWdpb24uc2NhbGVYID0gbWFwLmhhc093blByb3BlcnR5KFwic2NhbGVYXCIpID8gbWFwW1wic2NhbGVYXCJdIDogMTtcblx0XHRcdHJlZ2lvbi5zY2FsZVkgPSBtYXAuaGFzT3duUHJvcGVydHkoXCJzY2FsZVlcIikgPyBtYXBbXCJzY2FsZVlcIl0gOiAxO1xuXHRcdFx0cmVnaW9uLnJvdGF0aW9uID0gbWFwW1wicm90YXRpb25cIl0gfHwgMDtcblx0XHRcdHJlZ2lvbi53aWR0aCA9IChtYXBbXCJ3aWR0aFwiXSB8fCAwKSAqIHNjYWxlO1xuXHRcdFx0cmVnaW9uLmhlaWdodCA9IChtYXBbXCJoZWlnaHRcIl0gfHwgMCkgKiBzY2FsZTtcblxuXHRcdFx0dmFyIGNvbG9yID0gbWFwW1wiY29sb3JcIl07XG5cdFx0XHRpZiAoY29sb3IpIHtcblx0XHRcdFx0cmVnaW9uLnIgPSB0aGlzLnRvQ29sb3IoY29sb3IsIDApO1xuXHRcdFx0XHRyZWdpb24uZyA9IHRoaXMudG9Db2xvcihjb2xvciwgMSk7XG5cdFx0XHRcdHJlZ2lvbi5iID0gdGhpcy50b0NvbG9yKGNvbG9yLCAyKTtcblx0XHRcdFx0cmVnaW9uLmEgPSB0aGlzLnRvQ29sb3IoY29sb3IsIDMpO1xuXHRcdFx0fVxuXG5cdFx0XHRyZWdpb24udXBkYXRlT2Zmc2V0KCk7XG5cdFx0XHRyZXR1cm4gcmVnaW9uO1xuXHRcdH0gZWxzZSBpZiAodHlwZSA9PSBzcGluZS5BdHRhY2htZW50VHlwZS5tZXNoKSB7XG5cdFx0XHR2YXIgbWVzaCA9IHRoaXMuYXR0YWNobWVudExvYWRlci5uZXdNZXNoQXR0YWNobWVudChza2luLCBuYW1lLCBwYXRoKTtcblx0XHRcdGlmICghbWVzaCkgcmV0dXJuIG51bGw7XG5cdFx0XHRtZXNoLnBhdGggPSBwYXRoO1xuXHRcdFx0bWVzaC52ZXJ0aWNlcyA9IHRoaXMuZ2V0RmxvYXRBcnJheShtYXAsIFwidmVydGljZXNcIiwgc2NhbGUpO1xuXHRcdFx0bWVzaC50cmlhbmdsZXMgPSB0aGlzLmdldEludEFycmF5KG1hcCwgXCJ0cmlhbmdsZXNcIik7XG5cdFx0XHRtZXNoLnJlZ2lvblVWcyA9IHRoaXMuZ2V0RmxvYXRBcnJheShtYXAsIFwidXZzXCIsIDEpO1xuXHRcdFx0bWVzaC51cGRhdGVVVnMoKTtcblxuXHRcdFx0Y29sb3IgPSBtYXBbXCJjb2xvclwiXTtcblx0XHRcdGlmIChjb2xvcikge1xuXHRcdFx0XHRtZXNoLnIgPSB0aGlzLnRvQ29sb3IoY29sb3IsIDApO1xuXHRcdFx0XHRtZXNoLmcgPSB0aGlzLnRvQ29sb3IoY29sb3IsIDEpO1xuXHRcdFx0XHRtZXNoLmIgPSB0aGlzLnRvQ29sb3IoY29sb3IsIDIpO1xuXHRcdFx0XHRtZXNoLmEgPSB0aGlzLnRvQ29sb3IoY29sb3IsIDMpO1xuXHRcdFx0fVxuXG5cdFx0XHRtZXNoLmh1bGxMZW5ndGggPSAobWFwW1wiaHVsbFwiXSB8fCAwKSAqIDI7XG5cdFx0XHRpZiAobWFwW1wiZWRnZXNcIl0pIG1lc2guZWRnZXMgPSB0aGlzLmdldEludEFycmF5KG1hcCwgXCJlZGdlc1wiKTtcblx0XHRcdG1lc2gud2lkdGggPSAobWFwW1wid2lkdGhcIl0gfHwgMCkgKiBzY2FsZTtcblx0XHRcdG1lc2guaGVpZ2h0ID0gKG1hcFtcImhlaWdodFwiXSB8fCAwKSAqIHNjYWxlO1xuXHRcdFx0cmV0dXJuIG1lc2g7XG5cdFx0fSBlbHNlIGlmICh0eXBlID09IHNwaW5lLkF0dGFjaG1lbnRUeXBlLnNraW5uZWRtZXNoKSB7XG5cdFx0XHR2YXIgbWVzaCA9IHRoaXMuYXR0YWNobWVudExvYWRlci5uZXdTa2lubmVkTWVzaEF0dGFjaG1lbnQoc2tpbiwgbmFtZSwgcGF0aCk7XG5cdFx0XHRpZiAoIW1lc2gpIHJldHVybiBudWxsO1xuXHRcdFx0bWVzaC5wYXRoID0gcGF0aDtcblxuXHRcdFx0dmFyIHV2cyA9IHRoaXMuZ2V0RmxvYXRBcnJheShtYXAsIFwidXZzXCIsIDEpO1xuXHRcdFx0dmFyIHZlcnRpY2VzID0gdGhpcy5nZXRGbG9hdEFycmF5KG1hcCwgXCJ2ZXJ0aWNlc1wiLCAxKTtcblx0XHRcdHZhciB3ZWlnaHRzID0gW107XG5cdFx0XHR2YXIgYm9uZXMgPSBbXTtcblx0XHRcdGZvciAodmFyIGkgPSAwLCBuID0gdmVydGljZXMubGVuZ3RoOyBpIDwgbjsgKSB7XG5cdFx0XHRcdHZhciBib25lQ291bnQgPSB2ZXJ0aWNlc1tpKytdIHwgMDtcblx0XHRcdFx0Ym9uZXNbYm9uZXMubGVuZ3RoXSA9IGJvbmVDb3VudDtcblx0XHRcdFx0Zm9yICh2YXIgbm4gPSBpICsgYm9uZUNvdW50ICogNDsgaSA8IG5uOyApIHtcblx0XHRcdFx0XHRib25lc1tib25lcy5sZW5ndGhdID0gdmVydGljZXNbaV07XG5cdFx0XHRcdFx0d2VpZ2h0c1t3ZWlnaHRzLmxlbmd0aF0gPSB2ZXJ0aWNlc1tpICsgMV0gKiBzY2FsZTtcblx0XHRcdFx0XHR3ZWlnaHRzW3dlaWdodHMubGVuZ3RoXSA9IHZlcnRpY2VzW2kgKyAyXSAqIHNjYWxlO1xuXHRcdFx0XHRcdHdlaWdodHNbd2VpZ2h0cy5sZW5ndGhdID0gdmVydGljZXNbaSArIDNdO1xuXHRcdFx0XHRcdGkgKz0gNDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0bWVzaC5ib25lcyA9IGJvbmVzO1xuXHRcdFx0bWVzaC53ZWlnaHRzID0gd2VpZ2h0cztcblx0XHRcdG1lc2gudHJpYW5nbGVzID0gdGhpcy5nZXRJbnRBcnJheShtYXAsIFwidHJpYW5nbGVzXCIpO1xuXHRcdFx0bWVzaC5yZWdpb25VVnMgPSB1dnM7XG5cdFx0XHRtZXNoLnVwZGF0ZVVWcygpO1xuXG5cdFx0XHRjb2xvciA9IG1hcFtcImNvbG9yXCJdO1xuXHRcdFx0aWYgKGNvbG9yKSB7XG5cdFx0XHRcdG1lc2guciA9IHRoaXMudG9Db2xvcihjb2xvciwgMCk7XG5cdFx0XHRcdG1lc2guZyA9IHRoaXMudG9Db2xvcihjb2xvciwgMSk7XG5cdFx0XHRcdG1lc2guYiA9IHRoaXMudG9Db2xvcihjb2xvciwgMik7XG5cdFx0XHRcdG1lc2guYSA9IHRoaXMudG9Db2xvcihjb2xvciwgMyk7XG5cdFx0XHR9XG5cblx0XHRcdG1lc2guaHVsbExlbmd0aCA9IChtYXBbXCJodWxsXCJdIHx8IDApICogMjtcblx0XHRcdGlmIChtYXBbXCJlZGdlc1wiXSkgbWVzaC5lZGdlcyA9IHRoaXMuZ2V0SW50QXJyYXkobWFwLCBcImVkZ2VzXCIpO1xuXHRcdFx0bWVzaC53aWR0aCA9IChtYXBbXCJ3aWR0aFwiXSB8fCAwKSAqIHNjYWxlO1xuXHRcdFx0bWVzaC5oZWlnaHQgPSAobWFwW1wiaGVpZ2h0XCJdIHx8IDApICogc2NhbGU7XG5cdFx0XHRyZXR1cm4gbWVzaDtcblx0XHR9IGVsc2UgaWYgKHR5cGUgPT0gc3BpbmUuQXR0YWNobWVudFR5cGUuYm91bmRpbmdib3gpIHtcblx0XHRcdHZhciBhdHRhY2htZW50ID0gdGhpcy5hdHRhY2htZW50TG9hZGVyLm5ld0JvdW5kaW5nQm94QXR0YWNobWVudChza2luLCBuYW1lKTtcblx0XHRcdHZhciB2ZXJ0aWNlcyA9IG1hcFtcInZlcnRpY2VzXCJdO1xuXHRcdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSB2ZXJ0aWNlcy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRcdGF0dGFjaG1lbnQudmVydGljZXMucHVzaCh2ZXJ0aWNlc1tpXSAqIHNjYWxlKTtcblx0XHRcdHJldHVybiBhdHRhY2htZW50O1xuXHRcdH1cblx0XHR0aHJvdyBcIlVua25vd24gYXR0YWNobWVudCB0eXBlOiBcIiArIHR5cGU7XG5cdH0sXG5cdHJlYWRBbmltYXRpb246IGZ1bmN0aW9uIChuYW1lLCBtYXAsIHNrZWxldG9uRGF0YSkge1xuXHRcdHZhciB0aW1lbGluZXMgPSBbXTtcblx0XHR2YXIgZHVyYXRpb24gPSAwO1xuXG5cdFx0dmFyIHNsb3RzID0gbWFwW1wic2xvdHNcIl07XG5cdFx0Zm9yICh2YXIgc2xvdE5hbWUgaW4gc2xvdHMpIHtcblx0XHRcdGlmICghc2xvdHMuaGFzT3duUHJvcGVydHkoc2xvdE5hbWUpKSBjb250aW51ZTtcblx0XHRcdHZhciBzbG90TWFwID0gc2xvdHNbc2xvdE5hbWVdO1xuXHRcdFx0dmFyIHNsb3RJbmRleCA9IHNrZWxldG9uRGF0YS5maW5kU2xvdEluZGV4KHNsb3ROYW1lKTtcblxuXHRcdFx0Zm9yICh2YXIgdGltZWxpbmVOYW1lIGluIHNsb3RNYXApIHtcblx0XHRcdFx0aWYgKCFzbG90TWFwLmhhc093blByb3BlcnR5KHRpbWVsaW5lTmFtZSkpIGNvbnRpbnVlO1xuXHRcdFx0XHR2YXIgdmFsdWVzID0gc2xvdE1hcFt0aW1lbGluZU5hbWVdO1xuXHRcdFx0XHRpZiAodGltZWxpbmVOYW1lID09IFwiY29sb3JcIikge1xuXHRcdFx0XHRcdHZhciB0aW1lbGluZSA9IG5ldyBzcGluZS5Db2xvclRpbWVsaW5lKHZhbHVlcy5sZW5ndGgpO1xuXHRcdFx0XHRcdHRpbWVsaW5lLnNsb3RJbmRleCA9IHNsb3RJbmRleDtcblxuXHRcdFx0XHRcdHZhciBmcmFtZUluZGV4ID0gMDtcblx0XHRcdFx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHZhbHVlcy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcblx0XHRcdFx0XHRcdHZhciB2YWx1ZU1hcCA9IHZhbHVlc1tpXTtcblx0XHRcdFx0XHRcdHZhciBjb2xvciA9IHZhbHVlTWFwW1wiY29sb3JcIl07XG5cdFx0XHRcdFx0XHR2YXIgciA9IHRoaXMudG9Db2xvcihjb2xvciwgMCk7XG5cdFx0XHRcdFx0XHR2YXIgZyA9IHRoaXMudG9Db2xvcihjb2xvciwgMSk7XG5cdFx0XHRcdFx0XHR2YXIgYiA9IHRoaXMudG9Db2xvcihjb2xvciwgMik7XG5cdFx0XHRcdFx0XHR2YXIgYSA9IHRoaXMudG9Db2xvcihjb2xvciwgMyk7XG5cdFx0XHRcdFx0XHR0aW1lbGluZS5zZXRGcmFtZShmcmFtZUluZGV4LCB2YWx1ZU1hcFtcInRpbWVcIl0sIHIsIGcsIGIsIGEpO1xuXHRcdFx0XHRcdFx0dGhpcy5yZWFkQ3VydmUodGltZWxpbmUsIGZyYW1lSW5kZXgsIHZhbHVlTWFwKTtcblx0XHRcdFx0XHRcdGZyYW1lSW5kZXgrKztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dGltZWxpbmVzLnB1c2godGltZWxpbmUpO1xuXHRcdFx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoZHVyYXRpb24sIHRpbWVsaW5lLmZyYW1lc1t0aW1lbGluZS5nZXRGcmFtZUNvdW50KCkgKiA1IC0gNV0pO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAodGltZWxpbmVOYW1lID09IFwiYXR0YWNobWVudFwiKSB7XG5cdFx0XHRcdFx0dmFyIHRpbWVsaW5lID0gbmV3IHNwaW5lLkF0dGFjaG1lbnRUaW1lbGluZSh2YWx1ZXMubGVuZ3RoKTtcblx0XHRcdFx0XHR0aW1lbGluZS5zbG90SW5kZXggPSBzbG90SW5kZXg7XG5cblx0XHRcdFx0XHR2YXIgZnJhbWVJbmRleCA9IDA7XG5cdFx0XHRcdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSB2YWx1ZXMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRcdFx0XHR2YXIgdmFsdWVNYXAgPSB2YWx1ZXNbaV07XG5cdFx0XHRcdFx0XHR0aW1lbGluZS5zZXRGcmFtZShmcmFtZUluZGV4KyssIHZhbHVlTWFwW1widGltZVwiXSwgdmFsdWVNYXBbXCJuYW1lXCJdKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dGltZWxpbmVzLnB1c2godGltZWxpbmUpO1xuXHRcdFx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoZHVyYXRpb24sIHRpbWVsaW5lLmZyYW1lc1t0aW1lbGluZS5nZXRGcmFtZUNvdW50KCkgLSAxXSk7XG5cblx0XHRcdFx0fSBlbHNlXG5cdFx0XHRcdFx0dGhyb3cgXCJJbnZhbGlkIHRpbWVsaW5lIHR5cGUgZm9yIGEgc2xvdDogXCIgKyB0aW1lbGluZU5hbWUgKyBcIiAoXCIgKyBzbG90TmFtZSArIFwiKVwiO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHZhciBib25lcyA9IG1hcFtcImJvbmVzXCJdO1xuXHRcdGZvciAodmFyIGJvbmVOYW1lIGluIGJvbmVzKSB7XG5cdFx0XHRpZiAoIWJvbmVzLmhhc093blByb3BlcnR5KGJvbmVOYW1lKSkgY29udGludWU7XG5cdFx0XHR2YXIgYm9uZUluZGV4ID0gc2tlbGV0b25EYXRhLmZpbmRCb25lSW5kZXgoYm9uZU5hbWUpO1xuXHRcdFx0aWYgKGJvbmVJbmRleCA9PSAtMSkgdGhyb3cgXCJCb25lIG5vdCBmb3VuZDogXCIgKyBib25lTmFtZTtcblx0XHRcdHZhciBib25lTWFwID0gYm9uZXNbYm9uZU5hbWVdO1xuXG5cdFx0XHRmb3IgKHZhciB0aW1lbGluZU5hbWUgaW4gYm9uZU1hcCkge1xuXHRcdFx0XHRpZiAoIWJvbmVNYXAuaGFzT3duUHJvcGVydHkodGltZWxpbmVOYW1lKSkgY29udGludWU7XG5cdFx0XHRcdHZhciB2YWx1ZXMgPSBib25lTWFwW3RpbWVsaW5lTmFtZV07XG5cdFx0XHRcdGlmICh0aW1lbGluZU5hbWUgPT0gXCJyb3RhdGVcIikge1xuXHRcdFx0XHRcdHZhciB0aW1lbGluZSA9IG5ldyBzcGluZS5Sb3RhdGVUaW1lbGluZSh2YWx1ZXMubGVuZ3RoKTtcblx0XHRcdFx0XHR0aW1lbGluZS5ib25lSW5kZXggPSBib25lSW5kZXg7XG5cblx0XHRcdFx0XHR2YXIgZnJhbWVJbmRleCA9IDA7XG5cdFx0XHRcdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSB2YWx1ZXMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRcdFx0XHR2YXIgdmFsdWVNYXAgPSB2YWx1ZXNbaV07XG5cdFx0XHRcdFx0XHR0aW1lbGluZS5zZXRGcmFtZShmcmFtZUluZGV4LCB2YWx1ZU1hcFtcInRpbWVcIl0sIHZhbHVlTWFwW1wiYW5nbGVcIl0pO1xuXHRcdFx0XHRcdFx0dGhpcy5yZWFkQ3VydmUodGltZWxpbmUsIGZyYW1lSW5kZXgsIHZhbHVlTWFwKTtcblx0XHRcdFx0XHRcdGZyYW1lSW5kZXgrKztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dGltZWxpbmVzLnB1c2godGltZWxpbmUpO1xuXHRcdFx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoZHVyYXRpb24sIHRpbWVsaW5lLmZyYW1lc1t0aW1lbGluZS5nZXRGcmFtZUNvdW50KCkgKiAyIC0gMl0pO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAodGltZWxpbmVOYW1lID09IFwidHJhbnNsYXRlXCIgfHwgdGltZWxpbmVOYW1lID09IFwic2NhbGVcIikge1xuXHRcdFx0XHRcdHZhciB0aW1lbGluZTtcblx0XHRcdFx0XHR2YXIgdGltZWxpbmVTY2FsZSA9IDE7XG5cdFx0XHRcdFx0aWYgKHRpbWVsaW5lTmFtZSA9PSBcInNjYWxlXCIpXG5cdFx0XHRcdFx0XHR0aW1lbGluZSA9IG5ldyBzcGluZS5TY2FsZVRpbWVsaW5lKHZhbHVlcy5sZW5ndGgpO1xuXHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0dGltZWxpbmUgPSBuZXcgc3BpbmUuVHJhbnNsYXRlVGltZWxpbmUodmFsdWVzLmxlbmd0aCk7XG5cdFx0XHRcdFx0XHR0aW1lbGluZVNjYWxlID0gdGhpcy5zY2FsZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dGltZWxpbmUuYm9uZUluZGV4ID0gYm9uZUluZGV4O1xuXG5cdFx0XHRcdFx0dmFyIGZyYW1lSW5kZXggPSAwO1xuXHRcdFx0XHRcdGZvciAodmFyIGkgPSAwLCBuID0gdmFsdWVzLmxlbmd0aDsgaSA8IG47IGkrKykge1xuXHRcdFx0XHRcdFx0dmFyIHZhbHVlTWFwID0gdmFsdWVzW2ldO1xuXHRcdFx0XHRcdFx0dmFyIHggPSAodmFsdWVNYXBbXCJ4XCJdIHx8IDApICogdGltZWxpbmVTY2FsZTtcblx0XHRcdFx0XHRcdHZhciB5ID0gKHZhbHVlTWFwW1wieVwiXSB8fCAwKSAqIHRpbWVsaW5lU2NhbGU7XG5cdFx0XHRcdFx0XHR0aW1lbGluZS5zZXRGcmFtZShmcmFtZUluZGV4LCB2YWx1ZU1hcFtcInRpbWVcIl0sIHgsIHkpO1xuXHRcdFx0XHRcdFx0dGhpcy5yZWFkQ3VydmUodGltZWxpbmUsIGZyYW1lSW5kZXgsIHZhbHVlTWFwKTtcblx0XHRcdFx0XHRcdGZyYW1lSW5kZXgrKztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dGltZWxpbmVzLnB1c2godGltZWxpbmUpO1xuXHRcdFx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoZHVyYXRpb24sIHRpbWVsaW5lLmZyYW1lc1t0aW1lbGluZS5nZXRGcmFtZUNvdW50KCkgKiAzIC0gM10pO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAodGltZWxpbmVOYW1lID09IFwiZmxpcFhcIiB8fCB0aW1lbGluZU5hbWUgPT0gXCJmbGlwWVwiKSB7XG5cdFx0XHRcdFx0dmFyIHggPSB0aW1lbGluZU5hbWUgPT0gXCJmbGlwWFwiO1xuXHRcdFx0XHRcdHZhciB0aW1lbGluZSA9IHggPyBuZXcgc3BpbmUuRmxpcFhUaW1lbGluZSh2YWx1ZXMubGVuZ3RoKSA6IG5ldyBzcGluZS5GbGlwWVRpbWVsaW5lKHZhbHVlcy5sZW5ndGgpO1xuXHRcdFx0XHRcdHRpbWVsaW5lLmJvbmVJbmRleCA9IGJvbmVJbmRleDtcblxuXHRcdFx0XHRcdHZhciBmaWVsZCA9IHggPyBcInhcIiA6IFwieVwiO1xuXHRcdFx0XHRcdHZhciBmcmFtZUluZGV4ID0gMDtcblx0XHRcdFx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHZhbHVlcy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcblx0XHRcdFx0XHRcdHZhciB2YWx1ZU1hcCA9IHZhbHVlc1tpXTtcblx0XHRcdFx0XHRcdHRpbWVsaW5lLnNldEZyYW1lKGZyYW1lSW5kZXgsIHZhbHVlTWFwW1widGltZVwiXSwgdmFsdWVNYXBbZmllbGRdIHx8IGZhbHNlKTtcblx0XHRcdFx0XHRcdGZyYW1lSW5kZXgrKztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dGltZWxpbmVzLnB1c2godGltZWxpbmUpO1xuXHRcdFx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoZHVyYXRpb24sIHRpbWVsaW5lLmZyYW1lc1t0aW1lbGluZS5nZXRGcmFtZUNvdW50KCkgKiAyIC0gMl0pO1xuXHRcdFx0XHR9IGVsc2Vcblx0XHRcdFx0XHR0aHJvdyBcIkludmFsaWQgdGltZWxpbmUgdHlwZSBmb3IgYSBib25lOiBcIiArIHRpbWVsaW5lTmFtZSArIFwiIChcIiArIGJvbmVOYW1lICsgXCIpXCI7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dmFyIGlrTWFwID0gbWFwW1wiaWtcIl07XG5cdFx0Zm9yICh2YXIgaWtDb25zdHJhaW50TmFtZSBpbiBpa01hcCkge1xuXHRcdFx0aWYgKCFpa01hcC5oYXNPd25Qcm9wZXJ0eShpa0NvbnN0cmFpbnROYW1lKSkgY29udGludWU7XG5cdFx0XHR2YXIgaWtDb25zdHJhaW50ID0gc2tlbGV0b25EYXRhLmZpbmRJa0NvbnN0cmFpbnQoaWtDb25zdHJhaW50TmFtZSk7XG5cdFx0XHR2YXIgdmFsdWVzID0gaWtNYXBbaWtDb25zdHJhaW50TmFtZV07XG5cdFx0XHR2YXIgdGltZWxpbmUgPSBuZXcgc3BpbmUuSWtDb25zdHJhaW50VGltZWxpbmUodmFsdWVzLmxlbmd0aCk7XG5cdFx0XHR0aW1lbGluZS5pa0NvbnN0cmFpbnRJbmRleCA9IHNrZWxldG9uRGF0YS5pa0NvbnN0cmFpbnRzLmluZGV4T2YoaWtDb25zdHJhaW50KTtcblx0XHRcdHZhciBmcmFtZUluZGV4ID0gMDtcblx0XHRcdGZvciAodmFyIGkgPSAwLCBuID0gdmFsdWVzLmxlbmd0aDsgaSA8IG47IGkrKykge1xuXHRcdFx0XHR2YXIgdmFsdWVNYXAgPSB2YWx1ZXNbaV07XG5cdFx0XHRcdHZhciBtaXggPSB2YWx1ZU1hcC5oYXNPd25Qcm9wZXJ0eShcIm1peFwiKSA/IHZhbHVlTWFwW1wibWl4XCJdIDogMTtcblx0XHRcdFx0dmFyIGJlbmREaXJlY3Rpb24gPSAoIXZhbHVlTWFwLmhhc093blByb3BlcnR5KFwiYmVuZFBvc2l0aXZlXCIpIHx8IHZhbHVlTWFwW1wiYmVuZFBvc2l0aXZlXCJdKSA/IDEgOiAtMTtcblx0XHRcdFx0dGltZWxpbmUuc2V0RnJhbWUoZnJhbWVJbmRleCwgdmFsdWVNYXBbXCJ0aW1lXCJdLCBtaXgsIGJlbmREaXJlY3Rpb24pO1xuXHRcdFx0XHR0aGlzLnJlYWRDdXJ2ZSh0aW1lbGluZSwgZnJhbWVJbmRleCwgdmFsdWVNYXApO1xuXHRcdFx0XHRmcmFtZUluZGV4Kys7XG5cdFx0XHR9XG5cdFx0XHR0aW1lbGluZXMucHVzaCh0aW1lbGluZSk7XG5cdFx0XHRkdXJhdGlvbiA9IE1hdGgubWF4KGR1cmF0aW9uLCB0aW1lbGluZS5mcmFtZXNbdGltZWxpbmUuZnJhbWVDb3VudCAqIDMgLSAzXSk7XG5cdFx0fVxuXG5cdFx0dmFyIGZmZCA9IG1hcFtcImZmZFwiXTtcblx0XHRmb3IgKHZhciBza2luTmFtZSBpbiBmZmQpIHtcblx0XHRcdHZhciBza2luID0gc2tlbGV0b25EYXRhLmZpbmRTa2luKHNraW5OYW1lKTtcblx0XHRcdHZhciBzbG90TWFwID0gZmZkW3NraW5OYW1lXTtcblx0XHRcdGZvciAoc2xvdE5hbWUgaW4gc2xvdE1hcCkge1xuXHRcdFx0XHR2YXIgc2xvdEluZGV4ID0gc2tlbGV0b25EYXRhLmZpbmRTbG90SW5kZXgoc2xvdE5hbWUpO1xuXHRcdFx0XHR2YXIgbWVzaE1hcCA9IHNsb3RNYXBbc2xvdE5hbWVdO1xuXHRcdFx0XHRmb3IgKHZhciBtZXNoTmFtZSBpbiBtZXNoTWFwKSB7XG5cdFx0XHRcdFx0dmFyIHZhbHVlcyA9IG1lc2hNYXBbbWVzaE5hbWVdO1xuXHRcdFx0XHRcdHZhciB0aW1lbGluZSA9IG5ldyBzcGluZS5GZmRUaW1lbGluZSh2YWx1ZXMubGVuZ3RoKTtcblx0XHRcdFx0XHR2YXIgYXR0YWNobWVudCA9IHNraW4uZ2V0QXR0YWNobWVudChzbG90SW5kZXgsIG1lc2hOYW1lKTtcblx0XHRcdFx0XHRpZiAoIWF0dGFjaG1lbnQpIHRocm93IFwiRkZEIGF0dGFjaG1lbnQgbm90IGZvdW5kOiBcIiArIG1lc2hOYW1lO1xuXHRcdFx0XHRcdHRpbWVsaW5lLnNsb3RJbmRleCA9IHNsb3RJbmRleDtcblx0XHRcdFx0XHR0aW1lbGluZS5hdHRhY2htZW50ID0gYXR0YWNobWVudDtcblxuXHRcdFx0XHRcdHZhciBpc01lc2ggPSBhdHRhY2htZW50LnR5cGUgPT0gc3BpbmUuQXR0YWNobWVudFR5cGUubWVzaDtcblx0XHRcdFx0XHR2YXIgdmVydGV4Q291bnQ7XG5cdFx0XHRcdFx0aWYgKGlzTWVzaClcblx0XHRcdFx0XHRcdHZlcnRleENvdW50ID0gYXR0YWNobWVudC52ZXJ0aWNlcy5sZW5ndGg7XG5cdFx0XHRcdFx0ZWxzZVxuXHRcdFx0XHRcdFx0dmVydGV4Q291bnQgPSBhdHRhY2htZW50LndlaWdodHMubGVuZ3RoIC8gMyAqIDI7XG5cblx0XHRcdFx0XHR2YXIgZnJhbWVJbmRleCA9IDA7XG5cdFx0XHRcdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSB2YWx1ZXMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRcdFx0XHR2YXIgdmFsdWVNYXAgPSB2YWx1ZXNbaV07XG5cdFx0XHRcdFx0XHR2YXIgdmVydGljZXM7XG5cdFx0XHRcdFx0XHRpZiAoIXZhbHVlTWFwW1widmVydGljZXNcIl0pIHtcblx0XHRcdFx0XHRcdFx0aWYgKGlzTWVzaClcblx0XHRcdFx0XHRcdFx0XHR2ZXJ0aWNlcyA9IGF0dGFjaG1lbnQudmVydGljZXM7XG5cdFx0XHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdHZlcnRpY2VzID0gW107XG5cdFx0XHRcdFx0XHRcdFx0dmVydGljZXMubGVuZ3RoID0gdmVydGV4Q291bnQ7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdHZhciB2ZXJ0aWNlc1ZhbHVlID0gdmFsdWVNYXBbXCJ2ZXJ0aWNlc1wiXTtcblx0XHRcdFx0XHRcdFx0dmFyIHZlcnRpY2VzID0gW107XG5cdFx0XHRcdFx0XHRcdHZlcnRpY2VzLmxlbmd0aCA9IHZlcnRleENvdW50O1xuXHRcdFx0XHRcdFx0XHR2YXIgc3RhcnQgPSB2YWx1ZU1hcFtcIm9mZnNldFwiXSB8fCAwO1xuXHRcdFx0XHRcdFx0XHR2YXIgbm4gPSB2ZXJ0aWNlc1ZhbHVlLmxlbmd0aDtcblx0XHRcdFx0XHRcdFx0aWYgKHRoaXMuc2NhbGUgPT0gMSkge1xuXHRcdFx0XHRcdFx0XHRcdGZvciAodmFyIGlpID0gMDsgaWkgPCBubjsgaWkrKylcblx0XHRcdFx0XHRcdFx0XHRcdHZlcnRpY2VzW2lpICsgc3RhcnRdID0gdmVydGljZXNWYWx1ZVtpaV07XG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0Zm9yICh2YXIgaWkgPSAwOyBpaSA8IG5uOyBpaSsrKVxuXHRcdFx0XHRcdFx0XHRcdFx0dmVydGljZXNbaWkgKyBzdGFydF0gPSB2ZXJ0aWNlc1ZhbHVlW2lpXSAqIHRoaXMuc2NhbGU7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0aWYgKGlzTWVzaCkge1xuXHRcdFx0XHRcdFx0XHRcdHZhciBtZXNoVmVydGljZXMgPSBhdHRhY2htZW50LnZlcnRpY2VzO1xuXHRcdFx0XHRcdFx0XHRcdGZvciAodmFyIGlpID0gMCwgbm4gPSB2ZXJ0aWNlcy5sZW5ndGg7IGlpIDwgbm47IGlpKyspXG5cdFx0XHRcdFx0XHRcdFx0XHR2ZXJ0aWNlc1tpaV0gKz0gbWVzaFZlcnRpY2VzW2lpXTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR0aW1lbGluZS5zZXRGcmFtZShmcmFtZUluZGV4LCB2YWx1ZU1hcFtcInRpbWVcIl0sIHZlcnRpY2VzKTtcblx0XHRcdFx0XHRcdHRoaXMucmVhZEN1cnZlKHRpbWVsaW5lLCBmcmFtZUluZGV4LCB2YWx1ZU1hcCk7XG5cdFx0XHRcdFx0XHRmcmFtZUluZGV4Kys7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHRpbWVsaW5lc1t0aW1lbGluZXMubGVuZ3RoXSA9IHRpbWVsaW5lO1xuXHRcdFx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoZHVyYXRpb24sIHRpbWVsaW5lLmZyYW1lc1t0aW1lbGluZS5mcmFtZUNvdW50IC0gMV0pO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dmFyIGRyYXdPcmRlclZhbHVlcyA9IG1hcFtcImRyYXdPcmRlclwiXTtcblx0XHRpZiAoIWRyYXdPcmRlclZhbHVlcykgZHJhd09yZGVyVmFsdWVzID0gbWFwW1wiZHJhd29yZGVyXCJdO1xuXHRcdGlmIChkcmF3T3JkZXJWYWx1ZXMpIHtcblx0XHRcdHZhciB0aW1lbGluZSA9IG5ldyBzcGluZS5EcmF3T3JkZXJUaW1lbGluZShkcmF3T3JkZXJWYWx1ZXMubGVuZ3RoKTtcblx0XHRcdHZhciBzbG90Q291bnQgPSBza2VsZXRvbkRhdGEuc2xvdHMubGVuZ3RoO1xuXHRcdFx0dmFyIGZyYW1lSW5kZXggPSAwO1xuXHRcdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBkcmF3T3JkZXJWYWx1ZXMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRcdHZhciBkcmF3T3JkZXJNYXAgPSBkcmF3T3JkZXJWYWx1ZXNbaV07XG5cdFx0XHRcdHZhciBkcmF3T3JkZXIgPSBudWxsO1xuXHRcdFx0XHRpZiAoZHJhd09yZGVyTWFwW1wib2Zmc2V0c1wiXSkge1xuXHRcdFx0XHRcdGRyYXdPcmRlciA9IFtdO1xuXHRcdFx0XHRcdGRyYXdPcmRlci5sZW5ndGggPSBzbG90Q291bnQ7XG5cdFx0XHRcdFx0Zm9yICh2YXIgaWkgPSBzbG90Q291bnQgLSAxOyBpaSA+PSAwOyBpaS0tKVxuXHRcdFx0XHRcdFx0ZHJhd09yZGVyW2lpXSA9IC0xO1xuXHRcdFx0XHRcdHZhciBvZmZzZXRzID0gZHJhd09yZGVyTWFwW1wib2Zmc2V0c1wiXTtcblx0XHRcdFx0XHR2YXIgdW5jaGFuZ2VkID0gW107XG5cdFx0XHRcdFx0dW5jaGFuZ2VkLmxlbmd0aCA9IHNsb3RDb3VudCAtIG9mZnNldHMubGVuZ3RoO1xuXHRcdFx0XHRcdHZhciBvcmlnaW5hbEluZGV4ID0gMCwgdW5jaGFuZ2VkSW5kZXggPSAwO1xuXHRcdFx0XHRcdGZvciAodmFyIGlpID0gMCwgbm4gPSBvZmZzZXRzLmxlbmd0aDsgaWkgPCBubjsgaWkrKykge1xuXHRcdFx0XHRcdFx0dmFyIG9mZnNldE1hcCA9IG9mZnNldHNbaWldO1xuXHRcdFx0XHRcdFx0dmFyIHNsb3RJbmRleCA9IHNrZWxldG9uRGF0YS5maW5kU2xvdEluZGV4KG9mZnNldE1hcFtcInNsb3RcIl0pO1xuXHRcdFx0XHRcdFx0aWYgKHNsb3RJbmRleCA9PSAtMSkgdGhyb3cgXCJTbG90IG5vdCBmb3VuZDogXCIgKyBvZmZzZXRNYXBbXCJzbG90XCJdO1xuXHRcdFx0XHRcdFx0Ly8gQ29sbGVjdCB1bmNoYW5nZWQgaXRlbXMuXG5cdFx0XHRcdFx0XHR3aGlsZSAob3JpZ2luYWxJbmRleCAhPSBzbG90SW5kZXgpXG5cdFx0XHRcdFx0XHRcdHVuY2hhbmdlZFt1bmNoYW5nZWRJbmRleCsrXSA9IG9yaWdpbmFsSW5kZXgrKztcblx0XHRcdFx0XHRcdC8vIFNldCBjaGFuZ2VkIGl0ZW1zLlxuXHRcdFx0XHRcdFx0ZHJhd09yZGVyW29yaWdpbmFsSW5kZXggKyBvZmZzZXRNYXBbXCJvZmZzZXRcIl1dID0gb3JpZ2luYWxJbmRleCsrO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHQvLyBDb2xsZWN0IHJlbWFpbmluZyB1bmNoYW5nZWQgaXRlbXMuXG5cdFx0XHRcdFx0d2hpbGUgKG9yaWdpbmFsSW5kZXggPCBzbG90Q291bnQpXG5cdFx0XHRcdFx0XHR1bmNoYW5nZWRbdW5jaGFuZ2VkSW5kZXgrK10gPSBvcmlnaW5hbEluZGV4Kys7XG5cdFx0XHRcdFx0Ly8gRmlsbCBpbiB1bmNoYW5nZWQgaXRlbXMuXG5cdFx0XHRcdFx0Zm9yICh2YXIgaWkgPSBzbG90Q291bnQgLSAxOyBpaSA+PSAwOyBpaS0tKVxuXHRcdFx0XHRcdFx0aWYgKGRyYXdPcmRlcltpaV0gPT0gLTEpIGRyYXdPcmRlcltpaV0gPSB1bmNoYW5nZWRbLS11bmNoYW5nZWRJbmRleF07XG5cdFx0XHRcdH1cblx0XHRcdFx0dGltZWxpbmUuc2V0RnJhbWUoZnJhbWVJbmRleCsrLCBkcmF3T3JkZXJNYXBbXCJ0aW1lXCJdLCBkcmF3T3JkZXIpO1xuXHRcdFx0fVxuXHRcdFx0dGltZWxpbmVzLnB1c2godGltZWxpbmUpO1xuXHRcdFx0ZHVyYXRpb24gPSBNYXRoLm1heChkdXJhdGlvbiwgdGltZWxpbmUuZnJhbWVzW3RpbWVsaW5lLmdldEZyYW1lQ291bnQoKSAtIDFdKTtcblx0XHR9XG5cblx0XHR2YXIgZXZlbnRzID0gbWFwW1wiZXZlbnRzXCJdO1xuXHRcdGlmIChldmVudHMpIHtcblx0XHRcdHZhciB0aW1lbGluZSA9IG5ldyBzcGluZS5FdmVudFRpbWVsaW5lKGV2ZW50cy5sZW5ndGgpO1xuXHRcdFx0dmFyIGZyYW1lSW5kZXggPSAwO1xuXHRcdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBldmVudHMubGVuZ3RoOyBpIDwgbjsgaSsrKSB7XG5cdFx0XHRcdHZhciBldmVudE1hcCA9IGV2ZW50c1tpXTtcblx0XHRcdFx0dmFyIGV2ZW50RGF0YSA9IHNrZWxldG9uRGF0YS5maW5kRXZlbnQoZXZlbnRNYXBbXCJuYW1lXCJdKTtcblx0XHRcdFx0aWYgKCFldmVudERhdGEpIHRocm93IFwiRXZlbnQgbm90IGZvdW5kOiBcIiArIGV2ZW50TWFwW1wibmFtZVwiXTtcblx0XHRcdFx0dmFyIGV2ZW50ID0gbmV3IHNwaW5lLkV2ZW50KGV2ZW50RGF0YSk7XG5cdFx0XHRcdGV2ZW50LmludFZhbHVlID0gZXZlbnRNYXAuaGFzT3duUHJvcGVydHkoXCJpbnRcIikgPyBldmVudE1hcFtcImludFwiXSA6IGV2ZW50RGF0YS5pbnRWYWx1ZTtcblx0XHRcdFx0ZXZlbnQuZmxvYXRWYWx1ZSA9IGV2ZW50TWFwLmhhc093blByb3BlcnR5KFwiZmxvYXRcIikgPyBldmVudE1hcFtcImZsb2F0XCJdIDogZXZlbnREYXRhLmZsb2F0VmFsdWU7XG5cdFx0XHRcdGV2ZW50LnN0cmluZ1ZhbHVlID0gZXZlbnRNYXAuaGFzT3duUHJvcGVydHkoXCJzdHJpbmdcIikgPyBldmVudE1hcFtcInN0cmluZ1wiXSA6IGV2ZW50RGF0YS5zdHJpbmdWYWx1ZTtcblx0XHRcdFx0dGltZWxpbmUuc2V0RnJhbWUoZnJhbWVJbmRleCsrLCBldmVudE1hcFtcInRpbWVcIl0sIGV2ZW50KTtcblx0XHRcdH1cblx0XHRcdHRpbWVsaW5lcy5wdXNoKHRpbWVsaW5lKTtcblx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoZHVyYXRpb24sIHRpbWVsaW5lLmZyYW1lc1t0aW1lbGluZS5nZXRGcmFtZUNvdW50KCkgLSAxXSk7XG5cdFx0fVxuXG5cdFx0c2tlbGV0b25EYXRhLmFuaW1hdGlvbnMucHVzaChuZXcgc3BpbmUuQW5pbWF0aW9uKG5hbWUsIHRpbWVsaW5lcywgZHVyYXRpb24pKTtcblx0fSxcblx0cmVhZEN1cnZlOiBmdW5jdGlvbiAodGltZWxpbmUsIGZyYW1lSW5kZXgsIHZhbHVlTWFwKSB7XG5cdFx0dmFyIGN1cnZlID0gdmFsdWVNYXBbXCJjdXJ2ZVwiXTtcblx0XHRpZiAoIWN1cnZlKVxuXHRcdFx0dGltZWxpbmUuY3VydmVzLnNldExpbmVhcihmcmFtZUluZGV4KTtcblx0XHRlbHNlIGlmIChjdXJ2ZSA9PSBcInN0ZXBwZWRcIilcblx0XHRcdHRpbWVsaW5lLmN1cnZlcy5zZXRTdGVwcGVkKGZyYW1lSW5kZXgpO1xuXHRcdGVsc2UgaWYgKGN1cnZlIGluc3RhbmNlb2YgQXJyYXkpXG5cdFx0XHR0aW1lbGluZS5jdXJ2ZXMuc2V0Q3VydmUoZnJhbWVJbmRleCwgY3VydmVbMF0sIGN1cnZlWzFdLCBjdXJ2ZVsyXSwgY3VydmVbM10pO1xuXHR9LFxuXHR0b0NvbG9yOiBmdW5jdGlvbiAoaGV4U3RyaW5nLCBjb2xvckluZGV4KSB7XG5cdFx0aWYgKGhleFN0cmluZy5sZW5ndGggIT0gOCkgdGhyb3cgXCJDb2xvciBoZXhpZGVjaW1hbCBsZW5ndGggbXVzdCBiZSA4LCByZWNpZXZlZDogXCIgKyBoZXhTdHJpbmc7XG5cdFx0cmV0dXJuIHBhcnNlSW50KGhleFN0cmluZy5zdWJzdHJpbmcoY29sb3JJbmRleCAqIDIsIChjb2xvckluZGV4ICogMikgKyAyKSwgMTYpIC8gMjU1O1xuXHR9LFxuXHRnZXRGbG9hdEFycmF5OiBmdW5jdGlvbiAobWFwLCBuYW1lLCBzY2FsZSkge1xuXHRcdHZhciBsaXN0ID0gbWFwW25hbWVdO1xuXHRcdHZhciB2YWx1ZXMgPSBuZXcgc3BpbmUuRmxvYXQzMkFycmF5KGxpc3QubGVuZ3RoKTtcblx0XHR2YXIgaSA9IDAsIG4gPSBsaXN0Lmxlbmd0aDtcblx0XHRpZiAoc2NhbGUgPT0gMSkge1xuXHRcdFx0Zm9yICg7IGkgPCBuOyBpKyspXG5cdFx0XHRcdHZhbHVlc1tpXSA9IGxpc3RbaV07XG5cdFx0fSBlbHNlIHtcblx0XHRcdGZvciAoOyBpIDwgbjsgaSsrKVxuXHRcdFx0XHR2YWx1ZXNbaV0gPSBsaXN0W2ldICogc2NhbGU7XG5cdFx0fVxuXHRcdHJldHVybiB2YWx1ZXM7XG5cdH0sXG5cdGdldEludEFycmF5OiBmdW5jdGlvbiAobWFwLCBuYW1lKSB7XG5cdFx0dmFyIGxpc3QgPSBtYXBbbmFtZV07XG5cdFx0dmFyIHZhbHVlcyA9IG5ldyBzcGluZS5VaW50MTZBcnJheShsaXN0Lmxlbmd0aCk7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBsaXN0Lmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdHZhbHVlc1tpXSA9IGxpc3RbaV0gfCAwO1xuXHRcdHJldHVybiB2YWx1ZXM7XG5cdH1cbn07XG5cbnNwaW5lLkF0bGFzID0gZnVuY3Rpb24gKGF0bGFzVGV4dCwgdGV4dHVyZUxvYWRlcikge1xuXHR0aGlzLnRleHR1cmVMb2FkZXIgPSB0ZXh0dXJlTG9hZGVyO1xuXHR0aGlzLnBhZ2VzID0gW107XG5cdHRoaXMucmVnaW9ucyA9IFtdO1xuXG5cdHZhciByZWFkZXIgPSBuZXcgc3BpbmUuQXRsYXNSZWFkZXIoYXRsYXNUZXh0KTtcblx0dmFyIHR1cGxlID0gW107XG5cdHR1cGxlLmxlbmd0aCA9IDQ7XG5cdHZhciBwYWdlID0gbnVsbDtcblx0d2hpbGUgKHRydWUpIHtcblx0XHR2YXIgbGluZSA9IHJlYWRlci5yZWFkTGluZSgpO1xuXHRcdGlmIChsaW5lID09PSBudWxsKSBicmVhaztcblx0XHRsaW5lID0gcmVhZGVyLnRyaW0obGluZSk7XG5cdFx0aWYgKCFsaW5lLmxlbmd0aClcblx0XHRcdHBhZ2UgPSBudWxsO1xuXHRcdGVsc2UgaWYgKCFwYWdlKSB7XG5cdFx0XHRwYWdlID0gbmV3IHNwaW5lLkF0bGFzUGFnZSgpO1xuXHRcdFx0cGFnZS5uYW1lID0gbGluZTtcblxuXHRcdFx0aWYgKHJlYWRlci5yZWFkVHVwbGUodHVwbGUpID09IDIpIHsgLy8gc2l6ZSBpcyBvbmx5IG9wdGlvbmFsIGZvciBhbiBhdGxhcyBwYWNrZWQgd2l0aCBhbiBvbGQgVGV4dHVyZVBhY2tlci5cblx0XHRcdFx0cGFnZS53aWR0aCA9IHBhcnNlSW50KHR1cGxlWzBdKTtcblx0XHRcdFx0cGFnZS5oZWlnaHQgPSBwYXJzZUludCh0dXBsZVsxXSk7XG5cdFx0XHRcdHJlYWRlci5yZWFkVHVwbGUodHVwbGUpO1xuXHRcdFx0fVxuXHRcdFx0cGFnZS5mb3JtYXQgPSBzcGluZS5BdGxhcy5Gb3JtYXRbdHVwbGVbMF1dO1xuXG5cdFx0XHRyZWFkZXIucmVhZFR1cGxlKHR1cGxlKTtcblx0XHRcdHBhZ2UubWluRmlsdGVyID0gc3BpbmUuQXRsYXMuVGV4dHVyZUZpbHRlclt0dXBsZVswXV07XG5cdFx0XHRwYWdlLm1hZ0ZpbHRlciA9IHNwaW5lLkF0bGFzLlRleHR1cmVGaWx0ZXJbdHVwbGVbMV1dO1xuXG5cdFx0XHR2YXIgZGlyZWN0aW9uID0gcmVhZGVyLnJlYWRWYWx1ZSgpO1xuXHRcdFx0cGFnZS51V3JhcCA9IHNwaW5lLkF0bGFzLlRleHR1cmVXcmFwLmNsYW1wVG9FZGdlO1xuXHRcdFx0cGFnZS52V3JhcCA9IHNwaW5lLkF0bGFzLlRleHR1cmVXcmFwLmNsYW1wVG9FZGdlO1xuXHRcdFx0aWYgKGRpcmVjdGlvbiA9PSBcInhcIilcblx0XHRcdFx0cGFnZS51V3JhcCA9IHNwaW5lLkF0bGFzLlRleHR1cmVXcmFwLnJlcGVhdDtcblx0XHRcdGVsc2UgaWYgKGRpcmVjdGlvbiA9PSBcInlcIilcblx0XHRcdFx0cGFnZS52V3JhcCA9IHNwaW5lLkF0bGFzLlRleHR1cmVXcmFwLnJlcGVhdDtcblx0XHRcdGVsc2UgaWYgKGRpcmVjdGlvbiA9PSBcInh5XCIpXG5cdFx0XHRcdHBhZ2UudVdyYXAgPSBwYWdlLnZXcmFwID0gc3BpbmUuQXRsYXMuVGV4dHVyZVdyYXAucmVwZWF0O1xuXG5cdFx0XHR0ZXh0dXJlTG9hZGVyLmxvYWQocGFnZSwgbGluZSwgdGhpcyk7XG5cblx0XHRcdHRoaXMucGFnZXMucHVzaChwYWdlKTtcblxuXHRcdH0gZWxzZSB7XG5cdFx0XHR2YXIgcmVnaW9uID0gbmV3IHNwaW5lLkF0bGFzUmVnaW9uKCk7XG5cdFx0XHRyZWdpb24ubmFtZSA9IGxpbmU7XG5cdFx0XHRyZWdpb24ucGFnZSA9IHBhZ2U7XG5cblx0XHRcdHJlZ2lvbi5yb3RhdGUgPSByZWFkZXIucmVhZFZhbHVlKCkgPT0gXCJ0cnVlXCI7XG5cblx0XHRcdHJlYWRlci5yZWFkVHVwbGUodHVwbGUpO1xuXHRcdFx0dmFyIHggPSBwYXJzZUludCh0dXBsZVswXSk7XG5cdFx0XHR2YXIgeSA9IHBhcnNlSW50KHR1cGxlWzFdKTtcblxuXHRcdFx0cmVhZGVyLnJlYWRUdXBsZSh0dXBsZSk7XG5cdFx0XHR2YXIgd2lkdGggPSBwYXJzZUludCh0dXBsZVswXSk7XG5cdFx0XHR2YXIgaGVpZ2h0ID0gcGFyc2VJbnQodHVwbGVbMV0pO1xuXG5cdFx0XHRyZWdpb24udSA9IHggLyBwYWdlLndpZHRoO1xuXHRcdFx0cmVnaW9uLnYgPSB5IC8gcGFnZS5oZWlnaHQ7XG5cdFx0XHRpZiAocmVnaW9uLnJvdGF0ZSkge1xuXHRcdFx0XHRyZWdpb24udTIgPSAoeCArIGhlaWdodCkgLyBwYWdlLndpZHRoO1xuXHRcdFx0XHRyZWdpb24udjIgPSAoeSArIHdpZHRoKSAvIHBhZ2UuaGVpZ2h0O1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cmVnaW9uLnUyID0gKHggKyB3aWR0aCkgLyBwYWdlLndpZHRoO1xuXHRcdFx0XHRyZWdpb24udjIgPSAoeSArIGhlaWdodCkgLyBwYWdlLmhlaWdodDtcblx0XHRcdH1cblx0XHRcdHJlZ2lvbi54ID0geDtcblx0XHRcdHJlZ2lvbi55ID0geTtcblx0XHRcdHJlZ2lvbi53aWR0aCA9IE1hdGguYWJzKHdpZHRoKTtcblx0XHRcdHJlZ2lvbi5oZWlnaHQgPSBNYXRoLmFicyhoZWlnaHQpO1xuXG5cdFx0XHRpZiAocmVhZGVyLnJlYWRUdXBsZSh0dXBsZSkgPT0gNCkgeyAvLyBzcGxpdCBpcyBvcHRpb25hbFxuXHRcdFx0XHRyZWdpb24uc3BsaXRzID0gW3BhcnNlSW50KHR1cGxlWzBdKSwgcGFyc2VJbnQodHVwbGVbMV0pLCBwYXJzZUludCh0dXBsZVsyXSksIHBhcnNlSW50KHR1cGxlWzNdKV07XG5cblx0XHRcdFx0aWYgKHJlYWRlci5yZWFkVHVwbGUodHVwbGUpID09IDQpIHsgLy8gcGFkIGlzIG9wdGlvbmFsLCBidXQgb25seSBwcmVzZW50IHdpdGggc3BsaXRzXG5cdFx0XHRcdFx0cmVnaW9uLnBhZHMgPSBbcGFyc2VJbnQodHVwbGVbMF0pLCBwYXJzZUludCh0dXBsZVsxXSksIHBhcnNlSW50KHR1cGxlWzJdKSwgcGFyc2VJbnQodHVwbGVbM10pXTtcblxuXHRcdFx0XHRcdHJlYWRlci5yZWFkVHVwbGUodHVwbGUpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdHJlZ2lvbi5vcmlnaW5hbFdpZHRoID0gcGFyc2VJbnQodHVwbGVbMF0pO1xuXHRcdFx0cmVnaW9uLm9yaWdpbmFsSGVpZ2h0ID0gcGFyc2VJbnQodHVwbGVbMV0pO1xuXG5cdFx0XHRyZWFkZXIucmVhZFR1cGxlKHR1cGxlKTtcblx0XHRcdHJlZ2lvbi5vZmZzZXRYID0gcGFyc2VJbnQodHVwbGVbMF0pO1xuXHRcdFx0cmVnaW9uLm9mZnNldFkgPSBwYXJzZUludCh0dXBsZVsxXSk7XG5cblx0XHRcdHJlZ2lvbi5pbmRleCA9IHBhcnNlSW50KHJlYWRlci5yZWFkVmFsdWUoKSk7XG5cblx0XHRcdHRoaXMucmVnaW9ucy5wdXNoKHJlZ2lvbik7XG5cdFx0fVxuXHR9XG59O1xuc3BpbmUuQXRsYXMucHJvdG90eXBlID0ge1xuXHRmaW5kUmVnaW9uOiBmdW5jdGlvbiAobmFtZSkge1xuXHRcdHZhciByZWdpb25zID0gdGhpcy5yZWdpb25zO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gcmVnaW9ucy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRpZiAocmVnaW9uc1tpXS5uYW1lID09IG5hbWUpIHJldHVybiByZWdpb25zW2ldO1xuXHRcdHJldHVybiBudWxsO1xuXHR9LFxuXHRkaXNwb3NlOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIHBhZ2VzID0gdGhpcy5wYWdlcztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHBhZ2VzLmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdHRoaXMudGV4dHVyZUxvYWRlci51bmxvYWQocGFnZXNbaV0ucmVuZGVyZXJPYmplY3QpO1xuXHR9LFxuXHR1cGRhdGVVVnM6IGZ1bmN0aW9uIChwYWdlKSB7XG5cdFx0dmFyIHJlZ2lvbnMgPSB0aGlzLnJlZ2lvbnM7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSByZWdpb25zLmxlbmd0aDsgaSA8IG47IGkrKykge1xuXHRcdFx0dmFyIHJlZ2lvbiA9IHJlZ2lvbnNbaV07XG5cdFx0XHRpZiAocmVnaW9uLnBhZ2UgIT0gcGFnZSkgY29udGludWU7XG5cdFx0XHRyZWdpb24udSA9IHJlZ2lvbi54IC8gcGFnZS53aWR0aDtcblx0XHRcdHJlZ2lvbi52ID0gcmVnaW9uLnkgLyBwYWdlLmhlaWdodDtcblx0XHRcdGlmIChyZWdpb24ucm90YXRlKSB7XG5cdFx0XHRcdHJlZ2lvbi51MiA9IChyZWdpb24ueCArIHJlZ2lvbi5oZWlnaHQpIC8gcGFnZS53aWR0aDtcblx0XHRcdFx0cmVnaW9uLnYyID0gKHJlZ2lvbi55ICsgcmVnaW9uLndpZHRoKSAvIHBhZ2UuaGVpZ2h0O1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cmVnaW9uLnUyID0gKHJlZ2lvbi54ICsgcmVnaW9uLndpZHRoKSAvIHBhZ2Uud2lkdGg7XG5cdFx0XHRcdHJlZ2lvbi52MiA9IChyZWdpb24ueSArIHJlZ2lvbi5oZWlnaHQpIC8gcGFnZS5oZWlnaHQ7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG59O1xuXG5zcGluZS5BdGxhcy5Gb3JtYXQgPSB7XG5cdGFscGhhOiAwLFxuXHRpbnRlbnNpdHk6IDEsXG5cdGx1bWluYW5jZUFscGhhOiAyLFxuXHRyZ2I1NjU6IDMsXG5cdHJnYmE0NDQ0OiA0LFxuXHRyZ2I4ODg6IDUsXG5cdHJnYmE4ODg4OiA2XG59O1xuXG5zcGluZS5BdGxhcy5UZXh0dXJlRmlsdGVyID0ge1xuXHRuZWFyZXN0OiAwLFxuXHRsaW5lYXI6IDEsXG5cdG1pcE1hcDogMixcblx0bWlwTWFwTmVhcmVzdE5lYXJlc3Q6IDMsXG5cdG1pcE1hcExpbmVhck5lYXJlc3Q6IDQsXG5cdG1pcE1hcE5lYXJlc3RMaW5lYXI6IDUsXG5cdG1pcE1hcExpbmVhckxpbmVhcjogNlxufTtcblxuc3BpbmUuQXRsYXMuVGV4dHVyZVdyYXAgPSB7XG5cdG1pcnJvcmVkUmVwZWF0OiAwLFxuXHRjbGFtcFRvRWRnZTogMSxcblx0cmVwZWF0OiAyXG59O1xuXG5zcGluZS5BdGxhc1BhZ2UgPSBmdW5jdGlvbiAoKSB7fTtcbnNwaW5lLkF0bGFzUGFnZS5wcm90b3R5cGUgPSB7XG5cdG5hbWU6IG51bGwsXG5cdGZvcm1hdDogbnVsbCxcblx0bWluRmlsdGVyOiBudWxsLFxuXHRtYWdGaWx0ZXI6IG51bGwsXG5cdHVXcmFwOiBudWxsLFxuXHR2V3JhcDogbnVsbCxcblx0cmVuZGVyZXJPYmplY3Q6IG51bGwsXG5cdHdpZHRoOiAwLFxuXHRoZWlnaHQ6IDBcbn07XG5cbnNwaW5lLkF0bGFzUmVnaW9uID0gZnVuY3Rpb24gKCkge307XG5zcGluZS5BdGxhc1JlZ2lvbi5wcm90b3R5cGUgPSB7XG5cdHBhZ2U6IG51bGwsXG5cdG5hbWU6IG51bGwsXG5cdHg6IDAsIHk6IDAsXG5cdHdpZHRoOiAwLCBoZWlnaHQ6IDAsXG5cdHU6IDAsIHY6IDAsIHUyOiAwLCB2MjogMCxcblx0b2Zmc2V0WDogMCwgb2Zmc2V0WTogMCxcblx0b3JpZ2luYWxXaWR0aDogMCwgb3JpZ2luYWxIZWlnaHQ6IDAsXG5cdGluZGV4OiAwLFxuXHRyb3RhdGU6IGZhbHNlLFxuXHRzcGxpdHM6IG51bGwsXG5cdHBhZHM6IG51bGxcbn07XG5cbnNwaW5lLkF0bGFzUmVhZGVyID0gZnVuY3Rpb24gKHRleHQpIHtcblx0dGhpcy5saW5lcyA9IHRleHQuc3BsaXQoL1xcclxcbnxcXHJ8XFxuLyk7XG59O1xuc3BpbmUuQXRsYXNSZWFkZXIucHJvdG90eXBlID0ge1xuXHRpbmRleDogMCxcblx0dHJpbTogZnVuY3Rpb24gKHZhbHVlKSB7XG5cdFx0cmV0dXJuIHZhbHVlLnJlcGxhY2UoL15cXHMrfFxccyskL2csIFwiXCIpO1xuXHR9LFxuXHRyZWFkTGluZTogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLmluZGV4ID49IHRoaXMubGluZXMubGVuZ3RoKSByZXR1cm4gbnVsbDtcblx0XHRyZXR1cm4gdGhpcy5saW5lc1t0aGlzLmluZGV4KytdO1xuXHR9LFxuXHRyZWFkVmFsdWU6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgbGluZSA9IHRoaXMucmVhZExpbmUoKTtcblx0XHR2YXIgY29sb24gPSBsaW5lLmluZGV4T2YoXCI6XCIpO1xuXHRcdGlmIChjb2xvbiA9PSAtMSkgdGhyb3cgXCJJbnZhbGlkIGxpbmU6IFwiICsgbGluZTtcblx0XHRyZXR1cm4gdGhpcy50cmltKGxpbmUuc3Vic3RyaW5nKGNvbG9uICsgMSkpO1xuXHR9LFxuXHQvKiogUmV0dXJucyB0aGUgbnVtYmVyIG9mIHR1cGxlIHZhbHVlcyByZWFkICgxLCAyIG9yIDQpLiAqL1xuXHRyZWFkVHVwbGU6IGZ1bmN0aW9uICh0dXBsZSkge1xuXHRcdHZhciBsaW5lID0gdGhpcy5yZWFkTGluZSgpO1xuXHRcdHZhciBjb2xvbiA9IGxpbmUuaW5kZXhPZihcIjpcIik7XG5cdFx0aWYgKGNvbG9uID09IC0xKSB0aHJvdyBcIkludmFsaWQgbGluZTogXCIgKyBsaW5lO1xuXHRcdHZhciBpID0gMCwgbGFzdE1hdGNoID0gY29sb24gKyAxO1xuXHRcdGZvciAoOyBpIDwgMzsgaSsrKSB7XG5cdFx0XHR2YXIgY29tbWEgPSBsaW5lLmluZGV4T2YoXCIsXCIsIGxhc3RNYXRjaCk7XG5cdFx0XHRpZiAoY29tbWEgPT0gLTEpIGJyZWFrO1xuXHRcdFx0dHVwbGVbaV0gPSB0aGlzLnRyaW0obGluZS5zdWJzdHIobGFzdE1hdGNoLCBjb21tYSAtIGxhc3RNYXRjaCkpO1xuXHRcdFx0bGFzdE1hdGNoID0gY29tbWEgKyAxO1xuXHRcdH1cblx0XHR0dXBsZVtpXSA9IHRoaXMudHJpbShsaW5lLnN1YnN0cmluZyhsYXN0TWF0Y2gpKTtcblx0XHRyZXR1cm4gaSArIDE7XG5cdH1cbn07XG5cbnNwaW5lLkF0bGFzQXR0YWNobWVudExvYWRlciA9IGZ1bmN0aW9uIChhdGxhcykge1xuXHR0aGlzLmF0bGFzID0gYXRsYXM7XG59O1xuc3BpbmUuQXRsYXNBdHRhY2htZW50TG9hZGVyLnByb3RvdHlwZSA9IHtcblx0bmV3UmVnaW9uQXR0YWNobWVudDogZnVuY3Rpb24gKHNraW4sIG5hbWUsIHBhdGgpIHtcblx0XHR2YXIgcmVnaW9uID0gdGhpcy5hdGxhcy5maW5kUmVnaW9uKHBhdGgpO1xuXHRcdGlmICghcmVnaW9uKSB0aHJvdyBcIlJlZ2lvbiBub3QgZm91bmQgaW4gYXRsYXM6IFwiICsgcGF0aCArIFwiIChyZWdpb24gYXR0YWNobWVudDogXCIgKyBuYW1lICsgXCIpXCI7XG5cdFx0dmFyIGF0dGFjaG1lbnQgPSBuZXcgc3BpbmUuUmVnaW9uQXR0YWNobWVudChuYW1lKTtcblx0XHRhdHRhY2htZW50LnJlbmRlcmVyT2JqZWN0ID0gcmVnaW9uO1xuXHRcdGF0dGFjaG1lbnQuc2V0VVZzKHJlZ2lvbi51LCByZWdpb24udiwgcmVnaW9uLnUyLCByZWdpb24udjIsIHJlZ2lvbi5yb3RhdGUpO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT2Zmc2V0WCA9IHJlZ2lvbi5vZmZzZXRYO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT2Zmc2V0WSA9IHJlZ2lvbi5vZmZzZXRZO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uV2lkdGggPSByZWdpb24ud2lkdGg7XG5cdFx0YXR0YWNobWVudC5yZWdpb25IZWlnaHQgPSByZWdpb24uaGVpZ2h0O1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT3JpZ2luYWxXaWR0aCA9IHJlZ2lvbi5vcmlnaW5hbFdpZHRoO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT3JpZ2luYWxIZWlnaHQgPSByZWdpb24ub3JpZ2luYWxIZWlnaHQ7XG5cdFx0cmV0dXJuIGF0dGFjaG1lbnQ7XG5cdH0sXG5cdG5ld01lc2hBdHRhY2htZW50OiBmdW5jdGlvbiAoc2tpbiwgbmFtZSwgcGF0aCkge1xuXHRcdHZhciByZWdpb24gPSB0aGlzLmF0bGFzLmZpbmRSZWdpb24ocGF0aCk7XG5cdFx0aWYgKCFyZWdpb24pIHRocm93IFwiUmVnaW9uIG5vdCBmb3VuZCBpbiBhdGxhczogXCIgKyBwYXRoICsgXCIgKG1lc2ggYXR0YWNobWVudDogXCIgKyBuYW1lICsgXCIpXCI7XG5cdFx0dmFyIGF0dGFjaG1lbnQgPSBuZXcgc3BpbmUuTWVzaEF0dGFjaG1lbnQobmFtZSk7XG5cdFx0YXR0YWNobWVudC5yZW5kZXJlck9iamVjdCA9IHJlZ2lvbjtcblx0XHRhdHRhY2htZW50LnJlZ2lvblUgPSByZWdpb24udTtcblx0XHRhdHRhY2htZW50LnJlZ2lvblYgPSByZWdpb24udjtcblx0XHRhdHRhY2htZW50LnJlZ2lvblUyID0gcmVnaW9uLnUyO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uVjIgPSByZWdpb24udjI7XG5cdFx0YXR0YWNobWVudC5yZWdpb25Sb3RhdGUgPSByZWdpb24ucm90YXRlO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT2Zmc2V0WCA9IHJlZ2lvbi5vZmZzZXRYO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT2Zmc2V0WSA9IHJlZ2lvbi5vZmZzZXRZO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uV2lkdGggPSByZWdpb24ud2lkdGg7XG5cdFx0YXR0YWNobWVudC5yZWdpb25IZWlnaHQgPSByZWdpb24uaGVpZ2h0O1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT3JpZ2luYWxXaWR0aCA9IHJlZ2lvbi5vcmlnaW5hbFdpZHRoO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uT3JpZ2luYWxIZWlnaHQgPSByZWdpb24ub3JpZ2luYWxIZWlnaHQ7XG5cdFx0cmV0dXJuIGF0dGFjaG1lbnQ7XG5cdH0sXG5cdG5ld1NraW5uZWRNZXNoQXR0YWNobWVudDogZnVuY3Rpb24gKHNraW4sIG5hbWUsIHBhdGgpIHtcblx0XHR2YXIgcmVnaW9uID0gdGhpcy5hdGxhcy5maW5kUmVnaW9uKHBhdGgpO1xuXHRcdGlmICghcmVnaW9uKSB0aHJvdyBcIlJlZ2lvbiBub3QgZm91bmQgaW4gYXRsYXM6IFwiICsgcGF0aCArIFwiIChza2lubmVkIG1lc2ggYXR0YWNobWVudDogXCIgKyBuYW1lICsgXCIpXCI7XG5cdFx0dmFyIGF0dGFjaG1lbnQgPSBuZXcgc3BpbmUuU2tpbm5lZE1lc2hBdHRhY2htZW50KG5hbWUpO1xuXHRcdGF0dGFjaG1lbnQucmVuZGVyZXJPYmplY3QgPSByZWdpb247XG5cdFx0YXR0YWNobWVudC5yZWdpb25VID0gcmVnaW9uLnU7XG5cdFx0YXR0YWNobWVudC5yZWdpb25WID0gcmVnaW9uLnY7XG5cdFx0YXR0YWNobWVudC5yZWdpb25VMiA9IHJlZ2lvbi51Mjtcblx0XHRhdHRhY2htZW50LnJlZ2lvblYyID0gcmVnaW9uLnYyO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uUm90YXRlID0gcmVnaW9uLnJvdGF0ZTtcblx0XHRhdHRhY2htZW50LnJlZ2lvbk9mZnNldFggPSByZWdpb24ub2Zmc2V0WDtcblx0XHRhdHRhY2htZW50LnJlZ2lvbk9mZnNldFkgPSByZWdpb24ub2Zmc2V0WTtcblx0XHRhdHRhY2htZW50LnJlZ2lvbldpZHRoID0gcmVnaW9uLndpZHRoO1xuXHRcdGF0dGFjaG1lbnQucmVnaW9uSGVpZ2h0ID0gcmVnaW9uLmhlaWdodDtcblx0XHRhdHRhY2htZW50LnJlZ2lvbk9yaWdpbmFsV2lkdGggPSByZWdpb24ub3JpZ2luYWxXaWR0aDtcblx0XHRhdHRhY2htZW50LnJlZ2lvbk9yaWdpbmFsSGVpZ2h0ID0gcmVnaW9uLm9yaWdpbmFsSGVpZ2h0O1xuXHRcdHJldHVybiBhdHRhY2htZW50O1xuXHR9LFxuXHRuZXdCb3VuZGluZ0JveEF0dGFjaG1lbnQ6IGZ1bmN0aW9uIChza2luLCBuYW1lKSB7XG5cdFx0cmV0dXJuIG5ldyBzcGluZS5Cb3VuZGluZ0JveEF0dGFjaG1lbnQobmFtZSk7XG5cdH1cbn07XG5cbnNwaW5lLlNrZWxldG9uQm91bmRzID0gZnVuY3Rpb24gKCkge1xuXHR0aGlzLnBvbHlnb25Qb29sID0gW107XG5cdHRoaXMucG9seWdvbnMgPSBbXTtcblx0dGhpcy5ib3VuZGluZ0JveGVzID0gW107XG59O1xuc3BpbmUuU2tlbGV0b25Cb3VuZHMucHJvdG90eXBlID0ge1xuXHRtaW5YOiAwLCBtaW5ZOiAwLCBtYXhYOiAwLCBtYXhZOiAwLFxuXHR1cGRhdGU6IGZ1bmN0aW9uIChza2VsZXRvbiwgdXBkYXRlQWFiYikge1xuXHRcdHZhciBzbG90cyA9IHNrZWxldG9uLnNsb3RzO1xuXHRcdHZhciBzbG90Q291bnQgPSBzbG90cy5sZW5ndGg7XG5cdFx0dmFyIHggPSBza2VsZXRvbi54LCB5ID0gc2tlbGV0b24ueTtcblx0XHR2YXIgYm91bmRpbmdCb3hlcyA9IHRoaXMuYm91bmRpbmdCb3hlcztcblx0XHR2YXIgcG9seWdvblBvb2wgPSB0aGlzLnBvbHlnb25Qb29sO1xuXHRcdHZhciBwb2x5Z29ucyA9IHRoaXMucG9seWdvbnM7XG5cblx0XHRib3VuZGluZ0JveGVzLmxlbmd0aCA9IDA7XG5cdFx0Zm9yICh2YXIgaSA9IDAsIG4gPSBwb2x5Z29ucy5sZW5ndGg7IGkgPCBuOyBpKyspXG5cdFx0XHRwb2x5Z29uUG9vbC5wdXNoKHBvbHlnb25zW2ldKTtcblx0XHRwb2x5Z29ucy5sZW5ndGggPSAwO1xuXG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBzbG90Q291bnQ7IGkrKykge1xuXHRcdFx0dmFyIHNsb3QgPSBzbG90c1tpXTtcblx0XHRcdHZhciBib3VuZGluZ0JveCA9IHNsb3QuYXR0YWNobWVudDtcblx0XHRcdGlmIChib3VuZGluZ0JveC50eXBlICE9IHNwaW5lLkF0dGFjaG1lbnRUeXBlLmJvdW5kaW5nYm94KSBjb250aW51ZTtcblx0XHRcdGJvdW5kaW5nQm94ZXMucHVzaChib3VuZGluZ0JveCk7XG5cblx0XHRcdHZhciBwb29sQ291bnQgPSBwb2x5Z29uUG9vbC5sZW5ndGgsIHBvbHlnb247XG5cdFx0XHRpZiAocG9vbENvdW50ID4gMCkge1xuXHRcdFx0XHRwb2x5Z29uID0gcG9seWdvblBvb2xbcG9vbENvdW50IC0gMV07XG5cdFx0XHRcdHBvbHlnb25Qb29sLnNwbGljZShwb29sQ291bnQgLSAxLCAxKTtcblx0XHRcdH0gZWxzZVxuXHRcdFx0XHRwb2x5Z29uID0gW107XG5cdFx0XHRwb2x5Z29ucy5wdXNoKHBvbHlnb24pO1xuXG5cdFx0XHRwb2x5Z29uLmxlbmd0aCA9IGJvdW5kaW5nQm94LnZlcnRpY2VzLmxlbmd0aDtcblx0XHRcdGJvdW5kaW5nQm94LmNvbXB1dGVXb3JsZFZlcnRpY2VzKHgsIHksIHNsb3QuYm9uZSwgcG9seWdvbik7XG5cdFx0fVxuXG5cdFx0aWYgKHVwZGF0ZUFhYmIpIHRoaXMuYWFiYkNvbXB1dGUoKTtcblx0fSxcblx0YWFiYkNvbXB1dGU6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgcG9seWdvbnMgPSB0aGlzLnBvbHlnb25zO1xuXHRcdHZhciBtaW5YID0gTnVtYmVyLk1BWF9WQUxVRSwgbWluWSA9IE51bWJlci5NQVhfVkFMVUUsIG1heFggPSBOdW1iZXIuTUlOX1ZBTFVFLCBtYXhZID0gTnVtYmVyLk1JTl9WQUxVRTtcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHBvbHlnb25zLmxlbmd0aDsgaSA8IG47IGkrKykge1xuXHRcdFx0dmFyIHZlcnRpY2VzID0gcG9seWdvbnNbaV07XG5cdFx0XHRmb3IgKHZhciBpaSA9IDAsIG5uID0gdmVydGljZXMubGVuZ3RoOyBpaSA8IG5uOyBpaSArPSAyKSB7XG5cdFx0XHRcdHZhciB4ID0gdmVydGljZXNbaWldO1xuXHRcdFx0XHR2YXIgeSA9IHZlcnRpY2VzW2lpICsgMV07XG5cdFx0XHRcdG1pblggPSBNYXRoLm1pbihtaW5YLCB4KTtcblx0XHRcdFx0bWluWSA9IE1hdGgubWluKG1pblksIHkpO1xuXHRcdFx0XHRtYXhYID0gTWF0aC5tYXgobWF4WCwgeCk7XG5cdFx0XHRcdG1heFkgPSBNYXRoLm1heChtYXhZLCB5KTtcblx0XHRcdH1cblx0XHR9XG5cdFx0dGhpcy5taW5YID0gbWluWDtcblx0XHR0aGlzLm1pblkgPSBtaW5ZO1xuXHRcdHRoaXMubWF4WCA9IG1heFg7XG5cdFx0dGhpcy5tYXhZID0gbWF4WTtcblx0fSxcblx0LyoqIFJldHVybnMgdHJ1ZSBpZiB0aGUgYXhpcyBhbGlnbmVkIGJvdW5kaW5nIGJveCBjb250YWlucyB0aGUgcG9pbnQuICovXG5cdGFhYmJDb250YWluc1BvaW50OiBmdW5jdGlvbiAoeCwgeSkge1xuXHRcdHJldHVybiB4ID49IHRoaXMubWluWCAmJiB4IDw9IHRoaXMubWF4WCAmJiB5ID49IHRoaXMubWluWSAmJiB5IDw9IHRoaXMubWF4WTtcblx0fSxcblx0LyoqIFJldHVybnMgdHJ1ZSBpZiB0aGUgYXhpcyBhbGlnbmVkIGJvdW5kaW5nIGJveCBpbnRlcnNlY3RzIHRoZSBsaW5lIHNlZ21lbnQuICovXG5cdGFhYmJJbnRlcnNlY3RzU2VnbWVudDogZnVuY3Rpb24gKHgxLCB5MSwgeDIsIHkyKSB7XG5cdFx0dmFyIG1pblggPSB0aGlzLm1pblgsIG1pblkgPSB0aGlzLm1pblksIG1heFggPSB0aGlzLm1heFgsIG1heFkgPSB0aGlzLm1heFk7XG5cdFx0aWYgKCh4MSA8PSBtaW5YICYmIHgyIDw9IG1pblgpIHx8ICh5MSA8PSBtaW5ZICYmIHkyIDw9IG1pblkpIHx8ICh4MSA+PSBtYXhYICYmIHgyID49IG1heFgpIHx8ICh5MSA+PSBtYXhZICYmIHkyID49IG1heFkpKVxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdHZhciBtID0gKHkyIC0geTEpIC8gKHgyIC0geDEpO1xuXHRcdHZhciB5ID0gbSAqIChtaW5YIC0geDEpICsgeTE7XG5cdFx0aWYgKHkgPiBtaW5ZICYmIHkgPCBtYXhZKSByZXR1cm4gdHJ1ZTtcblx0XHR5ID0gbSAqIChtYXhYIC0geDEpICsgeTE7XG5cdFx0aWYgKHkgPiBtaW5ZICYmIHkgPCBtYXhZKSByZXR1cm4gdHJ1ZTtcblx0XHR2YXIgeCA9IChtaW5ZIC0geTEpIC8gbSArIHgxO1xuXHRcdGlmICh4ID4gbWluWCAmJiB4IDwgbWF4WCkgcmV0dXJuIHRydWU7XG5cdFx0eCA9IChtYXhZIC0geTEpIC8gbSArIHgxO1xuXHRcdGlmICh4ID4gbWluWCAmJiB4IDwgbWF4WCkgcmV0dXJuIHRydWU7XG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9LFxuXHQvKiogUmV0dXJucyB0cnVlIGlmIHRoZSBheGlzIGFsaWduZWQgYm91bmRpbmcgYm94IGludGVyc2VjdHMgdGhlIGF4aXMgYWxpZ25lZCBib3VuZGluZyBib3ggb2YgdGhlIHNwZWNpZmllZCBib3VuZHMuICovXG5cdGFhYmJJbnRlcnNlY3RzU2tlbGV0b246IGZ1bmN0aW9uIChib3VuZHMpIHtcblx0XHRyZXR1cm4gdGhpcy5taW5YIDwgYm91bmRzLm1heFggJiYgdGhpcy5tYXhYID4gYm91bmRzLm1pblggJiYgdGhpcy5taW5ZIDwgYm91bmRzLm1heFkgJiYgdGhpcy5tYXhZID4gYm91bmRzLm1pblk7XG5cdH0sXG5cdC8qKiBSZXR1cm5zIHRoZSBmaXJzdCBib3VuZGluZyBib3ggYXR0YWNobWVudCB0aGF0IGNvbnRhaW5zIHRoZSBwb2ludCwgb3IgbnVsbC4gV2hlbiBkb2luZyBtYW55IGNoZWNrcywgaXQgaXMgdXN1YWxseSBtb3JlXG5cdCAqIGVmZmljaWVudCB0byBvbmx5IGNhbGwgdGhpcyBtZXRob2QgaWYge0BsaW5rICNhYWJiQ29udGFpbnNQb2ludChmbG9hdCwgZmxvYXQpfSByZXR1cm5zIHRydWUuICovXG5cdGNvbnRhaW5zUG9pbnQ6IGZ1bmN0aW9uICh4LCB5KSB7XG5cdFx0dmFyIHBvbHlnb25zID0gdGhpcy5wb2x5Z29ucztcblx0XHRmb3IgKHZhciBpID0gMCwgbiA9IHBvbHlnb25zLmxlbmd0aDsgaSA8IG47IGkrKylcblx0XHRcdGlmICh0aGlzLnBvbHlnb25Db250YWluc1BvaW50KHBvbHlnb25zW2ldLCB4LCB5KSkgcmV0dXJuIHRoaXMuYm91bmRpbmdCb3hlc1tpXTtcblx0XHRyZXR1cm4gbnVsbDtcblx0fSxcblx0LyoqIFJldHVybnMgdGhlIGZpcnN0IGJvdW5kaW5nIGJveCBhdHRhY2htZW50IHRoYXQgY29udGFpbnMgdGhlIGxpbmUgc2VnbWVudCwgb3IgbnVsbC4gV2hlbiBkb2luZyBtYW55IGNoZWNrcywgaXQgaXMgdXN1YWxseVxuXHQgKiBtb3JlIGVmZmljaWVudCB0byBvbmx5IGNhbGwgdGhpcyBtZXRob2QgaWYge0BsaW5rICNhYWJiSW50ZXJzZWN0c1NlZ21lbnQoZmxvYXQsIGZsb2F0LCBmbG9hdCwgZmxvYXQpfSByZXR1cm5zIHRydWUuICovXG5cdGludGVyc2VjdHNTZWdtZW50OiBmdW5jdGlvbiAoeDEsIHkxLCB4MiwgeTIpIHtcblx0XHR2YXIgcG9seWdvbnMgPSB0aGlzLnBvbHlnb25zO1xuXHRcdGZvciAodmFyIGkgPSAwLCBuID0gcG9seWdvbnMubGVuZ3RoOyBpIDwgbjsgaSsrKVxuXHRcdFx0aWYgKHBvbHlnb25zW2ldLmludGVyc2VjdHNTZWdtZW50KHgxLCB5MSwgeDIsIHkyKSkgcmV0dXJuIHRoaXMuYm91bmRpbmdCb3hlc1tpXTtcblx0XHRyZXR1cm4gbnVsbDtcblx0fSxcblx0LyoqIFJldHVybnMgdHJ1ZSBpZiB0aGUgcG9seWdvbiBjb250YWlucyB0aGUgcG9pbnQuICovXG5cdHBvbHlnb25Db250YWluc1BvaW50OiBmdW5jdGlvbiAocG9seWdvbiwgeCwgeSkge1xuXHRcdHZhciBubiA9IHBvbHlnb24ubGVuZ3RoO1xuXHRcdHZhciBwcmV2SW5kZXggPSBubiAtIDI7XG5cdFx0dmFyIGluc2lkZSA9IGZhbHNlO1xuXHRcdGZvciAodmFyIGlpID0gMDsgaWkgPCBubjsgaWkgKz0gMikge1xuXHRcdFx0dmFyIHZlcnRleFkgPSBwb2x5Z29uW2lpICsgMV07XG5cdFx0XHR2YXIgcHJldlkgPSBwb2x5Z29uW3ByZXZJbmRleCArIDFdO1xuXHRcdFx0aWYgKCh2ZXJ0ZXhZIDwgeSAmJiBwcmV2WSA+PSB5KSB8fCAocHJldlkgPCB5ICYmIHZlcnRleFkgPj0geSkpIHtcblx0XHRcdFx0dmFyIHZlcnRleFggPSBwb2x5Z29uW2lpXTtcblx0XHRcdFx0aWYgKHZlcnRleFggKyAoeSAtIHZlcnRleFkpIC8gKHByZXZZIC0gdmVydGV4WSkgKiAocG9seWdvbltwcmV2SW5kZXhdIC0gdmVydGV4WCkgPCB4KSBpbnNpZGUgPSAhaW5zaWRlO1xuXHRcdFx0fVxuXHRcdFx0cHJldkluZGV4ID0gaWk7XG5cdFx0fVxuXHRcdHJldHVybiBpbnNpZGU7XG5cdH0sXG5cdC8qKiBSZXR1cm5zIHRydWUgaWYgdGhlIHBvbHlnb24gY29udGFpbnMgdGhlIGxpbmUgc2VnbWVudC4gKi9cblx0cG9seWdvbkludGVyc2VjdHNTZWdtZW50OiBmdW5jdGlvbiAocG9seWdvbiwgeDEsIHkxLCB4MiwgeTIpIHtcblx0XHR2YXIgbm4gPSBwb2x5Z29uLmxlbmd0aDtcblx0XHR2YXIgd2lkdGgxMiA9IHgxIC0geDIsIGhlaWdodDEyID0geTEgLSB5Mjtcblx0XHR2YXIgZGV0MSA9IHgxICogeTIgLSB5MSAqIHgyO1xuXHRcdHZhciB4MyA9IHBvbHlnb25bbm4gLSAyXSwgeTMgPSBwb2x5Z29uW25uIC0gMV07XG5cdFx0Zm9yICh2YXIgaWkgPSAwOyBpaSA8IG5uOyBpaSArPSAyKSB7XG5cdFx0XHR2YXIgeDQgPSBwb2x5Z29uW2lpXSwgeTQgPSBwb2x5Z29uW2lpICsgMV07XG5cdFx0XHR2YXIgZGV0MiA9IHgzICogeTQgLSB5MyAqIHg0O1xuXHRcdFx0dmFyIHdpZHRoMzQgPSB4MyAtIHg0LCBoZWlnaHQzNCA9IHkzIC0geTQ7XG5cdFx0XHR2YXIgZGV0MyA9IHdpZHRoMTIgKiBoZWlnaHQzNCAtIGhlaWdodDEyICogd2lkdGgzNDtcblx0XHRcdHZhciB4ID0gKGRldDEgKiB3aWR0aDM0IC0gd2lkdGgxMiAqIGRldDIpIC8gZGV0Mztcblx0XHRcdGlmICgoKHggPj0geDMgJiYgeCA8PSB4NCkgfHwgKHggPj0geDQgJiYgeCA8PSB4MykpICYmICgoeCA+PSB4MSAmJiB4IDw9IHgyKSB8fCAoeCA+PSB4MiAmJiB4IDw9IHgxKSkpIHtcblx0XHRcdFx0dmFyIHkgPSAoZGV0MSAqIGhlaWdodDM0IC0gaGVpZ2h0MTIgKiBkZXQyKSAvIGRldDM7XG5cdFx0XHRcdGlmICgoKHkgPj0geTMgJiYgeSA8PSB5NCkgfHwgKHkgPj0geTQgJiYgeSA8PSB5MykpICYmICgoeSA+PSB5MSAmJiB5IDw9IHkyKSB8fCAoeSA+PSB5MiAmJiB5IDw9IHkxKSkpIHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0eDMgPSB4NDtcblx0XHRcdHkzID0geTQ7XG5cdFx0fVxuXHRcdHJldHVybiBmYWxzZTtcblx0fSxcblx0Z2V0UG9seWdvbjogZnVuY3Rpb24gKGF0dGFjaG1lbnQpIHtcblx0XHR2YXIgaW5kZXggPSB0aGlzLmJvdW5kaW5nQm94ZXMuaW5kZXhPZihhdHRhY2htZW50KTtcblx0XHRyZXR1cm4gaW5kZXggPT0gLTEgPyBudWxsIDogdGhpcy5wb2x5Z29uc1tpbmRleF07XG5cdH0sXG5cdGdldFdpZHRoOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMubWF4WCAtIHRoaXMubWluWDtcblx0fSxcblx0Z2V0SGVpZ2h0OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMubWF4WSAtIHRoaXMubWluWTtcblx0fVxufTtcbiIsIi8qKlxuICogQGZpbGUgICAgICAgIE1haW4gZXhwb3J0IG9mIHRoZSBQSVhJIHNwaW5lIGxpYnJhcnlcbiAqIEBhdXRob3IgICAgICBNYXQgR3JvdmVzIDxtYXRAZ29vZGJveWRpZ2l0YWwuY29tPlxuICogQGNvcHlyaWdodCAgIDIwMTMtMjAxNSBHb29kQm95RGlnaXRhbFxuICogQGxpY2Vuc2UgICAgIHtAbGluayBodHRwczovL2dpdGh1Yi5jb20vR29vZEJveURpZ2l0YWwvcGl4aS5qcy9ibG9iL21hc3Rlci9MSUNFTlNFfE1JVCBMaWNlbnNlfVxuICovXG5cbi8qKlxuICogQG5hbWVzcGFjZSBQSVhJXG4gKi9cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIFNwaW5lOiAgICAgICAgICAgICAgcmVxdWlyZSgnLi9TcGluZScpXG59O1xuIiwidmFyIGNvcmUgPSByZXF1aXJlKCcuLi9jb3JlJyk7XG5cbi8qKlxuICogQSBCaXRtYXBUZXh0IG9iamVjdCB3aWxsIGNyZWF0ZSBhIGxpbmUgb3IgbXVsdGlwbGUgbGluZXMgb2YgdGV4dCB1c2luZyBiaXRtYXAgZm9udC4gVG9cbiAqIHNwbGl0IGEgbGluZSB5b3UgY2FuIHVzZSAnXFxuJywgJ1xccicgb3IgJ1xcclxcbicgaW4geW91ciBzdHJpbmcuIFlvdSBjYW4gZ2VuZXJhdGUgdGhlIGZudCBmaWxlcyB1c2luZzpcbiAqXG4gKiBodHRwOi8vd3d3LmFuZ2VsY29kZS5jb20vcHJvZHVjdHMvYm1mb250LyBmb3Igd2luZG93cyBvclxuICogaHR0cDovL3d3dy5ibWdseXBoLmNvbS8gZm9yIG1hYy5cbiAqXG4gKiBAY2xhc3NcbiAqIEBleHRlbmRzIERpc3BsYXlPYmplY3RDb250YWluZXJcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHRleHQge3N0cmluZ30gVGhlIGNvcHkgdGhhdCB5b3Ugd291bGQgbGlrZSB0aGUgdGV4dCB0byBkaXNwbGF5XG4gKiBAcGFyYW0gc3R5bGUge29iamVjdH0gVGhlIHN0eWxlIHBhcmFtZXRlcnNcbiAqIEBwYXJhbSBzdHlsZS5mb250IHtzdHJpbmd9IFRoZSBzaXplIChvcHRpb25hbCkgYW5kIGJpdG1hcCBmb250IGlkIChyZXF1aXJlZCkgZXEgJ0FyaWFsJyBvciAnMjBweCBBcmlhbCcgKG11c3QgaGF2ZSBsb2FkZWQgcHJldmlvdXNseSlcbiAqIEBwYXJhbSBbc3R5bGUuYWxpZ249J2xlZnQnXSB7c3RyaW5nfSBBbGlnbm1lbnQgZm9yIG11bHRpbGluZSB0ZXh0ICgnbGVmdCcsICdjZW50ZXInIG9yICdyaWdodCcpLCBkb2VzIG5vdCBhZmZlY3Qgc2luZ2xlIGxpbmUgdGV4dFxuICovXG5mdW5jdGlvbiBCaXRtYXBUZXh0KHRleHQsIHN0eWxlKSB7XG4gICAgY29yZS5EaXNwbGF5T2JqZWN0Q29udGFpbmVyLmNhbGwodGhpcyk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgd2lkdGggb2YgdGhlIG92ZXJhbGwgdGV4dCwgZGlmZmVyZW50IGZyb20gZm9udFNpemUsXG4gICAgICogd2hpY2ggaXMgZGVmaW5lZCBpbiB0aGUgc3R5bGUgb2JqZWN0XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQHJlYWRPbmx5XG4gICAgICovXG4gICAgdGhpcy50ZXh0V2lkdGggPSAwO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGhlaWdodCBvZiB0aGUgb3ZlcmFsbCB0ZXh0LCBkaWZmZXJlbnQgZnJvbSBmb250U2l6ZSxcbiAgICAgKiB3aGljaCBpcyBkZWZpbmVkIGluIHRoZSBzdHlsZSBvYmplY3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAcmVhZE9ubHlcbiAgICAgKi9cbiAgICB0aGlzLnRleHRIZWlnaHQgPSAwO1xuXG4gICAgLyoqXG4gICAgICogUHJpdmF0ZSB0cmFja2VyIGZvciB0aGUgbGV0dGVyIHNwcml0ZSBwb29sLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7U3ByaXRlW119XG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICB0aGlzLl9wb29sID0gW107XG5cbiAgICAvKipcbiAgICAgKiBQcml2YXRlIHRyYWNrZXIgZm9yIHRoZSBjdXJyZW50IHN0eWxlLlxuICAgICAqXG4gICAgICogQG1lbWJlciB7b2JqZWN0fVxuICAgICAqIEBwcml2YXRlXG4gICAgICovXG4gICAgdGhpcy5fc3R5bGUgPSB7XG4gICAgICAgIHRpbnQ6IHN0eWxlLnRpbnQsXG4gICAgICAgIGFsaWduOiBzdHlsZS5hbGlnbixcbiAgICAgICAgZm9udE5hbWU6IG51bGwsXG4gICAgICAgIGZvbnRTaXplOiAwXG4gICAgfTtcbiAgICB0aGlzLmZvbnQgPSBzdHlsZS5mb250OyAvLyBydW4gZm9udCBzZXR0ZXJcblxuICAgIC8qKlxuICAgICAqIFByaXZhdGUgdHJhY2tlciBmb3IgdGhlIGN1cnJlbnQgdGV4dC5cbiAgICAgKlxuICAgICAqIEBtZW1iZXIge3N0cmluZ31cbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHRoaXMuX3RleHQgPSB0ZXh0O1xuXG4gICAgLyoqXG4gICAgICogVGhlIGRpcnR5IHN0YXRlIG9mIHRoaXMgb2JqZWN0LlxuICAgICAqXG4gICAgICogQG1lbWJlciB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLmRpcnR5ID0gZmFsc2U7XG5cbiAgICB0aGlzLnVwZGF0ZVRleHQoKTtcbn1cblxuLy8gY29uc3RydWN0b3JcbkJpdG1hcFRleHQucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShjb3JlLkRpc3BsYXlPYmplY3RDb250YWluZXIucHJvdG90eXBlKTtcbkJpdG1hcFRleHQucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gQml0bWFwVGV4dDtcbm1vZHVsZS5leHBvcnRzID0gQml0bWFwVGV4dDtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQml0bWFwVGV4dC5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBUaGUgdGludCBvZiB0aGUgQml0bWFwVGV4dCBvYmplY3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge251bWJlcn1cbiAgICAgKiBAbWVtYmVyb2YgQml0bWFwVGV4dCNcbiAgICAgKi9cbiAgICB0aW50OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3N0eWxlLnRpbnQ7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLl9zdHlsZS50aW50ID0gKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgJiYgdmFsdWUgPj0gMCkgPyB2YWx1ZSA6IDB4RkZGRkZGO1xuXG4gICAgICAgICAgICB0aGlzLmRpcnR5ID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgdGludCBvZiB0aGUgQml0bWFwVGV4dCBvYmplY3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge3N0cmluZ31cbiAgICAgKiBAZGVmYXVsdCAnbGVmdCdcbiAgICAgKiBAbWVtYmVyb2YgQml0bWFwVGV4dCNcbiAgICAgKi9cbiAgICBhbGlnbjoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9zdHlsZS5hbGlnbjtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuX3N0eWxlLmFsaWduID0gdmFsdWU7XG5cbiAgICAgICAgICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFRoZSB0aW50IG9mIHRoZSBCaXRtYXBUZXh0IG9iamVjdFxuICAgICAqXG4gICAgICogQG1lbWJlciB7Rm9udH1cbiAgICAgKiBAbWVtYmVyb2YgQml0bWFwVGV4dCNcbiAgICAgKi9cbiAgICBmb250OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3N0eWxlLmZvbnQ7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnNwbGl0KCcgJyk7XG5cbiAgICAgICAgICAgIC8vIFRPRE8gLSBUaGlzIHNob3VsZCBiZSBvYmplY3QtYmFzZWQgbm90IHN0cmluZyBiYXNlZCBsaWtlIGl0IGhhcyBiZWVuLlxuICAgICAgICAgICAgdGhpcy5fc3R5bGUuZm9udE5hbWUgPSB2YWx1ZVt2YWx1ZS5sZW5ndGggLSAxXTtcbiAgICAgICAgICAgIHRoaXMuX3N0eWxlLmZvbnRTaXplID0gdmFsdWUubGVuZ3RoID49IDIgPyBwYXJzZUludCh2YWx1ZVt2YWx1ZS5sZW5ndGggLSAyXSwgMTApIDogQml0bWFwVGV4dC5mb250c1t0aGlzLmZvbnROYW1lXS5zaXplO1xuXG4gICAgICAgICAgICB0aGlzLmRpcnR5ID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgdGV4dCBvZiB0aGUgQml0bWFwVGV4dCBvYmplY3RcbiAgICAgKlxuICAgICAqIEBtZW1iZXIge3N0cmluZ31cbiAgICAgKiBAbWVtYmVyb2YgQml0bWFwVGV4dCNcbiAgICAgKi9cbiAgICB0ZXh0OiB7XG4gICAgICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3RleHQ7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLl90ZXh0ID0gdmFsdWU7XG5cbiAgICAgICAgICAgIHRoaXMuZGlydHkgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfVxufSk7XG5cbi8qKlxuICogUmVuZGVycyB0ZXh0IGFuZCB1cGRhdGVzIGl0IHdoZW4gbmVlZGVkXG4gKlxuICogQHByaXZhdGVcbiAqL1xuQml0bWFwVGV4dC5wcm90b3R5cGUudXBkYXRlVGV4dCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZGF0YSA9IEJpdG1hcFRleHQuZm9udHNbdGhpcy5mb250TmFtZV07XG4gICAgdmFyIHBvcyA9IG5ldyBjb3JlLm1hdGguUG9pbnQoKTtcbiAgICB2YXIgcHJldkNoYXJDb2RlID0gbnVsbDtcbiAgICB2YXIgY2hhcnMgPSBbXTtcbiAgICB2YXIgbWF4TGluZVdpZHRoID0gMDtcbiAgICB2YXIgbGluZVdpZHRocyA9IFtdO1xuICAgIHZhciBsaW5lID0gMDtcbiAgICB2YXIgc2NhbGUgPSB0aGlzLmZvbnRTaXplIC8gZGF0YS5zaXplO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnRleHQubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGNoYXJDb2RlID0gdGhpcy50ZXh0LmNoYXJDb2RlQXQoaSk7XG5cbiAgICAgICAgaWYgKC8oPzpcXHJcXG58XFxyfFxcbikvLnRlc3QodGhpcy50ZXh0LmNoYXJBdChpKSkpIHtcbiAgICAgICAgICAgIGxpbmVXaWR0aHMucHVzaChwb3MueCk7XG4gICAgICAgICAgICBtYXhMaW5lV2lkdGggPSBNYXRoLm1heChtYXhMaW5lV2lkdGgsIHBvcy54KTtcbiAgICAgICAgICAgIGxpbmUrKztcblxuICAgICAgICAgICAgcG9zLnggPSAwO1xuICAgICAgICAgICAgcG9zLnkgKz0gZGF0YS5saW5lSGVpZ2h0O1xuICAgICAgICAgICAgcHJldkNoYXJDb2RlID0gbnVsbDtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGNoYXJEYXRhID0gZGF0YS5jaGFyc1tjaGFyQ29kZV07XG5cbiAgICAgICAgaWYgKCFjaGFyRGF0YSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocHJldkNoYXJDb2RlICYmIGNoYXJEYXRhLmtlcm5pbmdbcHJldkNoYXJDb2RlXSkge1xuICAgICAgICAgICAgcG9zLnggKz0gY2hhckRhdGEua2VybmluZ1twcmV2Q2hhckNvZGVdO1xuICAgICAgICB9XG5cbiAgICAgICAgY2hhcnMucHVzaCh7dGV4dHVyZTpjaGFyRGF0YS50ZXh0dXJlLCBsaW5lOiBsaW5lLCBjaGFyQ29kZTogY2hhckNvZGUsIHBvc2l0aW9uOiBuZXcgY29yZS5tYXRoLlBvaW50KHBvcy54ICsgY2hhckRhdGEueE9mZnNldCwgcG9zLnkgKyBjaGFyRGF0YS55T2Zmc2V0KX0pO1xuICAgICAgICBwb3MueCArPSBjaGFyRGF0YS54QWR2YW5jZTtcblxuICAgICAgICBwcmV2Q2hhckNvZGUgPSBjaGFyQ29kZTtcbiAgICB9XG5cbiAgICBsaW5lV2lkdGhzLnB1c2gocG9zLngpO1xuICAgIG1heExpbmVXaWR0aCA9IE1hdGgubWF4KG1heExpbmVXaWR0aCwgcG9zLngpO1xuXG4gICAgdmFyIGxpbmVBbGlnbk9mZnNldHMgPSBbXTtcblxuICAgIGZvciAoaSA9IDA7IGkgPD0gbGluZTsgaSsrKSB7XG4gICAgICAgIHZhciBhbGlnbk9mZnNldCA9IDA7XG5cbiAgICAgICAgaWYgKHRoaXMuc3R5bGUuYWxpZ24gPT09ICdyaWdodCcpIHtcbiAgICAgICAgICAgIGFsaWduT2Zmc2V0ID0gbWF4TGluZVdpZHRoIC0gbGluZVdpZHRoc1tpXTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0aGlzLnN0eWxlLmFsaWduID09PSAnY2VudGVyJykge1xuICAgICAgICAgICAgYWxpZ25PZmZzZXQgPSAobWF4TGluZVdpZHRoIC0gbGluZVdpZHRoc1tpXSkgLyAyO1xuICAgICAgICB9XG5cbiAgICAgICAgbGluZUFsaWduT2Zmc2V0cy5wdXNoKGFsaWduT2Zmc2V0KTtcbiAgICB9XG5cbiAgICB2YXIgbGVuQ2hpbGRyZW4gPSB0aGlzLmNoaWxkcmVuLmxlbmd0aDtcbiAgICB2YXIgbGVuQ2hhcnMgPSBjaGFycy5sZW5ndGg7XG4gICAgdmFyIHRpbnQgPSB0aGlzLnRpbnQ7XG5cbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuQ2hhcnM7IGkrKykge1xuICAgICAgICB2YXIgYyA9IGkgPCBsZW5DaGlsZHJlbiA/IHRoaXMuY2hpbGRyZW5baV0gOiB0aGlzLl9wb29sLnBvcCgpOyAvLyBnZXQgb2xkIGNoaWxkIGlmIGhhdmUuIGlmIG5vdCAtIHRha2UgZnJvbSBwb29sLlxuXG4gICAgICAgIGlmIChjKSB7XG4gICAgICAgICAgICBjLnNldFRleHR1cmUoY2hhcnNbaV0udGV4dHVyZSk7IC8vIGNoZWNrIGlmIGdvdCBvbmUgYmVmb3JlLlxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgYyA9IG5ldyBjb3JlLlNwcml0ZShjaGFyc1tpXS50ZXh0dXJlKTsgLy8gaWYgbm8gY3JlYXRlIG5ldyBvbmUuXG4gICAgICAgIH1cblxuICAgICAgICBjLnBvc2l0aW9uLnggPSAoY2hhcnNbaV0ucG9zaXRpb24ueCArIGxpbmVBbGlnbk9mZnNldHNbY2hhcnNbaV0ubGluZV0pICogc2NhbGU7XG4gICAgICAgIGMucG9zaXRpb24ueSA9IGNoYXJzW2ldLnBvc2l0aW9uLnkgKiBzY2FsZTtcbiAgICAgICAgYy5zY2FsZS54ID0gYy5zY2FsZS55ID0gc2NhbGU7XG4gICAgICAgIGMudGludCA9IHRpbnQ7XG5cbiAgICAgICAgaWYgKCFjLnBhcmVudCkge1xuICAgICAgICAgICAgdGhpcy5hZGRDaGlsZChjKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIHJlbW92ZSB1bm5lY2Vzc2FyeSBjaGlsZHJlbi5cbiAgICAvLyBhbmQgcHV0IHRoZWlyIGludG8gdGhlIHBvb2wuXG4gICAgd2hpbGUodGhpcy5jaGlsZHJlbi5sZW5ndGggPiBsZW5DaGFycykge1xuICAgICAgICB2YXIgY2hpbGQgPSB0aGlzLmdldENoaWxkQXQodGhpcy5jaGlsZHJlbi5sZW5ndGggLSAxKTtcbiAgICAgICAgdGhpcy5fcG9vbC5wdXNoKGNoaWxkKTtcbiAgICAgICAgdGhpcy5yZW1vdmVDaGlsZChjaGlsZCk7XG4gICAgfVxuXG4gICAgdGhpcy50ZXh0V2lkdGggPSBtYXhMaW5lV2lkdGggKiBzY2FsZTtcbiAgICB0aGlzLnRleHRIZWlnaHQgPSAocG9zLnkgKyBkYXRhLmxpbmVIZWlnaHQpICogc2NhbGU7XG59O1xuXG4vKipcbiAqIFVwZGF0ZXMgdGhlIHRyYW5zZm9ybSBvZiB0aGlzIG9iamVjdFxuICpcbiAqIEBwcml2YXRlXG4gKi9cbkJpdG1hcFRleHQucHJvdG90eXBlLnVwZGF0ZVRyYW5zZm9ybSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnVwZGF0ZVRleHQoKTtcbiAgICAgICAgdGhpcy5kaXJ0eSA9IGZhbHNlO1xuICAgIH1cblxuICAgIHRoaXMuZGlzcGxheU9iamVjdENvbnRhaW5lclVwZGF0ZVRyYW5zZm9ybSgpO1xufTtcblxuQml0bWFwVGV4dC5mb250cyA9IHt9O1xuIiwidmFyIGNvcmUgPSByZXF1aXJlKCcuLi9jb3JlJyk7XG5cbi8qKlxuICogQSBUZXh0IE9iamVjdCB3aWxsIGNyZWF0ZSBhIGxpbmUgb3IgbXVsdGlwbGUgbGluZXMgb2YgdGV4dC4gVG8gc3BsaXQgYSBsaW5lIHlvdSBjYW4gdXNlICdcXG4nIGluIHlvdXIgdGV4dCBzdHJpbmcsXG4gKiBvciBhZGQgYSB3b3JkV3JhcCBwcm9wZXJ0eSBzZXQgdG8gdHJ1ZSBhbmQgYW5kIHdvcmRXcmFwV2lkdGggcHJvcGVydHkgd2l0aCBhIHZhbHVlIGluIHRoZSBzdHlsZSBvYmplY3QuXG4gKlxuICogQGNsYXNzXG4gKiBAZXh0ZW5kcyBTcHJpdGVcbiAqIEBuYW1lc3BhY2UgUElYSVxuICogQHBhcmFtIHRleHQge3N0cmluZ30gVGhlIGNvcHkgdGhhdCB5b3Ugd291bGQgbGlrZSB0aGUgdGV4dCB0byBkaXNwbGF5XG4gKiBAcGFyYW0gW3N0eWxlXSB7b2JqZWN0fSBUaGUgc3R5bGUgcGFyYW1ldGVyc1xuICogQHBhcmFtIFtzdHlsZS5mb250XSB7c3RyaW5nfSBkZWZhdWx0ICdib2xkIDIwcHggQXJpYWwnIFRoZSBzdHlsZSBhbmQgc2l6ZSBvZiB0aGUgZm9udFxuICogQHBhcmFtIFtzdHlsZS5maWxsPSdibGFjayddIHtTdHJpbmd8TnVtYmVyfSBBIGNhbnZhcyBmaWxsc3R5bGUgdGhhdCB3aWxsIGJlIHVzZWQgb24gdGhlIHRleHQgZS5nICdyZWQnLCAnIzAwRkYwMCdcbiAqIEBwYXJhbSBbc3R5bGUuYWxpZ249J2xlZnQnXSB7c3RyaW5nfSBBbGlnbm1lbnQgZm9yIG11bHRpbGluZSB0ZXh0ICgnbGVmdCcsICdjZW50ZXInIG9yICdyaWdodCcpLCBkb2VzIG5vdCBhZmZlY3Qgc2luZ2xlIGxpbmUgdGV4dFxuICogQHBhcmFtIFtzdHlsZS5zdHJva2VdIHtTdHJpbmd8TnVtYmVyfSBBIGNhbnZhcyBmaWxsc3R5bGUgdGhhdCB3aWxsIGJlIHVzZWQgb24gdGhlIHRleHQgc3Ryb2tlIGUuZyAnYmx1ZScsICcjRkNGRjAwJ1xuICogQHBhcmFtIFtzdHlsZS5zdHJva2VUaGlja25lc3M9MF0ge251bWJlcn0gQSBudW1iZXIgdGhhdCByZXByZXNlbnRzIHRoZSB0aGlja25lc3Mgb2YgdGhlIHN0cm9rZS4gRGVmYXVsdCBpcyAwIChubyBzdHJva2UpXG4gKiBAcGFyYW0gW3N0eWxlLndvcmRXcmFwPWZhbHNlXSB7Ym9vbGVhbn0gSW5kaWNhdGVzIGlmIHdvcmQgd3JhcCBzaG91bGQgYmUgdXNlZFxuICogQHBhcmFtIFtzdHlsZS53b3JkV3JhcFdpZHRoPTEwMF0ge251bWJlcn0gVGhlIHdpZHRoIGF0IHdoaWNoIHRleHQgd2lsbCB3cmFwLCBpdCBuZWVkcyB3b3JkV3JhcCB0byBiZSBzZXQgdG8gdHJ1ZVxuICogQHBhcmFtIFtzdHlsZS5kcm9wU2hhZG93PWZhbHNlXSB7Ym9vbGVhbn0gU2V0IGEgZHJvcCBzaGFkb3cgZm9yIHRoZSB0ZXh0XG4gKiBAcGFyYW0gW3N0eWxlLmRyb3BTaGFkb3dDb2xvcj0nIzAwMDAwMCddIHtzdHJpbmd9IEEgZmlsbCBzdHlsZSB0byBiZSB1c2VkIG9uIHRoZSBkcm9wc2hhZG93IGUuZyAncmVkJywgJyMwMEZGMDAnXG4gKiBAcGFyYW0gW3N0eWxlLmRyb3BTaGFkb3dBbmdsZT1NYXRoLlBJLzRdIHtudW1iZXJ9IFNldCBhIGFuZ2xlIG9mIHRoZSBkcm9wIHNoYWRvd1xuICogQHBhcmFtIFtzdHlsZS5kcm9wU2hhZG93RGlzdGFuY2U9NV0ge251bWJlcn0gU2V0IGEgZGlzdGFuY2Ugb2YgdGhlIGRyb3Agc2hhZG93XG4gKi9cbmZ1bmN0aW9uIFRleHQodGV4dCwgc3R5bGUpIHtcbiAgICAvKipcbiAgICAgKiBUaGUgY2FudmFzIGVsZW1lbnQgdGhhdCBldmVyeXRoaW5nIGlzIGRyYXduIHRvXG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtIVE1MQ2FudmFzRWxlbWVudH1cbiAgICAgKi9cbiAgICB0aGlzLmNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGNhbnZhcyAyZCBjb250ZXh0IHRoYXQgZXZlcnl0aGluZyBpcyBkcmF3biB3aXRoXG4gICAgICogQG1lbWJlciB7SFRNTENhbnZhc0VsZW1lbnR9XG4gICAgICovXG4gICAgdGhpcy5jb250ZXh0ID0gdGhpcy5jYW52YXMuZ2V0Q29udGV4dCgnMmQnKTtcblxuICAgIC8qKlxuICAgICAqIFRoZSByZXNvbHV0aW9uIG9mIHRoZSBjYW52YXMuXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqL1xuICAgIHRoaXMucmVzb2x1dGlvbiA9IDE7XG5cbiAgICBjb3JlLlNwcml0ZS5jYWxsKHRoaXMsIGNvcmUuVGV4dHVyZS5mcm9tQ2FudmFzKHRoaXMuY2FudmFzKSk7XG5cbiAgICB0aGlzLnNldFRleHQodGV4dCk7XG4gICAgdGhpcy5zZXRTdHlsZShzdHlsZSk7XG59XG5cbi8vIGNvbnN0cnVjdG9yXG5UZXh0LnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoY29yZS5TcHJpdGUucHJvdG90eXBlKTtcblRleHQucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gVGV4dDtcbm1vZHVsZS5leHBvcnRzID0gVGV4dDtcblxuT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoVGV4dC5wcm90b3R5cGUsIHtcbiAgICAvKipcbiAgICAgKiBUaGUgd2lkdGggb2YgdGhlIFRleHQsIHNldHRpbmcgdGhpcyB3aWxsIGFjdHVhbGx5IG1vZGlmeSB0aGUgc2NhbGUgdG8gYWNoaWV2ZSB0aGUgdmFsdWUgc2V0XG4gICAgICpcbiAgICAgKiBAbWVtYmVyIHtudW1iZXJ9XG4gICAgICogQG1lbWJlcm9mIFRleHQjXG4gICAgICovXG4gICAgd2lkdGg6IHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlVGV4dCgpO1xuICAgICAgICAgICAgICAgIHRoaXMuZGlydHkgPSBmYWxzZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHRoaXMuc2NhbGUueCAqIHRoaXMudGV4dHVyZS5mcmFtZS53aWR0aDtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0OiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuc2NhbGUueCA9IHZhbHVlIC8gdGhpcy50ZXh0dXJlLmZyYW1lLndpZHRoO1xuICAgICAgICAgICAgdGhpcy5fd2lkdGggPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBUaGUgaGVpZ2h0IG9mIHRoZSBUZXh0LCBzZXR0aW5nIHRoaXMgd2lsbCBhY3R1YWxseSBtb2RpZnkgdGhlIHNjYWxlIHRvIGFjaGlldmUgdGhlIHZhbHVlIHNldFxuICAgICAqXG4gICAgICogQG1lbWJlciB7bnVtYmVyfVxuICAgICAqIEBtZW1iZXJvZiBUZXh0I1xuICAgICAqL1xuICAgIGhlaWdodDoge1xuICAgICAgICBnZXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLmRpcnR5KSB7XG4gICAgICAgICAgICAgICAgdGhpcy51cGRhdGVUZXh0KCk7XG4gICAgICAgICAgICAgICAgdGhpcy5kaXJ0eSA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gIHRoaXMuc2NhbGUueSAqIHRoaXMudGV4dHVyZS5mcmFtZS5oZWlnaHQ7XG4gICAgICAgIH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnNjYWxlLnkgPSB2YWx1ZSAvIHRoaXMudGV4dHVyZS5mcmFtZS5oZWlnaHQ7XG4gICAgICAgICAgICB0aGlzLl9oZWlnaHQgPSB2YWx1ZTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG4vKipcbiAqIFNldCB0aGUgc3R5bGUgb2YgdGhlIHRleHRcbiAqXG4gKiBAcGFyYW0gW3N0eWxlXSB7b2JqZWN0fSBUaGUgc3R5bGUgcGFyYW1ldGVyc1xuICogQHBhcmFtIFtzdHlsZS5mb250PSdib2xkIDIwcHQgQXJpYWwnXSB7c3RyaW5nfSBUaGUgc3R5bGUgYW5kIHNpemUgb2YgdGhlIGZvbnRcbiAqIEBwYXJhbSBbc3R5bGUuZmlsbD0nYmxhY2snXSB7b2JqZWN0fSBBIGNhbnZhcyBmaWxsc3R5bGUgdGhhdCB3aWxsIGJlIHVzZWQgb24gdGhlIHRleHQgZWcgJ3JlZCcsICcjMDBGRjAwJ1xuICogQHBhcmFtIFtzdHlsZS5hbGlnbj0nbGVmdCddIHtzdHJpbmd9IEFsaWdubWVudCBmb3IgbXVsdGlsaW5lIHRleHQgKCdsZWZ0JywgJ2NlbnRlcicgb3IgJ3JpZ2h0JyksIGRvZXMgbm90IGFmZmVjdCBzaW5nbGUgbGluZSB0ZXh0XG4gKiBAcGFyYW0gW3N0eWxlLnN0cm9rZT0nYmxhY2snXSB7c3RyaW5nfSBBIGNhbnZhcyBmaWxsc3R5bGUgdGhhdCB3aWxsIGJlIHVzZWQgb24gdGhlIHRleHQgc3Ryb2tlIGVnICdibHVlJywgJyNGQ0ZGMDAnXG4gKiBAcGFyYW0gW3N0eWxlLnN0cm9rZVRoaWNrbmVzcz0wXSB7bnVtYmVyfSBBIG51bWJlciB0aGF0IHJlcHJlc2VudHMgdGhlIHRoaWNrbmVzcyBvZiB0aGUgc3Ryb2tlLiBEZWZhdWx0IGlzIDAgKG5vIHN0cm9rZSlcbiAqIEBwYXJhbSBbc3R5bGUud29yZFdyYXA9ZmFsc2VdIHtib29sZWFufSBJbmRpY2F0ZXMgaWYgd29yZCB3cmFwIHNob3VsZCBiZSB1c2VkXG4gKiBAcGFyYW0gW3N0eWxlLndvcmRXcmFwV2lkdGg9MTAwXSB7bnVtYmVyfSBUaGUgd2lkdGggYXQgd2hpY2ggdGV4dCB3aWxsIHdyYXBcbiAqIEBwYXJhbSBbc3R5bGUuZHJvcFNoYWRvdz1mYWxzZV0ge2Jvb2xlYW59IFNldCBhIGRyb3Agc2hhZG93IGZvciB0aGUgdGV4dFxuICogQHBhcmFtIFtzdHlsZS5kcm9wU2hhZG93Q29sb3I9JyMwMDAwMDAnXSB7c3RyaW5nfSBBIGZpbGwgc3R5bGUgdG8gYmUgdXNlZCBvbiB0aGUgZHJvcHNoYWRvdyBlLmcgJ3JlZCcsICcjMDBGRjAwJ1xuICogQHBhcmFtIFtzdHlsZS5kcm9wU2hhZG93QW5nbGU9TWF0aC5QSS80XSB7bnVtYmVyfSBTZXQgYSBhbmdsZSBvZiB0aGUgZHJvcCBzaGFkb3dcbiAqIEBwYXJhbSBbc3R5bGUuZHJvcFNoYWRvd0Rpc3RhbmNlPTVdIHtudW1iZXJ9IFNldCBhIGRpc3RhbmNlIG9mIHRoZSBkcm9wIHNoYWRvd1xuICovXG5UZXh0LnByb3RvdHlwZS5zZXRTdHlsZSA9IGZ1bmN0aW9uIChzdHlsZSkge1xuICAgIHN0eWxlID0gc3R5bGUgfHwge307XG4gICAgc3R5bGUuZm9udCA9IHN0eWxlLmZvbnQgfHwgJ2JvbGQgMjBwdCBBcmlhbCc7XG4gICAgc3R5bGUuZmlsbCA9IHN0eWxlLmZpbGwgfHwgJ2JsYWNrJztcbiAgICBzdHlsZS5hbGlnbiA9IHN0eWxlLmFsaWduIHx8ICdsZWZ0JztcbiAgICBzdHlsZS5zdHJva2UgPSBzdHlsZS5zdHJva2UgfHwgJ2JsYWNrJzsgLy9wcm92aWRlIGEgZGVmYXVsdCwgc2VlOiBodHRwczovL2dpdGh1Yi5jb20vR29vZEJveURpZ2l0YWwvcGl4aS5qcy9pc3N1ZXMvMTM2XG4gICAgc3R5bGUuc3Ryb2tlVGhpY2tuZXNzID0gc3R5bGUuc3Ryb2tlVGhpY2tuZXNzIHx8IDA7XG4gICAgc3R5bGUud29yZFdyYXAgPSBzdHlsZS53b3JkV3JhcCB8fCBmYWxzZTtcbiAgICBzdHlsZS53b3JkV3JhcFdpZHRoID0gc3R5bGUud29yZFdyYXBXaWR0aCB8fCAxMDA7XG5cbiAgICBzdHlsZS5kcm9wU2hhZG93ID0gc3R5bGUuZHJvcFNoYWRvdyB8fCBmYWxzZTtcbiAgICBzdHlsZS5kcm9wU2hhZG93QW5nbGUgPSBzdHlsZS5kcm9wU2hhZG93QW5nbGUgfHwgTWF0aC5QSSAvIDY7XG4gICAgc3R5bGUuZHJvcFNoYWRvd0Rpc3RhbmNlID0gc3R5bGUuZHJvcFNoYWRvd0Rpc3RhbmNlIHx8IDQ7XG4gICAgc3R5bGUuZHJvcFNoYWRvd0NvbG9yID0gc3R5bGUuZHJvcFNoYWRvd0NvbG9yIHx8ICdibGFjayc7XG5cbiAgICB0aGlzLnN0eWxlID0gc3R5bGU7XG4gICAgdGhpcy5kaXJ0eSA9IHRydWU7XG59O1xuXG4vKipcbiAqIFNldCB0aGUgY29weSBmb3IgdGhlIHRleHQgb2JqZWN0LiBUbyBzcGxpdCBhIGxpbmUgeW91IGNhbiB1c2UgJ1xcbicuXG4gKlxuICogQHBhcmFtIHRleHQge3N0cmluZ30gVGhlIGNvcHkgdGhhdCB5b3Ugd291bGQgbGlrZSB0aGUgdGV4dCB0byBkaXNwbGF5XG4gKi9cblRleHQucHJvdG90eXBlLnNldFRleHQgPSBmdW5jdGlvbiAodGV4dCkge1xuICAgIHRoaXMudGV4dCA9IHRleHQudG9TdHJpbmcoKSB8fCAnICc7XG4gICAgdGhpcy5kaXJ0eSA9IHRydWU7XG59O1xuXG4vKipcbiAqIFJlbmRlcnMgdGV4dCBhbmQgdXBkYXRlcyBpdCB3aGVuIG5lZWRlZFxuICpcbiAqIEBwcml2YXRlXG4gKi9cblRleHQucHJvdG90eXBlLnVwZGF0ZVRleHQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy50ZXh0dXJlLmJhc2VUZXh0dXJlLnJlc29sdXRpb24gPSB0aGlzLnJlc29sdXRpb247XG5cbiAgICB0aGlzLmNvbnRleHQuZm9udCA9IHRoaXMuc3R5bGUuZm9udDtcblxuICAgIHZhciBvdXRwdXRUZXh0ID0gdGhpcy50ZXh0O1xuXG4gICAgLy8gd29yZCB3cmFwXG4gICAgLy8gcHJlc2VydmUgb3JpZ2luYWwgdGV4dFxuICAgIGlmICh0aGlzLnN0eWxlLndvcmRXcmFwKSB7XG4gICAgICAgIG91dHB1dFRleHQgPSB0aGlzLndvcmRXcmFwKHRoaXMudGV4dCk7XG4gICAgfVxuXG4gICAgLy9zcGxpdCB0ZXh0IGludG8gbGluZXNcbiAgICB2YXIgbGluZXMgPSBvdXRwdXRUZXh0LnNwbGl0KC8oPzpcXHJcXG58XFxyfFxcbikvKTtcblxuICAgIC8vY2FsY3VsYXRlIHRleHQgd2lkdGhcbiAgICB2YXIgbGluZVdpZHRocyA9IFtdO1xuICAgIHZhciBtYXhMaW5lV2lkdGggPSAwO1xuICAgIHZhciBmb250UHJvcGVydGllcyA9IHRoaXMuZGV0ZXJtaW5lRm9udFByb3BlcnRpZXModGhpcy5zdHlsZS5mb250KTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBsaW5lV2lkdGggPSB0aGlzLmNvbnRleHQubWVhc3VyZVRleHQobGluZXNbaV0pLndpZHRoO1xuICAgICAgICBsaW5lV2lkdGhzW2ldID0gbGluZVdpZHRoO1xuICAgICAgICBtYXhMaW5lV2lkdGggPSBNYXRoLm1heChtYXhMaW5lV2lkdGgsIGxpbmVXaWR0aCk7XG4gICAgfVxuXG4gICAgdmFyIHdpZHRoID0gbWF4TGluZVdpZHRoICsgdGhpcy5zdHlsZS5zdHJva2VUaGlja25lc3M7XG4gICAgaWYgKHRoaXMuc3R5bGUuZHJvcFNoYWRvdykge1xuICAgICAgICB3aWR0aCArPSB0aGlzLnN0eWxlLmRyb3BTaGFkb3dEaXN0YW5jZTtcbiAgICB9XG5cbiAgICB0aGlzLmNhbnZhcy53aWR0aCA9ICggd2lkdGggKyB0aGlzLmNvbnRleHQubGluZVdpZHRoICkgKiB0aGlzLnJlc29sdXRpb247XG5cbiAgICAvL2NhbGN1bGF0ZSB0ZXh0IGhlaWdodFxuICAgIHZhciBsaW5lSGVpZ2h0ID0gZm9udFByb3BlcnRpZXMuZm9udFNpemUgKyB0aGlzLnN0eWxlLnN0cm9rZVRoaWNrbmVzcztcblxuICAgIHZhciBoZWlnaHQgPSBsaW5lSGVpZ2h0ICogbGluZXMubGVuZ3RoO1xuICAgIGlmICh0aGlzLnN0eWxlLmRyb3BTaGFkb3cpIHtcbiAgICAgICAgaGVpZ2h0ICs9IHRoaXMuc3R5bGUuZHJvcFNoYWRvd0Rpc3RhbmNlO1xuICAgIH1cblxuICAgIHRoaXMuY2FudmFzLmhlaWdodCA9IGhlaWdodCAqIHRoaXMucmVzb2x1dGlvbjtcblxuICAgIHRoaXMuY29udGV4dC5zY2FsZSggdGhpcy5yZXNvbHV0aW9uLCB0aGlzLnJlc29sdXRpb24pO1xuXG4gICAgaWYgKG5hdmlnYXRvci5pc0NvY29vbkpTKSB7XG4gICAgICAgIHRoaXMuY29udGV4dC5jbGVhclJlY3QoMCwgMCwgdGhpcy5jYW52YXMud2lkdGgsIHRoaXMuY2FudmFzLmhlaWdodCk7XG4gICAgfVxuXG4gICAgLy8gdXNlZCBmb3IgZGVidWdnaW5nLi5cbiAgICAvL3RoaXMuY29udGV4dC5maWxsU3R5bGUgPVwiI0ZGMDAwMFwiXG4gICAgLy90aGlzLmNvbnRleHQuZmlsbFJlY3QoMCwgMCwgdGhpcy5jYW52YXMud2lkdGgsdGhpcy5jYW52YXMuaGVpZ2h0KTtcblxuICAgIHRoaXMuY29udGV4dC5mb250ID0gdGhpcy5zdHlsZS5mb250O1xuICAgIHRoaXMuY29udGV4dC5zdHJva2VTdHlsZSA9IHRoaXMuc3R5bGUuc3Ryb2tlO1xuICAgIHRoaXMuY29udGV4dC5saW5lV2lkdGggPSB0aGlzLnN0eWxlLnN0cm9rZVRoaWNrbmVzcztcbiAgICB0aGlzLmNvbnRleHQudGV4dEJhc2VsaW5lID0gJ2FscGhhYmV0aWMnO1xuICAgIC8vdGhpcy5jb250ZXh0LmxpbmVKb2luID0gJ3JvdW5kJztcblxuICAgIHZhciBsaW5lUG9zaXRpb25YO1xuICAgIHZhciBsaW5lUG9zaXRpb25ZO1xuXG4gICAgaWYgKHRoaXMuc3R5bGUuZHJvcFNoYWRvdykge1xuICAgICAgICB0aGlzLmNvbnRleHQuZmlsbFN0eWxlID0gdGhpcy5zdHlsZS5kcm9wU2hhZG93Q29sb3I7XG5cbiAgICAgICAgdmFyIHhTaGFkb3dPZmZzZXQgPSBNYXRoLmNvcyh0aGlzLnN0eWxlLmRyb3BTaGFkb3dBbmdsZSkgKiB0aGlzLnN0eWxlLmRyb3BTaGFkb3dEaXN0YW5jZTtcbiAgICAgICAgdmFyIHlTaGFkb3dPZmZzZXQgPSBNYXRoLnNpbih0aGlzLnN0eWxlLmRyb3BTaGFkb3dBbmdsZSkgKiB0aGlzLnN0eWxlLmRyb3BTaGFkb3dEaXN0YW5jZTtcblxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGxpbmVQb3NpdGlvblggPSB0aGlzLnN0eWxlLnN0cm9rZVRoaWNrbmVzcyAvIDI7XG4gICAgICAgICAgICBsaW5lUG9zaXRpb25ZID0gKHRoaXMuc3R5bGUuc3Ryb2tlVGhpY2tuZXNzIC8gMiArIGkgKiBsaW5lSGVpZ2h0KSArIGZvbnRQcm9wZXJ0aWVzLmFzY2VudDtcblxuICAgICAgICAgICAgaWYgKHRoaXMuc3R5bGUuYWxpZ24gPT09ICdyaWdodCcpIHtcbiAgICAgICAgICAgICAgICBsaW5lUG9zaXRpb25YICs9IG1heExpbmVXaWR0aCAtIGxpbmVXaWR0aHNbaV07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICh0aGlzLnN0eWxlLmFsaWduID09PSAnY2VudGVyJykge1xuICAgICAgICAgICAgICAgIGxpbmVQb3NpdGlvblggKz0gKG1heExpbmVXaWR0aCAtIGxpbmVXaWR0aHNbaV0pIC8gMjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMuc3R5bGUuZmlsbCkge1xuICAgICAgICAgICAgICAgIHRoaXMuY29udGV4dC5maWxsVGV4dChsaW5lc1tpXSwgbGluZVBvc2l0aW9uWCArIHhTaGFkb3dPZmZzZXQsIGxpbmVQb3NpdGlvblkgKyB5U2hhZG93T2Zmc2V0KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgIC8vICBpZiAoZHJvcFNoYWRvdylcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vc2V0IGNhbnZhcyB0ZXh0IHN0eWxlc1xuICAgIHRoaXMuY29udGV4dC5maWxsU3R5bGUgPSB0aGlzLnN0eWxlLmZpbGw7XG5cbiAgICAvL2RyYXcgbGluZXMgbGluZSBieSBsaW5lXG4gICAgZm9yIChpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGxpbmVQb3NpdGlvblggPSB0aGlzLnN0eWxlLnN0cm9rZVRoaWNrbmVzcyAvIDI7XG4gICAgICAgIGxpbmVQb3NpdGlvblkgPSAodGhpcy5zdHlsZS5zdHJva2VUaGlja25lc3MgLyAyICsgaSAqIGxpbmVIZWlnaHQpICsgZm9udFByb3BlcnRpZXMuYXNjZW50O1xuXG4gICAgICAgIGlmICh0aGlzLnN0eWxlLmFsaWduID09PSAncmlnaHQnKSB7XG4gICAgICAgICAgICBsaW5lUG9zaXRpb25YICs9IG1heExpbmVXaWR0aCAtIGxpbmVXaWR0aHNbaV07XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodGhpcy5zdHlsZS5hbGlnbiA9PT0gJ2NlbnRlcicpIHtcbiAgICAgICAgICAgIGxpbmVQb3NpdGlvblggKz0gKG1heExpbmVXaWR0aCAtIGxpbmVXaWR0aHNbaV0pIC8gMjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLnN0eWxlLnN0cm9rZSAmJiB0aGlzLnN0eWxlLnN0cm9rZVRoaWNrbmVzcykge1xuICAgICAgICAgICAgdGhpcy5jb250ZXh0LnN0cm9rZVRleHQobGluZXNbaV0sIGxpbmVQb3NpdGlvblgsIGxpbmVQb3NpdGlvblkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuc3R5bGUuZmlsbCkge1xuICAgICAgICAgICAgdGhpcy5jb250ZXh0LmZpbGxUZXh0KGxpbmVzW2ldLCBsaW5lUG9zaXRpb25YLCBsaW5lUG9zaXRpb25ZKTtcbiAgICAgICAgfVxuXG4gICAgICAvLyAgaWYgKGRyb3BTaGFkb3cpXG4gICAgfVxuXG4gICAgdGhpcy51cGRhdGVUZXh0dXJlKCk7XG59O1xuXG4vKipcbiAqIFVwZGF0ZXMgdGV4dHVyZSBzaXplIGJhc2VkIG9uIGNhbnZhcyBzaXplXG4gKlxuICogQHByaXZhdGVcbiAqL1xuVGV4dC5wcm90b3R5cGUudXBkYXRlVGV4dHVyZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnRleHR1cmUuYmFzZVRleHR1cmUud2lkdGggPSB0aGlzLmNhbnZhcy53aWR0aDtcbiAgICB0aGlzLnRleHR1cmUuYmFzZVRleHR1cmUuaGVpZ2h0ID0gdGhpcy5jYW52YXMuaGVpZ2h0O1xuICAgIHRoaXMudGV4dHVyZS5jcm9wLndpZHRoID0gdGhpcy50ZXh0dXJlLmZyYW1lLndpZHRoID0gdGhpcy5jYW52YXMud2lkdGg7XG4gICAgdGhpcy50ZXh0dXJlLmNyb3AuaGVpZ2h0ID0gdGhpcy50ZXh0dXJlLmZyYW1lLmhlaWdodCA9IHRoaXMuY2FudmFzLmhlaWdodDtcblxuICAgIHRoaXMuX3dpZHRoID0gdGhpcy5jYW52YXMud2lkdGg7XG4gICAgdGhpcy5faGVpZ2h0ID0gdGhpcy5jYW52YXMuaGVpZ2h0O1xuXG4gICAgLy8gdXBkYXRlIHRoZSBkaXJ0eSBiYXNlIHRleHR1cmVzXG4gICAgdGhpcy50ZXh0dXJlLmJhc2VUZXh0dXJlLmRpcnR5KCk7XG59O1xuXG4vKipcbiAqIFJlbmRlcnMgdGhlIG9iamVjdCB1c2luZyB0aGUgV2ViR0wgcmVuZGVyZXJcbipcbiAqIEBwYXJhbSByZW5kZXJlciB7V2ViR0xSZW5kZXJlcn1cbiAqL1xuVGV4dC5wcm90b3R5cGUucmVuZGVyV2ViR0wgPSBmdW5jdGlvbiAocmVuZGVyZXIpIHtcbiAgICBpZiAodGhpcy5kaXJ0eSkge1xuICAgICAgICB0aGlzLnJlc29sdXRpb24gPSByZW5kZXJlci5yZXNvbHV0aW9uO1xuXG4gICAgICAgIHRoaXMudXBkYXRlVGV4dCgpO1xuICAgICAgICB0aGlzLmRpcnR5ID0gZmFsc2U7XG4gICAgfVxuXG4gICAgY29yZS5TcHJpdGUucHJvdG90eXBlLnJlbmRlcldlYkdMLmNhbGwodGhpcywgcmVuZGVyZXIpO1xufTtcblxuLyoqXG4gKiBSZW5kZXJzIHRoZSBvYmplY3QgdXNpbmcgdGhlIENhbnZhcyByZW5kZXJlclxuKlxuICogQHBhcmFtIHJlbmRlcmVyIHtDYW52YXNSZW5kZXJlcn1cbiAqL1xuVGV4dC5wcm90b3R5cGUucmVuZGVyQ2FudmFzID0gZnVuY3Rpb24gKHJlbmRlcmVyKSB7XG4gICAgaWYgKHRoaXMuZGlydHkpIHtcbiAgICAgICAgdGhpcy5yZXNvbHV0aW9uID0gcmVuZGVyZXIucmVzb2x1dGlvbjtcblxuICAgICAgICB0aGlzLnVwZGF0ZVRleHQoKTtcbiAgICAgICAgdGhpcy5kaXJ0eSA9IGZhbHNlO1xuICAgIH1cblxuICAgIGNvcmUuU3ByaXRlLnByb3RvdHlwZS5yZW5kZXJDYW52YXMuY2FsbCh0aGlzLCByZW5kZXJlcik7XG59O1xuXG4vKipcbiAqIENhbGN1bGF0ZXMgdGhlIGFzY2VudCwgZGVzY2VudCBhbmQgZm9udFNpemUgb2YgYSBnaXZlbiBmb250U3R5bGVcbipcbiAqIEBwYXJhbSBmb250U3R5bGUge29iamVjdH1cbiAqIEBwcml2YXRlXG4gKi9cblRleHQucHJvdG90eXBlLmRldGVybWluZUZvbnRQcm9wZXJ0aWVzID0gZnVuY3Rpb24gKGZvbnRTdHlsZSkge1xuICAgIHZhciBwcm9wZXJ0aWVzID0gVGV4dC5mb250UHJvcGVydGllc0NhY2hlW2ZvbnRTdHlsZV07XG5cbiAgICBpZiAoIXByb3BlcnRpZXMpIHtcbiAgICAgICAgcHJvcGVydGllcyA9IHt9O1xuXG4gICAgICAgIHZhciBjYW52YXMgPSBUZXh0LmZvbnRQcm9wZXJ0aWVzQ2FudmFzO1xuICAgICAgICB2YXIgY29udGV4dCA9IFRleHQuZm9udFByb3BlcnRpZXNDb250ZXh0O1xuXG4gICAgICAgIGNvbnRleHQuZm9udCA9IGZvbnRTdHlsZTtcblxuICAgICAgICB2YXIgd2lkdGggPSBNYXRoLmNlaWwoY29udGV4dC5tZWFzdXJlVGV4dCgnfE1xJykud2lkdGgpO1xuICAgICAgICB2YXIgYmFzZWxpbmUgPSBNYXRoLmNlaWwoY29udGV4dC5tZWFzdXJlVGV4dCgnTScpLndpZHRoKTtcbiAgICAgICAgdmFyIGhlaWdodCA9IDIgKiBiYXNlbGluZTtcblxuICAgICAgICBiYXNlbGluZSA9IGJhc2VsaW5lICogMS40IHwgMDtcblxuICAgICAgICBjYW52YXMud2lkdGggPSB3aWR0aDtcbiAgICAgICAgY2FudmFzLmhlaWdodCA9IGhlaWdodDtcblxuICAgICAgICBjb250ZXh0LmZpbGxTdHlsZSA9ICcjZjAwJztcbiAgICAgICAgY29udGV4dC5maWxsUmVjdCgwLCAwLCB3aWR0aCwgaGVpZ2h0KTtcblxuICAgICAgICBjb250ZXh0LmZvbnQgPSBmb250U3R5bGU7XG5cbiAgICAgICAgY29udGV4dC50ZXh0QmFzZWxpbmUgPSAnYWxwaGFiZXRpYyc7XG4gICAgICAgIGNvbnRleHQuZmlsbFN0eWxlID0gJyMwMDAnO1xuICAgICAgICBjb250ZXh0LmZpbGxUZXh0KCd8TcOJcScsIDAsIGJhc2VsaW5lKTtcblxuICAgICAgICB2YXIgaW1hZ2VkYXRhID0gY29udGV4dC5nZXRJbWFnZURhdGEoMCwgMCwgd2lkdGgsIGhlaWdodCkuZGF0YTtcbiAgICAgICAgdmFyIHBpeGVscyA9IGltYWdlZGF0YS5sZW5ndGg7XG4gICAgICAgIHZhciBsaW5lID0gd2lkdGggKiA0O1xuXG4gICAgICAgIHZhciBpLCBqO1xuXG4gICAgICAgIHZhciBpZHggPSAwO1xuICAgICAgICB2YXIgc3RvcCA9IGZhbHNlO1xuXG4gICAgICAgIC8vIGFzY2VudC4gc2NhbiBmcm9tIHRvcCB0byBib3R0b20gdW50aWwgd2UgZmluZCBhIG5vbiByZWQgcGl4ZWxcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGJhc2VsaW5lOyBpKyspIHtcbiAgICAgICAgICAgIGZvciAoaiA9IDA7IGogPCBsaW5lOyBqICs9IDQpIHtcbiAgICAgICAgICAgICAgICBpZiAoaW1hZ2VkYXRhW2lkeCArIGpdICE9PSAyNTUpIHtcbiAgICAgICAgICAgICAgICAgICAgc3RvcCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghc3RvcCkge1xuICAgICAgICAgICAgICAgIGlkeCArPSBsaW5lO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBwcm9wZXJ0aWVzLmFzY2VudCA9IGJhc2VsaW5lIC0gaTtcblxuICAgICAgICBpZHggPSBwaXhlbHMgLSBsaW5lO1xuICAgICAgICBzdG9wID0gZmFsc2U7XG5cbiAgICAgICAgLy8gZGVzY2VudC4gc2NhbiBmcm9tIGJvdHRvbSB0byB0b3AgdW50aWwgd2UgZmluZCBhIG5vbiByZWQgcGl4ZWxcbiAgICAgICAgZm9yIChpID0gaGVpZ2h0OyBpID4gYmFzZWxpbmU7IGktLSkge1xuICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IGxpbmU7IGogKz0gNCkge1xuICAgICAgICAgICAgICAgIGlmIChpbWFnZWRhdGFbaWR4ICsgal0gIT09IDI1NSkge1xuICAgICAgICAgICAgICAgICAgICBzdG9wID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFzdG9wKSB7XG4gICAgICAgICAgICAgICAgaWR4IC09IGxpbmU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHByb3BlcnRpZXMuZGVzY2VudCA9IGkgLSBiYXNlbGluZTtcbiAgICAgICAgLy9UT0RPIG1pZ2h0IG5lZWQgYSB0d2Vhay4ga2luZCBvZiBhIHRlbXAgZml4IVxuICAgICAgICBwcm9wZXJ0aWVzLmRlc2NlbnQgKz0gNjtcbiAgICAgICAgcHJvcGVydGllcy5mb250U2l6ZSA9IHByb3BlcnRpZXMuYXNjZW50ICsgcHJvcGVydGllcy5kZXNjZW50O1xuXG4gICAgICAgIFRleHQuZm9udFByb3BlcnRpZXNDYWNoZVtmb250U3R5bGVdID0gcHJvcGVydGllcztcbiAgICB9XG5cbiAgICByZXR1cm4gcHJvcGVydGllcztcbn07XG5cbi8qKlxuICogQXBwbGllcyBuZXdsaW5lcyB0byBhIHN0cmluZyB0byBoYXZlIGl0IG9wdGltYWxseSBmaXQgaW50byB0aGUgaG9yaXpvbnRhbFxuICogYm91bmRzIHNldCBieSB0aGUgVGV4dCBvYmplY3QncyB3b3JkV3JhcFdpZHRoIHByb3BlcnR5LlxuICpcbiAqIEBwYXJhbSB0ZXh0IHtzdHJpbmd9XG4gKiBAcHJpdmF0ZVxuICovXG5UZXh0LnByb3RvdHlwZS53b3JkV3JhcCA9IGZ1bmN0aW9uICh0ZXh0KSB7XG4gICAgLy8gR3JlZWR5IHdyYXBwaW5nIGFsZ29yaXRobSB0aGF0IHdpbGwgd3JhcCB3b3JkcyBhcyB0aGUgbGluZSBncm93cyBsb25nZXJcbiAgICAvLyB0aGFuIGl0cyBob3Jpem9udGFsIGJvdW5kcy5cbiAgICB2YXIgcmVzdWx0ID0gJyc7XG4gICAgdmFyIGxpbmVzID0gdGV4dC5zcGxpdCgnXFxuJyk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGg7IGkrKykge1xuICAgICAgICB2YXIgc3BhY2VMZWZ0ID0gdGhpcy5zdHlsZS53b3JkV3JhcFdpZHRoO1xuICAgICAgICB2YXIgd29yZHMgPSBsaW5lc1tpXS5zcGxpdCgnICcpO1xuICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHdvcmRzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICB2YXIgd29yZFdpZHRoID0gdGhpcy5jb250ZXh0Lm1lYXN1cmVUZXh0KHdvcmRzW2pdKS53aWR0aDtcbiAgICAgICAgICAgIHZhciB3b3JkV2lkdGhXaXRoU3BhY2UgPSB3b3JkV2lkdGggKyB0aGlzLmNvbnRleHQubWVhc3VyZVRleHQoJyAnKS53aWR0aDtcbiAgICAgICAgICAgIGlmIChqID09PSAwIHx8IHdvcmRXaWR0aFdpdGhTcGFjZSA+IHNwYWNlTGVmdCkge1xuICAgICAgICAgICAgICAgIC8vIFNraXAgcHJpbnRpbmcgdGhlIG5ld2xpbmUgaWYgaXQncyB0aGUgZmlyc3Qgd29yZCBvZiB0aGUgbGluZSB0aGF0IGlzXG4gICAgICAgICAgICAgICAgLy8gZ3JlYXRlciB0aGFuIHRoZSB3b3JkIHdyYXAgd2lkdGguXG4gICAgICAgICAgICAgICAgaWYgKGogPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdCArPSAnXFxuJztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmVzdWx0ICs9IHdvcmRzW2pdO1xuICAgICAgICAgICAgICAgIHNwYWNlTGVmdCA9IHRoaXMuc3R5bGUud29yZFdyYXBXaWR0aCAtIHdvcmRXaWR0aDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHNwYWNlTGVmdCAtPSB3b3JkV2lkdGhXaXRoU3BhY2U7XG4gICAgICAgICAgICAgICAgcmVzdWx0ICs9ICcgJyArIHdvcmRzW2pdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGkgPCBsaW5lcy5sZW5ndGgtMSkge1xuICAgICAgICAgICAgcmVzdWx0ICs9ICdcXG4nO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdGhlIGJvdW5kcyBvZiB0aGUgVGV4dCBhcyBhIHJlY3RhbmdsZS4gVGhlIGJvdW5kcyBjYWxjdWxhdGlvbiB0YWtlcyB0aGUgd29ybGRUcmFuc2Zvcm0gaW50byBhY2NvdW50LlxuICpcbiAqIEBwYXJhbSBtYXRyaXgge01hdHJpeH0gdGhlIHRyYW5zZm9ybWF0aW9uIG1hdHJpeCBvZiB0aGUgVGV4dFxuICogQHJldHVybiB7UmVjdGFuZ2xlfSB0aGUgZnJhbWluZyByZWN0YW5nbGVcbiAqL1xuVGV4dC5wcm90b3R5cGUuZ2V0Qm91bmRzID0gZnVuY3Rpb24gKG1hdHJpeCkge1xuICAgIGlmICh0aGlzLmRpcnR5KSB7XG4gICAgICAgIHRoaXMudXBkYXRlVGV4dCgpO1xuICAgICAgICB0aGlzLmRpcnR5ID0gZmFsc2U7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNvcmUuU3ByaXRlLnByb3RvdHlwZS5nZXRCb3VuZHMuY2FsbCh0aGlzLCBtYXRyaXgpO1xufTtcblxuLyoqXG4gKiBEZXN0cm95cyB0aGlzIHRleHQgb2JqZWN0LlxuICpcbiAqIEBwYXJhbSBkZXN0cm95QmFzZVRleHR1cmUge2Jvb2xlYW59IHdoZXRoZXIgdG8gZGVzdHJveSB0aGUgYmFzZSB0ZXh0dXJlIGFzIHdlbGxcbiAqL1xuVGV4dC5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uIChkZXN0cm95QmFzZVRleHR1cmUpIHtcbiAgICAvLyBtYWtlIHN1cmUgdG8gcmVzZXQgdGhlIHRoZSBjb250ZXh0IGFuZCBjYW52YXMuLiBkb250IHdhbnQgdGhpcyBoYW5naW5nIGFyb3VuZCBpbiBtZW1vcnkhXG4gICAgdGhpcy5jb250ZXh0ID0gbnVsbDtcbiAgICB0aGlzLmNhbnZhcyA9IG51bGw7XG5cbiAgICB0aGlzLnRleHR1cmUuZGVzdHJveShkZXN0cm95QmFzZVRleHR1cmUgPT09IHVuZGVmaW5lZCA/IHRydWUgOiBkZXN0cm95QmFzZVRleHR1cmUpO1xufTtcblxuVGV4dC5mb250UHJvcGVydGllc0NhY2hlID0ge307XG5UZXh0LmZvbnRQcm9wZXJ0aWVzQ2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG5UZXh0LmZvbnRQcm9wZXJ0aWVzQ29udGV4dCA9IFRleHQuZm9udFByb3BlcnRpZXNDYW52YXMuZ2V0Q29udGV4dCgnMmQnKTtcbiIsIi8qKlxuICogQGZpbGUgICAgICAgIE1haW4gZXhwb3J0IG9mIHRoZSBQSVhJIHRleHQgbGlicmFyeVxuICogQGF1dGhvciAgICAgIE1hdCBHcm92ZXMgPG1hdEBnb29kYm95ZGlnaXRhbC5jb20+XG4gKiBAY29weXJpZ2h0ICAgMjAxMy0yMDE1IEdvb2RCb3lEaWdpdGFsXG4gKiBAbGljZW5zZSAgICAge0BsaW5rIGh0dHBzOi8vZ2l0aHViLmNvbS9Hb29kQm95RGlnaXRhbC9waXhpLmpzL2Jsb2IvbWFzdGVyL0xJQ0VOU0V8TUlUIExpY2Vuc2V9XG4gKi9cblxuLyoqXG4gKiBAbmFtZXNwYWNlIFBJWElcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgVGV4dDogICAgICAgcmVxdWlyZSgnLi9UZXh0JyksXG4gICAgQml0bWFwVGV4dDogcmVxdWlyZSgnLi9CaXRtYXBUZXh0Jylcbn07XG4iXX0= diff --git a/dist/pixi.min.js b/dist/pixi.min.js deleted file mode 100644 index 9f2f3aa..0000000 --- a/dist/pixi.min.js +++ /dev/null @@ -1,8 +0,0 @@ -!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;"undefined"!=typeof window?e=window:"undefined"!=typeof global?e=global:"undefined"!=typeof self&&(e=self),e.PIXI=t()}}(function(){return function t(e,i,r){function n(o,a){if(!i[o]){if(!e[o]){var h="function"==typeof require&&require;if(!a&&h)return h(o,!0);if(s)return s(o,!0);var l=new Error("Cannot find module '"+o+"'");throw l.code="MODULE_NOT_FOUND",l}var u=i[o]={exports:{}};e[o][0].call(u.exports,function(t){var i=e[o][1][t];return n(i?i:t)},u,u.exports,t,e,i,r)}return i[o].exports}for(var s="function"==typeof require&&require,o=0;o","Richard Davey "],main:"./src/index.js",homepage:"http://goodboydigital.com/",bugs:"https://github.com/GoodBoyDigital/pixi.js/issues",license:"MIT",repository:{type:"git",url:"https://github.com/GoodBoyDigital/pixi.js.git"},scripts:{test:"gulp test",docs:"./node_modules/.bin/jsdoc -c ./gulp/util/jsdoc.conf.json"},devDependencies:{browserify:"^8.0.2",chai:"^1.10.0",del:"^1.1.0",gulp:"^3.8.10","gulp-jshint":"^1.9.0","gulp-plumber":"^0.6.6","gulp-rename":"^1.2.0","gulp-uglify":"^1.0.2","gulp-util":"^3.0.1","ink-docstrap":"^0.4.12",jsdoc:"^3.3.0-alpha13","jshint-summary":"^0.4.0",karma:"^0.12.28","karma-firefox-launcher":"^0.1.0","karma-mocha":"^0.1.10","karma-spec-reporter":"^0.0.16",mocha:"^2.1.0","require-dir":"^0.1.0","run-sequence":"^1.0.2","vinyl-buffer":"^1.0.0","vinyl-source-stream":"^1.0.0",watchify:"^2.2.1"},dependencies:{"webgl-enabled":"^1.0.2"}}},{}],4:[function(t,e){e.exports={WEBGL_RENDERER:1,CANVAS_RENDERER:2,VERSION:t("../../package.json").version,blendModes:{NORMAL:0,ADD:1,MULTIPLY:2,SCREEN:3,OVERLAY:4,DARKEN:5,LIGHTEN:6,COLOR_DODGE:7,COLOR_BURN:8,HARD_LIGHT:9,SOFT_LIGHT:10,DIFFERENCE:11,EXCLUSION:12,HUE:13,SATURATION:14,COLOR:15,LUMINOSITY:16},scaleModes:{DEFAULT:0,LINEAR:0,NEAREST:1},RETINA_PREFIX:"@2x",defaultRenderOptions:{view:null,resolution:1,antialias:!1,autoResize:!1,transparent:!1,backgroundColor:0,clearBeforeRender:!0,preserveDrawingBuffer:!1},SHAPES:{POLY:0,RECT:1,CIRC:2,ELIP:3,RREC:4}}},{"../../package.json":3}],5:[function(t,e){function i(){this.position=new r.Point,this.scale=new r.Point(1,1),this.pivot=new r.Point(0,0),this.rotation=0,this.alpha=1,this.visible=!0,this.renderable=!1,this.parent=null,this.worldAlpha=1,this.worldTransform=new r.Matrix,this.filterArea=null,this._sr=0,this._cr=1,this._bounds=new r.Rectangle(0,0,1,1),this._currentBounds=null,this._mask=null,this._cacheIsDirty=!1}var r=t("../math");i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{x:{get:function(){return this.position.x},set:function(t){this.position.x=t}},y:{get:function(){return this.position.y},set:function(t){this.position.y=t}},worldVisible:{get:function(){var t=this;do{if(!t.visible)return!1;t=t.parent}while(t);return!0}},mask:{get:function(){return this._mask},set:function(t){this._mask&&(this._mask.isMask=!1),this._mask=t,this._mask&&(this._mask.isMask=!0)}},filters:{get:function(){return this._filters},set:function(t){if(t){for(var e=[],i=0;i=0&&e<=this.children.length)return t.parent&&t.parent.removeChild(t),t.parent=this,this.children.splice(e,0,t),t;throw new Error(t+"addChildAt: The index "+e+" supplied is out of bounds "+this.children.length)}},i.prototype.swapChildren=function(t,e){if(t!==e){var i=this.getChildIndex(t),r=this.getChildIndex(e);if(0>i||0>r)throw new Error("swapChildren: Both the supplied DisplayObjects must be a child of the caller.");this.children[i]=e,this.children[r]=t}},i.prototype.getChildIndex=function(t){var e=this.children.indexOf(t);if(-1===e)throw new Error("The supplied DisplayObject must be a child of the caller");return e},i.prototype.setChildIndex=function(t,e){if(0>e||e>=this.children.length)throw new Error("The supplied index is out of bounds");var i=this.getChildIndex(t);this.children.splice(i,1),this.children.splice(e,0,t)},i.prototype.getChildAt=function(t){if(0>t||t>=this.children.length)throw new Error("getChildAt: Supplied index "+t+" does not exist in the child list, or the supplied DisplayObject must be a child of the caller");return this.children[t]},i.prototype.removeChild=function(t){var e=this.children.indexOf(t);if(-1!==e)return this.removeChildAt(e)},i.prototype.removeChildAt=function(t){var e=this.getChildAt(t);return e.parent=null,this.children.splice(t,1),e},i.prototype.removeChildren=function(t,e){var i=t||0,r="number"==typeof e?e:this.children.length,n=r-i;if(n>0&&r>=n){for(var s=this.children.splice(i,n),o=0;ot;++t)this.children[t].updateTransform()},i.prototype.displayObjectContainerUpdateTransform=i.prototype.updateTransform,i.prototype.getBounds=function(){if(0===this.children.length)return r.Rectangle.EMPTY;for(var t,e,i,n=1/0,s=1/0,o=-1/0,a=-1/0,h=!1,l=0,u=this.children.length;u>l;++l){var c=this.children[l];c.visible&&(h=!0,t=this.children[l].getBounds(),n=ne?o:e,a=a>i?a:i)}return h?(this._bounds.x=n,this._bounds.y=s,this._bounds.width=o-n,this._bounds.height=a-s,this._bounds):r.Rectangle.EMPTY},i.prototype.getLocalBounds=function(){var t=this.worldTransform;this.worldTransform=r.Matrix.IDENTITY;for(var e=0,i=this.children.length;i>e;++e)this.children[e].updateTransform();return this.worldTransform=t,this.getBounds()},i.prototype.renderWebGL=function(t){if(this.visible&&!(this.alpha<=0)){if(this._cacheAsBitmap)return void this._renderCachedSprite(t);var e,i;if(this._mask||this._filters){for(this._filters&&(t.spriteBatch.flush(),t.filterManager.pushFilter(this._filterBlock)),this._mask&&(t.spriteBatch.stop(),t.maskManager.pushMask(this.mask,t),t.spriteBatch.start()),this.texture&&t.spriteBatch.render(this),e=0,i=this.children.length;i>e;e++)this.children[e].renderWebGL(t);t.spriteBatch.stop(),this._mask&&t.maskManager.popMask(this._mask,t),this._filters&&t.filterManager.popFilter(),t.spriteBatch.start()}else for(this.texture&&t.spriteBatch.render(this),e=0,i=this.children.length;i>e;++e)this.children[e].renderWebGL(t)}},i.prototype.renderCanvas=function(t){if(this.visible&&!(this.alpha<=0)){if(this._cacheAsBitmap)return void this._renderCachedSprite(t);this._mask&&t.maskManager.pushMask(this._mask,t);for(var e=0,i=this.children.length;i>e;++e)this.children[e].renderCanvas(t);this._mask&&t.maskManager.popMask(t)}},i.prototype._renderCachedSprite=function(t){this._cachedSprite.worldAlpha=this.worldAlpha,t.gl?this._cachedSprite.renderWebGL(t):this._cachedSprite.renderCanvas(t)},i.prototype._generateCachedSprite=function(){var t=this.getLocalBounds();if(this._cachedSprite)this._cachedSprite.texture.resize(0|t.width,0|t.height);else{var e=new s(renderer,0|t.width,0|t.height);this._cachedSprite=new Sprite(e),this._cachedSprite.worldTransform=this.worldTransform}var i=this._filters;this._filters=null,this._cachedSprite.filters=i,o.tx=-t.x,o.ty=-t.y,this._cachedSprite.texture.render(this,o,!0),this._cachedSprite.anchor.x=-(t.x/t.width),this._cachedSprite.anchor.y=-(t.y/t.height),this._filters=i},i.prototype._destroyCachedSprite=function(){this._cachedSprite&&(this._cachedSprite.destroy(!0,!0),this._cachedSprite=null)}},{"../math":12,"../textures/RenderTexture":43,"./DisplayObject":5}],7:[function(t,e){function i(t){s.call(this),this.anchor=new r.Point,this._texture=null,this._width=0,this._height=0,this.tint=16777215,this.blendMode=h.blendModes.NORMAL,this.shader=null,this.renderable=!0,this.texture=t||n.EMPTY}var r=t("../math"),n=t("../textures/Texture"),s=t("./DisplayObjectContainer"),o=t("../renderers/canvas/utils/CanvasTinter"),a=t("../utils"),h=t("../const");i.prototype.destroy=function(t,e){s.prototype.destroy.call(this),this.anchor=null,t&&this._texture.destroy(e),this._texture=null,this.shader=null},i.prototype=Object.create(s.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{width:{get:function(){return this.scale.x*this.texture.frame.width},set:function(t){this.scale.x=t/this.texture.frame.width,this._width=t}},height:{get:function(){return this.scale.y*this.texture.frame.height},set:function(t){this.scale.y=t/this.texture.frame.height,this._height=t}},texture:{get:function(){return this._texture},set:function(t){this._texture!==t&&(this._texture=t,this.cachedTint=16777215,t&&(t.baseTexture.hasLoaded?this._onTextureUpdate():t.once("update",this._onTextureUpdate.bind(this))))}}}),i.prototype._onTextureUpdate=function(){this._width&&(this.scale.x=this._width/this.texture.frame.width),this._height&&(this.scale.y=this._height/this.texture.frame.height)},i.prototype.getBounds=function(t){var e,i,r,n,s=this.texture.frame.width,o=this.texture.frame.height,a=s*(1-this.anchor.x),h=s*-this.anchor.x,l=o*(1-this.anchor.y),u=o*-this.anchor.y,c=t||this.worldTransform,d=c.a,f=c.b,p=c.c,v=c.d,m=c.tx,g=c.ty;if(0===f&&0===p)0>d&&(d*=-1),0>v&&(v*=-1),e=d*h+m,i=d*a+m,r=v*u+g,n=v*l+g;else{var x=d*h+p*u+m,y=v*u+f*h+g,b=d*a+p*u+m,T=v*u+f*a+g,w=d*a+p*l+m,S=v*l+f*a+g,A=d*h+p*l+m,_=v*l+f*h+g;e=x,e=e>b?b:e,e=e>w?w:e,e=e>A?A:e,r=y,r=r>T?T:r,r=r>S?S:r,r=r>_?_:r,i=x,i=b>i?b:i,i=w>i?w:i,i=A>i?A:i,n=y,n=T>n?T:n,n=S>n?S:n,n=_>n?_:n}var C=this._bounds;return C.x=e,C.width=i-e,C.y=r,C.height=n-r,this._currentBounds=C,C},i.prototype.renderCanvas=function(t){if(!(!this.visible||this.alpha<=0||this.texture.crop.width<=0||this.texture.crop.height<=0)){if(this.blendMode!==t.currentBlendMode&&(t.currentBlendMode=this.blendMode,t.context.globalCompositeOperation=t.blendModes[t.currentBlendMode]),this._mask&&t.maskManager.pushMask(this._mask,t),this.texture.valid){var e=this.texture.baseTexture.resolution/t.resolution;t.context.globalAlpha=this.worldAlpha,t.smoothProperty&&t.scaleMode!==this.texture.baseTexture.scaleMode&&(t.scaleMode=this.texture.baseTexture.scaleMode,t.context[t.smoothProperty]=t.scaleMode===h.scaleModes.LINEAR);var i=(this.texture.trim?this.texture.trim.x:0)-this.anchor.x*this.texture.trim.width,r=(this.texture.trim?this.texture.trim.y:0)-this.anchor.y*this.texture.trim.height;t.roundPixels?(t.context.setTransform(this.worldTransform.a,this.worldTransform.b,this.worldTransform.c,this.worldTransform.d,this.worldTransform.tx*t.resolution|0,this.worldTransform.ty*t.resolution|0),i=0|i,r=0|r):t.context.setTransform(this.worldTransform.a,this.worldTransform.b,this.worldTransform.c,this.worldTransform.d,this.worldTransform.tx*t.resolution,this.worldTransform.ty*t.resolution),16777215!==this.tint?(this.cachedTint!==this.tint&&(this.cachedTint=this.tint,this.tintedTexture=o.getTintedTexture(this,this.tint)),t.context.drawImage(this.tintedTexture,0,0,this.texture.crop.width,this.texture.crop.height,i/e,r/e,this.texture.crop.width/e,this.texture.crop.height/e)):t.context.drawImage(this.texture.baseTexture.source,this.texture.crop.x,this.texture.crop.y,this.texture.crop.width,this.texture.crop.height,i/e,r/e,this.texture.crop.width/e,this.texture.crop.height/e)}for(var n=0,s=this.children.length;s>n;n++)this.children[n].renderCanvas(t);this._mask&&t.maskManager.popMask(t)}},i.fromFrame=function(t){var e=a.TextureCache[t];if(!e)throw new Error('The frameId "'+t+'" does not exist in the texture cache'+this);return new i(e)},i.fromImage=function(t,e,r){return new i(n.fromImage(t,e,r))}},{"../const":4,"../math":12,"../renderers/canvas/utils/CanvasTinter":24,"../textures/Texture":44,"../utils":50,"./DisplayObjectContainer":6}],8:[function(t,e){function i(){r.call(this)}{var r=t("./DisplayObjectContainer");t("../renderers/webgl/utils/WebGLFastSpriteBatch")}i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,i.prototype.updateTransform=function(){this.displayObjectUpdateTransform()},i.prototype.renderWebGL=function(t){!this.visible||this.alpha<=0||!this.children.length||(t.spriteBatch.stop(),t.shaderManager.setShader(t.shaderManager.fastShader),t.fastSpriteBatch.begin(this),t.fastSpriteBatch.render(this),t.spriteBatch.start())},i.prototype.renderCanvas=function(t){if(this.visible&&!(this.alpha<=0)&&this.children.length){var e=t.context,i=this.worldTransform,r=!0;e.globalAlpha=this.worldAlpha,this.displayObjectUpdateTransform();for(var n=0;n=i+r},i.prototype.getBounds=function(){return new r(this.x-this.radius,this.y-this.radius,2*this.radius,2*this.radius)}},{"../../const":4,"./Rectangle":16}],14:[function(t,e){function i(t,e,i,r){this.x=t||0,this.y=e||0,this.width=i||0,this.height=r||0,this.type=n.SHAPES.ELIP}var r=t("./Rectangle"),n=t("../../const");i.prototype.constructor=i,e.exports=i,i.prototype.clone=function(){return new i(this.x,this.y,this.width,this.height)},i.prototype.contains=function(t,e){if(this.width<=0||this.height<=0)return!1;var i=(t-this.x)/this.width,r=(e-this.y)/this.height;return i*=i,r*=r,1>=i+r},i.prototype.getBounds=function(){return new r(this.x-this.width,this.y-this.height,this.width,this.height)}},{"../../const":4,"./Rectangle":16}],15:[function(t,e){function i(t){if(t instanceof Array||(t=Array.prototype.slice.call(arguments)),t[0]instanceof r){for(var e=[],i=0,s=t.length;s>i;i++)e.push(t[i].x,t[i].y);t=e}this.closed=!0,this.points=t,this.type=n.SHAPES.POLY}var r=t("../Point"),n=t("../../const");i.prototype.constructor=i,e.exports=i,i.prototype.clone=function(){return new i(this.points.slice())},i.prototype.contains=function(t,e){for(var i=!1,r=this.points.length/2,n=0,s=r-1;r>n;s=n++){var o=this.points[2*n],a=this.points[2*n+1],h=this.points[2*s],l=this.points[2*s+1],u=a>e!=l>e&&(h-o)*(e-a)/(l-a)+o>t;u&&(i=!i)}return i}},{"../../const":4,"../Point":11}],16:[function(t,e){function i(t,e,i,n){this.x=t||0,this.y=e||0,this.width=i||0,this.height=n||0,this.type=r.SHAPES.RECT}var r=t("../../const");i.prototype.constructor=i,e.exports=i,i.EMPTY=new i(0,0,0,0),i.prototype.clone=function(){return new i(this.x,this.y,this.width,this.height)},i.prototype.contains=function(t,e){return this.width<=0||this.height<=0?!1:t>=this.x&&t<=this.x+this.width&&e>=this.y&&e<=this.y+this.height?!0:!1}},{"../../const":4}],17:[function(t,e){function i(t,e,i,n,s){this.x=t||0,this.y=e||0,this.width=i||0,this.height=n||0,this.radius=s||20,this.type=r.SHAPES.RREC}var r=t("../../const");i.prototype.constructor=i,e.exports=i,i.prototype.clone=function(){return new i(this.x,this.y,this.width,this.height,this.radius)},i.prototype.contains=function(t,e){return this.width<=0||this.height<=0?!1:t>=this.x&&t<=this.x+this.width&&e>=this.y&&e<=this.y+this.height?!0:!1}},{"../../const":4}],18:[function(t,e){function i(){r.call(this),this.renderable=!0,this.fillAlpha=1,this.lineWidth=0,this.lineColor=0,this.graphicsData=[],this.tint=16777215,this.blendMode=c.blendModes.NORMAL,this.currentPath=null,this._webGL={},this.isMask=!1,this.boundsPadding=0,this._localBounds=new u.Rectangle(0,0,1,1),this.dirty=!0,this.glDirty=!1,this.cachedSpriteDirty=!1}var r=t("../display/DisplayObjectContainer"),n=t("../display/Sprite"),s=t("../textures/Texture"),o=t("../renderers/canvas/utils/CanvasBuffer"),a=t("../renderers/canvas/utils/CanvasGraphics"),h=t("../renderers/webgl/utils/WebGLGraphics"),l=t("./GraphicsData"),u=t("../math"),c=t("../const");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{cacheAsBitmap:{get:function(){return this._cacheAsBitmap},set:function(t){this._cacheAsBitmap=t,this._cacheAsBitmap?this._generateCachedSprite():(this.destroyCachedSprite(),this.dirty=!0)}}}),l.prototype.clone=function(){var t=new i;t.renderable=this.renderable,t.fillAlpha=this.fillAlpha,t.lineWidth=this.lineWidth,t.lineColor=this.lineColor,t.tint=this.tint,t.blendMode=this.blendMode,t.isMask=this.isMask,t.boundsPadding=this.boundsPadding,t.dirty=this.dirty,t.glDirty=this.glDirty,t.cachedSpriteDirty=this.cachedSpriteDirty;for(var e=0;e=c;++c)u=c/o,n=h+(t-h)*u,s=l+(e-l)*u,a.push(n+(t+(i-t)*u-n)*u,s+(e+(r-e)*u-s)*u);return this.dirty=!0,this},i.prototype.bezierCurveTo=function(t,e,i,r,n,s){this.currentPath?0===this.currentPath.shape.points.length&&(this.currentPath.shape.points=[0,0]):this.moveTo(0,0);for(var o,a,h,l,u,c=20,d=this.currentPath.shape.points,f=d[d.length-2],p=d[d.length-1],v=0,m=1;c>=m;++m)v=m/c,o=1-v,a=o*o,h=a*o,l=v*v,u=l*v,d.push(h*f+3*a*v*t+3*o*l*i+u*n,h*p+3*a*v*e+3*o*l*r+u*s);return this.dirty=!0,this},i.prototype.arcTo=function(t,e,i,r,n){this.currentPath?0===this.currentPath.shape.points.length&&this.currentPath.shape.points.push(t,e):this.moveTo(t,e);var s=this.currentPath.shape.points,o=s[s.length-2],a=s[s.length-1],h=a-e,l=o-t,u=r-e,c=i-t,d=Math.abs(h*c-l*u);if(1e-8>d||0===n)(s[s.length-2]!==t||s[s.length-1]!==e)&&s.push(t,e);else{var f=h*h+l*l,p=u*u+c*c,v=h*u+l*c,m=n*Math.sqrt(f)/d,g=n*Math.sqrt(p)/d,x=m*v/f,y=g*v/p,b=m*c+g*l,T=m*u+g*h,w=l*(g+x),S=h*(g+x),A=c*(m+y),_=u*(m+y),C=Math.atan2(S-T,w-b),E=Math.atan2(_-T,A-b);this.arc(b+t,T+e,n,C,E,l*u>c*h)}return this.dirty=!0,this},i.prototype.arc=function(t,e,i,r,n,s){var o,a=t+Math.cos(r)*i,h=e+Math.sin(r)*i;if(this.currentPath?(o=this.currentPath.shape.points,0===o.length?o.push(a,h):(o[o.length-2]!==a||o[o.length-1]!==h)&&o.push(a,h)):(this.moveTo(a,h),o=this.currentPath.shape.points),r===n)return this;!s&&r>=n?n+=2*Math.PI:s&&n>=r&&(r+=2*Math.PI);var l=s?-1*(r-n):n-r,u=Math.abs(l)/(2*Math.PI)*40;if(0===l)return this;for(var c=l/(2*u),d=2*c,f=Math.cos(c),p=Math.sin(c),v=u-1,m=v%1/v,g=0;v>=g;++g){var x=g+m*g,y=c+r+d*x,b=Math.cos(y),T=-Math.sin(y);o.push((f*b+p*T)*i+t,(f*-T+p*b)*i+e)}return this.dirty=!0,this},i.prototype.beginFill=function(t,e){return this.filling=!0,this.fillColor=t||0,this.fillAlpha=void 0===e?1:e,this.currentPath&&this.currentPath.shape.points.length<=2&&(this.currentPath.fill=this.filling,this.currentPath.fillColor=this.fillColor,this.currentPath.fillAlpha=this.fillAlpha),this},i.prototype.endFill=function(){return this.filling=!1,this.fillColor=null,this.fillAlpha=1,this},i.prototype.drawRect=function(t,e,i,r){return this.drawShape(new u.Rectangle(t,e,i,r)),this},i.prototype.drawRoundedRect=function(t,e,i,r,n){return this.drawShape(new u.RoundedRectangle(t,e,i,r,n)),this},i.prototype.drawCircle=function(t,e,i){return this.drawShape(new u.Circle(t,e,i)),this},i.prototype.drawEllipse=function(t,e,i,r){return this.drawShape(new u.Ellipse(t,e,i,r)),this},i.prototype.drawPolygon=function(t){return t instanceof Array||(t=Array.prototype.slice.call(arguments)),this.drawShape(new u.Polygon(t)),this},i.prototype.clear=function(){return this.lineWidth=0,this.filling=!1,this.dirty=!0,this.clearDirty=!0,this.graphicsData=[],this},i.prototype.generateTexture=function(t,e){t=t||1;var i=this.getBounds(),r=new o(i.width*t,i.height*t),n=s.fromCanvas(r.canvas,e);return n.baseTexture.resolution=t,r.context.scale(t,t),r.context.translate(-i.x,-i.y),a.renderGraphics(this,r.context),n},i.prototype.renderWebGL=function(t){if(this.visible&&!(this.alpha<=0)&&this.isMask!==!0){if(this._cacheAsBitmap)return(this.dirty||this.cachedSpriteDirty)&&(this._generateCachedSprite(),this.updateCachedSpriteTexture(),this.cachedSpriteDirty=!1,this.dirty=!1),this._cachedSprite.worldAlpha=this.worldAlpha,void n.prototype.renderWebGL.call(this._cachedSprite,t);if(t.spriteBatch.stop(),t.blendModeManager.setBlendMode(this.blendMode),this._mask&&t.maskManager.pushMask(this._mask,t),this._filters&&t.filterManager.pushFilter(this._filterBlock),this.blendMode!==t.spriteBatch.currentBlendMode){t.spriteBatch.currentBlendMode=this.blendMode;var e=t.blendModes[t.spriteBatch.currentBlendMode];t.spriteBatch.gl.blendFunc(e[0],e[1])}if(this.glDirty&&(this.dirty=!0,this.glDirty=!1),h.renderGraphics(this,t),this.children.length){t.spriteBatch.start();for(var i=0,r=this.children.length;r>i;++i)this.children[i].renderWebGL(t);t.spriteBatch.stop()}this._filters&&t.filterManager.popFilter(),this._mask&&t.maskManager.popMask(this.mask,t),t.drawCount++,t.spriteBatch.start()}},i.prototype.renderCanvas=function(t){if(this.visible&&!(this.alpha<=0)&&this.isMask!==!0){if(this._cacheAsBitmap)return(this.dirty||this.cachedSpriteDirty)&&(this._generateCachedSprite(),this.updateCachedSpriteTexture(),this.cachedSpriteDirty=!1,this.dirty=!1),this._cachedSprite.alpha=this.alpha,void n.prototype.renderCanvas.call(this._cachedSprite,t);var e=t.context,i=this.worldTransform;this.blendMode!==t.currentBlendMode&&(t.currentBlendMode=this.blendMode,e.globalCompositeOperation=t.blendModes[t.currentBlendMode]),this._mask&&t.maskManager.pushMask(this._mask,t);var r=t.resolution;e.setTransform(i.a*r,i.b*r,i.c*r,i.d*r,i.tx*r,i.ty*r),a.renderGraphics(this,e);for(var s=0,o=this.children.length;o>s;++s)this.children[s].renderCanvas(t);this._mask&&t.maskManager.popMask(t)}},i.prototype.getBounds=function(t){if(this.isMask)return u.Rectangle.EMPTY;this.dirty&&(this.updateLocalBounds(),this.glDirty=!0,this.cachedSpriteDirty=!0,this.dirty=!1);var e=this._localBounds,i=e.x,r=e.width+e.x,n=e.y,s=e.height+e.y,o=t||this.worldTransform,a=o.a,h=o.b,l=o.c,c=o.d,d=o.tx,f=o.ty,p=a*r+l*s+d,v=c*s+h*r+f,m=a*i+l*s+d,g=c*s+h*i+f,x=a*i+l*n+d,y=c*n+h*i+f,b=a*r+l*n+d,T=c*n+h*r+f,w=p,S=v,A=p,_=v;return A=A>m?m:A,A=A>x?x:A,A=A>b?b:A,_=_>g?g:_,_=_>y?y:_,_=_>T?T:_,w=m>w?m:w,w=x>w?x:w,w=b>w?b:w,S=g>S?g:S,S=y>S?y:S,S=T>S?T:S,this._bounds.x=A,this._bounds.width=w-A,this._bounds.y=_,this._bounds.height=S-_,this._bounds},i.prototype.updateLocalBounds=function(){var t=1/0,e=-1/0,i=1/0,r=-1/0;if(this.graphicsData.length)for(var n,s,o,a,h,l,u=0;uo?o:t,e=o+h>e?o+h:e,i=i>a?a:i,r=a+l>r?a+l:r;else if(f===c.SHAPES.CIRC)o=n.x,a=n.y,h=n.radius+p/2,l=n.radius+p/2,t=t>o-h?o-h:t,e=o+h>e?o+h:e,i=i>a-l?a-l:i,r=a+l>r?a+l:r;else if(f===c.SHAPES.ELIP)o=n.x,a=n.y,h=n.width+p/2,l=n.height+p/2,t=t>o-h?o-h:t,e=o+h>e?o+h:e,i=i>a-l?a-l:i,r=a+l>r?a+l:r;else{s=n.points;for(var v=0;vo-p?o-p:t,e=o+p>e?o+p:e,i=i>a-p?a-p:i,r=a+p>r?a+p:r}}else t=0,e=0,i=0,r=0;var m=this.boundsPadding;this._localBounds.x=t-m,this._localBounds.width=e-t+2*m,this._localBounds.y=i-m,this._localBounds.height=r-i+2*m -},i.prototype._generateCachedSprite=function(){var t=this.getLocalBounds();if(this._cachedSprite)this._cachedSprite.buffer.resize(t.width,t.height);else{var e=new o(t.width,t.height),i=s.fromCanvas(e.canvas);this._cachedSprite=new n(i),this._cachedSprite.buffer=e,this._cachedSprite.worldTransform=this.worldTransform}this._cachedSprite.anchor.x=-(t.x/t.width),this._cachedSprite.anchor.y=-(t.y/t.height),this._cachedSprite.buffer.context.translate(-t.x,-t.y),this.worldAlpha=1,a.renderGraphics(this,this._cachedSprite.buffer.context),this._cachedSprite.alpha=this.alpha},i.prototype.updateCachedSpriteTexture=function(){var t=this._cachedSprite,e=t.texture,i=t.buffer.canvas;e.baseTexture.width=i.width,e.baseTexture.height=i.height,e.crop.width=e.frame.width=i.width,e.crop.height=e.frame.height=i.height,t._width=i.width,t._height=i.height,e.baseTexture.dirty()},i.prototype.destroyCachedSprite=function(){this._cachedSprite.texture.destroy(!0),this._cachedSprite=null},i.prototype.drawShape=function(t){this.currentPath&&this.currentPath.shape.points.length<=2&&this.graphicsData.pop(),this.currentPath=null;var e=new l(this.lineWidth,this.lineColor,this.lineAlpha,this.fillColor,this.fillAlpha,this.filling,t);return this.graphicsData.push(e),e.type===c.SHAPES.POLY&&(e.shape.closed=this.filling,this.currentPath=e),this.dirty=!0,e}},{"../const":4,"../display/DisplayObjectContainer":6,"../display/Sprite":7,"../math":12,"../renderers/canvas/utils/CanvasBuffer":21,"../renderers/canvas/utils/CanvasGraphics":22,"../renderers/webgl/utils/WebGLGraphics":39,"../textures/Texture":44,"./GraphicsData":19}],19:[function(t,e){function i(t,e,i,r,n,s,o){this.lineWidth=t,this.lineColor=e,this.lineAlpha=i,this._lineTint=e,this.fillColor=r,this.fillAlpha=n,this._fillTint=r,this.fill=s,this.shape=o,this.type=o.type}i.prototype.constructor=i,e.exports=i,i.prototype.clone=function(){return new i(this.lineWidth,this.lineColor,this.lineAlpha,this.fillColor,this.fillAlpha,this.fill,this.shape)}},{}],20:[function(t,e){function i(t,e,i){if(n.sayHello("Canvas"),i)for(var o in s.defaultRenderOptions)"undefined"==typeof i[o]&&(i[o]=s.defaultRenderOptions[o]);else i=s.defaultRenderOptions;this.type=s.CANVAS_RENDERER,this.resolution=i.resolution,this.clearBeforeRender=i.clearBeforeRender,this._backgroundColor=0,this._backgroundColorString="#000000",this.backgroundColor=i.backgroundColor||this._backgroundColor,this.transparent=i.transparent,this.autoResize=i.autoResize||!1,this.width=t||800,this.height=e||600,this.width*=this.resolution,this.height*=this.resolution,this.view=i.view||document.createElement("canvas"),this.context=this.view.getContext("2d",{alpha:this.transparent}),this.refresh=!0,this.view.width=this.width*this.resolution,this.view.height=this.height*this.resolution,this.count=0,this.maskManager=new r,this.roundPixels=!1,this.scaleMode=null,this.smoothProperty=null,this.context.imageSmoothingEnabled?this.smoothProperty="imageSmoothingEnabled":this.context.webkitImageSmoothingEnabled?this.smoothProperty="webkitImageSmoothingEnabled":this.context.mozImageSmoothingEnabled?this.smoothProperty="mozImageSmoothingEnabled":this.context.oImageSmoothingEnabled?this.smoothProperty="oImageSmoothingEnabled":this.context.msImageSmoothingEnabled&&(this.smoothProperty="msImageSmoothingEnabled"),this.currentBlendMode=s.blendModes.NORMAL,this.blendModes=null,this._mapBlendModes(),this.resize(t,e)}var r=t("./utils/CanvasMaskManager"),n=t("../../utils"),s=t("../../const");i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{backgroundColor:{get:function(){return this._backgroundColor},set:function(t){this._backgroundColor=t,this._backgroundColorString=n.hex2string(t)}}}),i.prototype.render=function(t){t.updateTransform(),this.context.setTransform(1,0,0,1,0,0),this.context.globalAlpha=1,this.currentBlendMode=s.blendModes.NORMAL,this.context.globalCompositeOperation=this.blendModes[s.blendModes.NORMAL],navigator.isCocoonJS&&this.view.screencanvas&&(this.context.fillStyle="black",this.context.clear()),this.clearBeforeRender&&(this.transparent?this.context.clearRect(0,0,this.width,this.height):(this.context.fillStyle=this._backgroundColorString,this.context.fillRect(0,0,this.width,this.height))),this.renderDisplayObject(t)},i.prototype.destroy=function(t){t&&this.view.parent&&this.view.parent.removeChild(this.view),this.view=null,this.context=null,this.maskManager=null},i.prototype.resize=function(t,e){this.width=t*this.resolution,this.height=e*this.resolution,this.view.width=this.width,this.view.height=this.height,this.autoResize&&(this.view.style.width=this.width/this.resolution+"px",this.view.style.height=this.height/this.resolution+"px")},i.prototype.renderDisplayObject=function(t){t.renderCanvas(this)},i.prototype._mapBlendModes=function(){this.blendModes||(this.blendModes={},n.canUseNewCanvasBlendModes()?(this.blendModes[s.blendModes.NORMAL]="source-over",this.blendModes[s.blendModes.ADD]="lighter",this.blendModes[s.blendModes.MULTIPLY]="multiply",this.blendModes[s.blendModes.SCREEN]="screen",this.blendModes[s.blendModes.OVERLAY]="overlay",this.blendModes[s.blendModes.DARKEN]="darken",this.blendModes[s.blendModes.LIGHTEN]="lighten",this.blendModes[s.blendModes.COLOR_DODGE]="color-dodge",this.blendModes[s.blendModes.COLOR_BURN]="color-burn",this.blendModes[s.blendModes.HARD_LIGHT]="hard-light",this.blendModes[s.blendModes.SOFT_LIGHT]="soft-light",this.blendModes[s.blendModes.DIFFERENCE]="difference",this.blendModes[s.blendModes.EXCLUSION]="exclusion",this.blendModes[s.blendModes.HUE]="hue",this.blendModes[s.blendModes.SATURATION]="saturation",this.blendModes[s.blendModes.COLOR]="color",this.blendModes[s.blendModes.LUMINOSITY]="luminosity"):(this.blendModes[s.blendModes.NORMAL]="source-over",this.blendModes[s.blendModes.ADD]="lighter",this.blendModes[s.blendModes.MULTIPLY]="source-over",this.blendModes[s.blendModes.SCREEN]="source-over",this.blendModes[s.blendModes.OVERLAY]="source-over",this.blendModes[s.blendModes.DARKEN]="source-over",this.blendModes[s.blendModes.LIGHTEN]="source-over",this.blendModes[s.blendModes.COLOR_DODGE]="source-over",this.blendModes[s.blendModes.COLOR_BURN]="source-over",this.blendModes[s.blendModes.HARD_LIGHT]="source-over",this.blendModes[s.blendModes.SOFT_LIGHT]="source-over",this.blendModes[s.blendModes.DIFFERENCE]="source-over",this.blendModes[s.blendModes.EXCLUSION]="source-over",this.blendModes[s.blendModes.HUE]="source-over",this.blendModes[s.blendModes.SATURATION]="source-over",this.blendModes[s.blendModes.COLOR]="source-over",this.blendModes[s.blendModes.LUMINOSITY]="source-over"))}},{"../../const":4,"../../utils":50,"./utils/CanvasMaskManager":23}],21:[function(t,e){function i(t,e){this.canvas=document.createElement("canvas"),this.context=this.canvas.getContext("2d"),this.canvas.width=t,this.canvas.height=e}i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{width:{get:function(){return this.canvas.width},set:function(t){this.canvas.width=t}},height:{get:function(){return this.canvas.height},set:function(t){this.canvas.height=t}}}),i.prototype.clear=function(){this.context.setTransform(1,0,0,1,0,0),this.context.clearRect(0,0,this.canvas.width,this.canvas.height)},i.prototype.resize=function(t,e){this.canvas.width=t,this.canvas.height=e}},{}],22:[function(t,e){var i=t("../../../const"),r=e.exports={};r.renderGraphics=function(t,e){var r=t.worldAlpha;t.dirty&&(this.updateGraphicsTint(t),t.dirty=!1);for(var n=0;nE?E:C,e.beginPath(),e.moveTo(w,S+C),e.lineTo(w,S+_-C),e.quadraticCurveTo(w,S+_,w+C,S+_),e.lineTo(w+A-C,S+_),e.quadraticCurveTo(w+A,S+_,w+A,S+_-C),e.lineTo(w+A,S+C),e.quadraticCurveTo(w+A,S,w+A-C,S),e.lineTo(w+C,S),e.quadraticCurveTo(w,S,w,S+C),e.closePath(),(s.fillColor||0===s.fillColor)&&(e.globalAlpha=s.fillAlpha*r,e.fillStyle="#"+("00000"+(0|a).toString(16)).substr(-6),e.fill()),s.lineWidth&&(e.globalAlpha=s.lineAlpha*r,e.strokeStyle="#"+("00000"+(0|h).toString(16)).substr(-6),e.stroke())}}},r.renderGraphicsMask=function(t,e){var r=t.graphicsData.length;if(0!==r){e.beginPath();for(var n=0;r>n;n++){var s=t.graphicsData[n],o=s.shape;if(s.type===i.SHAPES.POLY){var a=o.points;e.moveTo(a[0],a[1]);for(var h=1;h_?_:A,e.moveTo(b,T+A),e.lineTo(b,T+S-A),e.quadraticCurveTo(b,T+S,b+A,T+S),e.lineTo(b+w-A,T+S),e.quadraticCurveTo(b+w,T+S,b+w,T+S-A),e.lineTo(b+w,T+A),e.quadraticCurveTo(b+w,T,b+w-A,T),e.lineTo(b+A,T),e.quadraticCurveTo(b,T,b,T+A),e.closePath()}}}},r.updateGraphicsTint=function(t){if(16777215!==t.tint)for(var e=(t.tint>>16&255)/255,i=(t.tint>>8&255)/255,r=(255&t.tint)/255,n=0;n>16&255)/255*e*255<<16)+((o>>8&255)/255*i*255<<8)+(255&o)/255*r*255,s._lineTint=((a>>16&255)/255*e*255<<16)+((a>>8&255)/255*i*255<<8)+(255&a)/255*r*255}}},{"../../../const":4}],23:[function(t,e){function i(){}var r=t("./CanvasGraphics");i.prototype.constructor=i,e.exports=i,i.prototype.pushMask=function(t,e){e.context.save();var i=t.alpha,n=t.worldTransform,s=e.resolution;e.context.setTransform(n.a*s,n.b*s,n.c*s,n.d*s,n.tx*s,n.ty*s),r.renderGraphicsMask(t,e.context),e.context.clip(),t.worldAlpha=i},i.prototype.popMask=function(t){t.context.restore()}},{"./CanvasGraphics":22}],24:[function(t,e){var i=t("../../../utils"),r=e.exports={};r.getTintedTexture=function(t,e){var i=t.texture;e=r.roundColor(e);var n="#"+("00000"+(0|e).toString(16)).substr(-6);if(i.tintCache=i.tintCache||{},i.tintCache[n])return i.tintCache[n];var s=r.canvas||document.createElement("canvas");if(r.tintMethod(i,e,s),r.convertTintToImage){var o=new Image;o.src=s.toDataURL(),i.tintCache[n]=o}else i.tintCache[n]=s,r.canvas=null;return s},r.tintWithMultiply=function(t,e,i){var r=i.getContext("2d"),n=t.crop;i.width=n.width,i.height=n.height,r.fillStyle="#"+("00000"+(0|e).toString(16)).substr(-6),r.fillRect(0,0,n.width,n.height),r.globalCompositeOperation="multiply",r.drawImage(t.baseTexture.source,n.x,n.y,n.width,n.height,0,0,n.width,n.height),r.globalCompositeOperation="destination-atop",r.drawImage(t.baseTexture.source,n.x,n.y,n.width,n.height,0,0,n.width,n.height)},r.tintWithOverlay=function(t,e,i){var r=i.getContext("2d"),n=t.crop;i.width=n.width,i.height=n.height,r.globalCompositeOperation="copy",r.fillStyle="#"+("00000"+(0|e).toString(16)).substr(-6),r.fillRect(0,0,n.width,n.height),r.globalCompositeOperation="destination-atop",r.drawImage(t.baseTexture.source,n.x,n.y,n.width,n.height,0,0,n.width,n.height)},r.tintWithPerPixel=function(t,e,r){var n=r.getContext("2d"),s=t.crop;r.width=s.width,r.height=s.height,n.globalCompositeOperation="copy",n.drawImage(t.baseTexture.source,s.x,s.y,s.width,s.height,0,0,s.width,s.height);for(var o=i.hex2rgb(e),a=o[0],h=o[1],l=o[2],u=n.getImageData(0,0,s.width,s.height),c=u.data,d=0;dthis.width&&(a.width=this.width-l),u+a.height>this.height&&(a.height=this.height-u),a.width<0&&(a.width=0),a.height<0&&(a.height=0),e.bindFramebuffer(e.FRAMEBUFFER,o.frameBuffer),e.viewport(0,0,a.width,a.height),i.x=a.width/2,i.y=-a.height/2,r.x=-a.x,r.y=-a.y,e.colorMask(!0,!0,!0,!0),e.clearColor(0,0,0,0),e.clear(e.COLOR_BUFFER_BIT),t._glFilterTexture=o},i.prototype.popFilter=function(){var t=this.renderer.gl,e=this.filterStack.pop(),i=e._filterArea,r=e._glFilterTexture,s=this.renderer.projection,o=this.renderer.offset;if(e.filterPasses.length>1){t.viewport(0,0,i.width,i.height),t.bindBuffer(t.ARRAY_BUFFER,this.vertexBuffer),this.vertexArray[0]=0,this.vertexArray[1]=i.height,this.vertexArray[2]=i.width,this.vertexArray[3]=i.height,this.vertexArray[4]=0,this.vertexArray[5]=0,this.vertexArray[6]=i.width,this.vertexArray[7]=0,t.bufferSubData(t.ARRAY_BUFFER,0,this.vertexArray),t.bindBuffer(t.ARRAY_BUFFER,this.uvBuffer),this.uvArray[2]=i.width/this.width,this.uvArray[5]=i.height/this.height,this.uvArray[6]=i.width/this.width,this.uvArray[7]=i.height/this.height,t.bufferSubData(t.ARRAY_BUFFER,0,this.uvArray);var a=r,h=this.texturePool.pop();h||(h=new n(this.renderer.gl,this.width,this.height)),h.resize(this.width,this.height),t.bindFramebuffer(t.FRAMEBUFFER,h.frameBuffer),t.clear(t.COLOR_BUFFER_BIT),t.disable(t.BLEND);for(var l=0;li;++i)s._array[2*i]=a[i].x,s._array[2*i+1]=a[i].y;t.uniform2fv(o,s._array);break;case"v3v":for(s._array||(s._array=new Float32Array(3*a.length)),i=0,n=a.length;n>i;++i)s._array[3*i]=a[i].x,s._array[3*i+1]=a[i].y,s._array[3*i+2]=a[i].z;t.uniform3fv(o,s._array);break;case"v4v":for(s._array||(s._array=new Float32Array(4*a.length)),i=0,n=a.length;n>i;++i)s._array[4*i]=a[i].x,s._array[4*i+1]=a[i].y,s._array[4*i+2]=a[i].z,s._array[4*i+3]=a[i].w;t.uniform4fv(o,s._array);break;case"t":case"sampler2D":if(!s.value||!s.value.baseTexture||!s.value.baseTexture.hasLoaded)break;t.activeTexture(t["TEXTURE"+this.textureCount]),t.bindTexture(t.TEXTURE_2D,s.value.baseTexture._glTextures[t.id]),t.uniform1i(s._location,this.textureCount),this.textureCount++,s._init||(this.initSampler2D(s),s._init=!0);break;default:window.console.warn("Pixi.js Shader Warning: Unknown uniform type: "+s.type)}}},i.prototype.initSampler2D=function(t){var e=this.gl;if(t.textureData){var i=t.textureData,r=i.magFilter?i.magFilter:e.LINEAR,n=i.minFilter?i.minFilter:e.LINEAR,s=i.wrapS?i.wrapS:e.CLAMP_TO_EDGE,o=i.wrapT?i.wrapT:e.CLAMP_TO_EDGE,a=i.luminance?e.LUMINANCE:e.RGBA;if(i.repeat&&(s=e.REPEAT,o=e.REPEAT),e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL,!!i.flipY),i.width){var h=i.width?i.width:512,l=i.height?i.height:2,u=i.border?i.border:0;e.texImage2D(e.TEXTURE_2D,0,a,h,l,u,a,e.UNSIGNED_BYTE,null)}else e.texImage2D(e.TEXTURE_2D,0,a,e.RGBA,e.UNSIGNED_BYTE,t.value.baseTexture.source);e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER,r),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,n),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,s),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,o)}},i.prototype.destroy=function(){this.gl.deleteProgram(this.program),this.gl=null,this.uniforms=null,this.attributes=null,this.vertexSrc=null,this.fragmentSrc=null},i.prototype._glCompile=function(t,e){var i=this.gl.createShader(t);return Array.isArray(e),this.gl.shaderSource(i,e),this.gl.compileShader(i),this.gl.getShaderParameter(i,this.gl.COMPILE_STATUS)?i:(window.console.log(this.gl.getShaderInfoLog(i)),null)}},{"../../../utils":50}],36:[function(t,e){function i(t){r.call(this,t,["attribute vec2 aVertexPosition;","attribute vec2 aTextureCoord;","uniform mat3 translationMatrix;","uniform vec2 projectionVector;","uniform vec2 offsetVector;","varying vec2 vTextureCoord;","void main(void) {"," vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);"," v -= offsetVector.xyx;"," gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);"," vTextureCoord = aTextureCoord;","}"].join("\n"),["precision mediump float;","uniform float alpha;","uniform sampler2D uSampler;","varying vec2 vTextureCoord;","void main(void) {"," gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y)) * alpha;","}"].join("\n"),{alpha:{type:"1f",value:0},translationMatrix:{type:"mat3",value:new Float32Array(9)}})}var r=t("./Shader");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i},{"./Shader":35}],37:[function(t,e){function i(t,e,i,n){this.gl=t,this.frameBuffer=t.createFramebuffer(),this.texture=t.createTexture(),n=n||r.scaleModes.DEFAULT,t.bindTexture(t.TEXTURE_2D,this.texture),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,n===r.scaleModes.LINEAR?t.LINEAR:t.NEAREST),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,n===r.scaleModes.LINEAR?t.LINEAR:t.NEAREST),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,t.CLAMP_TO_EDGE),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,t.CLAMP_TO_EDGE),t.bindFramebuffer(t.FRAMEBUFFER,this.frameBuffer),t.bindFramebuffer(t.FRAMEBUFFER,this.frameBuffer),t.framebufferTexture2D(t.FRAMEBUFFER,t.COLOR_ATTACHMENT0,t.TEXTURE_2D,this.texture,0),this.renderBuffer=t.createRenderbuffer(),t.bindRenderbuffer(t.RENDERBUFFER,this.renderBuffer),t.framebufferRenderbuffer(t.FRAMEBUFFER,t.DEPTH_STENCIL_ATTACHMENT,t.RENDERBUFFER,this.renderBuffer),t.bindRenderbuffer(t.RENDERBUFFER,null),this.resize(e,i)}var r=t("../../../const");i.prototype.constructor=i,e.exports=i,i.prototype.clear=function(){var t=this.gl;t.clearColor(0,0,0,0),t.clear(t.COLOR_BUFFER_BIT)},i.prototype.resize=function(t,e){if(this.width!==t||this.height!==e){this.width=t,this.height=e;var i=this.gl;i.bindTexture(i.TEXTURE_2D,this.texture),i.texImage2D(i.TEXTURE_2D,0,i.RGBA,t,e,0,i.RGBA,i.UNSIGNED_BYTE,null),i.bindRenderbuffer(i.RENDERBUFFER,this.renderBuffer),i.renderbufferStorage(i.RENDERBUFFER,i.DEPTH_STENCIL,t,e),i.bindRenderbuffer(i.RENDERBUFFER,null)}},i.prototype.destroy=function(){var t=this.gl;t.deleteFramebuffer(this.frameBuffer),t.deleteTexture(this.texture),this.frameBuffer=null,this.texture=null}},{"../../../const":4}],38:[function(t,e){function i(t){this.renderer=t,this.vertSize=10,this.maxSize=6e3,this.size=this.maxSize;var e=4*this.size*this.vertSize,i=6*this.maxSize;this.vertices=new Float32Array(e),this.indices=new Uint16Array(i),this.vertexBuffer=null,this.indexBuffer=null,this.lastIndexCount=0;for(var r=0,n=0;i>r;r+=6,n+=4)this.indices[r+0]=n+0,this.indices[r+1]=n+1,this.indices[r+2]=n+2,this.indices[r+3]=n+0,this.indices[r+4]=n+2,this.indices[r+5]=n+3;this.drawing=!1,this.currentBatchSize=0,this.currentBaseTexture=null,this.currentBlendMode=0,this.shader=null,this.matrix=null;var s=this;this.renderer.on("context",function(){s.setupContext()})}i.prototype.constructor=i,e.exports=i,i.prototype.setupContext=function(){var t=this.renderer.gl;this.vertexBuffer=t.createBuffer(),this.indexBuffer=t.createBuffer(),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.indexBuffer),t.bufferData(t.ELEMENT_ARRAY_BUFFER,this.indices,t.STATIC_DRAW),t.bindBuffer(t.ARRAY_BUFFER,this.vertexBuffer),t.bufferData(t.ARRAY_BUFFER,this.vertices,t.DYNAMIC_DRAW)},i.prototype.begin=function(t){this.shader=this.renderer.shaderManager.fastShader,this.matrix=t.worldTransform.toArray(!0),this.start()},i.prototype.end=function(){this.flush()},i.prototype.render=function(t){var e=t.children,i=e[0];if(i.texture._uvs){this.currentBaseTexture=i.texture.baseTexture,i.blendMode!==this.renderer.blendModeManager.currentBlendMode&&(this.flush(),this.renderer.blendModeManager.setBlendMode(i.blendMode));for(var r=0,n=e.length;n>r;r++)this.renderSprite(e[r]);this.flush()}},i.prototype.renderSprite=function(t){if(t.visible&&(t.texture.baseTexture===this.currentBaseTexture||(this.flush(),this.currentBaseTexture=t.texture.baseTexture,t.texture._uvs))){var e,i,r,n,s,o,a,h,l=this.vertices;if(e=t.texture._uvs,i=t.texture.frame.width,r=t.texture.frame.height,t.texture.trim){var u=t.texture.trim;s=u.x-t.anchor.x*u.width,n=s+t.texture.crop.width,a=u.y-t.anchor.y*u.height,o=a+t.texture.crop.height}else n=t.texture.frame.width*(1-t.anchor.x),s=t.texture.frame.width*-t.anchor.x,o=t.texture.frame.height*(1-t.anchor.y),a=t.texture.frame.height*-t.anchor.y;h=4*this.currentBatchSize*this.vertSize,l[h++]=s,l[h++]=a,l[h++]=t.position.x,l[h++]=t.position.y,l[h++]=t.scale.x,l[h++]=t.scale.y,l[h++]=t.rotation,l[h++]=e.x0,l[h++]=e.y1,l[h++]=t.alpha,l[h++]=n,l[h++]=a,l[h++]=t.position.x,l[h++]=t.position.y,l[h++]=t.scale.x,l[h++]=t.scale.y,l[h++]=t.rotation,l[h++]=e.x1,l[h++]=e.y1,l[h++]=t.alpha,l[h++]=n,l[h++]=o,l[h++]=t.position.x,l[h++]=t.position.y,l[h++]=t.scale.x,l[h++]=t.scale.y,l[h++]=t.rotation,l[h++]=e.x2,l[h++]=e.y2,l[h++]=t.alpha,l[h++]=s,l[h++]=o,l[h++]=t.position.x,l[h++]=t.position.y,l[h++]=t.scale.x,l[h++]=t.scale.y,l[h++]=t.rotation,l[h++]=e.x3,l[h++]=e.y3,l[h++]=t.alpha,this.currentBatchSize++,this.currentBatchSize>=this.size&&this.flush()}},i.prototype.flush=function(){if(0!==this.currentBatchSize){var t=this.renderer.gl;if(this.currentBaseTexture._glTextures[t.id]?t.bindTexture(t.TEXTURE_2D,this.currentBaseTexture._glTextures[t.id]):this.renderer.updateTexture(this.currentBaseTexture,t),this.currentBatchSize>.5*this.size)t.bufferSubData(t.ARRAY_BUFFER,0,this.vertices);else{var e=this.vertices.subarray(0,4*this.currentBatchSize*this.vertSize);t.bufferSubData(t.ARRAY_BUFFER,0,e)}t.drawElements(t.TRIANGLES,6*this.currentBatchSize,t.UNSIGNED_SHORT,0),this.currentBatchSize=0,this.renderer.drawCount++}},i.prototype.stop=function(){this.flush()},i.prototype.start=function(){var t=this.renderer.gl;t.activeTexture(t.TEXTURE0),t.bindBuffer(t.ARRAY_BUFFER,this.vertexBuffer),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.indexBuffer);var e=this.renderer.projection;t.uniform2f(this.shader.projectionVector,e.x,e.y),t.uniformMatrix3fv(this.shader.uMatrix,!1,this.matrix);var i=4*this.vertSize;t.vertexAttribPointer(this.shader.attributes.aVertexPosition,2,t.FLOAT,!1,i,0),t.vertexAttribPointer(this.shader.attributes.aPositionCoord,2,t.FLOAT,!1,i,8),t.vertexAttribPointer(this.shader.attributes.aScale,2,t.FLOAT,!1,i,16),t.vertexAttribPointer(this.shader.attributes.aRotation,1,t.FLOAT,!1,i,24),t.vertexAttribPointer(this.shader.attributes.aTextureCoord,2,t.FLOAT,!1,i,28),t.vertexAttribPointer(this.shader.attributes.aColor,1,t.FLOAT,!1,i,36)}},{}],39:[function(t,e){var i=t("../../../utils"),r=t("../../../math"),n=t("../../../const"),s=t("./WebGLGraphicsData"),o=e.exports={};o.renderGraphics=function(t,e){var r,n=e.gl,s=e.projection,a=e.offset,h=e.shaderManager.primitiveShader;t.dirty&&o.updateGraphics(t,n);for(var l=t._webGL[n.id],u=0;u=6)if(h.points.length<12){a=o.switchMode(i,0);var l=o.buildPoly(h,a);l||(a=o.switchMode(i,1),o.buildComplexPoly(h,a))}else a=o.switchMode(i,1),o.buildComplexPoly(h,a);h.lineWidth>0&&(a=o.switchMode(i,0),o.buildLine(h,a))}else a=o.switchMode(i,0),h.type===n.SHAPES.RECT?o.buildRectangle(h,a):h.type===n.SHAPES.CIRC||h.type===n.SHAPES.ELIP?o.buildCircle(h,a):h.type===n.SHAPES.RREC&&o.buildRoundedRectangle(h,a);i.lastIndex++}for(r=0;r=m;m++)v=m/f,a=o(t,i,v),h=o(e,r,v),l=o(i,n,v),u=o(r,s,v),c=o(a,l,v),d=o(h,u,v),p.push(c,d);return p},o.buildCircle=function(t,e){var r,s,a=t.shape,h=a.x,l=a.y;t.type===n.SHAPES.CIRC?(r=a.radius,s=a.radius):(r=a.width,s=a.height);var u=40,c=2*Math.PI/u,d=0;if(t.fill){var f=i.hex2rgb(t.fillColor),p=t.fillAlpha,v=f[0]*p,m=f[1]*p,g=f[2]*p,x=e.points,y=e.indices,b=x.length/6;for(y.push(b),d=0;u+1>d;d++)x.push(h,l,v,m,g,p),x.push(h+Math.sin(c*d)*r,l+Math.cos(c*d)*s,v,m,g,p),y.push(b++,b++);y.push(b-1)}if(t.lineWidth){var T=t.points;for(t.points=[],d=0;u+1>d;d++)t.points.push(h+Math.sin(c*d)*r,l+Math.cos(c*d)*s);o.buildLine(t,e),t.points=T}},o.buildLine=function(t,e){var n=0,s=t.points;if(0!==s.length){if(t.lineWidth%2)for(n=0;nn;n++)d=s[2*(n-1)],f=s[2*(n-1)+1],p=s[2*n],v=s[2*n+1],m=s[2*(n+1)],g=s[2*(n+1)+1],x=-(f-v),y=d-p,D=Math.sqrt(x*x+y*y),x/=D,y/=D,x*=U,y*=U,b=-(v-g),T=p-m,D=Math.sqrt(b*b+T*T),b/=D,T/=D,b*=U,T*=U,A=-y+f-(-y+v),_=-x+p-(-x+d),C=(-x+d)*(-y+v)-(-x+p)*(-y+f),E=-T+g-(-T+v),R=-b+p-(-b+m),M=(-b+m)*(-T+v)-(-b+p)*(-T+g),F=A*R-E*_,Math.abs(F)<.1?(F+=10.1,P.push(p-x,v-y,Y,X,G,j),P.push(p+x,v+y,Y,X,G,j)):(u=(_*M-R*C)/F,c=(E*C-A*M)/F,B=(u-p)*(u-p)+(c-v)+(c-v),B>19600?(w=x-b,S=y-T,D=Math.sqrt(w*w+S*S),w/=D,S/=D,w*=U,S*=U,P.push(p-w,v-S),P.push(Y,X,G,j),P.push(p+w,v+S),P.push(Y,X,G,j),P.push(p-w,v-S),P.push(Y,X,G,j),I++):(P.push(u,c),P.push(Y,X,G,j),P.push(p-(u-p),v-(c-v)),P.push(Y,X,G,j)));for(d=s[2*(O-2)],f=s[2*(O-2)+1],p=s[2*(O-1)],v=s[2*(O-1)+1],x=-(f-v),y=d-p,D=Math.sqrt(x*x+y*y),x/=D,y/=D,x*=U,y*=U,P.push(p-x,v-y),P.push(Y,X,G,j),P.push(p+x,v+y),P.push(Y,X,G,j),L.push(k),n=0;I>n;n++)L.push(k++);L.push(k-1)}},o.buildComplexPoly=function(t,e){var r=t.points.slice();if(!(r.length<6)){var n=e.indices;e.points=r,e.alpha=t.fillAlpha,e.color=i.hex2rgb(t.fillColor);for(var s,o,a=1/0,h=-1/0,l=1/0,u=-1/0,c=0;cs?s:a,h=s>h?s:h,l=l>o?o:l,u=o>u?o:u;r.push(a,l,h,l,h,u,a,u);var d=r.length/2;for(c=0;d>c;c++)n.push(c)}},o.buildPoly=function(t,e){var r=t.points;if(!(r.length<6)){var n=e.points,s=e.indices,o=r.length/2,a=i.hex2rgb(t.fillColor),h=t.fillAlpha,l=a[0]*h,u=a[1]*h,c=a[2]*h,d=i.PolyK.Triangulate(r);if(!d)return!1;var f=n.length/6,p=0;for(p=0;pp;p++)n.push(r[2*p],r[2*p+1],l,u,c,h);return!0}},o.graphicsDataPool=[]},{"../../../const":4,"../../../math":12,"../../../utils":50,"./WebGLGraphicsData":40}],40:[function(t,e){function i(t){this.gl=t,this.color=[0,0,0],this.points=[],this.indices=[],this.buffer=t.createBuffer(),this.indexBuffer=t.createBuffer(),this.mode=1,this.alpha=1,this.dirty=!0}i.prototype.constructor=i,e.exports=i,i.prototype.reset=function(){this.points.length=0,this.indices.length=0},i.prototype.upload=function(){var t=this.gl;this.glPoints=new Float32Array(this.points),t.bindBuffer(t.ARRAY_BUFFER,this.buffer),t.bufferData(t.ARRAY_BUFFER,this.glPoints,t.STATIC_DRAW),this.glIndicies=new Uint16Array(this.indices),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.indexBuffer),t.bufferData(t.ELEMENT_ARRAY_BUFFER,this.glIndicies,t.STATIC_DRAW),this.dirty=!1}},{}],41:[function(t,e){function i(t){this.renderer=t,this.vertSize=5,this.size=2e3;var e=4*this.size*4*this.vertSize,i=6*this.size;this.vertices=new ArrayBuffer(e),this.positions=new Float32Array(this.vertices),this.colors=new Uint32Array(this.vertices),this.indices=new Uint16Array(i),this.lastIndexCount=0;for(var r=0,n=0;i>r;r+=6,n+=4)this.indices[r+0]=n+0,this.indices[r+1]=n+1,this.indices[r+2]=n+2,this.indices[r+3]=n+0,this.indices[r+4]=n+2,this.indices[r+5]=n+3;this.drawing=!1,this.currentBatchSize=0,this.currentBaseTexture=null,this.dirty=!0,this.textures=[],this.blendModes=[],this.shaders=[],this.sprites=[],this.shader=null;var s=this;this.renderer.on("context",function(){s.setupContext()})}var r=t("../../../textures/TextureUvs"),n=t("../shaders/Shader");i.prototype.constructor=i,e.exports=i,i.prototype.setupContext=function(){var t=this.renderer.gl;this.shader=new n(t),this.vertexBuffer=t.createBuffer(),this.indexBuffer=t.createBuffer(),t.bindBuffer(t.ELEMENT_ARRAY_BUFFER,this.indexBuffer),t.bufferData(t.ELEMENT_ARRAY_BUFFER,this.indices,t.STATIC_DRAW),t.bindBuffer(t.ARRAY_BUFFER,this.vertexBuffer),t.bufferData(t.ARRAY_BUFFER,this.vertices,t.DYNAMIC_DRAW),this.currentBlendMode=99999},i.prototype.begin=function(){this.start()},i.prototype.end=function(){this.flush()},i.prototype.render=function(t){var e=t.texture;this.currentBatchSize>=this.size&&(this.flush(),this.currentBaseTexture=e.baseTexture);var i=e._uvs;if(i){var r,n,s,o,a=t.anchor.x,h=t.anchor.y;if(e.trim){var l=e.trim;n=l.x-a*l.width,r=n+e.crop.width,o=l.y-h*l.height,s=o+e.crop.height}else r=e.frame.width*(1-a),n=e.frame.width*-a,s=e.frame.height*(1-h),o=e.frame.height*-h;var u=4*this.currentBatchSize*this.vertSize,c=e.baseTexture.resolution,d=t.worldTransform,f=d.a/c,p=d.b/c,v=d.c/c,m=d.d/c,g=d.tx,x=d.ty,y=this.colors,b=this.positions;this.renderer.roundPixels?(b[u]=f*n+v*o+g|0,b[u+1]=m*o+p*n+x|0,b[u+5]=f*r+v*o+g|0,b[u+6]=m*o+p*r+x|0,b[u+10]=f*r+v*s+g|0,b[u+11]=m*s+p*r+x|0,b[u+15]=f*n+v*s+g|0,b[u+16]=m*s+p*n+x|0):(b[u]=f*n+v*o+g,b[u+1]=m*o+p*n+x,b[u+5]=f*r+v*o+g,b[u+6]=m*o+p*r+x,b[u+10]=f*r+v*s+g,b[u+11]=m*s+p*r+x,b[u+15]=f*n+v*s+g,b[u+16]=m*s+p*n+x),b[u+2]=i.x0,b[u+3]=i.y0,b[u+7]=i.x1,b[u+8]=i.y1,b[u+12]=i.x2,b[u+13]=i.y2,b[u+17]=i.x3,b[u+18]=i.y3;var T=t.tint;y[u+4]=y[u+9]=y[u+14]=y[u+19]=(T>>16)+(65280&T)+((255&T)<<16)+(255*t.worldAlpha<<24),this.sprites[this.currentBatchSize++]=t}},i.prototype.renderTilingSprite=function(t){var e=t.tilingTexture;this.currentBatchSize>=this.size&&(this.flush(),this.currentBaseTexture=e.baseTexture),t._uvs||(t._uvs=new r);var i=t._uvs;t.tilePosition.x%=e.baseTexture.width*t.tileScaleOffset.x,t.tilePosition.y%=e.baseTexture.height*t.tileScaleOffset.y;var n=t.tilePosition.x/(e.baseTexture.width*t.tileScaleOffset.x),s=t.tilePosition.y/(e.baseTexture.height*t.tileScaleOffset.y),o=t.width/e.baseTexture.width/(t.tileScale.x*t.tileScaleOffset.x),a=t.height/e.baseTexture.height/(t.tileScale.y*t.tileScaleOffset.y);i.x0=0-n,i.y0=0-s,i.x1=1*o-n,i.y1=0-s,i.x2=1*o-n,i.y2=1*a-s,i.x3=0-n,i.y3=1*a-s;var h=t.tint,l=(h>>16)+(65280&h)+((255&h)<<16)+(255*t.alpha<<24),u=this.positions,c=this.colors,d=t.width,f=t.height,p=t.anchor.x,v=t.anchor.y,m=d*(1-p),g=d*-p,x=f*(1-v),y=f*-v,b=4*this.currentBatchSize*this.vertSize,T=e.baseTexture.resolution,w=t.worldTransform,S=w.a/T,A=w.b/T,_=w.c/T,C=w.d/T,E=w.tx,R=w.ty;u[b++]=S*g+_*y+E,u[b++]=C*y+A*g+R,u[b++]=i.x0,u[b++]=i.y0,c[b++]=l,u[b++]=S*m+_*y+E,u[b++]=C*y+A*m+R,u[b++]=i.x1,u[b++]=i.y1,c[b++]=l,u[b++]=S*m+_*x+E,u[b++]=C*x+A*m+R,u[b++]=i.x2,u[b++]=i.y2,c[b++]=l,u[b++]=S*g+_*x+E,u[b++]=C*x+A*g+R,u[b++]=i.x3,u[b++]=i.y3,c[b++]=l,this.sprites[this.currentBatchSize++]=t},i.prototype.flush=function(){if(0!==this.currentBatchSize){var t,e=this.renderer.gl;if(this.dirty){this.dirty=!1,e.activeTexture(e.TEXTURE0),e.bindBuffer(e.ARRAY_BUFFER,this.vertexBuffer),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this.indexBuffer);var i=4*this.vertSize;e.vertexAttribPointer(this.shader.attributes.aVertexPosition,2,e.FLOAT,!1,i,0),e.vertexAttribPointer(this.shader.attributes.aTextureCoord,2,e.FLOAT,!1,i,8),e.vertexAttribPointer(this.shader.attributes.aColor,4,e.UNSIGNED_BYTE,!0,i,16)}if(this.currentBatchSize>.5*this.size)e.bufferSubData(e.ARRAY_BUFFER,0,this.vertices);else{var r=this.positions.subarray(0,4*this.currentBatchSize*this.vertSize);e.bufferSubData(e.ARRAY_BUFFER,0,r)}for(var s,o,a,h,l=0,u=0,c=null,d=this.renderer.blendModeManager.currentBlendMode,f=null,p=!1,v=!1,m=0,g=this.currentBatchSize;g>m;m++){if(h=this.sprites[m],s=h.texture.baseTexture,o=h.blendMode,a=h.shader||this.shader,p=d!==o,v=f!==a,(c!==s||p||v)&&(this.renderBatch(c,l,u),u=m,l=0,c=s,p&&(d=o,this.renderer.blendModeManager.setBlendMode(d)),v)){f=a,t=f.shaders?f.shaders[e.id]:f,t||(t=new n(e,null,f.fragmentSrc,f.uniforms),f.shaders[e.id]=t),this.renderer.shaderManager.setShader(t),t.dirty&&t.syncUniforms();var x=this.renderer.projection;e.uniform2f(t.uniforms.projectionVector._location,x.x,x.y);var y=this.renderer.offset;e.uniform2f(t.uniforms.offsetVector._location,y.x,y.y)}l++}this.renderBatch(c,l,u),this.currentBatchSize=0}},i.prototype.renderBatch=function(t,e,i){if(0!==e){var r=this.renderer.gl;t._glTextures[r.id]?r.bindTexture(r.TEXTURE_2D,t._glTextures[r.id]):this.renderer.updateTexture(t),r.drawElements(r.TRIANGLES,6*e,r.UNSIGNED_SHORT,6*i*2),this.renderer.drawCount++}},i.prototype.stop=function(){this.flush(),this.dirty=!0},i.prototype.start=function(){this.dirty=!0},i.prototype.destroy=function(){this.renderer.gl.deleteBuffer(this.vertexBuffer),this.renderer.gl.deleteBuffer(this.indexBuffer),this.vertices=null,this.indices=null,this.vertexBuffer=null,this.indexBuffer=null,this.currentBaseTexture=null,this.renderer=null}},{"../../../textures/TextureUvs":45,"../shaders/Shader":35}],42:[function(t,e){function i(t,e){this.uuid=r.uuid(),this.resolution=1,this.width=100,this.height=100,this.scaleMode=e||n.scaleModes.DEFAULT,this.hasLoaded=!1,this.isLoading=!1,this.source=null,this.premultipliedAlpha=!0,this.imageUrl=null,this._powerOf2=!1,this.mipmap=!1,this._glTextures={},this._needsUpdate=!1,t&&this.loadSource(t)}var r=t("../utils"),n=t("../const");i.prototype.constructor=i,e.exports=i,r.eventTarget.mixin(i.prototype),Object.defineProperties(i.prototype,{needsUpdate:{get:function(){return this._needsUpdate},set:function(t){this._needsUpdate=t,t&&this.emit("update",this)}}}),i.prototype.loadSource=function(t){var e=this.isLoading;if(this.hasLoaded=!1,this.isLoading=!1,e&&this.source&&(this.source.onload=null,this.source.onerror=null),this.source=t,(this.source.complete||this.source.getContext)&&this.source.width&&this.source.height)this._sourceLoaded();else if(!t.getContext){this.isLoading=!0;var i=this;t.onload=function(){t.onload=null,t.onerror=null,i.isLoading&&(i.isLoading=!1,i._sourceLoaded(),i.emit("loaded",i))},t.onerror=function(){t.onload=null,t.onerror=null,i.isLoading&&(i.isLoading=!1,i.emit("error",i))},t.complete&&(this.isLoading=!1,t.onload=null,t.onerror=null,t.width&&t.height?(this._sourceLoaded(),e&&this.emit("loaded",this)):e&&this.emit("error",this))}},i.prototype._sourceLoaded=function(){this.hasLoaded=!0,this.width=this.source.naturalWidth||this.source.width,this.height=this.source.naturalHeight||this.source.height,this.needsUpdate=!0},i.prototype.destroy=function(){this.imageUrl?(delete r.BaseTextureCache[this.imageUrl],delete r.TextureCache[this.imageUrl],this.imageUrl=null,navigator.isCocoonJS||(this.source.src="")):this.source&&this.source._pixiId&&delete r.BaseTextureCache[this.source._pixiId],this.source=null,this.dispose()},i.prototype.dispose=function(){this.emit("dispose",this)},i.prototype.updateSourceImage=function(t){this.source.src=t,this.loadSource(this.source)},i.fromImage=function(t,e,s){var o=r.BaseTextureCache[t];if(void 0===e&&0!==t.indexOf("data:")&&(e=!0),!o){var a=new Image;e&&(a.crossOrigin=""),a.src=t,o=new i(a,s),o.imageUrl=t,r.BaseTextureCache[t]=o,-1!==t.indexOf(n.RETINA_PREFIX+".")&&(o.resolution=2) -}return o},i.fromCanvas=function(t,e){t._pixiId||(t._pixiId="canvas_"+r.uuid());var n=r.BaseTextureCache[t._pixiId];return n||(n=new i(t,e),r.BaseTextureCache[t._pixiId]=n),n}},{"../const":4,"../utils":50}],43:[function(t,e){function i(t,e,i,l,u){if(!t)throw new Error("Unable to create RenderTexture, you must pass a renderer into the constructor.");if(this.width=e||100,this.height=i||100,this.resolution=u||1,this.frame=new a.Rectangle(0,0,this.width*this.resolution,this.height*this.resolution),this.crop=new a.Rectangle(0,0,this.width*this.resolution,this.height*this.resolution),this.render=null,this.baseTexture=new r,this.baseTexture.width=this.width*this.resolution,this.baseTexture.height=this.height*this.resolution,this.baseTexture._glTextures=[],this.baseTexture.resolution=this.resolution,this.baseTexture.scaleMode=l||h.scaleModes.DEFAULT,this.baseTexture.hasLoaded=!0,n.call(this,this.baseTexture,new a.Rectangle(0,0,this.width,this.height)),this.renderer=t,this.renderer.type===h.WEBGL_RENDERER){var c=this.renderer.gl;this.textureBuffer=new s(c,this.width*this.resolution,this.height*this.resolution,this.baseTexture.scaleMode),this.baseTexture._glTextures[c.id]=this.textureBuffer.texture,this.render=this.renderWebGL,this.projection=new a.Point(.5*this.width,.5*-this.height)}else this.render=this.renderCanvas,this.textureBuffer=new o(this.width*this.resolution,this.height*this.resolution),this.baseTexture.source=this.textureBuffer.canvas;this.valid=!0,this._updateUvs()}var r=t("./BaseTexture"),n=t("./Texture"),s=t("../renderers/webgl/utils/FilterTexture"),o=t("../renderers/canvas/utils/CanvasBuffer"),a=t("../math"),h=t("../const");i.prototype=Object.create(n.prototype),i.prototype.constructor=i,e.exports=i,i.prototype.resize=function(t,e,i){(t!==this.width||e!==this.height)&&(this.valid=t>0&&e>0,this.width=this.frame.width=this.crop.width=t,this.height=this.frame.height=this.crop.height=e,i&&(this.baseTexture.width=this.width,this.baseTexture.height=this.height),this.renderer.type===h.WEBGL_RENDERER&&(this.projection.x=this.width/2,this.projection.y=-this.height/2),this.valid&&this.textureBuffer.resize(this.width*this.resolution,this.height*this.resolution))},i.prototype.clear=function(){this.valid&&(this.renderer.type===h.WEBGL_RENDERER&&this.renderer.gl.bindFramebuffer(this.renderer.gl.FRAMEBUFFER,this.textureBuffer.frameBuffer),this.textureBuffer.clear())},i.prototype.renderWebGL=function(t,e,i,r){if(this.valid){"undefined"==typeof r&&(r=!0);var n,s;r&&(n=t.worldAlpha,s=t.worldTransform.toArray());var o=t.worldTransform;o.identity(),o.translate(0,2*this.projection.y),e&&o.append(e),o.scale(1,-1),t.worldAlpha=1;var a,h,l=t.children;for(a=0,h=l.length;h>a;++a)l[a].updateTransform();var u=this.renderer.gl;if(u.viewport(0,0,this.width*this.resolution,this.height*this.resolution),u.bindFramebuffer(u.FRAMEBUFFER,this.textureBuffer.frameBuffer),i&&this.textureBuffer.clear(),this.renderer.spriteBatch.dirty=!0,this.renderer.renderDisplayObject(t,this.projection,this.textureBuffer.frameBuffer),this.renderer.spriteBatch.dirty=!0,r)for(t.worldAlpha=n,t.worldTransform.fromArray(s),a=0,h=l.length;h>a;++a)l[a].updateTransform()}},i.prototype.renderCanvas=function(t,e,i,r){if(this.valid){"undefined"==typeof r&&(r=!0);var n,s;r&&(n=t.worldAlpha,s=t.worldTransform.toArray());var o=t.worldTransform;o.identity(),e&&o.append(e),t.worldAlpha=1;var a,h,l=t.children;for(a=0,h=l.length;h>a;++a)l[a].updateTransform();i&&this.textureBuffer.clear();var u=this.textureBuffer.context,c=this.renderer.resolution;if(this.renderer.resolution=this.resolution,this.renderer.renderDisplayObject(t,u),this.renderer.resolution=c,r)for(t.worldAlpha=n,t.worldTransform.fromArray(s),a=0,h=l.length;h>a;++a)l[a].updateTransform()}},i.prototype.getImage=function(){var t=new Image;return t.src=this.getBase64(),t},i.prototype.getBase64=function(){return this.getCanvas().toDataURL()},i.prototype.getCanvas=function(){if(this.renderer.type===h.WEBGL_RENDERER){var t=this.renderer.gl,e=this.textureBuffer.width,i=this.textureBuffer.height,r=new Uint8Array(4*e*i);t.bindFramebuffer(t.FRAMEBUFFER,this.textureBuffer.frameBuffer),t.readPixels(0,0,e,i,t.RGBA,t.UNSIGNED_BYTE,r),t.bindFramebuffer(t.FRAMEBUFFER,null);var n=new o(e,i),s=n.context.getImageData(0,0,e,i);return s.data.set(r),n.context.putImageData(s,0,0),n.canvas}return this.textureBuffer.canvas}},{"../const":4,"../math":12,"../renderers/canvas/utils/CanvasBuffer":21,"../renderers/webgl/utils/FilterTexture":37,"./BaseTexture":42,"./Texture":44}],44:[function(t,e){function i(t,e,r,n){this.noFrame=!1,e||(this.noFrame=!0,e=new a.Rectangle(0,0,1,1)),t instanceof i&&(t=t.baseTexture),this.baseTexture=t,this._frame=e,this.trim=n,this.valid=!1,this.requiresUpdate=!1,this._uvs=null,this.width=0,this.height=0,this.crop=r||new a.Rectangle(0,0,1,1),t.hasLoaded?(this.noFrame&&(e=new a.Rectangle(0,0,t.width,t.height)),this.frame=e):t.addEventListener("loaded",this.onBaseTextureLoaded.bind(this))}var r=t("./BaseTexture"),n=t("./VideoBaseTexture"),s=t("./TextureUvs"),o=t("../utils/eventTarget"),a=t("../math"),h=t("../utils");i.prototype.constructor=i,e.exports=i,o.mixin(i.prototype),Object.defineProperties(i.prototype,{needsUpdate:{get:function(){return this.baseTexture.needsUpdate},set:function(t){this.baseTexture.needsUpdate=t}},frame:{get:function(){return this._frame},set:function(t){if(this._frame=t,this.noFrame=!1,this.width=t.width,this.height=t.height,this.crop.x=t.x,this.crop.y=t.y,this.crop.width=t.width,this.crop.height=t.height,!this.trim&&(t.x+t.width>this.baseTexture.width||t.y+t.height>this.baseTexture.height))throw new Error("Texture Error: frame does not fit inside the base Texture dimensions "+this);this.valid=t&&t.width&&t.height&&this.baseTexture.source&&this.baseTexture.hasLoaded,this.trim&&(this.width=this.trim.width,this.height=this.trim.height,this._frame.width=this.trim.width,this._frame.height=this.trim.height),this.valid&&this._updateUvs()}}}),i.prototype.onBaseTextureLoaded=function(){var t=this.baseTexture;t.removeEventListener("loaded",this.onLoaded),this.noFrame&&(this.frame=new a.Rectangle(0,0,t.width,t.height)),this.dispatchEvent({type:"update",content:this})},i.prototype.destroy=function(t){t&&this.baseTexture.destroy(),this.valid=!1},i.prototype._updateUvs=function(){this._uvs||(this._uvs=new s);var t=this.crop,e=this.baseTexture.width,i=this.baseTexture.height;this._uvs.x0=t.x/e,this._uvs.y0=t.y/i,this._uvs.x1=(t.x+t.width)/e,this._uvs.y1=t.y/i,this._uvs.x2=(t.x+t.width)/e,this._uvs.y2=(t.y+t.height)/i,this._uvs.x3=t.x/e,this._uvs.y3=(t.y+t.height)/i},i.fromImage=function(t,e,n){var s=h.TextureCache[t];return s||(s=new i(r.fromImage(t,e,n)),h.TextureCache[t]=s),s},i.fromFrame=function(t){var e=h.TextureCache[t];if(!e)throw new Error('The frameId "'+t+'" does not exist in the texture cache ');return e},i.fromCanvas=function(t,e){return new i(r.fromCanvas(t,e))},i.fromVideo=function(t,e){return new i(n.baseTextureFromVideo(t,e))},i.addTextureToCache=function(t,e){h.TextureCache[e]=t},i.removeTextureFromCache=function(t){var e=h.TextureCache[t];return delete h.TextureCache[t],delete h.BaseTextureCache[t],e},i.emptyTexture=new i(new r)},{"../math":12,"../utils":50,"../utils/eventTarget":49,"./BaseTexture":42,"./TextureUvs":45,"./VideoBaseTexture":46}],45:[function(t,e){function i(){this.x0=0,this.y0=0,this.x1=0,this.y1=0,this.x2=0,this.y2=0,this.x3=0,this.y3=0}e.exports=i},{}],46:[function(t,e){function i(t,e){if(!t)throw new Error("No video source element specified.");(t.readyState===t.HAVE_ENOUGH_DATA||t.readyState===t.HAVE_FUTURE_DATA)&&t.width&&t.height&&(t.complete=!0),n.call(this,t,e),this.autoUpdate=!1,this._boundOnUpdate=this._onUpdate.bind(this),this._boundOnCanPlay=this._onCanPlay.bind(this),t.complete||(t.addEventListener("canplay",this._boundOnCanPlay),t.addEventListener("canplaythrough",this._boundOnCanPlay),t.addEventListener("play",this._onPlayStart.bind(this)),t.addEventListener("pause",this._onPlayStop.bind(this))),this.__loaded=!1}function r(t,e){e||(e="video/"+t.substr(t.lastIndexOf(".")+1));var i=document.createElement("source");return i.src=t,i.type=e,i}var n=t("./BaseTexture"),s=t("../utils");i.prototype=Object.create(n.prototype),i.prototype.constructor=i,e.exports=i,i.prototype._onUpdate=function(){this.autoUpdate&&(window.requestAnimationFrame(this._boundOnUpdate),this.needsUpdate=!0)},i.prototype._onPlayStart=function(){this.autoUpdate||(window.requestAnimationFrame(this._boundOnUpdate),this.autoUpdate=!0)},i.prototype._onPlayStop=function(){this.autoUpdate=!1},i.prototype._onCanPlay=function(){this.hasLoaded=!0,this.source&&(this.source.removeEventListener("canplay",this._boundOnCanPlay),this.source.removeEventListener("canplaythrough",this._boundOnCanPlay),this.width=this.source.videoWidth,this.height=this.source.videoHeight,this.source.play(),this.__loaded||(this.__loaded=!0,this.emit("loaded",this)))},i.prototype.destroy=function(){this.source&&this.source._pixiId&&(s.BaseTextureCache[this.source._pixiId]=null,delete s.BaseTextureCache[this.source._pixiId],this.source._pixiId=null,delete this.source._pixiId),n.prototype.destroy.call(this)},i.fromVideo=function(t,e){t._pixiId||(t._pixiId="video_"+s.uuid());var r=s.BaseTextureCache[t._pixiId];return r||(r=new i(t,e),s.BaseTextureCache[t._pixiId]=r),r},i.fromUrl=function(t,e){var n=document.createElement("video");if(Array.isArray(t))for(var s=0;s>1;if(3>r)return[];for(var n=[],s=[],o=0;r>o;o++)s.push(o);o=0;for(var a=r;a>3;){var h=s[(o+0)%a],l=s[(o+1)%a],u=s[(o+2)%a],c=t[2*h],d=t[2*h+1],f=t[2*l],p=t[2*l+1],v=t[2*u],m=t[2*u+1],g=!1;if(i._convex(c,d,f,p,v,m,e)){g=!0;for(var x=0;a>x;x++){var y=s[x];if(y!==h&&y!==l&&y!==u&&i._PointInTriangle(t[2*y],t[2*y+1],c,d,f,p,v,m)){g=!1;break}}}if(g)n.push(h,l,u),s.splice((o+1)%a,1),a--,o=0;else if(o++>3*a){if(!e)return null;for(n=[],s=[],o=0;r>o;o++)s.push(o);o=0,a=r,e=!1}}return n.push(s[0],s[1],s[2]),n},i._PointInTriangle=function(t,e,i,r,n,s,o,a){var h=o-i,l=a-r,u=n-i,c=s-r,d=t-i,f=e-r,p=h*h+l*l,v=h*u+l*c,m=h*d+l*f,g=u*u+c*c,x=u*d+c*f,y=1/(p*g-v*v),b=(g*m-v*x)*y,T=(p*x-v*m)*y;return b>=0&&T>=0&&1>b+T},i._convex=function(t,e,i,r,n,s,o){return(e-r)*(n-i)+(i-t)*(s-r)>=0===o}},{}],49:[function(t,e){function i(t){t.listeners=function(t){return this._listeners=this._listeners||{},this._listeners[t]?this._listeners[t].slice():[]},t.emit=t.dispatchEvent=function(t,e){if(this._listeners=this._listeners||{},this._listeners[t]){"object"==typeof t&&(e=t,t=t.type),e&&e.__isEventObject===!0||(e=new r(this,t,e));var i,n=this._listeners[t].slice(0),s=n.length,o=n[0];for(i=0;s>i;o=n[++i])if(o.call(this,e),e.stoppedImmediate)return this;return e.stopped?this:(this.parent&&this.parent.emit&&this.parent.emit.call(this.parent,t,e),this)}},t.on=t.addEventListener=function(t,e){return this._listeners=this._listeners||{},(this._listeners[t]=this._listeners[t]||[]).push(e),this},t.once=function(t,e){function i(){e.apply(r.off(t,i),arguments)}this._listeners=this._listeners||{};var r=this;return i._originalHandler=e,this.on(t,i)},t.off=t.removeEventListener=function(t,e){if(this._listeners=this._listeners||{},!this._listeners[t])return this;for(var i=this._listeners[t],r=e?i.length:0;r-->0;)(i[r]===e||i[r]._originalHandler===e)&&i.splice(r,1);return 0===i.length&&delete this._listeners[t],this},t.removeAllListeners=function(t){return this._listeners=this._listeners||{},this._listeners[t]?(delete this._listeners[t],this):this}}var r=t("./EventData");e.exports={mixin:function(t){i(t)}}},{"./EventData":47}],50:[function(t,e){var i=t("../const"),r=e.exports={_uid:0,_saidHello:!1,PolyK:t("./PolyK"),EventData:t("./EventData"),eventTarget:t("./eventTarget"),uuid:function(){return++r._uid},hex2rgb:function(t,e){return e=e||[],e[0]=(t>>16&255)/255,e[1]=(t>>8&255)/255,e[2]=(255&t)/255,e},hex2string:function(t){return t=t.toString(16),t="000000".substr(0,6-t.length)+t,"#"+t},rgb2hex:function(t){return(255*t[0]<<16)+(255*t[1]<<8)+255*t[2]},canUseNewCanvasBlendModes:function(){if("undefined"==typeof document)return!1;var t=document.createElement("canvas"),e=t.getContext("2d");return t.width=1,t.height=1,e.fillStyle="#000",e.fillRect(0,0,1,1),e.globalCompositeOperation="multiply",e.fillStyle="#fff",e.fillRect(0,0,1,1),0===e.getImageData(0,0,1,1).data[0]},getNextPowerOfTwo:function(t){if(t>0&&0===(t&t-1))return t;for(var e=1;t>e;)e<<=1;return e},isPowerOfTwo:function(t,e){return t>0&&0===(t&t-1)&&e>0&&0===(e&e-1)},sayHello:function(t){if(!r._saidHello){if(navigator.userAgent.toLowerCase().indexOf("chrome")>-1){var e=["%c %c %c Pixi.js "+i.VERSION+" - "+t+" %c %c http://www.pixijs.com/ %c %c ♥%c♥%c♥ ","background: #ff66a5","background: #ff66a5","color: #ff66a5; background: #030307;","background: #ff66a5","background: #ffc3dc","background: #ff66a5","color: #ff2424; background: #fff","color: #ff2424; background: #fff","color: #ff2424; background: #fff"];console.log.apply(console,e)}else window.console&&console.log("Pixi.js "+i.VERSION+" - "+t+" - http://www.pixijs.com/");r._saidHello=!0}},AjaxRequest:function(){var t=["Msxml2.XMLHTTP.6.0","Msxml2.XMLHTTP.3.0","Microsoft.XMLHTTP"];if(!window.ActiveXObject)return window.XMLHttpRequest?new window.XMLHttpRequest:!1;for(var e=0;et?this.loop?(this.currentFrame+=this.textures.length,this.texture=this.textures[this.currentFrame]):(this.gotoAndStop(0),this.onComplete&&this.onComplete()):this.loop||t=this.textures.length&&(this.gotoAndStop(this.textures.length-1),this.onComplete&&this.onComplete())}},e.fromFrames=function(t){for(var r=[],n=0;nh;h++)n=t[h],s=4*h,o=h/(a-1),h%2?(e[s]=o,e[s+1]=0,e[s+2]=o,e[s+3]=1):(e[s]=o,e[s+1]=0,e[s+2]=o,e[s+3]=1),s=2*h,r[s]=1,r[s+1]=1,s=2*h,i[s]=s,i[s+1]=s+1}},i.prototype.updateTransform=function(){var t=this.points;if(!(t.length<1)){for(var e,i,r,n,s,o,a=t[0],h=0,l=0,u=this.vertices,c=t.length,d=0;c>d;d++)i=t[d],r=4*d,e=d1&&(n=1),s=Math.sqrt(h*h+l*l),o=this.texture.height/2,h/=s,l/=s,h*=o,l*=o,u[r]=i.x+h,u[r+1]=i.y+l,u[r+2]=i.x-h,u[r+3]=i.y-l,a=i;this.displayObjectContainerUpdateTransform()}},i.prototype.setTexture=function(t){this.texture=t}},{"./Strip":53}],53:[function(t,e){function i(t){r.DisplayObjectContainer.call(this),this.texture=t,this.uvs=new Float32Array([0,1,1,1,1,0,0,1]),this.vertices=new Float32Array([0,0,100,0,100,100,0,100]),this.colors=new Float32Array([1,1,1,1]),this.indices=new Uint16Array([0,1,2,3]),this.dirty=!0,this.blendMode=r.CONST.blendModes.NORMAL,this.canvasPadding=0,this.drawMode=i.DrawModes.TRIANGLE_STRIP}var r=t("../core");i.prototype=Object.create(r.DisplayObjectContainer.prototype),i.prototype.constructor=i,e.exports=i,i.prototype.renderWebGL=function(t){!this.visible||this.alpha<=0||(t.spriteBatch.stop(),this._vertexBuffer||this._initWebGL(t),t.shaderManager.setShader(t.shaderManager.stripShader),this._renderStrip(t),t.spriteBatch.start())},i.prototype._initWebGL=function(t){var e=t.gl;this._vertexBuffer=e.createBuffer(),this._indexBuffer=e.createBuffer(),this._uvBuffer=e.createBuffer(),this._colorBuffer=e.createBuffer(),e.bindBuffer(e.ARRAY_BUFFER,this._vertexBuffer),e.bufferData(e.ARRAY_BUFFER,this.vertices,e.DYNAMIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,this._uvBuffer),e.bufferData(e.ARRAY_BUFFER,this.uvs,e.STATIC_DRAW),e.bindBuffer(e.ARRAY_BUFFER,this._colorBuffer),e.bufferData(e.ARRAY_BUFFER,this.colors,e.STATIC_DRAW),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this._indexBuffer),e.bufferData(e.ELEMENT_ARRAY_BUFFER,this.indices,e.STATIC_DRAW)},i.prototype._renderStrip=function(t){var e=t.gl,r=t.projection,n=t.offset,s=t.shaderManager.stripShader,o=this.drawMode===i.DrawModes.TRIANGLE_STRIP?e.TRIANGLE_STRIP:e.TRIANGLES;t.blendModeManager.setBlendMode(this.blendMode),e.uniformMatrix3fv(s.translationMatrix,!1,this.worldTransform.toArray(!0)),e.uniform2f(s.projectionVector,r.x,-r.y),e.uniform2f(s.offsetVector,-n.x,-n.y),e.uniform1f(s.alpha,this.worldAlpha),this.dirty?(this.dirty=!1,e.bindBuffer(e.ARRAY_BUFFER,this._vertexBuffer),e.bufferData(e.ARRAY_BUFFER,this.vertices,e.STATIC_DRAW),e.vertexAttribPointer(s.aVertexPosition,2,e.FLOAT,!1,0,0),e.bindBuffer(e.ARRAY_BUFFER,this._uvBuffer),e.bufferData(e.ARRAY_BUFFER,this.uvs,e.STATIC_DRAW),e.vertexAttribPointer(s.aTextureCoord,2,e.FLOAT,!1,0,0),e.activeTexture(e.TEXTURE0),this.texture.baseTexture._dirty[e.id]?t.updateTexture(this.texture.baseTexture):e.bindTexture(e.TEXTURE_2D,this.texture.baseTexture._glTextures[e.id]),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this._indexBuffer),e.bufferData(e.ELEMENT_ARRAY_BUFFER,this.indices,e.STATIC_DRAW)):(e.bindBuffer(e.ARRAY_BUFFER,this._vertexBuffer),e.bufferSubData(e.ARRAY_BUFFER,0,this.vertices),e.vertexAttribPointer(s.aVertexPosition,2,e.FLOAT,!1,0,0),e.bindBuffer(e.ARRAY_BUFFER,this._uvBuffer),e.vertexAttribPointer(s.aTextureCoord,2,e.FLOAT,!1,0,0),e.activeTexture(e.TEXTURE0),this.texture.baseTexture._dirty[e.id]?t.updateTexture(this.texture.baseTexture):e.bindTexture(e.TEXTURE_2D,this.texture.baseTexture._glTextures[e.id]),e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,this._indexBuffer)),e.drawElements(o,this.indices.length,e.UNSIGNED_SHORT,0)},i.prototype.renderCanvas=function(t){var e=t.context,r=this.worldTransform;t.roundPixels?e.setTransform(r.a,r.b,r.c,r.d,0|r.tx,0|r.ty):e.setTransform(r.a,r.b,r.c,r.d,r.tx,r.ty),this.drawMode===i.DrawModes.TRIANGLE_STRIP?this._renderCanvasTriangleStrip(e):this._renderCanvasTriangles(e)},i.prototype._renderCanvasTriangleStrip=function(t){for(var e=this.vertices,i=this.uvs,r=e.length/2,n=0;r-2>n;n++){var s=2*n;this._renderCanvasDrawTriangle(t,e,i,s,s+2,s+4)}},i.prototype._renderCanvasTriangles=function(t){for(var e=this.vertices,i=this.uvs,r=this.indices,n=r.length,s=0;n>s;s+=3){var o=2*r[s],a=2*r[s+1],h=2*r[s+2];this._renderCanvasDrawTriangle(t,e,i,o,a,h)}},i.prototype._renderCanvasDrawTriangle=function(t,e,i,r,n,s){var o=this.texture.baseTexture.source,a=this.texture.width,h=this.texture.height,l=e[r],u=e[n],c=e[s],d=e[r+1],f=e[n+1],p=e[s+1],v=i[r]*a,m=i[n]*a,g=i[s]*a,x=i[r+1]*h,y=i[n+1]*h,b=i[s+1]*h;if(this.canvasPadding>0){var T=this.canvasPadding/this.worldTransform.a,w=this.canvasPadding/this.worldTransform.d,S=(l+u+c)/3,A=(d+f+p)/3,_=l-S,C=d-A,E=Math.sqrt(_*_+C*C);l=S+_/E*(E+T),d=A+C/E*(E+w),_=u-S,C=f-A,E=Math.sqrt(_*_+C*C),u=S+_/E*(E+T),f=A+C/E*(E+w),_=c-S,C=p-A,E=Math.sqrt(_*_+C*C),c=S+_/E*(E+T),p=A+C/E*(E+w)}t.save(),t.beginPath(),t.moveTo(l,d),t.lineTo(u,f),t.lineTo(c,p),t.closePath(),t.clip();var R=v*y+x*g+m*b-y*g-x*m-v*b,M=l*y+x*c+u*b-y*c-x*u-l*b,F=v*u+l*g+m*c-u*g-l*m-v*c,B=v*y*c+x*u*g+l*m*b-l*y*g-x*m*c-v*u*b,D=d*y+x*p+f*b-y*p-x*f-d*b,P=v*f+d*g+m*p-f*g-d*m-v*p,L=v*y*p+x*f*g+d*m*b-d*y*g-x*m*p-v*f*b;t.transform(M/R,D/R,F/R,P/R,B/R,L/R),t.drawImage(o,0,0),t.restore()},i.prototype.renderStripFlat=function(t){var e=this.context,i=t.vertices,r=i.length/2;e.beginPath();for(var n=1;r-2>n;n++){var s=2*n,o=i[s],a=i[s+2],h=i[s+4],l=i[s+1],u=i[s+3],c=i[s+5];e.moveTo(o,l),e.lineTo(a,u),e.lineTo(h,c)}e.fillStyle="#FF0000",e.fill(),e.closePath()},i.prototype.onTextureUpdate=function(){this.updateFrame=!0},i.prototype.getBounds=function(t){for(var e=t||this.worldTransform,i=e.a,n=e.b,s=e.c,o=e.d,a=e.tx,h=e.ty,l=-1/0,u=-1/0,c=1/0,d=1/0,f=this.vertices,p=0,v=f.length;v>p;p+=2){var m=f[p],g=f[p+1],x=i*m+s*g+a,y=o*g+n*m+h;c=c>x?x:c,d=d>y?y:d,l=x>l?x:l,u=y>u?y:u}if(c===-1/0||1/0===u)return r.math.Rectangle.EMPTY;var b=this._bounds;return b.x=c,b.width=l-c,b.y=d,b.height=u-d,this._currentBounds=b,b},i.DrawModes={TRIANGLE_STRIP:0,TRIANGLES:1}},{"../core":9}],54:[function(t,e){function i(t,e,i){r.Sprite.call(this,t),this._width=e||100,this._height=i||100,this.tileScale=new r.math.Point(1,1),this.tileScaleOffset=new r.math.Point(1,1),this.tilePosition=new r.math.Point(0,0),this.renderable=!0,this.tint=16777215,this.blendMode=r.CONST.blendModes.NORMAL}var r=t("../core");i.prototype=Object.create(r.Sprite.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{width:{get:function(){return this._width},set:function(t){this._width=t}},height:{get:function(){return this._height},set:function(t){this._height=t}},texture:{get:function(){return this._texture},set:function(t){this._texture!==t&&(this._texture=t,this.refreshTexture=!0,this.cachedTint=16777215)}}}),i.prototype.renderWebGL=function(t){if(this.visible&&!(this.alpha<=0)){var e,i;for(this._mask&&(t.spriteBatch.stop(),t.maskManager.pushMask(this.mask,t),t.spriteBatch.start()),this._filters&&(t.spriteBatch.flush(),t.filterManager.pushFilter(this._filterBlock)),!this.tilingTexture||this.refreshTexture?(this.generateTilingTexture(!0),this.tilingTexture&&this.tilingTexture.needsUpdate&&(t.updateTexture(this.tilingTexture.baseTexture),this.tilingTexture.needsUpdate=!1)):t.spriteBatch.renderTilingSprite(this),e=0,i=this.children.length;i>e;e++)this.children[e].renderWebGL(t);t.spriteBatch.stop(),this._filters&&t.filterManager.popFilter(),this._mask&&t.maskManager.popMask(this._mask,t),t.spriteBatch.start()}},i.prototype.renderCanvas=function(t){if(this.visible&&!(this.alpha<=0)){var e=t.context;this._mask&&t.maskManager.pushMask(this._mask,e),e.globalAlpha=this.worldAlpha;var i,r,n=this.worldTransform,s=t.resolution;if(e.setTransform(n.a*s,n.b*s,n.c*s,n.d*s,n.tx*s,n.ty*s),!this.__tilePattern||this.refreshTexture){if(this.generateTilingTexture(!1),!this.tilingTexture)return;this.__tilePattern=e.createPattern(this.tilingTexture.baseTexture.source,"repeat")}this.blendMode!==t.currentBlendMode&&(t.currentBlendMode=this.blendMode,e.globalCompositeOperation=t.blendModes[t.currentBlendMode]);var o=this.tilePosition,a=this.tileScale;for(o.x%=this.tilingTexture.baseTexture.width,o.y%=this.tilingTexture.baseTexture.height,e.scale(a.x,a.y),e.translate(o.x+this.anchor.x*-this._width,o.y+this.anchor.y*-this._height),e.fillStyle=this.__tilePattern,e.fillRect(-o.x,-o.y,this._width/a.x,this._height/a.y),e.translate(-o.x+this.anchor.x*this._width,-o.y+this.anchor.y*this._height),e.scale(1/a.x,1/a.y),this._mask&&t.maskManager.popMask(t.context),i=0,r=this.children.length;r>i;++i)this.children[i].renderCanvas(t)}},i.prototype.getBounds=function(){var t,e,i,r,n=this._width,s=this._height,o=n*(1-this.anchor.x),a=n*-this.anchor.x,h=s*(1-this.anchor.y),l=s*-this.anchor.y,u=this.worldTransform,c=u.a,d=u.b,f=u.c,p=u.d,v=u.tx,m=u.ty,g=c*a+f*l+v,x=p*l+d*a+m,y=c*o+f*l+v,b=p*l+d*o+m,T=c*o+f*h+v,w=p*h+d*o+m,S=c*a+f*h+v,A=p*h+d*a+m;t=g,t=t>y?y:t,t=t>T?T:t,t=t>S?S:t,i=x,i=i>b?b:i,i=i>w?w:i,i=i>A?A:i,e=g,e=y>e?y:e,e=T>e?T:e,e=S>e?S:e,r=x,r=b>r?b:r,r=w>r?w:r,r=A>r?A:r;var _=this._bounds;return _.x=t,_.width=e-t,_.y=i,_.height=r-i,this._currentBounds=_,_},i.prototype.onTextureUpdate=function(){},i.prototype.generateTilingTexture=function(t){if(this.texture.baseTexture.hasLoaded){var e,i,n=this.originalTexture||this.texture,s=n.frame,o=s.width!==n.baseTexture.width||s.height!==n.baseTexture.height,a=!1;if(t?(e=r.utils.getNextPowerOfTwo(s.width),i=r.utils.getNextPowerOfTwo(s.height),(s.width!==e||s.height!==i||n.baseTexture.width!==e||n.baseTexture.height||i)&&(a=!0)):o&&(e=s.width,i=s.height,a=!0),a){var h;this.tilingTexture&&this.tilingTexture.isTiling?(h=this.tilingTexture.canvasBuffer,h.resize(e,i),this.tilingTexture.baseTexture.width=e,this.tilingTexture.baseTexture.height=i,this.tilingTexture.needsUpdate=!0):(h=new r.CanvasBuffer(e,i),this.tilingTexture=r.Texture.fromCanvas(h.canvas),this.tilingTexture.canvasBuffer=h,this.tilingTexture.isTiling=!0),h.context.drawImage(n.baseTexture.source,n.crop.x,n.crop.y,n.crop.width,n.crop.height,0,0,e,i),this.tileScaleOffset.x=s.width/e,this.tileScaleOffset.y=s.height/i}else this.tilingTexture&&this.tilingTexture.isTiling&&this.tilingTexture.destroy(!0),this.tileScaleOffset.x=1,this.tileScaleOffset.y=1,this.tilingTexture=n;this.refreshTexture=!1,this.originalTexture=this.texture,this.texture=this.tilingTexture,this.tilingTexture.baseTexture._powerOf2=!0}}},{"../core":9}],55:[function(t,e){e.exports={MovieClip:t("./MovieClip"),Rope:t("./Rope"),Strip:t("./Strip"),TilingSprite:t("./TilingSprite")}},{"./MovieClip":51,"./Rope":52,"./Strip":53,"./TilingSprite":54}],56:[function(t,e){function i(t,e){this.passes=[this],this.shaders=[],this.padding=0,this.uniforms=e||{},this.fragmentSrc="string"==typeof t?t.split(""):t||[]}i.prototype.constructor=i,e.exports=i,i.prototype.syncUniforms=function(){for(var t=0,e=this.shaders.length;e>t;++t)this.shaders[t].dirty=!0}},{}],57:[function(t,e){function i(t){r.call(this),t.baseTexture._powerOf2=!0,this.uniforms={mask:{type:"sampler2D",value:t},mapDimensions:{type:"2f",value:{x:1,y:5112}},dimensions:{type:"4fv",value:[0,0,0,0]},offset:{type:"2f",value:{x:0,y:0}}},t.baseTexture.hasLoaded?(this.uniforms.mask.value.x=t.width,this.uniforms.mask.value.y=t.height):(this.boundLoadedFunction=this.onTextureLoaded.bind(this),t.baseTexture.on("loaded",this.boundLoadedFunction)),this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying vec4 vColor;","uniform sampler2D uSampler;","uniform sampler2D mask;","uniform vec2 mapDimensions;","uniform vec4 dimensions;","uniform vec2 offset;","void main() {"," vec2 mapCords = vTextureCoord.xy;"," mapCords += (dimensions.zw + offset)/ dimensions.xy ;"," mapCords.y *= -1.0;"," mapCords.y += 1.0;"," mapCords *= dimensions.xy / mapDimensions;"," vec4 original = texture2D(uSampler, vTextureCoord);"," float maskAlpha = texture2D(mask, mapCords).r;"," original *= maskAlpha;"," gl_FragColor = original;","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,i.prototype.onTextureLoaded=function(){this.uniforms.mapDimensions.value.x=this.uniforms.mask.value.width,this.uniforms.mapDimensions.value.y=this.uniforms.mask.value.height,this.uniforms.mask.value.baseTexture.off("loaded",this.boundLoadedFunction)},Object.defineProperties(i.prototype,{map:{get:function(){return this.uniforms.mask.value},set:function(t){this.uniforms.mask.value=t}},offset:{get:function(){return this.uniforms.offset.value},set:function(t){this.uniforms.offset.value=t}}})},{"./AbstractFilter":56}],58:[function(t,e){function i(){r.call(this),this.uniforms={dimensions:{type:"4fv",value:new Float32Array([1e4,100,10,10])},pixelSize:{type:"1f",value:8}},this.fragmentSrc=["precision mediump float;","uniform vec4 dimensions;","uniform float pixelSize;","uniform sampler2D uSampler;","float character(float n, vec2 p)","{"," p = floor(p*vec2(4.0, -4.0) + 2.5);"," if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y)"," {"," if (int(mod(n/exp2(p.x + 5.0*p.y), 2.0)) == 1) return 1.0;"," }"," return 0.0;","}","void main()","{"," vec2 uv = gl_FragCoord.xy;"," vec3 col = texture2D(uSampler, floor( uv / pixelSize ) * pixelSize / dimensions.xy).rgb;"," #ifdef HAS_GREENSCREEN"," float gray = (col.r + col.b)/2.0;"," #else"," float gray = (col.r + col.g + col.b)/3.0;"," #endif"," float n = 65536.0; // ."," if (gray > 0.2) n = 65600.0; // :"," if (gray > 0.3) n = 332772.0; // *"," if (gray > 0.4) n = 15255086.0; // o"," if (gray > 0.5) n = 23385164.0; // &"," if (gray > 0.6) n = 15252014.0; // 8"," if (gray > 0.7) n = 13199452.0; // @"," if (gray > 0.8) n = 11512810.0; // #"," vec2 p = mod( uv / ( pixelSize * 0.5 ), 2.0) - vec2(1.0);"," col = col * character(n, p);"," gl_FragColor = vec4(col, 1.0);","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{size:{get:function(){return this.uniforms.pixelSize.value},set:function(t){this.uniforms.pixelSize.value=t}}})},{"./AbstractFilter":56}],59:[function(t,e){function i(){r.call(this),this.blurXFilter=new n,this.blurYFilter=new s,this.passes=[this.blurXFilter,this.blurYFilter]}var r=t("./AbstractFilter"),n=t("./BlurXFilter"),s=t("./BlurYFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{blur:{get:function(){return this.blurXFilter.blur},set:function(t){this.blurXFilter.blur=this.blurYFilter.blur=t}},blurX:{get:function(){return this.blurXFilter.blur},set:function(t){this.blurXFilter.blur=t}},blurY:{get:function(){return this.blurYFilter.blur},set:function(t){this.blurYFilter.blur=t}}})},{"./AbstractFilter":56,"./BlurXFilter":60,"./BlurYFilter":61}],60:[function(t,e){function i(){r.call(this),this.uniforms={blur:{type:"1f",value:1/512}},this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying vec4 vColor;","uniform float blur;","uniform sampler2D uSampler;","void main(void) {"," vec4 sum = vec4(0.0);"," sum += texture2D(uSampler, vec2(vTextureCoord.x - 4.0*blur, vTextureCoord.y)) * 0.05;"," sum += texture2D(uSampler, vec2(vTextureCoord.x - 3.0*blur, vTextureCoord.y)) * 0.09;"," sum += texture2D(uSampler, vec2(vTextureCoord.x - 2.0*blur, vTextureCoord.y)) * 0.12;"," sum += texture2D(uSampler, vec2(vTextureCoord.x - blur, vTextureCoord.y)) * 0.15;"," sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y)) * 0.16;"," sum += texture2D(uSampler, vec2(vTextureCoord.x + blur, vTextureCoord.y)) * 0.15;"," sum += texture2D(uSampler, vec2(vTextureCoord.x + 2.0*blur, vTextureCoord.y)) * 0.12;"," sum += texture2D(uSampler, vec2(vTextureCoord.x + 3.0*blur, vTextureCoord.y)) * 0.09;"," sum += texture2D(uSampler, vec2(vTextureCoord.x + 4.0*blur, vTextureCoord.y)) * 0.05;"," gl_FragColor = sum;","}"]}var r=t("./AbstractFilter"),n=1/7e3;i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{blur:{get:function(){return this.uniforms.blur.value/n -},set:function(t){this.uniforms.blur.value=n*t}}})},{"./AbstractFilter":56}],61:[function(t,e){function i(){r.call(this),this.uniforms={blur:{type:"1f",value:1/512}},this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying vec4 vColor;","uniform float blur;","uniform sampler2D uSampler;","void main(void) {"," vec4 sum = vec4(0.0);"," sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - 4.0*blur)) * 0.05;"," sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - 3.0*blur)) * 0.09;"," sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - 2.0*blur)) * 0.12;"," sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - blur)) * 0.15;"," sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y)) * 0.16;"," sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + blur)) * 0.15;"," sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + 2.0*blur)) * 0.12;"," sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + 3.0*blur)) * 0.09;"," sum += texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + 4.0*blur)) * 0.05;"," gl_FragColor = sum;","}"]}var r=t("./AbstractFilter"),n=1/7e3;i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{blur:{get:function(){return this.uniforms.blur.value/n},set:function(t){this.uniforms.blur.value=n*t}}})},{"./AbstractFilter":56}],62:[function(t,e){function i(){r.call(this),this.uniforms={matrix:{type:"mat4",value:[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]}},this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying vec4 vColor;","uniform float invert;","uniform mat4 matrix;","uniform sampler2D uSampler;","void main(void) {"," gl_FragColor = texture2D(uSampler, vTextureCoord) * matrix;","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{matrix:{get:function(){return this.uniforms.matrix.value},set:function(t){this.uniforms.matrix.value=t}}})},{"./AbstractFilter":56}],63:[function(t,e){function i(){r.call(this),this.uniforms={step:{type:"1f",value:5}},this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying vec4 vColor;","uniform sampler2D uSampler;","uniform float step;","void main(void) {"," vec4 color = texture2D(uSampler, vTextureCoord);"," color = floor(color * step) / step;"," gl_FragColor = color;","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{step:{get:function(){return this.uniforms.step.value},set:function(t){this.uniforms.step.value=t}}})},{"./AbstractFilter":56}],64:[function(t,e){function i(t,e,i){r.call(this),this.uniforms={matrix:{type:"1fv",value:new Float32Array(t)},texelSizeX:{type:"1f",value:1/e},texelSizeY:{type:"1f",value:1/i}},this.fragmentSrc=["precision mediump float;","varying mediump vec2 vTextureCoord;","uniform sampler2D texture;","uniform float texelSizeX;","uniform float texelSizeY;","uniform float matrix[9];","vec2 px = vec2(texelSizeX, texelSizeY);","void main(void) {"," vec4 c11 = texture2D(texture, vTextureCoord - px);"," vec4 c12 = texture2D(texture, vec2(vTextureCoord.x, vTextureCoord.y - px.y));"," vec4 c13 = texture2D(texture, vec2(vTextureCoord.x + px.x, vTextureCoord.y - px.y));"," vec4 c21 = texture2D(texture, vec2(vTextureCoord.x - px.x, vTextureCoord.y) );"," vec4 c22 = texture2D(texture, vTextureCoord);"," vec4 c23 = texture2D(texture, vec2(vTextureCoord.x + px.x, vTextureCoord.y) );"," vec4 c31 = texture2D(texture, vec2(vTextureCoord.x - px.x, vTextureCoord.y + px.y) );"," vec4 c32 = texture2D(texture, vec2(vTextureCoord.x, vTextureCoord.y + px.y) );"," vec4 c33 = texture2D(texture, vTextureCoord + px );"," gl_FragColor = "," c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] +"," c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] +"," c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8];"," gl_FragColor.a = c22.a;","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{matrix:{get:function(){return this.uniforms.matrix.value},set:function(t){this.uniforms.matrix.value=new Float32Array(t)}},width:{get:function(){return this.uniforms.texelSizeX.value},set:function(t){this.uniforms.texelSizeX.value=1/t}},height:{get:function(){return this.uniforms.texelSizeY.value},set:function(t){this.uniforms.texelSizeY.value=1/t}}})},{"./AbstractFilter":56}],65:[function(t,e){function i(){r.call(this),this.uniforms={blur:{type:"1f",value:1/512}},this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying vec4 vColor;","uniform float blur;","uniform sampler2D uSampler;","void main(void) {"," float lum = length(texture2D(uSampler, vTextureCoord.xy).rgb);"," gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);"," if (lum < 1.00) {"," if (mod(gl_FragCoord.x + gl_FragCoord.y, 10.0) == 0.0) {"," gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);"," }"," }"," if (lum < 0.75) {"," if (mod(gl_FragCoord.x - gl_FragCoord.y, 10.0) == 0.0) {"," gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);"," }"," }"," if (lum < 0.50) {"," if (mod(gl_FragCoord.x + gl_FragCoord.y - 5.0, 10.0) == 0.0) {"," gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);"," }"," }"," if (lum < 0.3) {"," if (mod(gl_FragCoord.x - gl_FragCoord.y - 5.0, 10.0) == 0.0) {"," gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);"," }"," }","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{blur:{get:function(){return this.uniforms.blur.value/(1/7e3)},set:function(t){this.uniforms.blur.value=1/7e3*t}}})},{"./AbstractFilter":56}],66:[function(t,e){function i(t){r.call(this),t.baseTexture._powerOf2=!0,this.uniforms={displacementMap:{type:"sampler2D",value:t},scale:{type:"2f",value:{x:30,y:30}},offset:{type:"2f",value:{x:0,y:0}},mapDimensions:{type:"2f",value:{x:1,y:5112}},dimensions:{type:"4fv",value:[0,0,0,0]}},t.baseTexture.hasLoaded?this.onTextureLoaded():(this.boundLoadedFunction=this.onTextureLoaded.bind(this),t.baseTexture.on("loaded",this.boundLoadedFunction)),this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying vec4 vColor;","uniform sampler2D displacementMap;","uniform sampler2D uSampler;","uniform vec2 scale;","uniform vec2 offset;","uniform vec4 dimensions;","uniform vec2 mapDimensions;","void main(void) {"," vec2 mapCords = vTextureCoord.xy;"," mapCords += (dimensions.zw + offset)/ dimensions.xy ;"," mapCords.y *= -1.0;"," mapCords.y += 1.0;"," vec2 matSample = texture2D(displacementMap, mapCords).xy;"," matSample -= 0.5;"," matSample *= scale;"," matSample /= mapDimensions;"," gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x + matSample.x, vTextureCoord.y + matSample.y));"," gl_FragColor.rgb = mix( gl_FragColor.rgb, gl_FragColor.rgb, 1.0);","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,i.prototype.onTextureLoaded=function(){this.uniforms.mapDimensions.value.x=this.uniforms.displacementMap.value.width,this.uniforms.mapDimensions.value.y=this.uniforms.displacementMap.value.height,this.uniforms.displacementMap.value.baseTexture.off("loaded",this.boundLoadedFunction)},Object.defineProperties(i.prototype,{map:{get:function(){return this.uniforms.displacementMap.value},set:function(t){this.uniforms.displacementMap.value=t}},scale:{get:function(){return this.uniforms.scale.value},set:function(t){this.uniforms.scale.value=t}},offset:{get:function(){return this.uniforms.offset.value},set:function(t){this.uniforms.offset.value=t}}})},{"./AbstractFilter":56}],67:[function(t,e){function i(){r.call(this),this.uniforms={scale:{type:"1f",value:1},angle:{type:"1f",value:5},dimensions:{type:"4fv",value:[0,0,0,0]}},this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying vec4 vColor;","uniform vec4 dimensions;","uniform sampler2D uSampler;","uniform float angle;","uniform float scale;","float pattern() {"," float s = sin(angle), c = cos(angle);"," vec2 tex = vTextureCoord * dimensions.xy;"," vec2 point = vec2("," c * tex.x - s * tex.y,"," s * tex.x + c * tex.y"," ) * scale;"," return (sin(point.x) * sin(point.y)) * 4.0;","}","void main() {"," vec4 color = texture2D(uSampler, vTextureCoord);"," float average = (color.r + color.g + color.b) / 3.0;"," gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a);","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{scale:{get:function(){return this.uniforms.scale.value},set:function(t){this.uniforms.scale.value=t}},angle:{get:function(){return this.uniforms.angle.value},set:function(t){this.uniforms.angle.value=t}}})},{"./AbstractFilter":56}],68:[function(t,e){function i(){this.visible=!0,this.renderable=!0}i.prototype.constructor=i,e.exports=i},{}],69:[function(t,e){function i(){r.call(this),this.uniforms={gray:{type:"1f",value:1}},this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying vec4 vColor;","uniform sampler2D uSampler;","uniform float gray;","void main(void) {"," gl_FragColor = texture2D(uSampler, vTextureCoord);"," gl_FragColor.rgb = mix(gl_FragColor.rgb, vec3(0.2126*gl_FragColor.r + 0.7152*gl_FragColor.g + 0.0722*gl_FragColor.b), gray);","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{gray:{get:function(){return this.uniforms.gray.value},set:function(t){this.uniforms.gray.value=t}}})},{"./AbstractFilter":56}],70:[function(t,e){function i(){r.call(this),this.uniforms={invert:{type:"1f",value:1}},this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying vec4 vColor;","uniform float invert;","uniform sampler2D uSampler;","void main(void) {"," gl_FragColor = texture2D(uSampler, vTextureCoord);"," gl_FragColor.rgb = mix( (vec3(1)-gl_FragColor.rgb) * gl_FragColor.a, gl_FragColor.rgb, 1.0 - invert);","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{invert:{get:function(){return this.uniforms.invert.value},set:function(t){this.uniforms.invert.value=t}}})},{"./AbstractFilter":56}],71:[function(t,e){function i(){r.call(this),this.uniforms={noise:{type:"1f",value:.5}},this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying vec4 vColor;","uniform float noise;","uniform sampler2D uSampler;","float rand(vec2 co) {"," return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);","}","void main() {"," vec4 color = texture2D(uSampler, vTextureCoord);"," float diff = (rand(vTextureCoord) - 0.5) * noise;"," color.r += diff;"," color.g += diff;"," color.b += diff;"," gl_FragColor = color;","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{noise:{get:function(){return this.uniforms.noise.value},set:function(t){this.dirty=!0,this.uniforms.noise.value=t}}})},{"./AbstractFilter":56}],72:[function(t,e){function i(t){r.call(this),t.baseTexture._powerOf2=!0,this.uniforms={displacementMap:{type:"sampler2D",value:t},scale:{type:"2f",value:{x:15,y:15}},offset:{type:"2f",value:{x:0,y:0}},mapDimensions:{type:"2f",value:{x:1,y:1}},dimensions:{type:"4f",value:[0,0,0,0]},LightPos:{type:"3f",value:[0,1,0]}},t.baseTexture.hasLoaded?this.onTextureLoaded():(this.boundLoadedFunction=this.onTextureLoaded.bind(this),t.baseTexture.on("loaded",this.boundLoadedFunction)),this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying float vColor;","uniform sampler2D displacementMap;","uniform sampler2D uSampler;","uniform vec4 dimensions;","const vec2 Resolution = vec2(1.0,1.0);","uniform vec3 LightPos;","const vec4 LightColor = vec4(1.0, 1.0, 1.0, 1.0);","const vec4 AmbientColor = vec4(1.0, 1.0, 1.0, 0.5);","const vec3 Falloff = vec3(0.0, 1.0, 0.2);","uniform vec3 LightDir;","uniform vec2 mapDimensions;","void main(void) {"," vec2 mapCords = vTextureCoord.xy;"," vec4 color = texture2D(uSampler, vTextureCoord.st);"," vec3 nColor = texture2D(displacementMap, vTextureCoord.st).rgb;"," mapCords *= vec2(dimensions.x/512.0, dimensions.y/512.0);"," mapCords.y *= -1.0;"," mapCords.y += 1.0;"," vec4 DiffuseColor = texture2D(uSampler, vTextureCoord);"," vec3 NormalMap = texture2D(displacementMap, mapCords).rgb;"," vec3 LightDir = vec3(LightPos.xy - (mapCords.xy), LightPos.z);"," float D = length(LightDir);"," vec3 N = normalize(NormalMap * 2.0 - 1.0);"," vec3 L = normalize(LightDir);"," vec3 Diffuse = (LightColor.rgb * LightColor.a) * max(dot(N, L), 0.0);"," vec3 Ambient = AmbientColor.rgb * AmbientColor.a;"," float Attenuation = 1.0 / ( Falloff.x + (Falloff.y*D) + (Falloff.z*D*D) );"," vec3 Intensity = Ambient + Diffuse * Attenuation;"," vec3 FinalColor = DiffuseColor.rgb * Intensity;"," gl_FragColor = vColor * vec4(FinalColor, DiffuseColor.a);","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,i.prototype.onTextureLoaded=function(){this.uniforms.mapDimensions.value.x=this.uniforms.displacementMap.value.width,this.uniforms.mapDimensions.value.y=this.uniforms.displacementMap.value.height,this.uniforms.displacementMap.value.baseTexture.off("loaded",this.boundLoadedFunction)},Object.defineProperties(i.prototype,{map:{get:function(){return this.uniforms.displacementMap.value},set:function(t){this.uniforms.displacementMap.value=t}},scale:{get:function(){return this.uniforms.scale.value},set:function(t){this.uniforms.scale.value=t}},offset:{get:function(){return this.uniforms.offset.value},set:function(t){this.uniforms.offset.value=t}}})},{"./AbstractFilter":56}],73:[function(t,e){function i(){r.call(this),this.uniforms={invert:{type:"1f",value:0},dimensions:{type:"4fv",value:new Float32Array([1e4,100,10,10])},pixelSize:{type:"2f",value:{x:10,y:10}}},this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying vec4 vColor;","uniform vec2 testDim;","uniform vec4 dimensions;","uniform vec2 pixelSize;","uniform sampler2D uSampler;","void main(void) {"," vec2 coord = vTextureCoord;"," vec2 size = dimensions.xy/pixelSize;"," vec2 color = floor( ( vTextureCoord * size ) ) / size + pixelSize/dimensions.xy * 0.5;"," gl_FragColor = texture2D(uSampler, color);","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{size:{get:function(){return this.uniforms.pixelSize.value},set:function(t){this.uniforms.pixelSize.value=t}}})},{"./AbstractFilter":56}],74:[function(t,e){function i(){r.call(this),this.passes=[this],this.uniforms={red:{type:"2f",value:{x:20,y:20}},green:{type:"2f",value:{x:-20,y:20}},blue:{type:"2f",value:{x:20,y:-20}},dimensions:{type:"4fv",value:[0,0,0,0]}},this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying vec4 vColor;","uniform vec2 red;","uniform vec2 green;","uniform vec2 blue;","uniform vec4 dimensions;","uniform sampler2D uSampler;","void main(void) {"," gl_FragColor.r = texture2D(uSampler, vTextureCoord + red/dimensions.xy).r;"," gl_FragColor.g = texture2D(uSampler, vTextureCoord + green/dimensions.xy).g;"," gl_FragColor.b = texture2D(uSampler, vTextureCoord + blue/dimensions.xy).b;"," gl_FragColor.a = texture2D(uSampler, vTextureCoord).a;","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{red:{get:function(){return this.uniforms.red.value},set:function(t){this.uniforms.red.value=t}},green:{get:function(){return this.uniforms.green.value},set:function(t){this.uniforms.green.value=t}},blue:{get:function(){return this.uniforms.blue.value},set:function(t){this.uniforms.blue.value=t}}})},{"./AbstractFilter":56}],75:[function(t,e){function i(){r.call(this),this.uniforms={sepia:{type:"1f",value:1}},this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying vec4 vColor;","uniform float sepia;","uniform sampler2D uSampler;","const mat3 sepiaMatrix = mat3(0.3588, 0.7044, 0.1368, 0.2990, 0.5870, 0.1140, 0.2392, 0.4696, 0.0912);","void main(void) {"," gl_FragColor = texture2D(uSampler, vTextureCoord);"," gl_FragColor.rgb = mix( gl_FragColor.rgb, gl_FragColor.rgb * sepiaMatrix, sepia);","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{sepia:{get:function(){return this.uniforms.sepia.value},set:function(t){this.uniforms.sepia.value=t}}})},{"./AbstractFilter":56}],76:[function(t,e){function i(){r.call(this),this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","uniform sampler2D uSampler;","const vec2 delta = vec2(1.0/10.0, 0.0);","float random(vec3 scale, float seed) {"," return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);","}","void main(void) {"," vec4 color = vec4(0.0);"," float total = 0.0;"," float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);"," for (float t = -30.0; t <= 30.0; t++) {"," float percent = (t + offset - 0.5) / 30.0;"," float weight = 1.0 - abs(percent);"," vec4 sample = texture2D(uSampler, vTextureCoord + delta * percent);"," sample.rgb *= sample.a;"," color += sample * weight;"," total += weight;"," }"," gl_FragColor = color / total;"," gl_FragColor.rgb /= gl_FragColor.a + 0.00001;","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i},{"./AbstractFilter":56}],77:[function(t,e){function i(){r.call(this),this.tiltShiftXFilter=new n,this.tiltShiftYFilter=new s,this.tiltShiftXFilter.updateDelta(),this.tiltShiftXFilter.updateDelta(),this.passes=[this.tiltShiftXFilter,this.tiltShiftYFilter]}var r=t("./AbstractFilter"),n=t("./TiltShiftXFilter"),s=t("./TiltShiftYFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{blur:{get:function(){return this.tiltShiftXFilter.blur},set:function(t){this.tiltShiftXFilter.blur=this.tiltShiftYFilter.blur=t}},gradientBlur:{get:function(){return this.tiltShiftXFilter.gradientBlur},set:function(t){this.tiltShiftXFilter.gradientBlur=this.tiltShiftYFilter.gradientBlur=t}},start:{get:function(){return this.tiltShiftXFilter.start},set:function(t){this.tiltShiftXFilter.start=this.tiltShiftYFilter.start=t}},end:{get:function(){return this.tiltShiftXFilter.end},set:function(t){this.tiltShiftXFilter.end=this.tiltShiftYFilter.end=t}}})},{"./AbstractFilter":56,"./TiltShiftXFilter":78,"./TiltShiftYFilter":79}],78:[function(t,e){function i(){r.call(this),this.uniforms={blur:{type:"1f",value:100},gradientBlur:{type:"1f",value:600},start:{type:"2f",value:{x:0,y:window.screenHeight/2}},end:{type:"2f",value:{x:600,y:window.screenHeight/2}},delta:{type:"2f",value:{x:30,y:30}},texSize:{type:"2f",value:{x:window.screenWidth,y:window.screenHeight}}},this.updateDelta(),this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","uniform sampler2D uSampler;","uniform float blur;","uniform float gradientBlur;","uniform vec2 start;","uniform vec2 end;","uniform vec2 delta;","uniform vec2 texSize;","float random(vec3 scale, float seed) {"," return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);","}","void main(void) {"," vec4 color = vec4(0.0);"," float total = 0.0;"," float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);"," vec2 normal = normalize(vec2(start.y - end.y, end.x - start.x));"," float radius = smoothstep(0.0, 1.0, abs(dot(vTextureCoord * texSize - start, normal)) / gradientBlur) * blur;"," for (float t = -30.0; t <= 30.0; t++) {"," float percent = (t + offset - 0.5) / 30.0;"," float weight = 1.0 - abs(percent);"," vec4 sample = texture2D(uSampler, vTextureCoord + delta / texSize * percent * radius);"," sample.rgb *= sample.a;"," color += sample * weight;"," total += weight;"," }"," gl_FragColor = color / total;"," gl_FragColor.rgb /= gl_FragColor.a + 0.00001;","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,i.prototype.updateDelta=function(){var t=this.uniforms.end.value.x-this.uniforms.start.value.x,e=this.uniforms.end.value.y-this.uniforms.start.value.y,i=Math.sqrt(t*t+e*e);this.uniforms.delta.value.x=t/i,this.uniforms.delta.value.y=e/i},Object.defineProperties(i.prototype,{blur:{get:function(){return this.uniforms.blur.value},set:function(t){this.uniforms.blur.value=t}},gradientBlur:{get:function(){return this.uniforms.gradientBlur.value},set:function(t){this.uniforms.gradientBlur.value=t}},start:{get:function(){return this.uniforms.start.value},set:function(t){this.uniforms.start.value=t,this.updateDelta()}},end:{get:function(){return this.uniforms.end.value},set:function(t){this.uniforms.end.value=t,this.updateDelta()}}})},{"./AbstractFilter":56}],79:[function(t,e){function i(){r.call(this),this.uniforms={blur:{type:"1f",value:100},gradientBlur:{type:"1f",value:600},start:{type:"2f",value:{x:0,y:window.screenHeight/2}},end:{type:"2f",value:{x:600,y:window.screenHeight/2}},delta:{type:"2f",value:{x:30,y:30}},texSize:{type:"2f",value:{x:window.screenWidth,y:window.screenHeight}}},this.updateDelta(),this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","uniform sampler2D uSampler;","uniform float blur;","uniform float gradientBlur;","uniform vec2 start;","uniform vec2 end;","uniform vec2 delta;","uniform vec2 texSize;","float random(vec3 scale, float seed) {"," return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed);","}","void main(void) {"," vec4 color = vec4(0.0);"," float total = 0.0;"," float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0);"," vec2 normal = normalize(vec2(start.y - end.y, end.x - start.x));"," float radius = smoothstep(0.0, 1.0, abs(dot(vTextureCoord * texSize - start, normal)) / gradientBlur) * blur;"," for (float t = -30.0; t <= 30.0; t++) {"," float percent = (t + offset - 0.5) / 30.0;"," float weight = 1.0 - abs(percent);"," vec4 sample = texture2D(uSampler, vTextureCoord + delta / texSize * percent * radius);"," sample.rgb *= sample.a;"," color += sample * weight;"," total += weight;"," }"," gl_FragColor = color / total;"," gl_FragColor.rgb /= gl_FragColor.a + 0.00001;","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,i.prototype.updateDelta=function(){var t=this.uniforms.end.value.x-this.uniforms.start.value.x,e=this.uniforms.end.value.y-this.uniforms.start.value.y,i=Math.sqrt(t*t+e*e);this.uniforms.delta.value.x=-e/i,this.uniforms.delta.value.y=t/i},Object.defineProperties(i.prototype,{blur:{get:function(){return this.uniforms.blur.value},set:function(t){this.uniforms.blur.value=t}},gradientBlur:{get:function(){return this.uniforms.gradientBlur.value},set:function(t){this.uniforms.gradientBlur.value=t}},start:{get:function(){return this.uniforms.start.value},set:function(t){this.uniforms.start.value=t,this.updateDelta()}},end:{get:function(){return this.uniforms.end.value},set:function(t){this.uniforms.end.value=t,this.updateDelta()}}})},{"./AbstractFilter":56}],80:[function(t,e){function i(){r.call(this),this.uniforms={radius:{type:"1f",value:.5},angle:{type:"1f",value:5},offset:{type:"2f",value:{x:.5,y:.5}}},this.fragmentSrc=["precision mediump float;","varying vec2 vTextureCoord;","varying vec4 vColor;","uniform float radius;","uniform float angle;","uniform vec2 offset;","uniform sampler2D uSampler;","void main(void) {"," vec2 coord = vTextureCoord - offset;"," float distance = length(coord);"," if (distance < radius) {"," float ratio = (radius - distance) / radius;"," float angleMod = ratio * ratio * angle;"," float s = sin(angleMod);"," float c = cos(angleMod);"," coord = vec2(coord.x * c - coord.y * s, coord.x * s + coord.y * c);"," }"," gl_FragColor = texture2D(uSampler, coord+offset);","}"]}var r=t("./AbstractFilter");i.prototype=Object.create(r.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{offset:{get:function(){return this.uniforms.offset.value},set:function(t){this.uniforms.offset.value=t}},radius:{get:function(){return this.uniforms.radius.value},set:function(t){this.uniforms.radius.value=t}},angle:{get:function(){return this.uniforms.angle.value},set:function(t){this.uniforms.angle.value=t}}})},{"./AbstractFilter":56}],81:[function(t,e){e.exports={AbstractFilter:t("./AbstractFilter"),AlphaMaskFilter:t("./AlphaMaskFilter"),AsciiFilter:t("./AsciiFilter"),BlurFilter:t("./BlurFilter"),BlurXFilter:t("./BlurXFilter"),BlurYFilter:t("./BlurYFilter"),ColorMatrixFilter:t("./ColorMatrixFilter"),ColorStepFilter:t("./ColorStepFilter"),ConvolutionFilter:t("./ConvolutionFilter"),CrossHatchFilter:t("./CrossHatchFilter"),DisplacementFilter:t("./DisplacementFilter"),DotScreenFilter:t("./DotScreenFilter"),FilterBlock:t("./FilterBlock"),GrayFilter:t("./GrayFilter"),InvertFilter:t("./InvertFilter"),NoiseFilter:t("./NoiseFilter"),NormalMapFilter:t("./NormalMapFilter"),PixelateFilter:t("./PixelateFilter"),RGBSplitFilter:t("./RGBSplitFilter"),SepiaFilter:t("./SepiaFilter"),SmartBlurFilter:t("./SmartBlurFilter"),TiltShiftFilter:t("./TiltShiftFilter"),TiltShiftXFilter:t("./TiltShiftXFilter"),TiltShiftYFilter:t("./TiltShiftYFilter"),TwistFilter:t("./TwistFilter")}},{"./AbstractFilter":56,"./AlphaMaskFilter":57,"./AsciiFilter":58,"./BlurFilter":59,"./BlurXFilter":60,"./BlurYFilter":61,"./ColorMatrixFilter":62,"./ColorStepFilter":63,"./ConvolutionFilter":64,"./CrossHatchFilter":65,"./DisplacementFilter":66,"./DotScreenFilter":67,"./FilterBlock":68,"./GrayFilter":69,"./InvertFilter":70,"./NoiseFilter":71,"./NormalMapFilter":72,"./PixelateFilter":73,"./RGBSplitFilter":74,"./SepiaFilter":75,"./SmartBlurFilter":76,"./TiltShiftFilter":77,"./TiltShiftXFilter":78,"./TiltShiftYFilter":79,"./TwistFilter":80}],82:[function(t,e){function i(){this.global=new r.math.Point,this.target=null,this.originalEvent=null}var r=t("../core");i.prototype.constructor=i,e.exports=i,i.prototype.getLocalPosition=function(t,e){var i=t.worldTransform,n=this.global,s=i.a,o=i.c,a=i.tx,h=i.b,l=i.d,u=i.ty,c=1/(s*l+o*-h);return e=e||new r.math.Point,e.x=l*c*n.x+-o*c*n.y+(u*o-a*l)*c,e.y=s*c*n.y+-h*c*n.x+(-u*s+a*h)*c,e}},{"../core":9}],83:[function(t,e){function i(t){this.stage=t,this.mouse=new n,this.touches={},this.tempPoint=new r.math.Point,this.mouseoverEnabled=!0,this.pool=[],this.interactiveItems=[],this.interactionDOMElement=null,this.eventsAdded=!1,this.onMouseMove=this.onMouseMove.bind(this),this.onMouseDown=this.onMouseDown.bind(this),this.onMouseOut=this.onMouseOut.bind(this),this.onMouseUp=this.onMouseUp.bind(this),this.onTouchStart=this.onTouchStart.bind(this),this.onTouchEnd=this.onTouchEnd.bind(this),this.onTouchMove=this.onTouchMove.bind(this),this.last=0,this.currentCursorStyle="inherit",this.mouseOut=!1,this.resolution=1,this._tempPoint=new r.math.Point}var r=t("../core"),n=t("./InteractionData"),s=30,o=!0;i.prototype.constructor=i,e.exports=i,i.prototype.collectInteractiveSprite=function(t,e){for(var i=t.children,r=i.length,n=r-1;n>=0;n--){var s=i[n];s._interactive?(e.interactiveChildren=!0,this.interactiveItems.push(s),s.children.length>0&&this.collectInteractiveSprite(s,s)):(s.__iParent=null,s.children.length>0&&this.collectInteractiveSprite(s,e))}},i.prototype.setTargetElement=function(t,e){this.removeEvents(),this.interactionDOMElement=t,this.resolution=e||1,this.addEvents()},i.prototype.addEvents=function(){this.interactionDOMElement&&(window.navigator.msPointerEnabled&&(this.interactionDOMElement.style["-ms-content-zooming"]="none",this.interactionDOMElement.style["-ms-touch-action"]="none"),this.interactionDOMElement.addEventListener("mousemove",this.onMouseMove,!0),this.interactionDOMElement.addEventListener("mousedown",this.onMouseDown,!0),this.interactionDOMElement.addEventListener("mouseout",this.onMouseOut,!0),this.interactionDOMElement.addEventListener("touchstart",this.onTouchStart,!0),this.interactionDOMElement.addEventListener("touchend",this.onTouchEnd,!0),this.interactionDOMElement.addEventListener("touchmove",this.onTouchMove,!0),window.addEventListener("mouseup",this.onMouseUp,!0),this.eventsAdded=!0)},i.prototype.removeEvents=function(){this.interactionDOMElement&&(window.navigator.msPointerEnabled&&(this.interactionDOMElement.style["-ms-content-zooming"]="",this.interactionDOMElement.style["-ms-touch-action"]=""),this.interactionDOMElement.removeEventListener("mousemove",this.onMouseMove,!0),this.interactionDOMElement.removeEventListener("mousedown",this.onMouseDown,!0),this.interactionDOMElement.removeEventListener("mouseout",this.onMouseOut,!0),this.interactionDOMElement.removeEventListener("touchstart",this.onTouchStart,!0),this.interactionDOMElement.removeEventListener("touchend",this.onTouchEnd,!0),this.interactionDOMElement.removeEventListener("touchmove",this.onTouchMove,!0),this.interactionDOMElement=null,window.removeEventListener("mouseup",this.onMouseUp,!0),this.eventsAdded=!1)},i.prototype.update=function(){if(this.interactionDOMElement){var t=Date.now(),e=t-this.last;if(e=e*s/1e3,!(1>e)){this.last=t;var i=0;this.dirty&&this.rebuildInteractiveGraph();var r=this.interactiveItems.length,n="inherit",o=!1;for(i=0;r>i;i++){var a=this.interactiveItems[i];a.__hit=this.hitTest(a,this.mouse),this.mouse.target=a,a.__hit&&!o?(a.buttonMode&&(n=a.defaultCursor),a.interactiveChildren||(o=!0),a.__isOver||(a.mouseover&&a.mouseover(this.mouse),a.__isOver=!0)):a.__isOver&&(a.mouseout&&a.mouseout(this.mouse),a.__isOver=!1)}this.currentCursorStyle!==n&&(this.currentCursorStyle=n,this.interactionDOMElement.style.cursor=n)}}},i.prototype.rebuildInteractiveGraph=function(){this.dirty=!1;for(var t=this.interactiveItems.length,e=0;t>e;e++)this.interactiveItems[e].interactiveChildren=!1;this.interactiveItems.length=0,this.stage.interactive&&this.interactiveItems.push(this.stage),this.collectInteractiveSprite(this.stage,this.stage)},i.prototype.onMouseMove=function(t){this.dirty&&this.rebuildInteractiveGraph(),this.mouse.originalEvent=t;var e=this.interactionDOMElement.getBoundingClientRect();this.mouse.global.x=(t.clientX-e.left)*(this.interactionDOMElement.width/e.width)/this.resolution,this.mouse.global.y=(t.clientY-e.top)*(this.interactionDOMElement.height/e.height)/this.resolution;for(var i=this.interactiveItems.length,r=0;i>r;r++){var n=this.interactiveItems[r];n.mousemove&&n.mousemove(this.mouse)}},i.prototype.onMouseDown=function(t){this.dirty&&this.rebuildInteractiveGraph(),this.mouse.originalEvent=t,o&&this.mouse.originalEvent.preventDefault();for(var e=this.interactiveItems.length,i=this.mouse.originalEvent,r=2===i.button||3===i.which,n=r?"rightdown":"mousedown",s=r?"rightclick":"click",a=r?"__rightIsDown":"__mouseIsDown",h=r?"__isRightDown":"__isDown",l=0;e>l;l++){var u=this.interactiveItems[l];if((u[n]||u[s])&&(u[a]=!0,u.__hit=this.hitTest(u,this.mouse),u.__hit&&(u[n]&&u[n](this.mouse),u[h]=!0,!u.interactiveChildren)))break}},i.prototype.onMouseOut=function(t){this.dirty&&this.rebuildInteractiveGraph(),this.mouse.originalEvent=t;var e=this.interactiveItems.length; -this.interactionDOMElement.style.cursor="inherit";for(var i=0;e>i;i++){var r=this.interactiveItems[i];r.__isOver&&(this.mouse.target=r,r.mouseout&&r.mouseout(this.mouse),r.__isOver=!1)}this.mouseOut=!0,this.mouse.global.x=-1e4,this.mouse.global.y=-1e4},i.prototype.onMouseUp=function(t){this.dirty&&this.rebuildInteractiveGraph(),this.mouse.originalEvent=t;for(var e=this.interactiveItems.length,i=!1,r=this.mouse.originalEvent,n=2===r.button||3===r.which,s=n?"rightup":"mouseup",o=n?"rightclick":"click",a=n?"rightupoutside":"mouseupoutside",h=n?"__isRightDown":"__isDown",l=0;e>l;l++){var u=this.interactiveItems[l];(u[o]||u[s]||u[a])&&(u.__hit=this.hitTest(u,this.mouse),u.__hit&&!i?(u[s]&&u[s](this.mouse),u[h]&&u[o]&&u[o](this.mouse),u.interactiveChildren||(i=!0)):u[h]&&u[a]&&u[a](this.mouse),u[h]=!1)}},i.prototype.hitTest=function(t,e){var i=e.global;if(!t.worldVisible)return!1;t.worldTransform.applyInverse(i,this._tempPoint);var n,s=this._tempPoint.x,o=this._tempPoint.y;if(e.target=t,t.hitArea&&t.hitArea.contains)return t.hitArea.contains(s,o);if(t instanceof r.Sprite){var a,h=t.texture.frame.width,l=t.texture.frame.height,u=-h*t.anchor.x;if(s>u&&u+h>s&&(a=-l*t.anchor.y,o>a&&a+l>o))return!0}else if(t instanceof r.Graphics){var c=t.graphicsData;for(n=0;nn;n++){var p=t.children[n],v=this.hitTest(p,e);if(v)return e.target=t,!0}return!1},i.prototype.onTouchMove=function(t){this.dirty&&this.rebuildInteractiveGraph();var e,i=this.interactionDOMElement.getBoundingClientRect(),r=t.changedTouches,n=0;for(n=0;nl;l++){var u=this.interactiveItems[l];if((u.touchstart||u.tap)&&(u.__hit=this.hitTest(u,a),u.__hit&&(u.touchstart&&u.touchstart(a),u.__isDown=!0,u.__touchData=u.__touchData||{},u.__touchData[s.identifier]=a,!u.interactiveChildren)))break}}},i.prototype.onTouchEnd=function(t){this.dirty&&this.rebuildInteractiveGraph();for(var e=this.interactionDOMElement.getBoundingClientRect(),i=t.changedTouches,r=0;rh;h++){var l=this.interactiveItems[h];l.__touchData&&l.__touchData[n.identifier]&&(l.__hit=this.hitTest(l,l.__touchData[n.identifier]),s.originalEvent=t,(l.touchend||l.tap)&&(l.__hit&&!o?(l.touchend&&l.touchend(s),l.__isDown&&l.tap&&l.tap(s),l.interactiveChildren||(o=!0)):l.__isDown&&l.touchendoutside&&l.touchendoutside(s),l.__isDown=!1),l.__touchData[n.identifier]=null)}this.pool.push(s),this.touches[n.identifier]=null}}},{"../core":9,"./InteractionData":82}],84:[function(t,e){e.exports={InteractionData:t("./InteractionData"),InteractionManager:t("./InteractionManager")}},{"./InteractionData":82,"./InteractionManager":83}],85:[function(t,e){function i(t,e){this.url=t,this.baseUrl=t.replace(/[^\/]*$/,""),this.crossorigin=e,this.loaded=!1}var r=t("../core"),n=t("./ImageLoader");i.prototype.constructor=i,e.exports=i,r.utils.eventTarget.mixin(i.prototype),i.prototype.load=function(){this.ajaxRequest=new r.utils.AjaxRequest,this.ajaxRequest.onreadystatechange=this.onAtlasLoaded.bind(this),this.ajaxRequest.open("GET",this.url,!0),this.ajaxRequest.overrideMimeType&&this.ajaxRequest.overrideMimeType("application/json"),this.ajaxRequest.send(null)},i.prototype.onAtlasLoaded=function(){if(4===this.ajaxRequest.readyState)if(200===this.ajaxRequest.status||-1===window.location.href.indexOf("http")){this.atlas={meta:{image:[]},frames:[]};var t=this.ajaxRequest.responseText.split(/\r?\n/),e=-3,i=0,s=null,o=!1,a=0,h=0,l=this.onLoaded.bind(this);for(a=0;a0){if(o===a)this.atlas.meta.image.push(t[a]),i=this.atlas.meta.image.length-1,this.atlas.frames.push({}),e=-3;else if(e>0)if(e%7===1)null!=s&&(this.atlas.frames[i][s.name]=s),s={name:t[a],frame:{}};else{var u=t[a].split(" ");if(e%7===3)s.frame.x=Number(u[1].replace(",","")),s.frame.y=Number(u[2]);else if(e%7===4)s.frame.w=Number(u[1].replace(",","")),s.frame.h=Number(u[2]);else if(e%7===5){var c={x:0,y:0,w:Number(u[1].replace(",","")),h:Number(u[2])};c.w>s.frame.w||c.h>s.frame.h?(s.trimmed=!0,s.realSize=c):s.trimmed=!1}}e++}if(null!=s&&(this.atlas.frames[i][s.name]=s),this.atlas.meta.image.length>0){for(this.images=[],h=0;hthis.currentImageId?(this.currentImageId++,this.images[this.currentImageId].load()):(this.loaded=!0,this.emit("loaded",{content:this}))},i.prototype.onError=function(){this.emit("error",{content:this})}},{"../core":9,"./ImageLoader":87}],86:[function(t,e){function i(t,e){this.url=t,this.crossorigin=e,this.baseUrl=t.replace(/[^\/]*$/,""),this.texture=null}var r=t("../core"),n=t("./ImageLoader");i.prototype.constructor=i,e.exports=i,r.utils.eventTarget.mixin(i.prototype),i.prototype.load=function(){this.ajaxRequest=new r.utils.AjaxRequest,this.ajaxRequest.onreadystatechange=this.onXMLLoaded.bind(this),this.ajaxRequest.open("GET",this.url,!0),this.ajaxRequest.overrideMimeType&&this.ajaxRequest.overrideMimeType("application/xml"),this.ajaxRequest.send(null)},i.prototype.onXMLLoaded=function(){if(4===this.ajaxRequest.readyState&&(200===this.ajaxRequest.status||-1===window.location.protocol.indexOf("http"))){var t=this.ajaxRequest.responseXML;if(!t||/MSIE 9/i.test(navigator.userAgent)||navigator.isCocoonJS)if("function"==typeof window.DOMParser){var e=new DOMParser;t=e.parseFromString(this.ajaxRequest.responseText,"text/xml")}else{var i=document.createElement("div");i.innerHTML=this.ajaxRequest.responseText,t=i}var s=this.baseUrl+t.getElementsByTagName("page")[0].getAttribute("file"),o=new n(s,this.crossorigin);this.texture=o.texture.baseTexture;var a={},h=t.getElementsByTagName("info")[0],l=t.getElementsByTagName("common")[0];a.font=h.getAttribute("face"),a.size=parseInt(h.getAttribute("size"),10),a.lineHeight=parseInt(l.getAttribute("lineHeight"),10),a.chars={};for(var u=t.getElementsByTagName("char"),c=0;ca;++a)for(var h=0;n>h;++h,++o){var l=new r.Texture(this.texture.baseTexture,new r.math.Rectangle(h*t,a*e,t,e));this.frames.push(l),i&&(r.utils.TextureCache[i+"-"+o]=l)}this.load()}},{"../core":9}],88:[function(t,e){function i(t,e){this.url=t,this.crossorigin=e,this.baseUrl=t.replace(/[^\/]*$/,""),this.loaded=!1}var r=t("../core"),n=t("../spine/SpineRuntime"),s=t("./ImageLoader"),o=t("./SpineTextureLoader");i.prototype.constructor=i,e.exports=i,r.utils.eventTarget.mixin(i.prototype),i.prototype.load=function(){window.XDomainRequest&&this.crossorigin?(this.ajaxRequest=new window.XDomainRequest,this.ajaxRequest.timeout=3e3,this.ajaxRequest.onerror=this.onError.bind(this),this.ajaxRequest.ontimeout=this.onError.bind(this),this.ajaxRequest.onprogress=function(){},this.ajaxRequest.onload=this.onJSONLoaded.bind(this)):(this.ajaxRequest=window.XMLHttpRequest?new window.XMLHttpRequest:new window.ActiveXObject("Microsoft.XMLHTTP"),this.ajaxRequest.onreadystatechange=this.onReadyStateChanged.bind(this)),this.ajaxRequest.open("GET",this.url,!0),this.ajaxRequest.send()},i.prototype.onReadyStateChanged=function(){4!==this.ajaxRequest.readyState||200!==this.ajaxRequest.status&&-1!==window.location.href.indexOf("http")||this.onJSONLoaded()},i.prototype.onJSONLoaded=function(){if(!this.ajaxRequest.responseText)return void this.onError();if(this.json=JSON.parse(this.ajaxRequest.responseText),this.json.frames){var t=this.baseUrl+this.json.meta.image,e=new s(t,this.crossorigin),a=this.json.frames;this.texture=e.texture.baseTexture,e.addEventListener("loaded",this.onLoaded.bind(this)),e.addEventListener("error",this.onError.bind(this));for(var h in a){var l=a[h].frame;if(l){var u=new r.math.Rectangle(l.x,l.y,l.w,l.h),c=u.clone(),d=null;if(a[h].trimmed){var f=a[h].sourceSize,p=a[h].spriteSourceSize;d=new r.math.Rectangle(p.x,p.y,f.w,f.h)}r.utils.TextureCache[h]=new r.Texture(this.texture,u,c,d)}}e.load()}else if(this.json.bones)if(r.utils.AnimCache[this.url])this.onLoaded();else{var v=this.url.substr(0,this.url.lastIndexOf("."))+".atlas",m=new i(v,this.crossorigin),g=this;m.onJSONLoaded=function(){if(!this.ajaxRequest.responseText)return void this.onError();var t=new o(this.url.substring(0,this.url.lastIndexOf("/"))),e=new n.Atlas(this.ajaxRequest.responseText,t),i=new n.AtlasAttachmentLoader(e),s=new n.SkeletonJson(i),a=s.readSkeletonData(g.json);r.utils.AnimCache[g.url]=a,g.spine=a,g.spineAtlas=e,g.spineAtlasLoader=m,t.loadingCount>0?t.addEventListener("loadedBaseTexture",function(t){t.content.content.loadingCount<=0&&g.onLoaded()}):g.onLoaded()},m.load()}else this.onLoaded()},i.prototype.onLoaded=function(){this.loaded=!0,this.dispatchEvent({type:"loaded",content:this})},i.prototype.onError=function(){this.dispatchEvent({type:"error",content:this})}},{"../core":9,"../spine/SpineRuntime":94,"./ImageLoader":87,"./SpineTextureLoader":90}],89:[function(t,e){function i(t,e){this.url=t,this.crossorigin=e,this.loaded=!1}var r=t("../core"),n=t("./JsonLoader");i.prototype.constructor=i,e.exports=i,r.utils.eventTarget.mixin(i.prototype),i.prototype.load=function(){var t=this,e=new n(this.url,this.crossorigin);e.on("loaded",function(e){t.json=e.data.content.json,t.onLoaded()}),e.load()},i.prototype.onLoaded=function(){this.loaded=!0,this.emit("loaded",{content:this})}},{"../core":9,"./JsonLoader":88}],90:[function(t,e){function i(t,e){this.basePath=t,this.crossorigin=e,this.loadingCount=0}var r=t("../core");i.prototype.constructor=i,e.exports=i,r.utils.eventTarget.mixin(i.prototype),i.prototype.load=function(t,e){if(t.rendererObject=r.BaseTexture.fromImage(this.basePath+"/"+e,this.crossorigin),!t.rendererObject.hasLoaded){var i=this;++i.loadingCount,t.rendererObject.addEventListener("loaded",function(){--i.loadingCount,i.dispatchEvent({type:"loadedBaseTexture",content:i})})}},i.prototype.unload=function(t){t.destroy(!0)}},{"../core":9}],91:[function(t,e){function i(t,e){this.url=t,this.crossorigin=e,this.baseUrl=t.replace(/[^\/]*$/,""),this.texture=null,this.frames={}}var r=t("../core"),n=t("./JsonLoader");i.prototype.constructor=i,e.exports=i,r.utils.eventTarget.mixin(i.prototype),i.prototype.load=function(){var t=this,e=new n(this.url,this.crossorigin);e.on("loaded",function(e){t.json=e.data.content.json,t.onLoaded()}),e.load()},i.prototype.onLoaded=function(){this.emit("loaded",{content:this})}},{"../core":9,"./JsonLoader":88}],92:[function(t,e){e.exports={AtlasLoader:t("./AtlasLoader"),BitmapFontLoader:t("./BitmapFontLoader"),ImageLoader:t("./ImageLoader"),JsonLoader:t("./JsonLoader"),SpineLoader:t("./SpineLoader"),SpriteSheetLoader:t("./SpriteSheetLoader")}},{"./AtlasLoader":85,"./BitmapFontLoader":86,"./ImageLoader":87,"./JsonLoader":88,"./SpineLoader":89,"./SpriteSheetLoader":91}],93:[function(t,e){function i(t){if(r.DisplayObjectContainer.call(this),this.spineData=r.utils.AnimCache[t],!this.spineData)throw new Error("Spine data must be preloaded using SpineLoader or AssetLoader: "+t);this.skeleton=new n.Skeleton(this.spineData),this.skeleton.updateWorldTransform(),this.stateData=new n.AnimationStateData(this.spineData),this.state=new n.AnimationState(this.stateData),this.slotContainers=[];for(var e=0,i=this.skeleton.drawOrder.length;i>e;e++){var s=this.skeleton.drawOrder[e],o=s.attachment,a=new r.DisplayObjectContainer;if(this.slotContainers.push(a),this.addChild(a),o instanceof n.RegionAttachment){var h=o.rendererObject.name,l=this.createSprite(s,o);s.currentSprite=l,s.currentSpriteName=h,a.addChild(l)}else{if(!(o instanceof n.MeshAttachment))continue;var u=this.createMesh(s,o);s.currentMesh=u,s.currentMeshName=o.name,a.addChild(u)}}this.autoUpdate=!0}var r=t("../core"),n=t("./SpineRuntime");n.Bone.yDown=!0,i.prototype=Object.create(r.DisplayObjectContainer.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{autoUpdate:{get:function(){return this.updateTransform===i.prototype.autoUpdateTransform},set:function(t){this.updateTransform=t?i.prototype.autoUpdateTransform:r.DisplayObjectContainer.prototype.updateTransform}}}),i.prototype.update=function(t){this.state.update(t),this.state.apply(this.skeleton),this.skeleton.updateWorldTransform();for(var e=this.skeleton.drawOrder,i=0,s=e.length;s>i;i++){var o=e[i],a=o.attachment,h=this.slotContainers[i];if(a){var l=a.type;if(l===n.AttachmentType.region){if(a.rendererObject&&(!o.currentSpriteName||o.currentSpriteName!==a.rendererObject.name)){var u=a.rendererObject.name;if(void 0!==o.currentSprite&&(o.currentSprite.visible=!1),o.sprites=o.sprites||{},void 0!==o.sprites[u])o.sprites[u].visible=!0;else{var c=this.createSprite(o,a);h.addChild(c)}o.currentSprite=o.sprites[u],o.currentSpriteName=u}var d=o.bone;h.position.x=d.worldX+a.x*d.m00+a.y*d.m01,h.position.y=d.worldY+a.x*d.m10+a.y*d.m11,h.scale.x=d.worldScaleX,h.scale.y=d.worldScaleY,h.rotation=-(o.bone.worldRotation*n.degRad),o.currentSprite.tint=r.utils.rgb2hex([o.r,o.g,o.b])}else{if(l!==n.AttachmentType.skinnedmesh){h.visible=!1;continue}if(!o.currentMeshName||o.currentMeshName!==a.name){var f=a.name;if(void 0!==o.currentMesh&&(o.currentMesh.visible=!1),o.meshes=o.meshes||{},void 0!==o.meshes[f])o.meshes[f].visible=!0;else{var p=this.createMesh(o,a);h.addChild(p)}o.currentMesh=o.meshes[f],o.currentMeshName=f}a.computeWorldVertices(o.bone.skeleton.x,o.bone.skeleton.y,o,o.currentMesh.vertices)}h.visible=!0,h.alpha=o.a}else h.visible=!1}},i.prototype.autoUpdateTransform=function(){this.lastTime=this.lastTime||Date.now();var t=.001*(Date.now()-this.lastTime);this.lastTime=Date.now(),this.update(t),r.DisplayObjectContainer.prototype.updateTransform.call(this)},i.prototype.createSprite=function(t,e){var i=e.rendererObject,s=i.page.rendererObject,o=new r.math.Rectangle(i.x,i.y,i.rotate?i.height:i.width,i.rotate?i.width:i.height),a=new r.Texture(s,o),h=new r.Sprite(a),l=i.rotate?.5*Math.PI:0;return h.scale.set(i.width/i.originalWidth,i.height/i.originalHeight),h.rotation=l-e.rotation*n.degRad,h.anchor.x=h.anchor.y=.5,t.sprites=t.sprites||{},t.sprites[i.name]=h,h},i.prototype.createMesh=function(t,e){var i=e.rendererObject,n=i.page.rendererObject,s=new r.Texture(n),o=new r.Strip(s);return o.drawMode=r.Strip.DrawModes.TRIANGLES,o.canvasPadding=1.5,o.vertices=new Float32Array(e.uvs.length),o.uvs=e.uvs,o.indices=e.triangles,t.meshes=t.meshes||{},t.meshes[e.name]=o,o}},{"../core":9,"./SpineRuntime":94}],94:[function(t,e){var i=e.exports={radDeg:180/Math.PI,degRad:Math.PI/180,temp:[],Float32Array:"undefined"==typeof Float32Array?Array:Float32Array,Uint16Array:"undefined"==typeof Uint16Array?Array:Uint16Array};i.BoneData=function(t,e){this.name=t,this.parent=e},i.BoneData.prototype={length:0,x:0,y:0,rotation:0,scaleX:1,scaleY:1,inheritScale:!0,inheritRotation:!0,flipX:!1,flipY:!1},i.SlotData=function(t,e){this.name=t,this.boneData=e},i.SlotData.prototype={r:1,g:1,b:1,a:1,attachmentName:null,additiveBlending:!1},i.IkConstraintData=function(t){this.name=t,this.bones=[]},i.IkConstraintData.prototype={target:null,bendDirection:1,mix:1},i.Bone=function(t,e,i){this.data=t,this.skeleton=e,this.parent=i,this.setToSetupPose()},i.Bone.yDown=!1,i.Bone.prototype={x:0,y:0,rotation:0,rotationIK:0,scaleX:1,scaleY:1,flipX:!1,flipY:!1,m00:0,m01:0,worldX:0,m10:0,m11:0,worldY:0,worldRotation:0,worldScaleX:1,worldScaleY:1,worldFlipX:!1,worldFlipY:!1,updateWorldTransform:function(){var t=this.parent;if(t)this.worldX=this.x*t.m00+this.y*t.m01+t.worldX,this.worldY=this.x*t.m10+this.y*t.m11+t.worldY,this.data.inheritScale?(this.worldScaleX=t.worldScaleX*this.scaleX,this.worldScaleY=t.worldScaleY*this.scaleY):(this.worldScaleX=this.scaleX,this.worldScaleY=this.scaleY),this.worldRotation=this.data.inheritRotation?t.worldRotation+this.rotationIK:this.rotationIK,this.worldFlipX=t.worldFlipX!=this.flipX,this.worldFlipY=t.worldFlipY!=this.flipY;else{var e=this.skeleton.flipX,r=this.skeleton.flipY;this.worldX=e?-this.x:this.x,this.worldY=r!=i.Bone.yDown?-this.y:this.y,this.worldScaleX=this.scaleX,this.worldScaleY=this.scaleY,this.worldRotation=this.rotationIK,this.worldFlipX=e!=this.flipX,this.worldFlipY=r!=this.flipY}var n=this.worldRotation*i.degRad,s=Math.cos(n),o=Math.sin(n);this.worldFlipX?(this.m00=-s*this.worldScaleX,this.m01=o*this.worldScaleY):(this.m00=s*this.worldScaleX,this.m01=-o*this.worldScaleY),this.worldFlipY!=i.Bone.yDown?(this.m10=-o*this.worldScaleX,this.m11=-s*this.worldScaleY):(this.m10=o*this.worldScaleX,this.m11=s*this.worldScaleY)},setToSetupPose:function(){var t=this.data;this.x=t.x,this.y=t.y,this.rotation=t.rotation,this.rotationIK=this.rotation,this.scaleX=t.scaleX,this.scaleY=t.scaleY,this.flipX=t.flipX,this.flipY=t.flipY},worldToLocal:function(t){var e=t[0]-this.worldX,r=t[1]-this.worldY,n=this.m00,s=this.m10,o=this.m01,a=this.m11;this.worldFlipX!=(this.worldFlipY!=i.Bone.yDown)&&(n=-n,a=-a);var h=1/(n*a-o*s);t[0]=e*n*h-r*o*h,t[1]=r*a*h-e*s*h},localToWorld:function(t){var e=t[0],i=t[1];t[0]=e*this.m00+i*this.m01+this.worldX,t[1]=e*this.m10+i*this.m11+this.worldY}},i.Slot=function(t,e){this.data=t,this.bone=e,this.setToSetupPose()},i.Slot.prototype={r:1,g:1,b:1,a:1,_attachmentTime:0,attachment:null,attachmentVertices:[],setAttachment:function(t){this.attachment=t,this._attachmentTime=this.bone.skeleton.time,this.attachmentVertices.length=0},setAttachmentTime:function(t){this._attachmentTime=this.bone.skeleton.time-t},getAttachmentTime:function(){return this.bone.skeleton.time-this._attachmentTime},setToSetupPose:function(){var t=this.data;this.r=t.r,this.g=t.g,this.b=t.b,this.a=t.a;for(var e=this.bone.skeleton.data.slots,i=0,r=e.length;r>i;i++)if(e[i]==t){this.setAttachment(t.attachmentName?this.bone.skeleton.getAttachmentBySlotIndex(i,t.attachmentName):null);break}}},i.IkConstraint=function(t,e){this.data=t,this.mix=t.mix,this.bendDirection=t.bendDirection,this.bones=[];for(var i=0,r=t.bones.length;r>i;i++)this.bones.push(e.findBone(t.bones[i].name));this.target=e.findBone(t.target.name)},i.IkConstraint.prototype={apply:function(){var t=this.target,e=this.bones;switch(e.length){case 1:i.IkConstraint.apply1(e[0],t.worldX,t.worldY,this.mix);break;case 2:i.IkConstraint.apply2(e[0],e[1],t.worldX,t.worldY,this.bendDirection,this.mix)}}},i.IkConstraint.apply1=function(t,e,r,n){var s=t.data.inheritRotation&&t.parent?t.parent.worldRotation:0,o=t.rotation,a=Math.atan2(r-t.worldY,e-t.worldX)*i.radDeg-s;t.rotationIK=o+(a-o)*n},i.IkConstraint.apply2=function(t,e,r,n,s,o){var a=e.rotation,h=t.rotation;if(!o)return e.rotationIK=a,void(t.rotationIK=h);var l,u,c=i.temp,d=t.parent;d?(c[0]=r,c[1]=n,d.worldToLocal(c),r=(c[0]-t.x)*d.worldScaleX,n=(c[1]-t.y)*d.worldScaleY):(r-=t.x,n-=t.y),e.parent==t?(l=e.x,u=e.y):(c[0]=e.x,c[1]=e.y,e.parent.localToWorld(c),t.worldToLocal(c),l=c[0],u=c[1]);var f=l*t.worldScaleX,p=u*t.worldScaleY,v=Math.atan2(p,f),m=Math.sqrt(f*f+p*p),g=e.data.length*e.worldScaleX,x=2*m*g;if(1e-4>x)return void(e.rotationIK=a+(Math.atan2(n,r)*i.radDeg-h-a)*o);var y=(r*r+n*n-m*m-g*g)/x;-1>y?y=-1:y>1&&(y=1);var b=Math.acos(y)*s,T=m+g*y,w=g*Math.sin(b),S=Math.atan2(n*T-r*w,r*T+n*w),A=(S-v)*i.radDeg-h;A>180?A-=360:-180>A&&(A+=360),t.rotationIK=h+A*o,A=(b+v)*i.radDeg-a,A>180?A-=360:-180>A&&(A+=360),e.rotationIK=a+(A+t.worldRotation-e.parent.worldRotation)*o},i.Skin=function(t){this.name=t,this.attachments={}},i.Skin.prototype={addAttachment:function(t,e,i){this.attachments[t+":"+e]=i},getAttachment:function(t,e){return this.attachments[t+":"+e]},_attachAll:function(t,e){for(var i in e.attachments){var r=i.indexOf(":"),n=parseInt(i.substring(0,r)),s=i.substring(r+1),o=t.slots[n];if(o.attachment&&o.attachment.name==s){var a=this.getAttachment(n,s);a&&o.setAttachment(a)}}}},i.Animation=function(t,e,i){this.name=t,this.timelines=e,this.duration=i},i.Animation.prototype={apply:function(t,e,i,r,n){r&&0!=this.duration&&(i%=this.duration,e%=this.duration);for(var s=this.timelines,o=0,a=s.length;a>o;o++)s[o].apply(t,e,i,n,1)},mix:function(t,e,i,r,n,s){r&&0!=this.duration&&(i%=this.duration,e%=this.duration);for(var o=this.timelines,a=0,h=o.length;h>a;a++)o[a].apply(t,e,i,n,s)}},i.Animation.binarySearch=function(t,e,i){var r=0,n=Math.floor(t.length/i)-2;if(!n)return i;for(var s=n>>>1;;){if(t[(s+1)*i]<=e?r=s+1:n=s,r==n)return(r+1)*i;s=r+n>>>1}},i.Animation.binarySearch1=function(t,e){var i=0,r=t.length-2;if(!r)return 1;for(var n=r>>>1;;){if(t[n+1]<=e?i=n+1:r=n,i==r)return i+1;n=i+r>>>1}},i.Animation.linearSearch=function(t,e,i){for(var r=0,n=t.length-i;n>=r;r+=i)if(t[r]>e)return r;return-1},i.Curves=function(){this.curves=[]},i.Curves.prototype={setLinear:function(t){this.curves[19*t]=0},setStepped:function(t){this.curves[19*t]=1},setCurve:function(t,e,i,r,n){var s=.1,o=s*s,a=o*s,h=3*s,l=3*o,u=6*o,c=6*a,d=2*-e+r,f=2*-i+n,p=3*(e-r)+1,v=3*(i-n)+1,m=e*h+d*l+p*a,g=i*h+f*l+v*a,x=d*u+p*c,y=f*u+v*c,b=p*c,T=v*c,w=19*t,S=this.curves;S[w++]=2;for(var A=m,_=g,C=w+19-1;C>w;w+=2)S[w]=A,S[w+1]=_,m+=x,g+=y,x+=b,y+=T,A+=m,_+=g},getCurvePercent:function(t,e){e=0>e?0:e>1?1:e;var i=this.curves,r=19*t,n=i[r];if(0===n)return e;if(1==n)return 0;r++;for(var s=0,o=r,a=r+19-1;a>r;r+=2)if(s=i[r],s>=e){var h,l;return r==o?(h=0,l=0):(h=i[r-2],l=i[r-1]),l+(i[r+1]-l)*(e-h)/(s-h)}var u=i[r-1];return u+(1-u)*(e-s)/(1-s)}},i.RotateTimeline=function(t){this.curves=new i.Curves(t),this.frames=[],this.frames.length=2*t},i.RotateTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/2},setFrame:function(t,e,i){t*=2,this.frames[t]=e,this.frames[t+1]=i},apply:function(t,e,r,n,s){var o=this.frames;if(!(r=o[o.length-2]){for(var h=a.data.rotation+o[o.length-1]-a.rotation;h>180;)h-=360;for(;-180>h;)h+=360;return void(a.rotation+=h*s)}var l=i.Animation.binarySearch(o,r,2),u=o[l-1],c=o[l],d=1-(r-c)/(o[l-2]-c);d=this.curves.getCurvePercent(l/2-1,d);for(var h=o[l+1]-u;h>180;)h-=360;for(;-180>h;)h+=360;for(h=a.data.rotation+(u+h*d)-a.rotation;h>180;)h-=360;for(;-180>h;)h+=360;a.rotation+=h*s}}},i.TranslateTimeline=function(t){this.curves=new i.Curves(t),this.frames=[],this.frames.length=3*t},i.TranslateTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/3},setFrame:function(t,e,i,r){t*=3,this.frames[t]=e,this.frames[t+1]=i,this.frames[t+2]=r},apply:function(t,e,r,n,s){var o=this.frames;if(!(r=o[o.length-3])return a.x+=(a.data.x+o[o.length-2]-a.x)*s,void(a.y+=(a.data.y+o[o.length-1]-a.y)*s);var h=i.Animation.binarySearch(o,r,3),l=o[h-2],u=o[h-1],c=o[h],d=1-(r-c)/(o[h+-3]-c);d=this.curves.getCurvePercent(h/3-1,d),a.x+=(a.data.x+l+(o[h+1]-l)*d-a.x)*s,a.y+=(a.data.y+u+(o[h+2]-u)*d-a.y)*s}}},i.ScaleTimeline=function(t){this.curves=new i.Curves(t),this.frames=[],this.frames.length=3*t},i.ScaleTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/3},setFrame:function(t,e,i,r){t*=3,this.frames[t]=e,this.frames[t+1]=i,this.frames[t+2]=r},apply:function(t,e,r,n,s){var o=this.frames;if(!(r=o[o.length-3])return a.scaleX+=(a.data.scaleX*o[o.length-2]-a.scaleX)*s,void(a.scaleY+=(a.data.scaleY*o[o.length-1]-a.scaleY)*s);var h=i.Animation.binarySearch(o,r,3),l=o[h-2],u=o[h-1],c=o[h],d=1-(r-c)/(o[h+-3]-c);d=this.curves.getCurvePercent(h/3-1,d),a.scaleX+=(a.data.scaleX*(l+(o[h+1]-l)*d)-a.scaleX)*s,a.scaleY+=(a.data.scaleY*(u+(o[h+2]-u)*d)-a.scaleY)*s}}},i.ColorTimeline=function(t){this.curves=new i.Curves(t),this.frames=[],this.frames.length=5*t},i.ColorTimeline.prototype={slotIndex:0,getFrameCount:function(){return this.frames.length/5},setFrame:function(t,e,i,r,n,s){t*=5,this.frames[t]=e,this.frames[t+1]=i,this.frames[t+2]=r,this.frames[t+3]=n,this.frames[t+4]=s},apply:function(t,e,r,n,s){var o=this.frames;if(!(r=o[o.length-5]){var c=o.length-1;a=o[c-3],h=o[c-2],l=o[c-1],u=o[c]}else{var d=i.Animation.binarySearch(o,r,5),f=o[d-4],p=o[d-3],v=o[d-2],m=o[d-1],g=o[d],x=1-(r-g)/(o[d-5]-g);x=this.curves.getCurvePercent(d/5-1,x),a=f+(o[d+1]-f)*x,h=p+(o[d+2]-p)*x,l=v+(o[d+3]-v)*x,u=m+(o[d+4]-m)*x}var y=t.slots[this.slotIndex];1>s?(y.r+=(a-y.r)*s,y.g+=(h-y.g)*s,y.b+=(l-y.b)*s,y.a+=(u-y.a)*s):(y.r=a,y.g=h,y.b=l,y.a=u)}}},i.AttachmentTimeline=function(t){this.curves=new i.Curves(t),this.frames=[],this.frames.length=t,this.attachmentNames=[],this.attachmentNames.length=t},i.AttachmentTimeline.prototype={slotIndex:0,getFrameCount:function(){return this.frames.length},setFrame:function(t,e,i){this.frames[t]=e,this.attachmentNames[t]=i},apply:function(t,e,r){var n=this.frames;if(rr&&this.apply(t,e,Number.MAX_VALUE,null,0));e>r&&(e=-1);var s=r>=n[n.length-1]?n.length-1:i.Animation.binarySearch1(n,r)-1;if(!(n[s]r)this.apply(t,e,Number.MAX_VALUE,n,s),e=-1;else if(e>=o[a-1])return;if(!(r0&&o[h-1]==l;)h--}for(var u=this.events;a>h&&r>=o[h];h++)n.push(u[h])}}}},i.DrawOrderTimeline=function(t){this.frames=[],this.frames.length=t,this.drawOrders=[],this.drawOrders.length=t},i.DrawOrderTimeline.prototype={getFrameCount:function(){return this.frames.length},setFrame:function(t,e,i){this.frames[t]=e,this.drawOrders[t]=i},apply:function(t,e,r){var n=this.frames;if(!(r=n[n.length-1]?n.length-1:i.Animation.binarySearch1(n,r)-1;var o=t.drawOrder,a=t.slots,h=this.drawOrders[s];if(h)for(var l=0,u=h.length;u>l;l++)o[l]=t.slots[h[l]];else for(var l=0,u=a.length;u>l;l++)o[l]=a[l]}}},i.FfdTimeline=function(t){this.curves=new i.Curves(t),this.frames=[],this.frames.length=t,this.frameVertices=[],this.frameVertices.length=t},i.FfdTimeline.prototype={slotIndex:0,attachment:0,getFrameCount:function(){return this.frames.length},setFrame:function(t,e,i){this.frames[t]=e,this.frameVertices[t]=i},apply:function(t,e,r,n,s){var o=t.slots[this.slotIndex];if(o.attachment==this.attachment){var a=this.frames;if(!(r=a[a.length-1]){var c=h[a.length-1];if(1>s)for(var d=0;l>d;d++)u[d]+=(c[d]-u[d])*s;else for(var d=0;l>d;d++)u[d]=c[d]}else{var f=i.Animation.binarySearch1(a,r),p=a[f],v=1-(r-p)/(a[f-1]-p);v=this.curves.getCurvePercent(f-1,0>v?0:v>1?1:v);var m=h[f-1],g=h[f];if(1>s)for(var d=0;l>d;d++){var x=m[d];u[d]+=(x+(g[d]-x)*v-u[d])*s}else for(var d=0;l>d;d++){var x=m[d];u[d]=x+(g[d]-x)*v}}}}}},i.IkConstraintTimeline=function(t){this.curves=new i.Curves(t),this.frames=[],this.frames.length=3*t},i.IkConstraintTimeline.prototype={ikConstraintIndex:0,getFrameCount:function(){return this.frames.length/3},setFrame:function(t,e,i,r){t*=3,this.frames[t]=e,this.frames[t+1]=i,this.frames[t+2]=r},apply:function(t,e,r,n,s){var o=this.frames;if(!(r=o[o.length-3])return a.mix+=(o[o.length-2]-a.mix)*s,void(a.bendDirection=o[o.length-1]);var h=i.Animation.binarySearch(o,r,3),l=o[h+-2],u=o[h],c=1-(r-u)/(o[h+-3]-u);c=this.curves.getCurvePercent(h/3-1,c);var d=l+(o[h+1]-l)*c;a.mix+=(d-a.mix)*s,a.bendDirection=o[h+-1]}}},i.FlipXTimeline=function(t){this.curves=new i.Curves(t),this.frames=[],this.frames.length=2*t},i.FlipXTimeline.prototype={boneIndex:0,getFrameCount:function(){return this.frames.length/2},setFrame:function(t,e,i){t*=2,this.frames[t]=e,this.frames[t+1]=i?1:0},apply:function(t,e,r){var n=this.frames;if(rr&&this.apply(t,e,Number.MAX_VALUE,null,0));e>r&&(e=-1);var s=(r>=n[n.length-2]?n.length:i.Animation.binarySearch(n,r,2))-2;n[s]r&&this.apply(t,e,Number.MAX_VALUE,null,0));e>r&&(e=-1);var s=(r>=n[n.length-2]?n.length:i.Animation.binarySearch(n,r,2))-2;n[s]i;i++)if(e[i].name==t)return e[i];return null},findBoneIndex:function(t){for(var e=this.bones,i=0,r=e.length;r>i;i++)if(e[i].name==t)return i;return-1},findSlot:function(t){for(var e=this.slots,i=0,r=e.length;r>i;i++)if(e[i].name==t)return slot[i];return null},findSlotIndex:function(t){for(var e=this.slots,i=0,r=e.length;r>i;i++)if(e[i].name==t)return i;return-1},findSkin:function(t){for(var e=this.skins,i=0,r=e.length;r>i;i++)if(e[i].name==t)return e[i];return null},findEvent:function(t){for(var e=this.events,i=0,r=e.length;r>i;i++)if(e[i].name==t)return e[i];return null},findAnimation:function(t){for(var e=this.animations,i=0,r=e.length;r>i;i++)if(e[i].name==t)return e[i];return null},findIkConstraint:function(t){for(var e=this.ikConstraints,i=0,r=e.length;r>i;i++)if(e[i].name==t)return e[i];return null}},i.Skeleton=function(t){this.data=t,this.bones=[];for(var e=0,r=t.bones.length;r>e;e++){var n=t.bones[e],s=n.parent?this.bones[t.bones.indexOf(n.parent)]:null;this.bones.push(new i.Bone(n,this,s))}this.slots=[],this.drawOrder=[];for(var e=0,r=t.slots.length;r>e;e++){var o=t.slots[e],a=this.bones[t.bones.indexOf(o.boneData)],h=new i.Slot(o,a);this.slots.push(h),this.drawOrder.push(h)}this.ikConstraints=[];for(var e=0,r=t.ikConstraints.length;r>e;e++)this.ikConstraints.push(new i.IkConstraint(t.ikConstraints[e],this));this.boneCache=[],this.updateCache()},i.Skeleton.prototype={x:0,y:0,skin:null,r:1,g:1,b:1,a:1,time:0,flipX:!1,flipY:!1,updateCache:function(){var t=this.ikConstraints,e=t.length,i=e+1,r=this.boneCache;r.length>i&&(r.length=i);for(var n=0,s=r.length;s>n;n++)r[n].length=0;for(;r.lengthn;n++){var h=a[n],l=h;do{for(var u=0;e>u;u++)for(var c=t[u],d=c.bones[0],f=c.bones[c.bones.length-1];;){if(l==f){r[u].push(h),r[u+1].push(h);continue t}if(f==d)break;f=f.parent}l=l.parent}while(l);o[o.length]=h}},updateWorldTransform:function(){for(var t=this.bones,e=0,i=t.length;i>e;e++){var r=t[e];r.rotationIK=r.rotation}for(var e=0,n=this.boneCache.length-1;;){for(var s=this.boneCache[e],o=0,a=s.length;a>o;o++)s[o].updateWorldTransform();if(e==n)break;this.ikConstraints[e].apply(),e++}},setToSetupPose:function(){this.setBonesToSetupPose(),this.setSlotsToSetupPose()},setBonesToSetupPose:function(){for(var t=this.bones,e=0,i=t.length;i>e;e++)t[e].setToSetupPose();for(var r=this.ikConstraints,e=0,i=r.length;i>e;e++){var n=r[e];n.bendDirection=n.data.bendDirection,n.mix=n.data.mix}},setSlotsToSetupPose:function(){for(var t=this.slots,e=this.drawOrder,i=0,r=t.length;r>i;i++)e[i]=t[i],t[i].setToSetupPose(i)},getRootBone:function(){return this.bones.length?this.bones[0]:null},findBone:function(t){for(var e=this.bones,i=0,r=e.length;r>i;i++)if(e[i].data.name==t)return e[i];return null},findBoneIndex:function(t){for(var e=this.bones,i=0,r=e.length;r>i;i++)if(e[i].data.name==t)return i;return-1},findSlot:function(t){for(var e=this.slots,i=0,r=e.length;r>i;i++)if(e[i].data.name==t)return e[i];return null},findSlotIndex:function(t){for(var e=this.slots,i=0,r=e.length;r>i;i++)if(e[i].data.name==t)return i;return-1},setSkinByName:function(t){var e=this.data.findSkin(t);if(!e)throw"Skin not found: "+t;this.setSkin(e)},setSkin:function(t){if(t)if(this.skin)t._attachAll(this,this.skin);else for(var e=this.slots,i=0,r=e.length;r>i;i++){var n=e[i],s=n.data.attachmentName;if(s){var o=t.getAttachment(i,s);o&&n.setAttachment(o)}}this.skin=t},getAttachmentBySlotName:function(t,e){return this.getAttachmentBySlotIndex(this.data.findSlotIndex(t),e)},getAttachmentBySlotIndex:function(t,e){if(this.skin){var i=this.skin.getAttachment(t,e);if(i)return i}return this.data.defaultSkin?this.data.defaultSkin.getAttachment(t,e):null},setAttachment:function(t,e){for(var i=this.slots,r=0,n=i.length;n>r;r++){var s=i[r];if(s.data.name==t){var o=null;if(e&&(o=this.getAttachmentBySlotIndex(r,e),!o))throw"Attachment not found: "+e+", for slot: "+t;return void s.setAttachment(o)}}throw"Slot not found: "+t},findIkConstraint:function(t){for(var e=this.ikConstraints,i=0,r=e.length;r>i;i++)if(e[i].data.name==t)return e[i];return null},update:function(t){this.time+=t}},i.EventData=function(t){this.name=t},i.EventData.prototype={intValue:0,floatValue:0,stringValue:null},i.Event=function(t){this.data=t},i.Event.prototype={intValue:0,floatValue:0,stringValue:null},i.AttachmentType={region:0,boundingbox:1,mesh:2,skinnedmesh:3},i.RegionAttachment=function(t){this.name=t,this.offset=[],this.offset.length=8,this.uvs=[],this.uvs.length=8},i.RegionAttachment.prototype={type:i.AttachmentType.region,x:0,y:0,rotation:0,scaleX:1,scaleY:1,width:0,height:0,r:1,g:1,b:1,a:1,path:null,rendererObject:null,regionOffsetX:0,regionOffsetY:0,regionWidth:0,regionHeight:0,regionOriginalWidth:0,regionOriginalHeight:0,setUVs:function(t,e,i,r,n){var s=this.uvs;n?(s[2]=t,s[3]=r,s[4]=t,s[5]=e,s[6]=i,s[7]=e,s[0]=i,s[1]=r):(s[0]=t,s[1]=r,s[2]=t,s[3]=e,s[4]=i,s[5]=e,s[6]=i,s[7]=r)},updateOffset:function(){var t=this.width/this.regionOriginalWidth*this.scaleX,e=this.height/this.regionOriginalHeight*this.scaleY,r=-this.width/2*this.scaleX+this.regionOffsetX*t,n=-this.height/2*this.scaleY+this.regionOffsetY*e,s=r+this.regionWidth*t,o=n+this.regionHeight*e,a=this.rotation*i.degRad,h=Math.cos(a),l=Math.sin(a),u=r*h+this.x,c=r*l,d=n*h+this.y,f=n*l,p=s*h+this.x,v=s*l,m=o*h+this.y,g=o*l,x=this.offset;x[0]=u-f,x[1]=d+c,x[2]=u-g,x[3]=m+c,x[4]=p-g,x[5]=m+v,x[6]=p-f,x[7]=d+v},computeVertices:function(t,e,i,r){t+=i.worldX,e+=i.worldY;var n=i.m00,s=i.m01,o=i.m10,a=i.m11,h=this.offset;r[0]=h[0]*n+h[1]*s+t,r[1]=h[0]*o+h[1]*a+e,r[2]=h[2]*n+h[3]*s+t,r[3]=h[2]*o+h[3]*a+e,r[4]=h[4]*n+h[5]*s+t,r[5]=h[4]*o+h[5]*a+e,r[6]=h[6]*n+h[7]*s+t,r[7]=h[6]*o+h[7]*a+e}},i.MeshAttachment=function(t){this.name=t},i.MeshAttachment.prototype={type:i.AttachmentType.mesh,vertices:null,uvs:null,regionUVs:null,triangles:null,hullLength:0,r:1,g:1,b:1,a:1,path:null,rendererObject:null,regionU:0,regionV:0,regionU2:0,regionV2:0,regionRotate:!1,regionOffsetX:0,regionOffsetY:0,regionWidth:0,regionHeight:0,regionOriginalWidth:0,regionOriginalHeight:0,edges:null,width:0,height:0,updateUVs:function(){var t=this.regionU2-this.regionU,e=this.regionV2-this.regionV,r=this.regionUVs.length;if(this.uvs&&this.uvs.length==r||(this.uvs=new i.Float32Array(r)),this.regionRotate)for(var n=0;r>n;n+=2)this.uvs[n]=this.regionU+this.regionUVs[n+1]*t,this.uvs[n+1]=this.regionV+e-this.regionUVs[n]*e;else for(var n=0;r>n;n+=2)this.uvs[n]=this.regionU+this.regionUVs[n]*t,this.uvs[n+1]=this.regionV+this.regionUVs[n+1]*e},computeWorldVertices:function(t,e,i,r){var n=i.bone;t+=n.worldX,e+=n.worldY;var s=n.m00,o=n.m01,a=n.m10,h=n.m11,l=this.vertices,u=l.length;i.attachmentVertices.length==u&&(l=i.attachmentVertices);for(var c=0;u>c;c+=2){var d=l[c],f=l[c+1];r[c]=d*s+f*o+t,r[c+1]=d*a+f*h+e}}},i.SkinnedMeshAttachment=function(t){this.name=t},i.SkinnedMeshAttachment.prototype={type:i.AttachmentType.skinnedmesh,bones:null,weights:null,uvs:null,regionUVs:null,triangles:null,hullLength:0,r:1,g:1,b:1,a:1,path:null,rendererObject:null,regionU:0,regionV:0,regionU2:0,regionV2:0,regionRotate:!1,regionOffsetX:0,regionOffsetY:0,regionWidth:0,regionHeight:0,regionOriginalWidth:0,regionOriginalHeight:0,edges:null,width:0,height:0,updateUVs:function(){var t=this.regionU2-this.regionU,e=this.regionV2-this.regionV,r=this.regionUVs.length;if(this.uvs&&this.uvs.length==r||(this.uvs=new i.Float32Array(r)),this.regionRotate)for(var n=0;r>n;n+=2)this.uvs[n]=this.regionU+this.regionUVs[n+1]*t,this.uvs[n+1]=this.regionV+e-this.regionUVs[n]*e;else for(var n=0;r>n;n+=2)this.uvs[n]=this.regionU+this.regionUVs[n]*t,this.uvs[n+1]=this.regionV+this.regionUVs[n+1]*e},computeWorldVertices:function(t,e,i,r){var n,s,o,a,h,l,u,c=i.bone.skeleton.bones,d=this.weights,f=this.bones,p=0,v=0,m=0,g=0,x=f.length;if(i.attachmentVertices.length)for(var y=i.attachmentVertices;x>v;p+=2){for(s=0,o=0,n=f[v++]+v;n>v;v++,m+=3,g+=2)a=c[f[v]],h=d[m]+y[g],l=d[m+1]+y[g+1],u=d[m+2],s+=(h*a.m00+l*a.m01+a.worldX)*u,o+=(h*a.m10+l*a.m11+a.worldY)*u;r[p]=s+t,r[p+1]=o+e}else for(;x>v;p+=2){for(s=0,o=0,n=f[v++]+v;n>v;v++,m+=3)a=c[f[v]],h=d[m],l=d[m+1],u=d[m+2],s+=(h*a.m00+l*a.m01+a.worldX)*u,o+=(h*a.m10+l*a.m11+a.worldY)*u;r[p]=s+t,r[p+1]=o+e}}},i.BoundingBoxAttachment=function(t){this.name=t,this.vertices=[]},i.BoundingBoxAttachment.prototype={type:i.AttachmentType.boundingbox,computeWorldVertices:function(t,e,i,r){t+=i.worldX,e+=i.worldY;for(var n=i.m00,s=i.m01,o=i.m10,a=i.m11,h=this.vertices,l=0,u=h.length;u>l;l+=2){var c=h[l],d=h[l+1];r[l]=c*n+d*s+t,r[l+1]=c*o+d*a+e}}},i.AnimationStateData=function(t){this.skeletonData=t,this.animationToMixTime={}},i.AnimationStateData.prototype={defaultMix:0,setMixByName:function(t,e,i){var r=this.skeletonData.findAnimation(t);if(!r)throw"Animation not found: "+t;var n=this.skeletonData.findAnimation(e);if(!n)throw"Animation not found: "+e;this.setMix(r,n,i)},setMix:function(t,e,i){this.animationToMixTime[t.name+":"+e.name]=i},getMix:function(t,e){var i=t.name+":"+e.name;return this.animationToMixTime.hasOwnProperty(i)?this.animationToMixTime[i]:this.defaultMix}},i.TrackEntry=function(){},i.TrackEntry.prototype={next:null,previous:null,animation:null,loop:!1,delay:0,time:0,lastTime:-1,endTime:0,timeScale:1,mixTime:0,mixDuration:0,mix:1,onStart:null,onEnd:null,onComplete:null,onEvent:null},i.AnimationState=function(t){this.data=t,this.tracks=[],this.events=[]},i.AnimationState.prototype={onStart:null,onEnd:null,onComplete:null,onEvent:null,timeScale:1,update:function(t){t*=this.timeScale;for(var e=0;e=0&&this.setCurrent(e,n)):!i.loop&&i.lastTime>=i.endTime&&this.clearTrack(e)}}},apply:function(t){for(var e=0;es&&(r=s);var a=i.previous;if(a){var h=a.time;!a.loop&&h>a.endTime&&(h=a.endTime),a.animation.apply(t,h,h,a.loop,null);var l=i.mixTime/i.mixDuration*i.mix;l>=1&&(l=1,i.previous=null),i.animation.mix(t,i.lastTime,r,o,this.events,l)}else 1==i.mix?i.animation.apply(t,i.lastTime,r,o,this.events):i.animation.mix(t,i.lastTime,r,o,this.events,i.mix);for(var u=0,c=this.events.length;c>u;u++){var d=this.events[u];i.onEvent&&i.onEvent(e,d),this.onEvent&&this.onEvent(e,d)}if(o?n%s>r%s:s>n&&r>=s){var f=Math.floor(r/s);i.onComplete&&i.onComplete(e,f),this.onComplete&&this.onComplete(e,f)}i.lastTime=i.time}}},clearTracks:function(){for(var t=0,e=this.tracks.length;e>t;t++)this.clearTrack(t);this.tracks.length=0},clearTrack:function(t){if(!(t>=this.tracks.length)){var e=this.tracks[t];e&&(e.onEnd&&e.onEnd(t),this.onEnd&&this.onEnd(t),this.tracks[t]=null)}},_expandToIndex:function(t){if(t=this.tracks.length;)this.tracks.push(null);return null},setCurrent:function(t,e){var i=this._expandToIndex(t);if(i){var r=i.previous;i.previous=null,i.onEnd&&i.onEnd(t),this.onEnd&&this.onEnd(t),e.mixDuration=this.data.getMix(i.animation,e.animation),e.mixDuration>0&&(e.mixTime=0,e.previous=r&&i.mixTime/i.mixDuration<.5?r:i)}this.tracks[t]=e,e.onStart&&e.onStart(t),this.onStart&&this.onStart(t)},setAnimationByName:function(t,e,i){var r=this.data.skeletonData.findAnimation(e);if(!r)throw"Animation not found: "+e;return this.setAnimation(t,r,i)},setAnimation:function(t,e,r){var n=new i.TrackEntry;return n.animation=e,n.loop=r,n.endTime=e.duration,this.setCurrent(t,n),n},addAnimationByName:function(t,e,i,r){var n=this.data.skeletonData.findAnimation(e);if(!n)throw"Animation not found: "+e;return this.addAnimation(t,n,i,r)},addAnimation:function(t,e,r,n){var s=new i.TrackEntry;s.animation=e,s.loop=r,s.endTime=e.duration;var o=this._expandToIndex(t);if(o){for(;o.next;)o=o.next;o.next=s}else this.tracks[t]=s;return 0>=n&&(o?n+=o.endTime-this.data.getMix(o.animation,e):n=0),s.delay=n,s},getCurrent:function(t){return t>=this.tracks.length?null:this.tracks[t]}},i.SkeletonJson=function(t){this.attachmentLoader=t},i.SkeletonJson.prototype={scale:1,readSkeletonData:function(t,e){var r=new i.SkeletonData;r.name=e;var n=t.skeleton;n&&(r.hash=n.hash,r.version=n.spine,r.width=n.width||0,r.height=n.height||0);for(var s=t.bones,o=0,a=s.length;a>o;o++){var h=s[o],l=null;if(h.parent&&(l=r.findBone(h.parent),!l))throw"Parent bone not found: "+h.parent;var u=new i.BoneData(h.name,l);u.length=(h.length||0)*this.scale,u.x=(h.x||0)*this.scale,u.y=(h.y||0)*this.scale,u.rotation=h.rotation||0,u.scaleX=h.hasOwnProperty("scaleX")?h.scaleX:1,u.scaleY=h.hasOwnProperty("scaleY")?h.scaleY:1,u.inheritScale=h.hasOwnProperty("inheritScale")?h.inheritScale:!0,u.inheritRotation=h.hasOwnProperty("inheritRotation")?h.inheritRotation:!0,r.bones.push(u)}var c=t.ik;if(c)for(var o=0,a=c.length;a>o;o++){for(var d=c[o],f=new i.IkConstraintData(d.name),s=d.bones,p=0,v=s.length;v>p;p++){var m=r.findBone(s[p]);if(!m)throw"IK bone not found: "+s[p];f.bones.push(m)}if(f.target=r.findBone(d.target),!f.target)throw"Target bone not found: "+d.target;f.bendDirection=!d.hasOwnProperty("bendPositive")||d.bendPositive?1:-1,f.mix=d.hasOwnProperty("mix")?d.mix:1,r.ikConstraints.push(f)}for(var g=t.slots,o=0,a=g.length;a>o;o++){var x=g[o],u=r.findBone(x.bone);if(!u)throw"Slot bone not found: "+x.bone;var y=new i.SlotData(x.name,u),b=x.color;b&&(y.r=this.toColor(b,0),y.g=this.toColor(b,1),y.b=this.toColor(b,2),y.a=this.toColor(b,3)),y.attachmentName=x.attachment,y.additiveBlending=x.additive&&"true"==x.additive,r.slots.push(y)}var T=t.skins;for(var w in T)if(T.hasOwnProperty(w)){var S=T[w],A=new i.Skin(w);for(var _ in S)if(S.hasOwnProperty(_)){var C=r.findSlotIndex(_),E=S[_];for(var R in E)if(E.hasOwnProperty(R)){var M=this.readAttachment(A,R,E[R]);M&&A.addAttachment(C,R,M)}}r.skins.push(A),"default"==A.name&&(r.defaultSkin=A)}var F=t.events;for(var B in F)if(F.hasOwnProperty(B)){var D=F[B],P=new i.EventData(B);P.intValue=D["int"]||0,P.floatValue=D["float"]||0,P.stringValue=D.string||null,r.events.push(P)}var L=t.animations;for(var O in L)L.hasOwnProperty(O)&&this.readAnimation(O,L[O],r);return r},readAttachment:function(t,e,r){e=r.name||e;var n=i.AttachmentType[r.type||"region"],s=r.path||e,o=this.scale;if(n==i.AttachmentType.region){var a=this.attachmentLoader.newRegionAttachment(t,e,s);if(!a)return null;a.path=s,a.x=(r.x||0)*o,a.y=(r.y||0)*o,a.scaleX=r.hasOwnProperty("scaleX")?r.scaleX:1,a.scaleY=r.hasOwnProperty("scaleY")?r.scaleY:1,a.rotation=r.rotation||0,a.width=(r.width||0)*o,a.height=(r.height||0)*o;var h=r.color;return h&&(a.r=this.toColor(h,0),a.g=this.toColor(h,1),a.b=this.toColor(h,2),a.a=this.toColor(h,3)),a.updateOffset(),a}if(n==i.AttachmentType.mesh){var l=this.attachmentLoader.newMeshAttachment(t,e,s);return l?(l.path=s,l.vertices=this.getFloatArray(r,"vertices",o),l.triangles=this.getIntArray(r,"triangles"),l.regionUVs=this.getFloatArray(r,"uvs",1),l.updateUVs(),h=r.color,h&&(l.r=this.toColor(h,0),l.g=this.toColor(h,1),l.b=this.toColor(h,2),l.a=this.toColor(h,3)),l.hullLength=2*(r.hull||0),r.edges&&(l.edges=this.getIntArray(r,"edges")),l.width=(r.width||0)*o,l.height=(r.height||0)*o,l):null}if(n==i.AttachmentType.skinnedmesh){var l=this.attachmentLoader.newSkinnedMeshAttachment(t,e,s);if(!l)return null;l.path=s;for(var u=this.getFloatArray(r,"uvs",1),c=this.getFloatArray(r,"vertices",1),d=[],f=[],p=0,v=c.length;v>p;){var m=0|c[p++];f[f.length]=m;for(var g=p+4*m;g>p;)f[f.length]=c[p],d[d.length]=c[p+1]*o,d[d.length]=c[p+2]*o,d[d.length]=c[p+3],p+=4}return l.bones=f,l.weights=d,l.triangles=this.getIntArray(r,"triangles"),l.regionUVs=u,l.updateUVs(),h=r.color,h&&(l.r=this.toColor(h,0),l.g=this.toColor(h,1),l.b=this.toColor(h,2),l.a=this.toColor(h,3)),l.hullLength=2*(r.hull||0),r.edges&&(l.edges=this.getIntArray(r,"edges")),l.width=(r.width||0)*o,l.height=(r.height||0)*o,l}if(n==i.AttachmentType.boundingbox){for(var x=this.attachmentLoader.newBoundingBoxAttachment(t,e),c=r.vertices,p=0,v=c.length;v>p;p++)x.vertices.push(c[p]*o);return x}throw"Unknown attachment type: "+n},readAnimation:function(t,e,r){var n=[],s=0,o=e.slots;for(var a in o)if(o.hasOwnProperty(a)){var h=o[a],l=r.findSlotIndex(a);for(var u in h)if(h.hasOwnProperty(u)){var c=h[u];if("color"==u){var d=new i.ColorTimeline(c.length);d.slotIndex=l;for(var f=0,p=0,v=c.length;v>p;p++){var m=c[p],g=m.color,x=this.toColor(g,0),y=this.toColor(g,1),b=this.toColor(g,2),T=this.toColor(g,3);d.setFrame(f,m.time,x,y,b,T),this.readCurve(d,f,m),f++}n.push(d),s=Math.max(s,d.frames[5*d.getFrameCount()-5])}else{if("attachment"!=u)throw"Invalid timeline type for a slot: "+u+" ("+a+")";var d=new i.AttachmentTimeline(c.length);d.slotIndex=l;for(var f=0,p=0,v=c.length;v>p;p++){var m=c[p];d.setFrame(f++,m.time,m.name)}n.push(d),s=Math.max(s,d.frames[d.getFrameCount()-1])}}}var w=e.bones;for(var S in w)if(w.hasOwnProperty(S)){var A=r.findBoneIndex(S);if(-1==A)throw"Bone not found: "+S;var _=w[S];for(var u in _)if(_.hasOwnProperty(u)){var c=_[u];if("rotate"==u){var d=new i.RotateTimeline(c.length);d.boneIndex=A;for(var f=0,p=0,v=c.length;v>p;p++){var m=c[p];d.setFrame(f,m.time,m.angle),this.readCurve(d,f,m),f++}n.push(d),s=Math.max(s,d.frames[2*d.getFrameCount()-2])}else if("translate"==u||"scale"==u){var d,C=1;"scale"==u?d=new i.ScaleTimeline(c.length):(d=new i.TranslateTimeline(c.length),C=this.scale),d.boneIndex=A;for(var f=0,p=0,v=c.length;v>p;p++){var m=c[p],E=(m.x||0)*C,R=(m.y||0)*C;d.setFrame(f,m.time,E,R),this.readCurve(d,f,m),f++}n.push(d),s=Math.max(s,d.frames[3*d.getFrameCount()-3])}else{if("flipX"!=u&&"flipY"!=u)throw"Invalid timeline type for a bone: "+u+" ("+S+")";var E="flipX"==u,d=E?new i.FlipXTimeline(c.length):new i.FlipYTimeline(c.length);d.boneIndex=A;for(var M=E?"x":"y",f=0,p=0,v=c.length;v>p;p++){var m=c[p];d.setFrame(f,m.time,m[M]||!1),f++}n.push(d),s=Math.max(s,d.frames[2*d.getFrameCount()-2])}}}var F=e.ik;for(var B in F)if(F.hasOwnProperty(B)){var D=r.findIkConstraint(B),c=F[B],d=new i.IkConstraintTimeline(c.length);d.ikConstraintIndex=r.ikConstraints.indexOf(D);for(var f=0,p=0,v=c.length;v>p;p++){var m=c[p],P=m.hasOwnProperty("mix")?m.mix:1,L=!m.hasOwnProperty("bendPositive")||m.bendPositive?1:-1;d.setFrame(f,m.time,P,L),this.readCurve(d,f,m),f++}n.push(d),s=Math.max(s,d.frames[3*d.frameCount-3])}var O=e.ffd;for(var I in O){var k=r.findSkin(I),h=O[I];for(a in h){var l=r.findSlotIndex(a),U=h[a];for(var N in U){var c=U[N],d=new i.FfdTimeline(c.length),j=k.getAttachment(l,N);if(!j)throw"FFD attachment not found: "+N;d.slotIndex=l,d.attachment=j;var Y,X=j.type==i.AttachmentType.mesh;Y=X?j.vertices.length:j.weights.length/3*2;for(var f=0,p=0,v=c.length;v>p;p++){var G,m=c[p];if(m.vertices){var W=m.vertices,G=[];G.length=Y;var V=m.offset||0,z=W.length;if(1==this.scale)for(var H=0;z>H;H++)G[H+V]=W[H];else for(var H=0;z>H;H++)G[H+V]=W[H]*this.scale;if(X)for(var q=j.vertices,H=0,z=G.length;z>H;H++)G[H]+=q[H]}else X?G=j.vertices:(G=[],G.length=Y);d.setFrame(f,m.time,G),this.readCurve(d,f,m),f++}n[n.length]=d,s=Math.max(s,d.frames[d.frameCount-1])}}}var K=e.drawOrder;if(K||(K=e.draworder),K){for(var d=new i.DrawOrderTimeline(K.length),J=r.slots.length,f=0,p=0,v=K.length;v>p;p++){var Q=K[p],$=null;if(Q.offsets){$=[],$.length=J;for(var H=J-1;H>=0;H--)$[H]=-1;var Z=Q.offsets,te=[];te.length=J-Z.length;for(var ee=0,ie=0,H=0,z=Z.length;z>H;H++){var re=Z[H],l=r.findSlotIndex(re.slot);if(-1==l)throw"Slot not found: "+re.slot;for(;ee!=l;)te[ie++]=ee++;$[ee+re.offset]=ee++}for(;J>ee;)te[ie++]=ee++;for(var H=J-1;H>=0;H--)-1==$[H]&&($[H]=te[--ie])}d.setFrame(f++,Q.time,$)}n.push(d),s=Math.max(s,d.frames[d.getFrameCount()-1])}var ne=e.events;if(ne){for(var d=new i.EventTimeline(ne.length),f=0,p=0,v=ne.length;v>p;p++){var se=ne[p],oe=r.findEvent(se.name);if(!oe)throw"Event not found: "+se.name;var ae=new i.Event(oe);ae.intValue=se.hasOwnProperty("int")?se["int"]:oe.intValue,ae.floatValue=se.hasOwnProperty("float")?se["float"]:oe.floatValue,ae.stringValue=se.hasOwnProperty("string")?se.string:oe.stringValue,d.setFrame(f++,se.time,ae)}n.push(d),s=Math.max(s,d.frames[d.getFrameCount()-1])}r.animations.push(new i.Animation(t,n,s))},readCurve:function(t,e,i){var r=i.curve;r?"stepped"==r?t.curves.setStepped(e):r instanceof Array&&t.curves.setCurve(e,r[0],r[1],r[2],r[3]):t.curves.setLinear(e)},toColor:function(t,e){if(8!=t.length)throw"Color hexidecimal length must be 8, recieved: "+t;return parseInt(t.substring(2*e,2*e+2),16)/255},getFloatArray:function(t,e,r){var n=t[e],s=new i.Float32Array(n.length),o=0,a=n.length;if(1==r)for(;a>o;o++)s[o]=n[o];else for(;a>o;o++)s[o]=n[o]*r;return s},getIntArray:function(t,e){for(var r=t[e],n=new i.Uint16Array(r.length),s=0,o=r.length;o>s;s++)n[s]=0|r[s];return n}},i.Atlas=function(t,e){this.textureLoader=e,this.pages=[],this.regions=[];var r=new i.AtlasReader(t),n=[];n.length=4;for(var s=null;;){var o=r.readLine();if(null===o)break;if(o=r.trim(o),o.length)if(s){var a=new i.AtlasRegion;a.name=o,a.page=s,a.rotate="true"==r.readValue(),r.readTuple(n);var h=parseInt(n[0]),l=parseInt(n[1]);r.readTuple(n);var u=parseInt(n[0]),c=parseInt(n[1]);a.u=h/s.width,a.v=l/s.height,a.rotate?(a.u2=(h+c)/s.width,a.v2=(l+u)/s.height):(a.u2=(h+u)/s.width,a.v2=(l+c)/s.height),a.x=h,a.y=l,a.width=Math.abs(u),a.height=Math.abs(c),4==r.readTuple(n)&&(a.splits=[parseInt(n[0]),parseInt(n[1]),parseInt(n[2]),parseInt(n[3])],4==r.readTuple(n)&&(a.pads=[parseInt(n[0]),parseInt(n[1]),parseInt(n[2]),parseInt(n[3])],r.readTuple(n))),a.originalWidth=parseInt(n[0]),a.originalHeight=parseInt(n[1]),r.readTuple(n),a.offsetX=parseInt(n[0]),a.offsetY=parseInt(n[1]),a.index=parseInt(r.readValue()),this.regions.push(a)}else{s=new i.AtlasPage,s.name=o,2==r.readTuple(n)&&(s.width=parseInt(n[0]),s.height=parseInt(n[1]),r.readTuple(n)),s.format=i.Atlas.Format[n[0]],r.readTuple(n),s.minFilter=i.Atlas.TextureFilter[n[0]],s.magFilter=i.Atlas.TextureFilter[n[1]];var d=r.readValue();s.uWrap=i.Atlas.TextureWrap.clampToEdge,s.vWrap=i.Atlas.TextureWrap.clampToEdge,"x"==d?s.uWrap=i.Atlas.TextureWrap.repeat:"y"==d?s.vWrap=i.Atlas.TextureWrap.repeat:"xy"==d&&(s.uWrap=s.vWrap=i.Atlas.TextureWrap.repeat),e.load(s,o,this),this.pages.push(s)}else s=null}},i.Atlas.prototype={findRegion:function(t){for(var e=this.regions,i=0,r=e.length;r>i;i++)if(e[i].name==t)return e[i];return null},dispose:function(){for(var t=this.pages,e=0,i=t.length;i>e;e++)this.textureLoader.unload(t[e].rendererObject)},updateUVs:function(t){for(var e=this.regions,i=0,r=e.length;r>i;i++){var n=e[i];n.page==t&&(n.u=n.x/t.width,n.v=n.y/t.height,n.rotate?(n.u2=(n.x+n.height)/t.width,n.v2=(n.y+n.width)/t.height):(n.u2=(n.x+n.width)/t.width,n.v2=(n.y+n.height)/t.height))}}},i.Atlas.Format={alpha:0,intensity:1,luminanceAlpha:2,rgb565:3,rgba4444:4,rgb888:5,rgba8888:6},i.Atlas.TextureFilter={nearest:0,linear:1,mipMap:2,mipMapNearestNearest:3,mipMapLinearNearest:4,mipMapNearestLinear:5,mipMapLinearLinear:6},i.Atlas.TextureWrap={mirroredRepeat:0,clampToEdge:1,repeat:2},i.AtlasPage=function(){},i.AtlasPage.prototype={name:null,format:null,minFilter:null,magFilter:null,uWrap:null,vWrap:null,rendererObject:null,width:0,height:0},i.AtlasRegion=function(){},i.AtlasRegion.prototype={page:null,name:null,x:0,y:0,width:0,height:0,u:0,v:0,u2:0,v2:0,offsetX:0,offsetY:0,originalWidth:0,originalHeight:0,index:0,rotate:!1,splits:null,pads:null},i.AtlasReader=function(t){this.lines=t.split(/\r\n|\r|\n/)},i.AtlasReader.prototype={index:0,trim:function(t){return t.replace(/^\s+|\s+$/g,"")},readLine:function(){return this.index>=this.lines.length?null:this.lines[this.index++]},readValue:function(){var t=this.readLine(),e=t.indexOf(":");if(-1==e)throw"Invalid line: "+t;return this.trim(t.substring(e+1))},readTuple:function(t){var e=this.readLine(),i=e.indexOf(":");if(-1==i)throw"Invalid line: "+e;for(var r=0,n=i+1;3>r;r++){var s=e.indexOf(",",n);if(-1==s)break;t[r]=this.trim(e.substr(n,s-n)),n=s+1}return t[r]=this.trim(e.substring(n)),r+1}},i.AtlasAttachmentLoader=function(t){this.atlas=t},i.AtlasAttachmentLoader.prototype={newRegionAttachment:function(t,e,r){var n=this.atlas.findRegion(r);if(!n)throw"Region not found in atlas: "+r+" (region attachment: "+e+")";var s=new i.RegionAttachment(e);return s.rendererObject=n,s.setUVs(n.u,n.v,n.u2,n.v2,n.rotate),s.regionOffsetX=n.offsetX,s.regionOffsetY=n.offsetY,s.regionWidth=n.width,s.regionHeight=n.height,s.regionOriginalWidth=n.originalWidth,s.regionOriginalHeight=n.originalHeight,s},newMeshAttachment:function(t,e,r){var n=this.atlas.findRegion(r);if(!n)throw"Region not found in atlas: "+r+" (mesh attachment: "+e+")";var s=new i.MeshAttachment(e);return s.rendererObject=n,s.regionU=n.u,s.regionV=n.v,s.regionU2=n.u2,s.regionV2=n.v2,s.regionRotate=n.rotate,s.regionOffsetX=n.offsetX,s.regionOffsetY=n.offsetY,s.regionWidth=n.width,s.regionHeight=n.height,s.regionOriginalWidth=n.originalWidth,s.regionOriginalHeight=n.originalHeight,s},newSkinnedMeshAttachment:function(t,e,r){var n=this.atlas.findRegion(r);if(!n)throw"Region not found in atlas: "+r+" (skinned mesh attachment: "+e+")";var s=new i.SkinnedMeshAttachment(e);return s.rendererObject=n,s.regionU=n.u,s.regionV=n.v,s.regionU2=n.u2,s.regionV2=n.v2,s.regionRotate=n.rotate,s.regionOffsetX=n.offsetX,s.regionOffsetY=n.offsetY,s.regionWidth=n.width,s.regionHeight=n.height,s.regionOriginalWidth=n.originalWidth,s.regionOriginalHeight=n.originalHeight,s},newBoundingBoxAttachment:function(t,e){return new i.BoundingBoxAttachment(e)}},i.SkeletonBounds=function(){this.polygonPool=[],this.polygons=[],this.boundingBoxes=[]},i.SkeletonBounds.prototype={minX:0,minY:0,maxX:0,maxY:0,update:function(t,e){var r=t.slots,n=r.length,s=t.x,o=t.y,a=this.boundingBoxes,h=this.polygonPool,l=this.polygons;a.length=0;for(var u=0,c=l.length;c>u;u++)h.push(l[u]);l.length=0;for(var u=0;n>u;u++){var d=r[u],f=d.attachment;if(f.type==i.AttachmentType.boundingbox){a.push(f);var p,v=h.length;v>0?(p=h[v-1],h.splice(v-1,1)):p=[],l.push(p),p.length=f.vertices.length,f.computeWorldVertices(s,o,d.bone,p)}}e&&this.aabbCompute()},aabbCompute:function(){for(var t=this.polygons,e=Number.MAX_VALUE,i=Number.MAX_VALUE,r=Number.MIN_VALUE,n=Number.MIN_VALUE,s=0,o=t.length;o>s;s++)for(var a=t[s],h=0,l=a.length;l>h;h+=2){var u=a[h],c=a[h+1];e=Math.min(e,u),i=Math.min(i,c),r=Math.max(r,u),n=Math.max(n,c)}this.minX=e,this.minY=i,this.maxX=r,this.maxY=n},aabbContainsPoint:function(t,e){return t>=this.minX&&t<=this.maxX&&e>=this.minY&&e<=this.maxY},aabbIntersectsSegment:function(t,e,i,r){var n=this.minX,s=this.minY,o=this.maxX,a=this.maxY;if(n>=t&&n>=i||s>=e&&s>=r||t>=o&&i>=o||e>=a&&r>=a)return!1;var h=(r-e)/(i-t),l=h*(n-t)+e;if(l>s&&a>l)return!0;if(l=h*(o-t)+e,l>s&&a>l)return!0;var u=(s-e)/h+t;return u>n&&o>u?!0:(u=(a-e)/h+t,u>n&&o>u?!0:!1)},aabbIntersectsSkeleton:function(t){return this.minXt.minX&&this.minYt.minY},containsPoint:function(t,e){for(var i=this.polygons,r=0,n=i.length;n>r;r++)if(this.polygonContainsPoint(i[r],t,e))return this.boundingBoxes[r];return null},intersectsSegment:function(t,e,i,r){for(var n=this.polygons,s=0,o=n.length;o>s;s++)if(n[s].intersectsSegment(t,e,i,r))return this.boundingBoxes[s];return null},polygonContainsPoint:function(t,e,i){for(var r=t.length,n=r-2,s=!1,o=0;r>o;o+=2){var a=t[o+1],h=t[n+1];if(i>a&&h>=i||i>h&&a>=i){var l=t[o];l+(i-a)/(h-a)*(t[n]-l)c;c+=2){var d=t[c],f=t[c+1],p=l*f-u*d,v=l-d,m=u-f,g=o*m-a*v,x=(h*v-o*p)/g;if((x>=l&&d>=x||x>=d&&l>=x)&&(x>=e&&r>=x||x>=r&&e>=x)){var y=(h*m-a*p)/g;if((y>=u&&f>=y||y>=f&&u>=y)&&(y>=i&&n>=y||y>=n&&i>=y))return!0}l=d,u=f}return!1},getPolygon:function(t){var e=this.boundingBoxes.indexOf(t);return-1==e?null:this.polygons[e]},getWidth:function(){return this.maxX-this.minX},getHeight:function(){return this.maxY-this.minY}}},{}],95:[function(t,e){e.exports={Spine:t("./Spine")}},{"./Spine":93}],96:[function(t,e){function i(t,e){r.DisplayObjectContainer.call(this),this.textWidth=0,this.textHeight=0,this._pool=[],this._style={tint:e.tint,align:e.align,fontName:null,fontSize:0},this.font=e.font,this._text=t,this.dirty=!1,this.updateText()}var r=t("../core");i.prototype=Object.create(r.DisplayObjectContainer.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{tint:{get:function(){return this._style.tint},set:function(t){this._style.tint="number"==typeof t&&t>=0?t:16777215,this.dirty=!0}},align:{get:function(){return this._style.align},set:function(t){this._style.align=t,this.dirty=!0}},font:{get:function(){return this._style.font},set:function(t){t=t.split(" "),this._style.fontName=t[t.length-1],this._style.fontSize=t.length>=2?parseInt(t[t.length-2],10):i.fonts[this.fontName].size,this.dirty=!0}},text:{get:function(){return this._text},set:function(t){this._text=t,this.dirty=!0}}}),i.prototype.updateText=function(){for(var t=i.fonts[this.fontName],e=new r.math.Point,n=null,s=[],o=0,a=[],h=0,l=this.fontSize/t.size,u=0;u=u;u++){var p=0;"right"===this.style.align?p=o-a[u]:"center"===this.style.align&&(p=(o-a[u])/2),f.push(p)}var v=this.children.length,m=s.length,g=this.tint;for(u=0;m>u;u++){var x=v>u?this.children[u]:this._pool.pop();x?x.setTexture(s[u].texture):x=new r.Sprite(s[u].texture),x.position.x=(s[u].position.x+f[s[u].line])*l,x.position.y=s[u].position.y*l,x.scale.x=x.scale.y=l,x.tint=g,x.parent||this.addChild(x)}for(;this.children.length>m;){var y=this.getChildAt(this.children.length-1);this._pool.push(y),this.removeChild(y)}this.textWidth=o*l,this.textHeight=(e.y+t.lineHeight)*l},i.prototype.updateTransform=function(){this.dirty&&(this.updateText(),this.dirty=!1),this.displayObjectContainerUpdateTransform()},i.fonts={}},{"../core":9}],97:[function(t,e){function i(t,e){this.canvas=document.createElement("canvas"),this.context=this.canvas.getContext("2d"),this.resolution=1,r.Sprite.call(this,r.Texture.fromCanvas(this.canvas)),this.setText(t),this.setStyle(e)}var r=t("../core");i.prototype=Object.create(r.Sprite.prototype),i.prototype.constructor=i,e.exports=i,Object.defineProperties(i.prototype,{width:{get:function(){return this.dirty&&(this.updateText(),this.dirty=!1),this.scale.x*this.texture.frame.width},set:function(t){this.scale.x=t/this.texture.frame.width,this._width=t}},height:{get:function(){return this.dirty&&(this.updateText(),this.dirty=!1),this.scale.y*this.texture.frame.height},set:function(t){this.scale.y=t/this.texture.frame.height,this._height=t}}}),i.prototype.setStyle=function(t){t=t||{},t.font=t.font||"bold 20pt Arial",t.fill=t.fill||"black",t.align=t.align||"left",t.stroke=t.stroke||"black",t.strokeThickness=t.strokeThickness||0,t.wordWrap=t.wordWrap||!1,t.wordWrapWidth=t.wordWrapWidth||100,t.dropShadow=t.dropShadow||!1,t.dropShadowAngle=t.dropShadowAngle||Math.PI/6,t.dropShadowDistance=t.dropShadowDistance||4,t.dropShadowColor=t.dropShadowColor||"black",this.style=t,this.dirty=!0},i.prototype.setText=function(t){this.text=t.toString()||" ",this.dirty=!0},i.prototype.updateText=function(){this.texture.baseTexture.resolution=this.resolution,this.context.font=this.style.font;var t=this.text;this.style.wordWrap&&(t=this.wordWrap(this.text));for(var e=t.split(/(?:\r\n|\r|\n)/),i=[],r=0,n=this.determineFontProperties(this.style.font),s=0;sh;h++){for(l=0;d>l;l+=4)if(255!==u[f+l]){p=!0;break}if(p)break;f+=d}for(e.ascent=o-h,f=c-d,p=!1,h=a;h>o;h--){for(l=0;d>l;l+=4)if(255!==u[f+l]){p=!0;break}if(p)break;f-=d}e.descent=h-o,e.descent+=6,e.fontSize=e.ascent+e.descent,i.fontPropertiesCache[t]=e}return e},i.prototype.wordWrap=function(t){for(var e="",i=t.split("\n"),r=0;rn?(o>0&&(e+="\n"),e+=s[o],n=this.style.wordWrapWidth-a):(n-=h,e+=" "+s[o])}r