diff --git a/dist/skifree.js b/dist/skifree.js index 761570a..7b937e0 100644 --- a/dist/skifree.js +++ b/dist/skifree.js @@ -1,6082 +1,317 @@ -(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 2) {\n this.spriteVersion = 0.1;\n } else {\n this.spriteVersion += 0.1;\n }\n\n if (xDiff >= 0) {\n return 'sEast' + Math.ceil(this.spriteVersion);\n } else if (xDiff < 0) {\n return 'sWest' + Math.ceil(this.spriteVersion);\n }\n };\n\n return _get(_getPrototypeOf(Monster.prototype), \"draw\", this).call(this, dContext, spritePartToUse());\n }\n }, {\n key: \"startEating\",\n value: function (_startEating) {\n function startEating(_x) {\n return _startEating.apply(this, arguments);\n }\n\n startEating.toString = function () {\n return _startEating.toString();\n };\n\n return startEating;\n }(function (whenDone) {\n this.eatingStage += 1;\n this.isEating = true;\n this.isMoving = false;\n\n if (eatingStage < 6) {\n setTimeout(function () {\n startEating(whenDone);\n }, 300);\n } else {\n eatingStage = 0;\n this.isEating = false;\n this.isMoving = true;\n whenDone();\n }\n })\n }]);\n\n return Monster;\n}(_sprite__WEBPACK_IMPORTED_MODULE_0__[\"default\"]);\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Monster);\n\n//# sourceURL=webpack:///./js/lib/monster.js?"); + +/***/ }), + +/***/ "./js/lib/plugins.js": +/*!***************************!*\ + !*** ./js/lib/plugins.js ***! + \***************************/ +/*! no static exports found */ +/***/ (function(module, exports) { + +eval("// Avoid `console` errors in browsers that lack a console.\n(function () {\n var method;\n\n var noop = function noop() {};\n\n var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];\n var length = methods.length;\n var console = window.console = window.console || {};\n\n while (length--) {\n method = methods[length]; // Only stub undefined methods.\n\n if (!console[method]) {\n console[method] = noop;\n }\n }\n})();\n\n//# sourceURL=webpack:///./js/lib/plugins.js?"); + +/***/ }), - this.images[key] = image; -}; +/***/ "./js/lib/skier.js": +/*!*************************!*\ + !*** ./js/lib/skier.js ***! + \*************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -CanvasRenderingContext2D.prototype.getLoadedImage = function (key) { - if (this.images[key]) { - return this.images[key]; - } -}; +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _sprite__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./sprite */ \"./js/lib/sprite.js\");\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _get(target, property, receiver) { if (typeof Reflect !== \"undefined\" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); }\n\nfunction _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n\n\nif (typeof navigator !== 'undefined') {\n navigator.vibrate = navigator.vibrate || navigator.webkitVibrate || navigator.mozVibrate || navigator.msVibrate;\n} else {\n navigator = {\n vibrate: false\n };\n}\n\nvar Skier =\n/*#__PURE__*/\nfunction (_Sprite) {\n _inherits(Skier, _Sprite);\n\n function Skier(data) {\n var _this;\n\n _classCallCheck(this, Skier);\n\n _this = _possibleConstructorReturn(this, _getPrototypeOf(Skier).call(this, data));\n _this.discreteDirections = {\n 'west': 270,\n 'wsWest': 240,\n 'sWest': 195,\n 'south': 180,\n 'sEast': 165,\n 'esEast': 120,\n 'east': 90\n };\n _this.sup = {\n draw: _this.superior('draw'),\n cycle: _this.superior('cycle'),\n getSpeedX: _this.superior('getSpeedX'),\n getSpeedY: _this.superior('getSpeedY'),\n hits: _this.superior('hits')\n };\n _this.directions = {\n esEast: function esEast(xDiff) {\n return xDiff > 300;\n },\n sEast: function sEast(xDiff) {\n return xDiff > 75;\n },\n wsWest: function wsWest(xDiff) {\n return xDiff < -300;\n },\n sWest: function sWest(xDiff) {\n return xDiff < -75;\n }\n };\n _this.cancelableStateTimeout;\n _this.cancelableStateInterval;\n _this.canSpeedBoost = true;\n _this.obstaclesHit = [];\n _this.pixelsTravelled = 0;\n _this.standardSpeed = 5;\n _this.boostMultiplier = 2;\n _this.turnEaseCycles = 70;\n _this.speedX = 0;\n _this.speedXFactor = 0;\n _this.speedY = 0;\n _this.speedYFactor = 1;\n _this.trickStep = 0; // There are three of these\n\n _this.isMoving = true;\n _this.hasBeenHit = false;\n _this.isJumping = false;\n _this.isPerformingTrick = false;\n\n _this.onHitObstacleCb = function () {};\n\n _this.setSpeed(_this.standardSpeed);\n\n return _this;\n }\n\n _createClass(Skier, [{\n key: \"reset\",\n value: function reset() {\n this.obstaclesHit = [];\n this.pixelsTravelled = 0;\n this.isMoving = true;\n this.hasBeenHit = false;\n this.canSpeedBoost = true;\n this.setNormal();\n }\n }, {\n key: \"setNormal\",\n value: function setNormal() {\n // console.log('back to normal')\n this.setSpeed(this.standardSpeed);\n this.isMoving = true;\n this.hasBeenHit = false;\n this.isJumping = false;\n this.isPerformingTrick = false;\n\n if (this.cancelableStateInterval) {\n this.clearInterval(this.cancelableStateInterval);\n }\n\n this.setMapPosition(undefined, undefined, 0);\n }\n }, {\n key: \"setCrashed\",\n value: function setCrashed() {\n this.isMoving = false;\n this.hasBeenHit = true;\n this.isJumping = false;\n this.isPerformingTrick = false;\n\n if (this.cancelableStateInterval) {\n clearInterval(this.cancelableStateInterval);\n }\n\n this.setMapPosition(undefined, undefined, 0);\n }\n }, {\n key: \"setJumping\",\n value: function setJumping() {\n var currentSpeed = this.getSpeed();\n this.setSpeed(currentSpeed + 2);\n this.setSpeedY(currentSpeed + 2);\n this.isMoving = true;\n this.hasBeenHit = false;\n this.isJumping = true;\n this.setMapPosition(undefined, undefined, 1);\n }\n }, {\n key: \"getDiscreteDirection\",\n value: function getDiscreteDirection() {\n if (this.direction) {\n if (this.direction <= 90) {\n return 'east';\n } else if (this.direction > 90 && this.direction < 150) {\n return 'esEast';\n } else if (this.direction >= 150 && this.direction < 180) {\n return 'sEast';\n } else if (this.direction === 180) {\n return 'south';\n } else if (this.direction > 180 && this.direction <= 210) {\n return 'sWest';\n } else if (this.direction > 210 && this.direction < 270) {\n return 'wsWest';\n } else if (this.direction >= 270) {\n return 'west';\n } else {\n return 'south';\n }\n } else {\n var xDiff = this.movingToward[0] - this.mapPosition[0];\n var yDiff = this.movingToward[1] - this.mapPosition[1];\n\n if (yDiff <= 0) {\n if (xDiff > 0) {\n return 'east';\n } else {\n return 'west';\n }\n }\n\n if (this.directions.esEast(xDiff)) {\n return 'esEast';\n } else if (this.directions.sEast(xDiff)) {\n return 'sEast';\n } else if (this.directions.wsWest(xDiff)) {\n return 'wsWest';\n } else if (this.directions.sWest(xDiff)) {\n return 'sWest';\n }\n }\n\n return 'south';\n }\n }, {\n key: \"setDiscreteDirection\",\n value: function setDiscreteDirection(d) {\n if (this.discreteDirections[d]) {\n this.setDirection(this.discreteDirections[d]);\n }\n\n if (d === 'west' || d === 'east') {\n this.isMoving = false;\n } else {\n this.isMoving = true;\n }\n }\n }, {\n key: \"getBeingEatenSprite\",\n value: function getBeingEatenSprite() {\n return 'blank';\n }\n }, {\n key: \"getJumpingSprite\",\n value: function getJumpingSprite() {\n return 'jumping';\n }\n }, {\n key: \"getTrickSprite\",\n value: function getTrickSprite() {\n console.log('Trick step is', this.trickStep);\n\n if (this.trickStep === 0) {\n return 'jumping';\n } else if (this.trickStep === 1) {\n return 'somersault1';\n } else {\n return 'somersault2';\n }\n }\n }, {\n key: \"stop\",\n value: function stop() {\n if (this.direction > 180) {\n this.setDiscreteDirection('west');\n } else {\n this.setDiscreteDirection('east');\n }\n }\n }, {\n key: \"turnEast\",\n value: function turnEast() {\n var discreteDirection = this.getDiscreteDirection();\n\n switch (discreteDirection) {\n case 'west':\n this.setDiscreteDirection('wsWest');\n break;\n\n case 'wsWest':\n this.setDiscreteDirection('sWest');\n break;\n\n case 'sWest':\n this.setDiscreteDirection('south');\n break;\n\n case 'south':\n this.setDiscreteDirection('sEast');\n break;\n\n case 'sEast':\n this.setDiscreteDirection('esEast');\n break;\n\n case 'esEast':\n this.setDiscreteDirection('east');\n break;\n\n default:\n this.setDiscreteDirection('south');\n break;\n }\n }\n }, {\n key: \"turnWest\",\n value: function turnWest() {\n var discreteDirection = this.getDiscreteDirection();\n\n switch (discreteDirection) {\n case 'east':\n this.setDiscreteDirection('esEast');\n break;\n\n case 'esEast':\n this.setDiscreteDirection('sEast');\n break;\n\n case 'sEast':\n this.setDiscreteDirection('south');\n break;\n\n case 'south':\n this.setDiscreteDirection('sWest');\n break;\n\n case 'sWest':\n this.setDiscreteDirection('wsWest');\n break;\n\n case 'wsWest':\n this.setDiscreteDirection('west');\n break;\n\n default:\n this.setDiscreteDirection('south');\n break;\n }\n }\n }, {\n key: \"stepWest\",\n value: function stepWest() {\n this.mapPosition[0] -= this.speed * 2;\n }\n }, {\n key: \"stepEast\",\n value: function stepEast() {\n this.mapPosition[0] += this.speed * 2;\n }\n }, {\n key: \"setMapPositionTarget\",\n value: function setMapPositionTarget(x, y) {\n if (this.hasBeenHit) return;\n\n if (Math.abs(this.mapPosition[0] - x) <= 75) {\n x = this.mapPosition[0];\n }\n\n this.movingToward = [x, y]; // this.resetDirection();\n }\n }, {\n key: \"startMovingIfPossible\",\n value: function startMovingIfPossible() {\n if (!this.hasBeenHit && !this.isBeingEaten) {\n this.isMoving = true;\n }\n }\n }, {\n key: \"setTurnEaseCycles\",\n value: function setTurnEaseCycles(c) {\n this.turnEaseCycles = c;\n }\n }, {\n key: \"getPixelsTravelledDownMountain\",\n value: function getPixelsTravelledDownMountain() {\n return this.pixelsTravelled;\n }\n }, {\n key: \"resetSpeed\",\n value: function resetSpeed() {\n this.setSpeed(this.standardSpeed);\n }\n }, {\n key: \"cycle\",\n value: function cycle() {\n if (this.getSpeedX() <= 0 && this.getSpeedY() <= 0) {\n this.isMoving = false;\n }\n\n if (this.isMoving) {\n this.pixelsTravelled += this.speed;\n }\n\n if (this.isJumping) {\n this.setMapPositionTarget(undefined, this.mapPosition[1] + this.getSpeed());\n }\n\n _get(_getPrototypeOf(Skier.prototype), \"cycle\", this).call(this);\n\n this.checkHittableObjects();\n }\n }, {\n key: \"draw\",\n value: function draw(dContext) {\n var _this2 = this;\n\n var spritePartToUse = function spritePartToUse() {\n if (_this2.isBeingEaten) {\n return getBeingEatenSprite();\n }\n\n if (_this2.isJumping) {\n if (_this2.isPerformingTrick) {\n return getTrickSprite();\n }\n\n return getJumpingSprite();\n }\n\n if (_this2.hasBeenHit) {\n return 'hit';\n }\n\n return _this2.getDiscreteDirection();\n };\n\n return _get(_getPrototypeOf(Skier.prototype), \"draw\", this).call(this, dContext, spritePartToUse());\n }\n }, {\n key: \"hits\",\n value: function hits(obs) {\n if (this.obstaclesHit.indexOf(obs.id) !== -1) {\n return false;\n }\n\n if (!obs.occupiesZIndex(this.mapPosition[2])) {\n return false;\n }\n\n if (_get(_getPrototypeOf(Skier.prototype), \"hits\", this).call(this, obs)) {\n return true;\n }\n\n return false;\n }\n }, {\n key: \"speedBoost\",\n value: function speedBoost() {\n var _this3 = this;\n\n var originalSpeed = this.speed;\n\n if (this.canSpeedBoost) {\n this.canSpeedBoost = false;\n this.setSpeed(this.speed * this.boostMultiplier);\n setTimeout(function () {\n _this3.setSpeed(originalSpeed);\n\n setTimeout(function () {\n _this3.canSpeedBoost = true;\n }, 10000);\n }, 2000);\n }\n }\n }, {\n key: \"attemptTrick\",\n value: function attemptTrick() {\n var _this4 = this;\n\n if (this.isJumping) {\n this.isPerformingTrick = true;\n this.cancelableStateInterval = setInterval(function () {\n if (_this4.trickStep >= 2) {\n _this4.trickStep = 0;\n } else {\n _this4.trickStep += 1;\n }\n }, 300);\n }\n }\n }, {\n key: \"getStandardSpeed\",\n value: function getStandardSpeed() {\n return this.standardSpeed;\n }\n }, {\n key: \"easeSpeedToTargetUsingFactor\",\n value: function easeSpeedToTargetUsingFactor(sp, targetSpeed, f) {\n if (f === 0 || f === 1) {\n return targetSpeed;\n }\n\n if (sp < targetSpeed) {\n sp += this.getSpeed() * (f / this.turnEaseCycles);\n }\n\n if (sp > targetSpeed) {\n sp -= this.getSpeed() * (f / this.turnEaseCycles);\n }\n\n return sp;\n }\n }, {\n key: \"getSpeedX\",\n value: function getSpeedX() {\n if (this.getDiscreteDirection() === 'esEast' || this.getDiscreteDirection() === 'wsWest') {\n this.speedXFactor = 0.5;\n this.speedX = this.easeSpeedToTargetUsingFactor(this.speedX, this.getSpeed() * this.speedXFactor, this.speedXFactor);\n return this.speedX;\n }\n\n if (this.getDiscreteDirection() === 'sEast' || this.getDiscreteDirection() === 'sWest') {\n this.speedXFactor = 0.33;\n this.speedX = this.easeSpeedToTargetUsingFactor(this.speedX, this.getSpeed() * this.speedXFactor, this.speedXFactor);\n return this.speedX;\n } // So it must be south\n\n\n this.speedX = this.easeSpeedToTargetUsingFactor(this.speedX, 0, this.speedXFactor);\n return this.speedX;\n }\n }, {\n key: \"setSpeedY\",\n value: function setSpeedY(sy) {\n this.speedY = sy;\n }\n }, {\n key: \"getSpeedY\",\n value: function getSpeedY() {\n var targetSpeed;\n\n if (this.isJumping) {\n return this.speedY;\n }\n\n if (this.getDiscreteDirection() === 'esEast' || this.getDiscreteDirection() === 'wsWest') {\n this.speedYFactor = 0.6;\n this.speedY = this.easeSpeedToTargetUsingFactor(this.speedY, this.getSpeed() * 0.6, 0.6);\n return this.speedY;\n }\n\n if (this.getDiscreteDirection() === 'sEast' || this.getDiscreteDirection() === 'sWest') {\n this.speedYFactor = 0.85;\n this.speedY = this.easeSpeedToTargetUsingFactor(this.speedY, this.getSpeed() * 0.85, 0.85);\n return this.speedY;\n }\n\n if (this.getDiscreteDirection() === 'east' || this.getDiscreteDirection() === 'west') {\n this.speedYFactor = 1;\n this.speedY = 0;\n return this.speedY;\n } // So it must be south\n\n\n this.speedY = this.easeSpeedToTargetUsingFactor(this.speedY, this.getSpeed(), this.speedYFactor);\n return this.speedY;\n }\n }, {\n key: \"hasHitObstacle\",\n value: function hasHitObstacle(obs) {\n var _this5 = this;\n\n this.setCrashed();\n\n if (navigator.vibrate) {\n navigator.vibrate(500);\n }\n\n this.obstaclesHit.push(obs.id);\n this.resetSpeed();\n this.onHitObstacleCb(obs);\n\n if (this.cancelableStateTimeout) {\n clearTimeout(this.cancelableStateTimeout);\n }\n\n this.cancelableStateTimeout = setTimeout(function () {\n _this5.setNormal();\n }, 1500);\n }\n }, {\n key: \"hasHitJump\",\n value: function hasHitJump() {\n var _this6 = this;\n\n this.setJumping();\n\n if (this.cancelableStateTimeout) {\n clearTimeout(this.cancelableStateTimeout);\n }\n\n this.cancelableStateTimeout = setTimeout(function () {\n _this6.setNormal();\n }, 1000);\n }\n }, {\n key: \"isEatenBy\",\n value: function isEatenBy(monster, whenEaten) {\n this.hasHitObstacle(monster);\n monster.startEating(whenEaten);\n this.obstaclesHit.push(monster.id);\n this.isMoving = false;\n this.isBeingEaten = true;\n }\n }, {\n key: \"reset\",\n value: function reset() {\n this.obstaclesHit = [];\n this.pixelsTravelled = 0;\n this.isMoving = true;\n this.isJumping = false;\n this.hasBeenHit = false;\n this.canSpeedBoost = true;\n }\n }, {\n key: \"setHitObstacleCb\",\n value: function setHitObstacleCb(fn) {\n this.onHitObstacleCb = fn || function () {};\n }\n }]);\n\n return Skier;\n}(_sprite__WEBPACK_IMPORTED_MODULE_0__[\"default\"]);\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Skier);\n\n//# sourceURL=webpack:///./js/lib/skier.js?"); -CanvasRenderingContext2D.prototype.followSprite = function (sprite) { - this.centralSprite = sprite; -}; +/***/ }), -CanvasRenderingContext2D.prototype.getCentralPosition = function () { - return { - map: this.centralSprite.mapPosition, - canvas: [ Math.round(this.canvas.width * 0.5), Math.round(this.canvas.height * 0.5), 0] - }; -}; +/***/ "./js/lib/snowboarder.js": +/*!*******************************!*\ + !*** ./js/lib/snowboarder.js ***! + \*******************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -CanvasRenderingContext2D.prototype.mapPositionToCanvasPosition = function (position) { - var central = this.getCentralPosition(); - var centralMapPosition = central.map; - var centralCanvasPosition = central.canvas; - var mapDifferenceX = centralMapPosition[0] - position[0]; - var mapDifferenceY = centralMapPosition[1] - position[1]; - return [ centralCanvasPosition[0] - mapDifferenceX, centralCanvasPosition[1] - mapDifferenceY ]; -}; +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _sprite__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./sprite */ \"./js/lib/sprite.js\");\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _get(target, property, receiver) { if (typeof Reflect !== \"undefined\" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); }\n\nfunction _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\n\n\nvar Snowboarder =\n/*#__PURE__*/\nfunction (_Sprite) {\n _inherits(Snowboarder, _Sprite);\n\n function Snowboarder(data) {\n var _this;\n\n _classCallCheck(this, Snowboarder);\n\n _this = _possibleConstructorReturn(this, _getPrototypeOf(Snowboarder).call(this, data));\n _this.directions = {\n sEast: function sEast(xDiff) {\n return xDiff > 0;\n },\n sWest: function sWest(xDiff) {\n return xDiff <= 0;\n }\n };\n var standardSpeed = 3;\n\n _this.setSpeed(standardSpeed);\n\n return _this;\n }\n\n _createClass(Snowboarder, [{\n key: \"getDirection\",\n value: function getDirection() {\n var xDiff = this.movingToward[0] - this.mapPosition[0];\n\n if (this.directions.sEast(xDiff)) {\n return 'sEast';\n } else {\n return 'sWest';\n }\n }\n }, {\n key: \"cycle\",\n value: function cycle(dContext) {\n if (Number.random(10) === 1) {\n this.setMapPositionTarget(dContext.getRandomlyInTheCentreOfMap());\n this.setSpeed(this.standardSpeed + Number.random(-1, 1));\n }\n\n this.setMapPositionTarget(undefined, dContext.getMapBelowViewport() + 600);\n\n _get(_getPrototypeOf(Snowboarder.prototype), \"cycle\", this).call(this);\n }\n }, {\n key: \"draw\",\n value: function draw(dContext) {\n return _get(_getPrototypeOf(Snowboarder.prototype), \"draw\", this).call(this, dContext, this.getDirection());\n }\n }]);\n\n return Snowboarder;\n}(_sprite__WEBPACK_IMPORTED_MODULE_0__[\"default\"]);\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Snowboarder);\n\n//# sourceURL=webpack:///./js/lib/snowboarder.js?"); -CanvasRenderingContext2D.prototype.canvasPositionToMapPosition = function (position) { - var central = this.getCentralPosition(); - var centralMapPosition = central.map; - var centralCanvasPosition = central.canvas; - var mapDifferenceX = centralCanvasPosition[0] - position[0]; - var mapDifferenceY = centralCanvasPosition[1] - position[1]; - return [ centralMapPosition[0] - mapDifferenceX, centralMapPosition[1] - mapDifferenceY ]; -}; +/***/ }), -CanvasRenderingContext2D.prototype.getCentreOfViewport = function () { - return (this.canvas.width / 2).floor(); -}; +/***/ "./js/lib/sprite.js": +/*!**************************!*\ + !*** ./js/lib/sprite.js ***! + \**************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -// Y-pos canvas functions -CanvasRenderingContext2D.prototype.getMiddleOfViewport = function () { - return (this.canvas.height / 2).floor(); -}; +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _guid__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./guid */ \"./js/lib/guid.js\");\n/* harmony import */ var _guid__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_guid__WEBPACK_IMPORTED_MODULE_0__);\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n\n\nvar Sprite =\n/*#__PURE__*/\nfunction () {\n function Sprite(data) {\n _classCallCheck(this, Sprite);\n\n this.data = data || {\n parts: {}\n };\n this.hittableObjects = {};\n this.zIndexesOccupied = [0];\n this.trackedSpriteToMoveToward;\n this.direction = undefined;\n this.mapPosition = [0, 0, 0];\n this.id = _guid__WEBPACK_IMPORTED_MODULE_0___default()();\n this.canvasX = 0;\n this.canvasY = 0;\n this.canvasZ = 0;\n this.height = 0;\n this.speed = 0;\n this.movingToward = [0, 0];\n this.metresDownTheMountain = 0;\n this.movingWithConviction = false;\n this.deleted = false;\n this.maxHeight = Object.values(this.data.parts).map(function (p) {\n return p[3];\n }).max();\n this.isMoving = true;\n\n if (!this.data.parts) {\n this.data.parts = {};\n }\n\n if (this.data && this.data.id) {\n this.id = this.data.id;\n }\n\n if (this.data && this.data.zIndexesOccupied) {\n this.zIndexesOccupied = this.data.zIndexesOccupied;\n }\n }\n\n _createClass(Sprite, [{\n key: \"incrementX\",\n value: function incrementX(amount) {\n this.canvasX += amount.toNumber();\n }\n }, {\n key: \"incrementY\",\n value: function incrementY(amount) {\n this.canvasY += amount.toNumber();\n }\n }, {\n key: \"getHitBox\",\n value: function getHitBox(forZIndex) {\n if (this.data.hitBoxes) {\n if (this.data.hitBoxes[forZIndex]) {\n return this.data.hitBoxes[forZIndex];\n }\n }\n }\n }, {\n key: \"roundHalf\",\n value: function roundHalf(num) {\n num = Math.round(num * 2) / 2;\n return num;\n }\n }, {\n key: \"move\",\n value: function move() {\n if (!this.isMoving) {\n return;\n }\n\n var currentX = this.mapPosition[0];\n var currentY = this.mapPosition[1];\n\n if (typeof this.direction !== 'undefined') {\n // For this we need to modify the this.direction so it relates to the horizontal\n var d = this.direction - 90;\n if (d < 0) d = 360 + d;\n currentX += this.roundHalf(this.speed * Math.cos(d * (Math.PI / 180)));\n currentY += this.roundHalf(this.speed * Math.sin(d * (Math.PI / 180)));\n } else {\n if (typeof this.movingToward[0] !== 'undefined') {\n if (currentX > this.movingToward[0]) {\n currentX -= Math.min(this.getSpeedX(), Math.abs(currentX - this.movingToward[0]));\n } else if (currentX < this.movingToward[0]) {\n currentX += Math.min(this.getSpeedX(), Math.abs(currentX - this.movingToward[0]));\n }\n }\n\n if (typeof this.movingToward[1] !== 'undefined') {\n if (currentY > this.movingToward[1]) {\n currentY -= Math.min(this.getSpeedY(), Math.abs(currentY - this.movingToward[1]));\n } else if (currentY < this.movingToward[1]) {\n currentY += Math.min(this.getSpeedY(), Math.abs(currentY - this.movingToward[1]));\n }\n }\n }\n\n this.setMapPosition(currentX, currentY);\n }\n }, {\n key: \"draw\",\n value: function draw(dCtx, spriteFrame) {\n var fr = this.data.parts[spriteFrame];\n this.height = fr[3];\n this.width = fr[2];\n var newCanvasPosition = dCtx.mapPositionToCanvasPosition(this.mapPosition);\n this.setCanvasPosition(newCanvasPosition[0], newCanvasPosition[1]);\n dCtx.drawImage(dCtx.getLoadedImage(this.data.$imageFile), fr[0], fr[1], fr[2], fr[3], this.canvasX, this.canvasY, fr[2], fr[3]);\n }\n }, {\n key: \"setMapPosition\",\n value: function setMapPosition(x, y, z) {\n if (typeof x === 'undefined') {\n x = this.mapPosition[0];\n }\n\n if (typeof y === 'undefined') {\n y = this.mapPosition[1];\n }\n\n if (typeof z === 'undefined') {\n z = this.mapPosition[2];\n } else {\n this.zIndexesOccupied = [z];\n }\n\n this.mapPosition = [x, y, z];\n }\n }, {\n key: \"setCanvasPosition\",\n value: function setCanvasPosition(cx, cy) {\n if (cx) {\n if (Object.isString(cx) && (cx.first() === '+' || cx.first() === '-')) this.incrementX(cx);else this.canvasX = cx;\n }\n\n if (cy) {\n if (Object.isString(cy) && (cy.first() === '+' || cy.first() === '-')) this.incrementY(cy);else this.canvasY = cy;\n }\n }\n }, {\n key: \"getCanvasPositionX\",\n value: function getCanvasPositionX() {\n return this.canvasX;\n }\n }, {\n key: \"getCanvasPositionY\",\n value: function getCanvasPositionY() {\n return this.canvasY;\n }\n }, {\n key: \"getLeftHitBoxEdge\",\n value: function getLeftHitBoxEdge(zIndex) {\n zIndex = zIndex || 0;\n var lhbe = this.getCanvasPositionX();\n\n if (this.getHitBox(zIndex)) {\n lhbe += this.getHitBox(zIndex)[0];\n }\n\n return lhbe;\n }\n }, {\n key: \"getTopHitBoxEdge\",\n value: function getTopHitBoxEdge(zIndex) {\n zIndex = zIndex || 0;\n var thbe = this.getCanvasPositionY();\n\n if (this.getHitBox(zIndex)) {\n thbe += this.getHitBox(zIndex)[1];\n }\n\n return thbe;\n }\n }, {\n key: \"getRightHitBoxEdge\",\n value: function getRightHitBoxEdge(zIndex) {\n zIndex = zIndex || 0;\n\n if (this.getHitBox(zIndex)) {\n return this.canvasX + this.getHitBox(zIndex)[2];\n }\n\n return this.canvasX + this.width;\n }\n }, {\n key: \"getBottomHitBoxEdge\",\n value: function getBottomHitBoxEdge(zIndex) {\n zIndex = zIndex || 0;\n\n if (this.getHitBox(zIndex)) {\n return this.canvasY + this.getHitBox(zIndex)[3];\n }\n\n return this.canvasY + this.height;\n }\n }, {\n key: \"getPositionInFrontOf\",\n value: function getPositionInFrontOf() {\n return [this.canvasX, this.canvasY + this.height];\n }\n }, {\n key: \"setSpeed\",\n value: function setSpeed(s) {\n this.speed = s;\n this.speedX = s;\n this.speedY = s;\n }\n }, {\n key: \"incrementSpeedBy\",\n value: function incrementSpeedBy(s) {\n this.speed += s;\n }\n }, {\n key: \"getSpeed\",\n value: function getSpeed() {\n return this.speed;\n }\n }, {\n key: \"getSpeedX\",\n value: function getSpeedX() {\n return this.speed;\n }\n }, {\n key: \"getSpeedY\",\n value: function getSpeedY() {\n return this.speed;\n }\n }, {\n key: \"setHeight\",\n value: function setHeight(h) {\n this.height = h;\n }\n }, {\n key: \"setWidth\",\n value: function setWidth(w) {\n this.width = w;\n }\n }, {\n key: \"getMaxHeight\",\n value: function getMaxHeight() {\n return this.maxHeight;\n }\n }, {\n key: \"getMovingTowardOpposite\",\n value: function getMovingTowardOpposite() {\n if (!this.isMoving) {\n return [0, 0];\n }\n\n var dx = this.movingToward[0] - this.mapPosition[0];\n var dy = this.movingToward[1] - this.mapPosition[1];\n var oppositeX = Math.abs(dx) > 75 ? 0 - dx : 0;\n var oppositeY = -dy;\n return [oppositeX, oppositeY];\n }\n }, {\n key: \"checkHittableObjects\",\n value: function checkHittableObjects() {\n var _this = this;\n\n Object.keys(this.hittableObjects, function (k, objectData) {\n if (objectData.object.deleted) {\n delete _this.hittableObjects[k];\n } else {\n if (objectData.object.hits(_this)) {\n objectData.callbacks.each(function (callback) {\n callback(this, objectData.object);\n });\n }\n }\n });\n }\n }, {\n key: \"cycle\",\n value: function cycle() {\n this.checkHittableObjects();\n\n if (this.trackedSpriteToMoveToward) {\n this.setMapPositionTarget(this.trackedSpriteToMoveToward.mapPosition[0], this.trackedSpriteToMoveToward.mapPosition[1], true);\n }\n\n this.move();\n }\n }, {\n key: \"setMapPositionTarget\",\n value: function setMapPositionTarget(x, y, override) {\n if (override) {\n this.movingWithConviction = false;\n }\n\n if (!this.movingWithConviction) {\n if (typeof x === 'undefined') {\n x = this.movingToward[0];\n }\n\n if (typeof y === 'undefined') {\n y = this.movingToward[1];\n }\n\n this.movingToward = [x, y];\n this.movingWithConviction = false;\n } // this.resetDirection();\n\n }\n }, {\n key: \"setDirection\",\n value: function setDirection(angle) {\n if (angle >= 360) {\n angle = 360 - angle;\n }\n\n this.direction = angle;\n this.movingToward = undefined;\n }\n }, {\n key: \"resetDirection\",\n value: function resetDirection() {\n this.direction = undefined;\n }\n }, {\n key: \"setMapPositionTargetWithConviction\",\n value: function setMapPositionTargetWithConviction(cx, cy) {\n this.setMapPositionTarget(cx, cy);\n this.movingWithConviction = true; // this.resetDirection();\n }\n }, {\n key: \"follow\",\n value: function follow(sprite) {\n this.trackedSpriteToMoveToward = sprite; // this.resetDirection();\n }\n }, {\n key: \"stopFollowing\",\n value: function stopFollowing() {\n this.trackedSpriteToMoveToward = false;\n }\n }, {\n key: \"onHitting\",\n value: function onHitting(objectToHit, callback) {\n if (this.hittableObjects[objectToHit.id]) {\n return this.hittableObjects[objectToHit.id].callbacks.push(callback);\n }\n\n this.hittableObjects[objectToHit.id] = {\n object: objectToHit,\n callbacks: [callback]\n };\n }\n }, {\n key: \"deleteOnNextCycle\",\n value: function deleteOnNextCycle() {\n this.deleted = true;\n }\n }, {\n key: \"occupiesZIndex\",\n value: function occupiesZIndex(z) {\n return this.zIndexesOccupied.indexOf(z) >= 0;\n }\n }, {\n key: \"hits\",\n value: function hits(other) {\n var verticalIntersect = false;\n var horizontalIntersect = false; // Test this.THIS has a bottom edge inside of the other object\n\n if (other.getTopHitBoxEdge(this.mapPosition[2]) <= this.getBottomHitBoxEdge(this.mapPosition[2]) && other.getBottomHitBoxEdge(this.mapPosition[2]) >= this.getBottomHitBoxEdge(this.mapPosition[2])) {\n verticalIntersect = true;\n } // Test this.THIS has a top edge inside of the other object\n\n\n if (other.getTopHitBoxEdge(this.mapPosition[2]) <= this.getTopHitBoxEdge(this.mapPosition[2]) && other.getBottomHitBoxEdge(this.mapPosition[2]) >= this.getTopHitBoxEdge(this.mapPosition[2])) {\n verticalIntersect = true;\n } // Test this.THIS has a right edge inside of the other object\n\n\n if (other.getLeftHitBoxEdge(this.mapPosition[2]) <= this.getRightHitBoxEdge(this.mapPosition[2]) && other.getRightHitBoxEdge(this.mapPosition[2]) >= this.getRightHitBoxEdge(this.mapPosition[2])) {\n horizontalIntersect = true;\n } // Test this.THIS has a left edge inside of the other object\n\n\n if (other.getLeftHitBoxEdge(this.mapPosition[2]) <= this.getLeftHitBoxEdge(this.mapPosition[2]) && other.getRightHitBoxEdge(this.mapPosition[2]) >= this.getLeftHitBoxEdge(this.mapPosition[2])) {\n horizontalIntersect = true;\n }\n\n return verticalIntersect && horizontalIntersect;\n }\n }, {\n key: \"isAboveOnCanvas\",\n value: function isAboveOnCanvas(cy) {\n return this.canvasY + this.height < cy;\n }\n }, {\n key: \"isBelowOnCanvas\",\n value: function isBelowOnCanvas(cy) {\n return this.canvasY > cy;\n }\n }]);\n\n return Sprite;\n}();\n\nSprite.createObjects = function createObjects(spriteInfoArray, opts) {\n if (!Array.isArray(spriteInfoArray)) spriteInfoArray = [spriteInfoArray];\n opts = Object.merge(opts, {\n rateModifier: 0,\n dropRate: 1,\n position: [0, 0]\n }, false, false);\n\n function createOne(spriteInfo) {\n var position = opts.position;\n\n if (Number.random(100 + opts.rateModifier) <= spriteInfo.dropRate) {\n var sprite = new Sprite(spriteInfo.sprite);\n sprite.setSpeed(0);\n\n if (Object.isFunction(position)) {\n position = position();\n }\n\n sprite.setMapPosition(position[0], position[1]);\n\n if (spriteInfo.sprite.hitBehaviour && spriteInfo.sprite.hitBehaviour.skier && opts.player) {\n sprite.onHitting(opts.player, spriteInfo.sprite.hitBehaviour.skier);\n }\n\n return sprite;\n }\n }\n\n var objects = spriteInfoArray.map(createOne).remove(undefined);\n return objects;\n};\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (Sprite);\n\n//# sourceURL=webpack:///./js/lib/sprite.js?"); -CanvasRenderingContext2D.prototype.getBelowViewport = function () { - return this.canvas.height.floor(); -}; +/***/ }), -CanvasRenderingContext2D.prototype.getMapBelowViewport = function () { - var below = this.getBelowViewport(); - return this.canvasPositionToMapPosition([ 0, below ])[1]; -}; +/***/ "./js/lib/spriteArray.js": +/*!*******************************!*\ + !*** ./js/lib/spriteArray.js ***! + \*******************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -CanvasRenderingContext2D.prototype.getRandomlyInTheCentreOfCanvas = function (buffer) { - var min = 0; - var max = this.canvas.width; +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _wrapNativeSuper(Class) { var _cache = typeof Map === \"function\" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== \"function\") { throw new TypeError(\"Super expression must either be null or a function\"); } if (typeof _cache !== \"undefined\") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); }\n\nfunction isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _construct(Parent, args, Class) { if (isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }\n\nfunction _isNativeFunction(fn) { return Function.toString.call(fn).indexOf(\"[native code]\") !== -1; }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\nvar SpriteArray =\n/*#__PURE__*/\nfunction (_Array) {\n _inherits(SpriteArray, _Array);\n\n function SpriteArray() {\n var _getPrototypeOf2;\n\n var _this;\n\n _classCallCheck(this, SpriteArray);\n\n for (var _len = arguments.length, items = new Array(_len), _key = 0; _key < _len; _key++) {\n items[_key] = arguments[_key];\n }\n\n _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(SpriteArray)).call.apply(_getPrototypeOf2, [this].concat(items)));\n _this.pushHandlers = [];\n return _this;\n }\n\n _createClass(SpriteArray, [{\n key: \"onPush\",\n value: function onPush(f, retroactive) {\n this.pushHandlers.push(f);\n\n if (retroactive) {\n this.each(f);\n }\n }\n }, {\n key: \"push\",\n value: function push(obj) {\n Array.prototype.push.call(this, obj);\n this.pushHandlers.each(function (handler) {\n handler(obj);\n });\n }\n }, {\n key: \"cull\",\n value: function cull() {\n this.each(function (obj, i) {\n if (obj.deleted) {\n return delete this[i];\n }\n });\n }\n }]);\n\n return SpriteArray;\n}(_wrapNativeSuper(Array));\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (SpriteArray); // (function (global) {\n// \tfunction SpriteArray() {\n// \t\tthis.pushHandlers = [];\n// \t\treturn this;\n// \t}\n// \tSpriteArray.prototype = Object.create(Array.prototype);\n// \tSpriteArray.prototype.onPush = function(f, retroactive) {\n// \t\tthis.pushHandlers.push(f);\n// \t\tif (retroactive) {\n// \t\t\tthis.each(f);\n// \t\t}\n// \t};\n// \tSpriteArray.prototype.push = function(obj) {\n// \t\tArray.prototype.push.call(this, obj);\n// \t\tthis.pushHandlers.each(function(handler) {\n// \t\t\thandler(obj);\n// \t\t});\n// \t};\n// \tSpriteArray.prototype.cull = function() {\n// \t\tthis.each(function (obj, i) {\n// \t\t\tif (obj.deleted) {\n// \t\t\t\treturn (delete this[i]);\n// \t\t\t}\n// \t\t});\n// \t};\n// \tglobal.spriteArray = SpriteArray;\n// })(this);\n// if (typeof module !== 'undefined') {\n// \tmodule.exports = this.spriteArray;\n// }\n\n//# sourceURL=webpack:///./js/lib/spriteArray.js?"); - if (buffer) { - min -= buffer; - max += buffer; - } +/***/ }), - return Number.random(min, max); -}; +/***/ "./js/main.js": +/*!********************!*\ + !*** ./js/main.js ***! + \********************/ +/*! no exports provided */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -CanvasRenderingContext2D.prototype.getRandomlyInTheCentreOfMap = function (buffer) { - var random = this.getRandomlyInTheCentreOfCanvas(buffer); - return this.canvasPositionToMapPosition([ random, 0 ])[0]; -}; +"use strict"; +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _lib_canvasRenderingContext2DExtensions__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./lib/canvasRenderingContext2DExtensions */ \"./js/lib/canvasRenderingContext2DExtensions.js\");\n/* harmony import */ var _lib_canvasRenderingContext2DExtensions__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_lib_canvasRenderingContext2DExtensions__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _lib_extenders__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./lib/extenders */ \"./js/lib/extenders.js\");\n/* harmony import */ var _lib_extenders__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_lib_extenders__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _lib_plugins__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./lib/plugins */ \"./js/lib/plugins.js\");\n/* harmony import */ var _lib_plugins__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_lib_plugins__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var hammerjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! hammerjs */ \"./node_modules/hammerjs/hammer.js\");\n/* harmony import */ var hammerjs__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(hammerjs__WEBPACK_IMPORTED_MODULE_3__);\n/* harmony import */ var br_mousetrap__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! br-mousetrap */ \"./node_modules/br-mousetrap/mousetrap.js\");\n/* harmony import */ var br_mousetrap__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(br_mousetrap__WEBPACK_IMPORTED_MODULE_4__);\n/* harmony import */ var _lib_isMobileDevice__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./lib/isMobileDevice */ \"./js/lib/isMobileDevice.js\");\n/* harmony import */ var _lib_isMobileDevice__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_lib_isMobileDevice__WEBPACK_IMPORTED_MODULE_5__);\n/* harmony import */ var _lib_monster__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./lib/monster */ \"./js/lib/monster.js\");\n/* harmony import */ var _lib_sprite__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./lib/sprite */ \"./js/lib/sprite.js\");\n/* harmony import */ var _lib_snowboarder__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./lib/snowboarder */ \"./js/lib/snowboarder.js\");\n/* harmony import */ var _lib_skier__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./lib/skier */ \"./js/lib/skier.js\");\n/* harmony import */ var _lib_infoBox__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./lib/infoBox */ \"./js/lib/infoBox.js\");\n/* harmony import */ var _lib_infoBox__WEBPACK_IMPORTED_MODULE_10___default = /*#__PURE__*/__webpack_require__.n(_lib_infoBox__WEBPACK_IMPORTED_MODULE_10__);\n/* harmony import */ var _lib_game__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./lib/game */ \"./js/lib/game.js\");\n/* harmony import */ var _spriteInfo__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./spriteInfo */ \"./js/spriteInfo.js\");\n/* harmony import */ var _spriteInfo__WEBPACK_IMPORTED_MODULE_12___default = /*#__PURE__*/__webpack_require__.n(_spriteInfo__WEBPACK_IMPORTED_MODULE_12__);\n// Global dependencies which return no modules\n\n\n // External dependencies\n\n\n // Method modules\n\n // Game Objects\n\n\n\n\n\n\n // Local variables for starting the game\n\nvar mainCanvas = document.getElementById('skifree-canvas');\nvar dContext = mainCanvas.getContext('2d');\nvar imageSources = ['sprite-characters.png', 'skifree-objects.png'];\nvar infoBoxControls = 'Use the mouse or WASD to control the player';\nif (_lib_isMobileDevice__WEBPACK_IMPORTED_MODULE_5___default()()) infoBoxControls = 'Tap or drag on the piste to control the player';\n\nvar pixelsPerMetre = 18;\nvar distanceTravelledInMetres = 0;\nvar monsterDistanceThreshold = 2000;\nvar livesLeft = 5;\nvar highScore = 0;\nvar loseLifeOnObstacleHit = false;\nvar dropRates = {\n smallTree: 4,\n tallTree: 2,\n jump: 1,\n thickSnow: 1,\n rock: 1\n};\nif (localStorage.getItem('highScore')) highScore = localStorage.getItem('highScore');\n\nfunction loadImages(sources, next) {\n var loaded = 0;\n var images = {};\n\n function finish() {\n loaded += 1;\n\n if (loaded === sources.length) {\n next(images);\n }\n }\n\n sources.each(function (src) {\n var im = new Image();\n im.onload = finish;\n im.src = src;\n dContext.storeLoadedImage(src, im);\n });\n}\n\nfunction monsterHitsSkierBehaviour(monster, skier) {\n skier.isEatenBy(monster, function () {\n livesLeft -= 1;\n monster.isFull = true;\n monster.isEating = false;\n skier.isBeingEaten = false;\n monster.setSpeed(skier.getSpeed());\n monster.stopFollowing();\n var randomPositionAbove = dContext.getRandomMapPositionAboveViewport();\n monster.setMapPositionTarget(randomPositionAbove[0], randomPositionAbove[1]);\n });\n}\n\nfunction startNeverEndingGame(images) {\n var player;\n var startSign;\n var infoBox;\n var game;\n\n function resetGame() {\n distanceTravelledInMetres = 0;\n livesLeft = 5;\n highScore = localStorage.getItem('highScore');\n game.reset();\n game.addStaticObject(startSign);\n }\n\n function detectEnd() {\n if (!game.isPaused()) {\n highScore = localStorage.setItem('highScore', distanceTravelledInMetres);\n infoBox.setLines(['Game over!', 'Hit space to restart']);\n game.pause();\n game.cycle();\n }\n }\n\n function randomlySpawnNPC(spawnFunction, dropRate) {\n var rateModifier = Math.max(800 - mainCanvas.width, 0);\n\n if (Number.random(1000 + rateModifier) <= dropRate) {\n spawnFunction();\n }\n }\n\n function spawnMonster() {\n var newMonster = new _lib_monster__WEBPACK_IMPORTED_MODULE_6__[\"default\"](_spriteInfo__WEBPACK_IMPORTED_MODULE_12___default.a.monster);\n var randomPosition = dContext.getRandomMapPositionAboveViewport();\n newMonster.setMapPosition(randomPosition[0], randomPosition[1]);\n newMonster.follow(player);\n newMonster.setSpeed(player.getStandardSpeed());\n newMonster.onHitting(player, monsterHitsSkierBehaviour);\n game.addMovingObject(newMonster, 'monster');\n }\n\n function spawnBoarder() {\n var newBoarder = new _lib_snowboarder__WEBPACK_IMPORTED_MODULE_8__[\"default\"](_spriteInfo__WEBPACK_IMPORTED_MODULE_12___default.a.snowboarder);\n var randomPositionAbove = dContext.getRandomMapPositionAboveViewport();\n var randomPositionBelow = dContext.getRandomMapPositionBelowViewport();\n newBoarder.setMapPosition(randomPositionAbove[0], randomPositionAbove[1]);\n newBoarder.setMapPositionTarget(randomPositionBelow[0], randomPositionBelow[1]);\n newBoarder.onHitting(player, _spriteInfo__WEBPACK_IMPORTED_MODULE_12___default.a.snowboarder.hitBehaviour.skier);\n game.addMovingObject(newBoarder);\n }\n\n player = new _lib_skier__WEBPACK_IMPORTED_MODULE_9__[\"default\"](_spriteInfo__WEBPACK_IMPORTED_MODULE_12___default.a.skier);\n player.setMapPosition(0, 0);\n player.setMapPositionTarget(0, -10);\n\n if (loseLifeOnObstacleHit) {\n player.setHitObstacleCb(function () {\n livesLeft -= 1;\n });\n }\n\n game = new _lib_game__WEBPACK_IMPORTED_MODULE_11__[\"default\"](mainCanvas, player);\n startSign = new _lib_sprite__WEBPACK_IMPORTED_MODULE_7__[\"default\"](_spriteInfo__WEBPACK_IMPORTED_MODULE_12___default.a.signStart);\n game.addStaticObject(startSign);\n startSign.setMapPosition(-50, 0);\n dContext.followSprite(player);\n infoBox = new _lib_infoBox__WEBPACK_IMPORTED_MODULE_10___default.a({\n initialLines: ['SkiFree.js', infoBoxControls, 'Travelled 0m', 'High Score: ' + highScore, 'Skiers left: ' + livesLeft, 'Created by Dan Hough (@basicallydan)'],\n position: {\n top: 15,\n right: 10\n }\n });\n game.beforeCycle(function () {\n var newObjects = [];\n\n if (player.isMoving) {\n newObjects = _lib_sprite__WEBPACK_IMPORTED_MODULE_7__[\"default\"].createObjects([{\n sprite: _spriteInfo__WEBPACK_IMPORTED_MODULE_12___default.a.smallTree,\n dropRate: dropRates.smallTree\n }, {\n sprite: _spriteInfo__WEBPACK_IMPORTED_MODULE_12___default.a.tallTree,\n dropRate: dropRates.tallTree\n }, {\n sprite: _spriteInfo__WEBPACK_IMPORTED_MODULE_12___default.a.jump,\n dropRate: dropRates.jump\n }, {\n sprite: _spriteInfo__WEBPACK_IMPORTED_MODULE_12___default.a.thickSnow,\n dropRate: dropRates.thickSnow\n }, {\n sprite: _spriteInfo__WEBPACK_IMPORTED_MODULE_12___default.a.rock,\n dropRate: dropRates.rock\n }], {\n rateModifier: Math.max(800 - mainCanvas.width, 0),\n position: function position() {\n return dContext.getRandomMapPositionBelowViewport();\n },\n player: player\n });\n }\n\n if (!game.isPaused()) {\n game.addStaticObjects(newObjects);\n randomlySpawnNPC(spawnBoarder, 0.1);\n distanceTravelledInMetres = parseFloat(player.getPixelsTravelledDownMountain() / pixelsPerMetre).toFixed(1);\n\n if (distanceTravelledInMetres > monsterDistanceThreshold) {\n randomlySpawnNPC(spawnMonster, 0.001);\n }\n\n infoBox.setLines(['SkiFree.js', infoBoxControls, 'Travelled ' + distanceTravelledInMetres + 'm', 'Skiers left: ' + livesLeft, 'High Score: ' + highScore, 'Created by Dan Hough (@basicallydan)', 'Current Speed: ' + player.getSpeed()\n /*,\n 'Skier Map Position: ' + player.mapPosition[0].toFixed(1) + ', ' + player.mapPosition[1].toFixed(1),\n 'Mouse Map Position: ' + mouseMapPosition[0].toFixed(1) + ', ' + mouseMapPosition[1].toFixed(1)*/\n ]);\n }\n });\n game.afterCycle(function () {\n if (livesLeft === 0) {\n detectEnd();\n }\n });\n game.addUIElement(infoBox);\n $(mainCanvas).mousemove(function (e) {\n game.setMouseX(e.pageX);\n game.setMouseY(e.pageY);\n player.resetDirection();\n player.startMovingIfPossible();\n }).bind('click', function (e) {\n game.setMouseX(e.pageX);\n game.setMouseY(e.pageY);\n player.resetDirection();\n player.startMovingIfPossible();\n }).focus(); // So we can listen to events immediately\n\n br_mousetrap__WEBPACK_IMPORTED_MODULE_4___default.a.bind('f', player.speedBoost);\n br_mousetrap__WEBPACK_IMPORTED_MODULE_4___default.a.bind('t', player.attemptTrick);\n br_mousetrap__WEBPACK_IMPORTED_MODULE_4___default.a.bind(['w', 'up'], function () {\n player.stop();\n });\n br_mousetrap__WEBPACK_IMPORTED_MODULE_4___default.a.bind(['a', 'left'], function () {\n if (player.direction === 270) {\n player.stepWest();\n } else {\n player.turnWest();\n }\n });\n br_mousetrap__WEBPACK_IMPORTED_MODULE_4___default.a.bind(['s', 'down'], function () {\n player.setDirection(180);\n player.startMovingIfPossible();\n });\n br_mousetrap__WEBPACK_IMPORTED_MODULE_4___default.a.bind(['d', 'right'], function () {\n if (player.direction === 90) {\n player.stepEast();\n } else {\n player.turnEast();\n }\n });\n br_mousetrap__WEBPACK_IMPORTED_MODULE_4___default.a.bind('m', spawnMonster);\n br_mousetrap__WEBPACK_IMPORTED_MODULE_4___default.a.bind('b', spawnBoarder);\n br_mousetrap__WEBPACK_IMPORTED_MODULE_4___default.a.bind('space', resetGame);\n var hammertime = new hammerjs__WEBPACK_IMPORTED_MODULE_3___default.a(mainCanvas);\n hammertime.on('press', function (e) {\n e.preventDefault();\n game.setMouseX(e.gesture.center.x);\n game.setMouseY(e.gesture.center.y);\n });\n hammertime.on('tap', function (e) {\n game.setMouseX(e.gesture.center.x);\n game.setMouseY(e.gesture.center.y);\n });\n hammertime.on('pan', function (e) {\n game.setMouseX(e.gesture.center.x);\n game.setMouseY(e.gesture.center.y);\n player.resetDirection();\n player.startMovingIfPossible();\n });\n hammertime.on('doubletap', function (e) {\n player.speedBoost();\n });\n player.isMoving = false;\n player.setDirection(270);\n game.start();\n}\n\nfunction resizeCanvas() {\n mainCanvas.width = window.innerWidth;\n mainCanvas.height = window.innerHeight;\n}\n\nwindow.addEventListener('resize', resizeCanvas, false);\nresizeCanvas();\nloadImages(imageSources, startNeverEndingGame);\n\n//# sourceURL=webpack:///./js/main.js?"); -CanvasRenderingContext2D.prototype.getRandomMapPositionBelowViewport = function () { - var xCanvas = this.getRandomlyInTheCentreOfCanvas(); - var yCanvas = this.getBelowViewport(); - return this.canvasPositionToMapPosition([ xCanvas, yCanvas ]); -}; +/***/ }), -CanvasRenderingContext2D.prototype.getRandomMapPositionAboveViewport = function () { - var xCanvas = this.getRandomlyInTheCentreOfCanvas(); - var yCanvas = this.getAboveViewport(); - return this.canvasPositionToMapPosition([ xCanvas, yCanvas ]); -}; +/***/ "./js/spriteInfo.js": +/*!**************************!*\ + !*** ./js/spriteInfo.js ***! + \**************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { -CanvasRenderingContext2D.prototype.getTopOfViewport = function () { - return this.canvasPositionToMapPosition([ 0, 0 ])[1]; -}; +eval("(function (global) {\n var sprites = {\n 'skier': {\n $imageFile: 'sprite-characters.png',\n parts: {\n blank: [0, 0, 0, 0],\n east: [0, 0, 24, 34],\n esEast: [24, 0, 24, 34],\n sEast: [49, 0, 17, 34],\n south: [65, 0, 17, 34],\n sWest: [49, 37, 17, 34],\n wsWest: [24, 37, 24, 34],\n west: [0, 37, 24, 34],\n hit: [0, 78, 31, 31],\n jumping: [84, 0, 32, 34],\n somersault1: [116, 0, 32, 34],\n somersault2: [148, 0, 32, 34]\n },\n hitBoxes: {\n 0: [7, 20, 27, 34]\n },\n id: 'player',\n hitBehaviour: {}\n },\n 'smallTree': {\n $imageFile: 'skifree-objects.png',\n parts: {\n main: [0, 28, 30, 34]\n },\n hitBoxes: {\n 0: [0, 18, 30, 34]\n },\n hitBehaviour: {}\n },\n 'tallTree': {\n $imageFile: 'skifree-objects.png',\n parts: {\n main: [95, 66, 32, 64]\n },\n zIndexesOccupied: [0, 1],\n hitBoxes: {\n 0: [0, 54, 32, 64],\n 1: [0, 10, 32, 54]\n },\n hitBehaviour: {}\n },\n 'thickSnow': {\n $imageFile: 'skifree-objects.png',\n parts: {\n main: [143, 53, 43, 10]\n },\n hitBehaviour: {}\n },\n 'rock': {\n $imageFile: 'skifree-objects.png',\n parts: {\n main: [30, 52, 23, 11]\n },\n hitBehaviour: {}\n },\n 'monster': {\n $imageFile: 'sprite-characters.png',\n parts: {\n sEast1: [64, 112, 26, 43],\n sEast2: [90, 112, 32, 43],\n sWest1: [64, 158, 26, 43],\n sWest2: [90, 158, 32, 43],\n eating1: [122, 112, 34, 43],\n eating2: [156, 112, 31, 43],\n eating3: [187, 112, 31, 43],\n eating4: [219, 112, 25, 43],\n eating5: [243, 112, 26, 43]\n },\n hitBehaviour: {}\n },\n 'jump': {\n $imageFile: 'skifree-objects.png',\n parts: {\n main: [109, 55, 32, 8]\n },\n hitBehaviour: {}\n },\n 'signStart': {\n $imageFile: 'skifree-objects.png',\n parts: {\n main: [260, 103, 42, 27]\n },\n hitBehaviour: {}\n },\n 'snowboarder': {\n $imageFile: 'sprite-characters.png',\n parts: {\n sEast: [73, 229, 20, 29],\n sWest: [95, 228, 26, 30]\n },\n hitBehaviour: {}\n },\n 'emptyChairLift': {\n $imageFile: 'skifree-objects.png',\n parts: {\n main: [92, 136, 26, 30]\n },\n zIndexesOccupied: [1]\n }\n };\n\n function monsterHitsTreeBehaviour(monster) {\n monster.deleteOnNextCycle();\n }\n\n sprites.monster.hitBehaviour.tree = monsterHitsTreeBehaviour;\n\n function treeHitsMonsterBehaviour(tree, monster) {\n monster.deleteOnNextCycle();\n }\n\n sprites.smallTree.hitBehaviour.monster = treeHitsMonsterBehaviour;\n sprites.tallTree.hitBehaviour.monster = treeHitsMonsterBehaviour;\n\n function skierHitsTreeBehaviour(skier, tree) {\n skier.hasHitObstacle(tree);\n }\n\n function treeHitsSkierBehaviour(tree, skier) {\n skier.hasHitObstacle(tree);\n }\n\n sprites.smallTree.hitBehaviour.skier = treeHitsSkierBehaviour;\n sprites.tallTree.hitBehaviour.skier = treeHitsSkierBehaviour;\n\n function rockHitsSkierBehaviour(rock, skier) {\n skier.hasHitObstacle(rock);\n }\n\n sprites.rock.hitBehaviour.skier = rockHitsSkierBehaviour;\n\n function skierHitsJumpBehaviour(skier, jump) {\n skier.hasHitJump(jump);\n }\n\n function jumpHitsSkierBehaviour(jump, skier) {\n skier.hasHitJump(jump);\n }\n\n sprites.jump.hitBehaviour.skier = jumpHitsSkierBehaviour; // Really not a fan of this behaviour.\n\n /*\tfunction skierHitsThickSnowBehaviour(skier, thickSnow) {\n \t\t// Need to implement this properly\n \t\tskier.setSpeed(2);\n \t\tsetTimeout(function() {\n \t\t\tskier.resetSpeed();\n \t\t}, 700);\n \t}\n \n \tfunction thickSnowHitsSkierBehaviour(thickSnow, skier) {\n \t\t// Need to implement this properly\n \t\tskier.setSpeed(2);\n \t\tsetTimeout(function() {\n \t\t\tskier.resetSpeed();\n \t\t}, 300);\n \t}*/\n // sprites.thickSnow.hitBehaviour.skier = thickSnowHitsSkierBehaviour;\n\n function snowboarderHitsSkierBehaviour(snowboarder, skier) {\n skier.hasHitObstacle(snowboarder);\n }\n\n sprites.snowboarder.hitBehaviour.skier = snowboarderHitsSkierBehaviour;\n global.spriteInfo = sprites;\n})(this);\n\nif (true) {\n module.exports = this.spriteInfo;\n}\n\n//# sourceURL=webpack:///./js/spriteInfo.js?"); -CanvasRenderingContext2D.prototype.getAboveViewport = function () { - return 0 - (this.canvas.height / 4).floor(); -}; -},{}],2:[function(require,module,exports){ -// Extends function so that new-able objects can be given new methods easily -Function.prototype.method = function (name, func) { - this.prototype[name] = func; - return this; -}; +/***/ }), -// Will return the original method of an object when inheriting from another -Object.method('superior', function (name) { - var that = this; - var method = that[name]; - return function() { - return method.apply(that, arguments); - }; -}); -},{}],3:[function(require,module,exports){ -var SpriteArray = require('./spriteArray'); -var EventedLoop = require('eventedloop'); +/***/ "./node_modules/br-mousetrap/mousetrap.js": +/*!************************************************!*\ + !*** ./node_modules/br-mousetrap/mousetrap.js ***! + \************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { -(function (global) { - function Game (mainCanvas, player) { - var staticObjects = new SpriteArray(); - var movingObjects = new SpriteArray(); - var uiElements = new SpriteArray(); - var dContext = mainCanvas.getContext('2d'); - var mouseX = dContext.getCentreOfViewport(); - var mouseY = 0; - var paused = false; - var that = this; - var beforeCycleCallbacks = []; - var afterCycleCallbacks = []; - var gameLoop = new EventedLoop(); +eval("var __WEBPACK_AMD_DEFINE_RESULT__;/**\n * Copyright 2012 Craig Campbell\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Mousetrap is a simple keyboard shortcut library for Javascript with\n * no external dependencies\n *\n * @version 1.1.3\n * @url craig.is/killing/mice\n */\n(function() {\n\n /**\n * mapping of special keycodes to their corresponding keys\n *\n * everything in this dictionary cannot use keypress events\n * so it has to be here to map to the correct keycodes for\n * keyup/keydown events\n *\n * @type {Object}\n */\n var _MAP = {\n 8: 'backspace',\n 9: 'tab',\n 13: 'enter',\n 16: 'shift',\n 17: 'ctrl',\n 18: 'alt',\n 20: 'capslock',\n 27: 'esc',\n 32: 'space',\n 33: 'pageup',\n 34: 'pagedown',\n 35: 'end',\n 36: 'home',\n 37: 'left',\n 38: 'up',\n 39: 'right',\n 40: 'down',\n 45: 'ins',\n 46: 'del',\n 91: 'meta',\n 93: 'meta',\n 224: 'meta'\n },\n\n /**\n * mapping for special characters so they can support\n *\n * this dictionary is only used incase you want to bind a\n * keyup or keydown event to one of these keys\n *\n * @type {Object}\n */\n _KEYCODE_MAP = {\n 106: '*',\n 107: '+',\n 109: '-',\n 110: '.',\n 111 : '/',\n 186: ';',\n 187: '=',\n 188: ',',\n 189: '-',\n 190: '.',\n 191: '/',\n 192: '`',\n 219: '[',\n 220: '\\\\',\n 221: ']',\n 222: '\\''\n },\n\n /**\n * this is a mapping of keys that require shift on a US keypad\n * back to the non shift equivelents\n *\n * this is so you can use keyup events with these keys\n *\n * note that this will only work reliably on US keyboards\n *\n * @type {Object}\n */\n _SHIFT_MAP = {\n '~': '`',\n '!': '1',\n '@': '2',\n '#': '3',\n '$': '4',\n '%': '5',\n '^': '6',\n '&': '7',\n '*': '8',\n '(': '9',\n ')': '0',\n '_': '-',\n '+': '=',\n ':': ';',\n '\\\"': '\\'',\n '<': ',',\n '>': '.',\n '?': '/',\n '|': '\\\\'\n },\n\n /**\n * this is a list of special strings you can use to map\n * to modifier keys when you specify your keyboard shortcuts\n *\n * @type {Object}\n */\n _SPECIAL_ALIASES = {\n 'option': 'alt',\n 'command': 'meta',\n 'return': 'enter',\n 'escape': 'esc'\n },\n\n /**\n * variable to store the flipped version of _MAP from above\n * needed to check if we should use keypress or not when no action\n * is specified\n *\n * @type {Object|undefined}\n */\n _REVERSE_MAP,\n\n /**\n * a list of all the callbacks setup via Mousetrap.bind()\n *\n * @type {Object}\n */\n _callbacks = {},\n\n /**\n * direct map of string combinations to callbacks used for trigger()\n *\n * @type {Object}\n */\n _direct_map = {},\n\n /**\n * keeps track of what level each sequence is at since multiple\n * sequences can start out with the same sequence\n *\n * @type {Object}\n */\n _sequence_levels = {},\n\n /**\n * variable to store the setTimeout call\n *\n * @type {null|number}\n */\n _reset_timer,\n\n /**\n * temporary state where we will ignore the next keyup\n *\n * @type {boolean|string}\n */\n _ignore_next_keyup = false,\n\n /**\n * are we currently inside of a sequence?\n * type of action (\"keyup\" or \"keydown\" or \"keypress\") or false\n *\n * @type {boolean|string}\n */\n _inside_sequence = false;\n\n /**\n * loop through the f keys, f1 to f19 and add them to the map\n * programatically\n */\n for (var i = 1; i < 20; ++i) {\n _MAP[111 + i] = 'f' + i;\n }\n\n /**\n * loop through to map numbers on the numeric keypad\n */\n for (i = 0; i <= 9; ++i) {\n _MAP[i + 96] = i;\n }\n\n /**\n * cross browser add event method\n *\n * @param {Element|HTMLDocument} object\n * @param {string} type\n * @param {Function} callback\n * @returns void\n */\n function _addEvent(object, type, callback) {\n if (object.addEventListener) {\n object.addEventListener(type, callback, false);\n return;\n }\n\n object.attachEvent('on' + type, callback);\n }\n\n /**\n * takes the event and returns the key character\n *\n * @param {Event} e\n * @return {string}\n */\n function _characterFromEvent(e) {\n\n // for keypress events we should return the character as is\n if (e.type == 'keypress') {\n return String.fromCharCode(e.which);\n }\n\n // for non keypress events the special maps are needed\n if (_MAP[e.which]) {\n return _MAP[e.which];\n }\n\n if (_KEYCODE_MAP[e.which]) {\n return _KEYCODE_MAP[e.which];\n }\n\n // if it is not in the special map\n return String.fromCharCode(e.which).toLowerCase();\n }\n\n /**\n * checks if two arrays are equal\n *\n * @param {Array} modifiers1\n * @param {Array} modifiers2\n * @returns {boolean}\n */\n function _modifiersMatch(modifiers1, modifiers2) {\n return modifiers1.sort().join(',') === modifiers2.sort().join(',');\n }\n\n /**\n * resets all sequence counters except for the ones passed in\n *\n * @param {Object} do_not_reset\n * @returns void\n */\n function _resetSequences(do_not_reset) {\n do_not_reset = do_not_reset || {};\n\n var active_sequences = false,\n key;\n\n for (key in _sequence_levels) {\n if (do_not_reset[key]) {\n active_sequences = true;\n continue;\n }\n _sequence_levels[key] = 0;\n }\n\n if (!active_sequences) {\n _inside_sequence = false;\n }\n }\n\n /**\n * finds all callbacks that match based on the keycode, modifiers,\n * and action\n *\n * @param {string} character\n * @param {Array} modifiers\n * @param {Event|Object} e\n * @param {boolean=} remove - should we remove any matches\n * @param {string=} combination\n * @returns {Array}\n */\n function _getMatches(character, modifiers, e, remove, combination) {\n var i,\n callback,\n matches = [],\n action = e.type;\n\n // if there are no events related to this keycode\n if (!_callbacks[character]) {\n return [];\n }\n\n // if a modifier key is coming up on its own we should allow it\n if (action == 'keyup' && _isModifier(character)) {\n modifiers = [character];\n }\n\n // loop through all callbacks for the key that was pressed\n // and see if any of them match\n for (i = 0; i < _callbacks[character].length; ++i) {\n callback = _callbacks[character][i];\n\n // if this is a sequence but it is not at the right level\n // then move onto the next match\n if (callback.seq && _sequence_levels[callback.seq] != callback.level) {\n continue;\n }\n\n // if the action we are looking for doesn't match the action we got\n // then we should keep going\n if (action != callback.action) {\n continue;\n }\n\n // if this is a keypress event and the meta key and control key\n // are not pressed that means that we need to only look at the\n // character, otherwise check the modifiers as well\n //\n // chrome will not fire a keypress if meta or control is down\n // safari will fire a keypress if meta or meta+shift is down\n // firefox will fire a keypress if meta or control is down\n if ((action == 'keypress' && !e.metaKey && !e.ctrlKey) || _modifiersMatch(modifiers, callback.modifiers)) {\n\n // remove is used so if you change your mind and call bind a\n // second time with a new function the first one is overwritten\n if (remove && callback.combo == combination) {\n _callbacks[character].splice(i, 1);\n }\n\n matches.push(callback);\n }\n }\n\n return matches;\n }\n\n /**\n * takes a key event and figures out what the modifiers are\n *\n * @param {Event} e\n * @returns {Array}\n */\n function _eventModifiers(e) {\n var modifiers = [];\n\n if (e.shiftKey) {\n modifiers.push('shift');\n }\n\n if (e.altKey) {\n modifiers.push('alt');\n }\n\n if (e.ctrlKey) {\n modifiers.push('ctrl');\n }\n\n if (e.metaKey) {\n modifiers.push('meta');\n }\n\n return modifiers;\n }\n\n /**\n * actually calls the callback function\n *\n * if your callback function returns false this will use the jquery\n * convention - prevent default and stop propogation on the event\n *\n * @param {Function} callback\n * @param {Event} e\n * @returns void\n */\n function _fireCallback(callback, e) {\n if (callback(e) === false) {\n if (e.preventDefault) {\n e.preventDefault();\n }\n\n if (e.stopPropagation) {\n e.stopPropagation();\n }\n\n e.returnValue = false;\n e.cancelBubble = true;\n }\n }\n\n /**\n * handles a character key event\n *\n * @param {string} character\n * @param {Event} e\n * @returns void\n */\n function _handleCharacter(character, e) {\n\n // if this event should not happen stop here\n if (Mousetrap.stopCallback(e, e.target || e.srcElement)) {\n return;\n }\n\n var callbacks = _getMatches(character, _eventModifiers(e), e),\n i,\n do_not_reset = {},\n processed_sequence_callback = false;\n\n // loop through matching callbacks for this key event\n for (i = 0; i < callbacks.length; ++i) {\n\n // fire for all sequence callbacks\n // this is because if for example you have multiple sequences\n // bound such as \"g i\" and \"g t\" they both need to fire the\n // callback for matching g cause otherwise you can only ever\n // match the first one\n if (callbacks[i].seq) {\n processed_sequence_callback = true;\n\n // keep a list of which sequences were matches for later\n do_not_reset[callbacks[i].seq] = 1;\n _fireCallback(callbacks[i].callback, e);\n continue;\n }\n\n // if there were no sequence matches but we are still here\n // that means this is a regular match so we should fire that\n if (!processed_sequence_callback && !_inside_sequence) {\n _fireCallback(callbacks[i].callback, e);\n }\n }\n\n // if you are inside of a sequence and the key you are pressing\n // is not a modifier key then we should reset all sequences\n // that were not matched by this key event\n if (e.type == _inside_sequence && !_isModifier(character)) {\n _resetSequences(do_not_reset);\n }\n }\n\n /**\n * handles a keydown event\n *\n * @param {Event} e\n * @returns void\n */\n function _handleKey(e) {\n\n // normalize e.which for key events\n // @see http://stackoverflow.com/questions/4285627/javascript-keycode-vs-charcode-utter-confusion\n e.which = typeof e.which == \"number\" ? e.which : e.keyCode;\n\n var character = _characterFromEvent(e);\n\n // no character found then stop\n if (!character) {\n return;\n }\n\n if (e.type == 'keyup' && _ignore_next_keyup == character) {\n _ignore_next_keyup = false;\n return;\n }\n\n _handleCharacter(character, e);\n }\n\n /**\n * determines if the keycode specified is a modifier key or not\n *\n * @param {string} key\n * @returns {boolean}\n */\n function _isModifier(key) {\n return key == 'shift' || key == 'ctrl' || key == 'alt' || key == 'meta';\n }\n\n /**\n * called to set a 1 second timeout on the specified sequence\n *\n * this is so after each key press in the sequence you have 1 second\n * to press the next key before you have to start over\n *\n * @returns void\n */\n function _resetSequenceTimer() {\n clearTimeout(_reset_timer);\n _reset_timer = setTimeout(_resetSequences, 1000);\n }\n\n /**\n * reverses the map lookup so that we can look for specific keys\n * to see what can and can't use keypress\n *\n * @return {Object}\n */\n function _getReverseMap() {\n if (!_REVERSE_MAP) {\n _REVERSE_MAP = {};\n for (var key in _MAP) {\n\n // pull out the numeric keypad from here cause keypress should\n // be able to detect the keys from the character\n if (key > 95 && key < 112) {\n continue;\n }\n\n if (_MAP.hasOwnProperty(key)) {\n _REVERSE_MAP[_MAP[key]] = key;\n }\n }\n }\n return _REVERSE_MAP;\n }\n\n /**\n * picks the best action based on the key combination\n *\n * @param {string} key - character for key\n * @param {Array} modifiers\n * @param {string=} action passed in\n */\n function _pickBestAction(key, modifiers, action) {\n\n // if no action was picked in we should try to pick the one\n // that we think would work best for this key\n if (!action) {\n action = _getReverseMap()[key] ? 'keydown' : 'keypress';\n }\n\n // modifier keys don't work as expected with keypress,\n // switch to keydown\n if (action == 'keypress' && modifiers.length) {\n action = 'keydown';\n }\n\n return action;\n }\n\n /**\n * binds a key sequence to an event\n *\n * @param {string} combo - combo specified in bind call\n * @param {Array} keys\n * @param {Function} callback\n * @param {string=} action\n * @returns void\n */\n function _bindSequence(combo, keys, callback, action) {\n\n // start off by adding a sequence level record for this combination\n // and setting the level to 0\n _sequence_levels[combo] = 0;\n\n // if there is no action pick the best one for the first key\n // in the sequence\n if (!action) {\n action = _pickBestAction(keys[0], []);\n }\n\n /**\n * callback to increase the sequence level for this sequence and reset\n * all other sequences that were active\n *\n * @param {Event} e\n * @returns void\n */\n var _increaseSequence = function(e) {\n _inside_sequence = action;\n ++_sequence_levels[combo];\n _resetSequenceTimer();\n },\n\n /**\n * wraps the specified callback inside of another function in order\n * to reset all sequence counters as soon as this sequence is done\n *\n * @param {Event} e\n * @returns void\n */\n _callbackAndReset = function(e) {\n _fireCallback(callback, e);\n\n // we should ignore the next key up if the action is key down\n // or keypress. this is so if you finish a sequence and\n // release the key the final key will not trigger a keyup\n if (action !== 'keyup') {\n _ignore_next_keyup = _characterFromEvent(e);\n }\n\n // weird race condition if a sequence ends with the key\n // another sequence begins with\n setTimeout(_resetSequences, 10);\n },\n i;\n\n // loop through keys one at a time and bind the appropriate callback\n // function. for any key leading up to the final one it should\n // increase the sequence. after the final, it should reset all sequences\n for (i = 0; i < keys.length; ++i) {\n _bindSingle(keys[i], i < keys.length - 1 ? _increaseSequence : _callbackAndReset, action, combo, i);\n }\n }\n\n /**\n * binds a single keyboard combination\n *\n * @param {string} combination\n * @param {Function} callback\n * @param {string=} action\n * @param {string=} sequence_name - name of sequence if part of sequence\n * @param {number=} level - what part of the sequence the command is\n * @returns void\n */\n function _bindSingle(combination, callback, action, sequence_name, level) {\n\n // make sure multiple spaces in a row become a single space\n combination = combination.replace(/\\s+/g, ' ');\n\n var sequence = combination.split(' '),\n i,\n key,\n keys,\n modifiers = [];\n\n // if this pattern is a sequence of keys then run through this method\n // to reprocess each pattern one key at a time\n if (sequence.length > 1) {\n _bindSequence(combination, sequence, callback, action);\n return;\n }\n\n // take the keys from this pattern and figure out what the actual\n // pattern is all about\n keys = combination === '+' ? ['+'] : combination.split('+');\n\n for (i = 0; i < keys.length; ++i) {\n key = keys[i];\n\n // normalize key names\n if (_SPECIAL_ALIASES[key]) {\n key = _SPECIAL_ALIASES[key];\n }\n\n // if this is not a keypress event then we should\n // be smart about using shift keys\n // this will only work for US keyboards however\n if (action && action != 'keypress' && _SHIFT_MAP[key]) {\n key = _SHIFT_MAP[key];\n modifiers.push('shift');\n }\n\n // if this key is a modifier then add it to the list of modifiers\n if (_isModifier(key)) {\n modifiers.push(key);\n }\n }\n\n // depending on what the key combination is\n // we will try to pick the best event for it\n action = _pickBestAction(key, modifiers, action);\n\n // make sure to initialize array if this is the first time\n // a callback is added for this key\n if (!_callbacks[key]) {\n _callbacks[key] = [];\n }\n\n // remove an existing match if there is one\n _getMatches(key, modifiers, {type: action}, !sequence_name, combination);\n\n // add this call back to the array\n // if it is a sequence put it at the beginning\n // if not put it at the end\n //\n // this is important because the way these are processed expects\n // the sequence ones to come first\n _callbacks[key][sequence_name ? 'unshift' : 'push']({\n callback: callback,\n modifiers: modifiers,\n action: action,\n seq: sequence_name,\n level: level,\n combo: combination\n });\n }\n\n /**\n * binds multiple combinations to the same callback\n *\n * @param {Array} combinations\n * @param {Function} callback\n * @param {string|undefined} action\n * @returns void\n */\n function _bindMultiple(combinations, callback, action) {\n for (var i = 0; i < combinations.length; ++i) {\n _bindSingle(combinations[i], callback, action);\n }\n }\n\n // start!\n _addEvent(document, 'keypress', _handleKey);\n _addEvent(document, 'keydown', _handleKey);\n _addEvent(document, 'keyup', _handleKey);\n\n var Mousetrap = {\n\n /**\n * binds an event to mousetrap\n *\n * can be a single key, a combination of keys separated with +,\n * an array of keys, or a sequence of keys separated by spaces\n *\n * be sure to list the modifier keys first to make sure that the\n * correct key ends up getting bound (the last key in the pattern)\n *\n * @param {string|Array} keys\n * @param {Function} callback\n * @param {string=} action - 'keypress', 'keydown', or 'keyup'\n * @returns void\n */\n bind: function(keys, callback, action) {\n _bindMultiple(keys instanceof Array ? keys : [keys], callback, action);\n _direct_map[keys + ':' + action] = callback;\n return this;\n },\n\n /**\n * unbinds an event to mousetrap\n *\n * the unbinding sets the callback function of the specified key combo\n * to an empty function and deletes the corresponding key in the\n * _direct_map dict.\n *\n * the keycombo+action has to be exactly the same as\n * it was defined in the bind method\n *\n * TODO: actually remove this from the _callbacks dictionary instead\n * of binding an empty function\n *\n * @param {string|Array} keys\n * @param {string} action\n * @returns void\n */\n unbind: function(keys, action) {\n if (_direct_map[keys + ':' + action]) {\n delete _direct_map[keys + ':' + action];\n this.bind(keys, function() {}, action);\n }\n return this;\n },\n\n /**\n * triggers an event that has already been bound\n *\n * @param {string} keys\n * @param {string=} action\n * @returns void\n */\n trigger: function(keys, action) {\n _direct_map[keys + ':' + action]();\n return this;\n },\n\n /**\n * resets the library back to its initial state. this is useful\n * if you want to clear out the current keyboard shortcuts and bind\n * new ones - for example if you switch to another page\n *\n * @returns void\n */\n reset: function() {\n _callbacks = {};\n _direct_map = {};\n return this;\n },\n\n /**\n * should we stop this event before firing off callbacks\n *\n * @param {Event} e\n * @param {Element} element\n * @return {boolean}\n */\n stopCallback: function(e, element) {\n\n // if the element has the class \"mousetrap\" then no need to stop\n if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) {\n return false;\n }\n\n // stop for input, select, and textarea\n return element.tagName == 'INPUT' || element.tagName == 'SELECT' || element.tagName == 'TEXTAREA' || (element.contentEditable && element.contentEditable == 'true');\n }\n };\n\n // expose mousetrap to the global object\n window.Mousetrap = Mousetrap;\n\n // expose mousetrap as an AMD module\n if (true) {\n !(__WEBPACK_AMD_DEFINE_RESULT__ = (function() { return Mousetrap; }).call(exports, __webpack_require__, exports, module),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n }\n // browserify support\n if( true && module.exports) {\n module.exports = Mousetrap;\n }\n}) ();\n\n\n//# sourceURL=webpack:///./node_modules/br-mousetrap/mousetrap.js?"); - this.addStaticObject = function (sprite) { - staticObjects.push(sprite); - }; +/***/ }), - this.addStaticObjects = function (sprites) { - sprites.forEach(this.addStaticObject.bind(this)); - }; +/***/ "./node_modules/eventedloop/lib/main.js": +/*!**********************************************!*\ + !*** ./node_modules/eventedloop/lib/main.js ***! + \**********************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { - this.addMovingObject = function (movingObject, movingObjectType) { - if (movingObjectType) { - staticObjects.onPush(function (obj) { - if (obj.data && obj.data.hitBehaviour[movingObjectType]) { - obj.onHitting(movingObject, obj.data.hitBehaviour[movingObjectType]); - } - }, true); - } +eval("/* WEBPACK VAR INJECTION */(function(global) {(function() {\n var root = this;\n var EventEmitter = __webpack_require__(/*! events */ \"./node_modules/events/events.js\").EventEmitter;\n\tvar _ = __webpack_require__(/*! underscore */ \"./node_modules/underscore/underscore.js\");\n\tvar intervalParser = /([0-9\\.]+)(ms|s|m|h)?/;\n\tvar root = global || window;\n\n\t// Lil bit of useful polyfill...\n\tif (typeof(Function.prototype.inherits) === 'undefined') {\n\t\tFunction.prototype.inherits = function(parent) {\n\t\t\tthis.prototype = Object.create(parent.prototype);\n\t\t};\n\t}\n\n\tif (typeof(Array.prototype.removeOne) === 'undefined') {\n\t\tArray.prototype.removeOne = function() {\n\t\t\tvar what, a = arguments, L = a.length, ax;\n\t\t\twhile (L && this.length) {\n\t\t\t\twhat = a[--L];\n\t\t\t\twhile ((ax = this.indexOf(what)) !== -1) {\n\t\t\t\t\treturn this.splice(ax, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\tfunction greatestCommonFactor(intervals) {\n\t\tvar sumOfModuli = 1;\n\t\tvar interval = _.min(intervals);\n\t\twhile (sumOfModuli !== 0) {\n\t\t\tsumOfModuli = _.reduce(intervals, function(memo, i){ return memo + (i % interval); }, 0);\n\t\t\tif (sumOfModuli !== 0) {\n\t\t\t\tinterval -= 10;\n\t\t\t}\n\t\t}\n\t\treturn interval;\n\t}\n\n\tfunction parseEvent(e) {\n\t\tvar intervalGroups = intervalParser.exec(e);\n\t\tif (!intervalGroups) {\n\t\t\tthrow new Error('I don\\'t understand that particular interval');\n\t\t}\n\t\tvar intervalAmount = +intervalGroups[1];\n\t\tvar intervalType = intervalGroups[2] || 'ms';\n\t\tif (intervalType === 's') {\n\t\t\tintervalAmount = intervalAmount * 1000;\n\t\t} else if (intervalType === 'm') {\n\t\t\tintervalAmount = intervalAmount * 1000 * 60;\n\t\t} else if (intervalType === 'h') {\n\t\t\tintervalAmount = intervalAmount * 1000 * 60 * 60;\n\t\t} else if (!!intervalType && intervalType !== 'ms') {\n\t\t\tthrow new Error('You can only specify intervals of ms, s, m, or h');\n\t\t}\n\t\tif (intervalAmount < 10 || intervalAmount % 10 !== 0) {\n\t\t\t// We only deal in 10's of milliseconds for simplicity\n\t\t\tthrow new Error('You can only specify 10s of milliseconds, trust me on this one');\n\t\t}\n\t\treturn {\n\t\t\tamount:intervalAmount,\n\t\t\ttype:intervalType\n\t\t};\n\t}\n\n\tfunction EventedLoop() {\n\t\tthis.intervalId = undefined;\n\t\tthis.intervalLength = undefined;\n\t\tthis.intervalsToEmit = {};\n\t\tthis.currentTick = 1;\n\t\tthis.maxTicks = 0;\n\t\tthis.listeningForFocus = false;\n\n\t\t// Private method\n\t\tvar determineIntervalLength = function () {\n\t\t\tvar potentialIntervalLength = greatestCommonFactor(_.keys(this.intervalsToEmit));\n\t\t\tvar changed = false;\n\n\t\t\tif (this.intervalLength) {\n\t\t\t\tif (potentialIntervalLength !== this.intervalLength) {\n\t\t\t\t\t// Looks like we need a new interval\n\t\t\t\t\tthis.intervalLength = potentialIntervalLength;\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.intervalLength = potentialIntervalLength;\n\t\t\t}\n\n\t\t\tthis.maxTicks = _.max(_.map(_.keys(this.intervalsToEmit), function(a) { return +a; })) / this.intervalLength;\n\t\t\treturn changed;\n\t\t}.bind(this);\n\n\t\tthis.on('newListener', function (e) {\n\t\t\tif (e === 'removeListener' || e === 'newListener') return; // We don't care about that one\n\t\t\tvar intervalInfo = parseEvent(e);\n\t\t\tvar intervalAmount = intervalInfo.amount;\n\n\t\t\tthis.intervalsToEmit[+intervalAmount] = _.union(this.intervalsToEmit[+intervalAmount] || [], [e]);\n\t\t\t\n\t\t\tif (determineIntervalLength() && this.isStarted()) {\n\t\t\t\tthis.stop().start();\n\t\t\t}\n\t\t});\n\n\t\tthis.on('removeListener', function (e) {\n\t\t\tif (EventEmitter.listenerCount(this, e) > 0) return;\n\t\t\tvar intervalInfo = parseEvent(e);\n\t\t\tvar intervalAmount = intervalInfo.amount;\n\n\t\t\tvar removedEvent = this.intervalsToEmit[+intervalAmount].removeOne(e);\n\t\t\tif (this.intervalsToEmit[+intervalAmount].length === 0) {\n\t\t\t\tdelete this.intervalsToEmit[+intervalAmount];\n\t\t\t}\n\t\t\tconsole.log('Determining interval length after removal of', removedEvent);\n\t\t\tdetermineIntervalLength();\n\n\t\t\tif (determineIntervalLength() && this.isStarted()) {\n\t\t\t\tthis.stop().start();\n\t\t\t}\n\t\t});\n\t}\n\n\tEventedLoop.inherits(EventEmitter);\n\n\t// Public methods\n\tEventedLoop.prototype.tick = function () {\n\t\tvar milliseconds = this.currentTick * this.intervalLength;\n\t\t_.each(this.intervalsToEmit, function (events, key) {\n\t\t\tif (milliseconds % key === 0) {\n\t\t\t\t_.each(events, function(e) { this.emit(e, e, key); }.bind(this));\n\t\t\t}\n\t\t}.bind(this));\n\t\tthis.currentTick += 1;\n\t\tif (this.currentTick > this.maxTicks) {\n\t\t\tthis.currentTick = 1;\n\t\t}\n\t\treturn this;\n\t};\n\n\tEventedLoop.prototype.start = function () {\n\t\tif (!this.intervalLength) {\n\t\t\tthrow new Error('You haven\\'t specified any interval callbacks. Use EventedLoop.on(\\'500ms\\', function () { ... }) to do so, and then you can start');\n\t\t}\n\t\tif (this.intervalId) {\n\t\t\treturn console.log('No need to start the loop again, it\\'s already started.');\n\t\t}\n\n\t\tthis.intervalId = setInterval(this.tick.bind(this), this.intervalLength);\n\n\t\tif (root && !this.listeningForFocus && root.addEventListener) {\n\t\t\troot.addEventListener('focus', function() {\n\t\t\t\tthis.start();\n\t\t\t}.bind(this));\n\n\t\t\troot.addEventListener('blur', function() {\n\t\t\t\tthis.stop();\n\t\t\t}.bind(this));\n\n\t\t\tthis.listeningForFocus = true;\n\t\t}\n\t\treturn this;\n\t};\n\n\tEventedLoop.prototype.stop = function () {\n\t\tclearInterval(this.intervalId);\n\t\tthis.intervalId = undefined;\n\t\treturn this;\n\t};\n\n\tEventedLoop.prototype.isStarted = function () {\n\t\treturn !!this.intervalId;\n\t};\n\n\tEventedLoop.prototype.every = EventedLoop.prototype.on;\n\n // Export the EventedLoop object for **Node.js** or other\n // commonjs systems. Otherwise, add it as a global object to the root\n if (true) {\n if ( true && module.exports) {\n exports = module.exports = EventedLoop;\n }\n exports.EventedLoop = EventedLoop;\n }\n if (typeof window !== 'undefined') {\n window.EventedLoop = EventedLoop;\n }\n}).call(this);\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../webpack/buildin/global.js */ \"./node_modules/webpack/buildin/global.js\")))\n\n//# sourceURL=webpack:///./node_modules/eventedloop/lib/main.js?"); - movingObjects.push(movingObject); - }; +/***/ }), - this.addUIElement = function (element) { - uiElements.push(element); - }; +/***/ "./node_modules/events/events.js": +/*!***************************************!*\ + !*** ./node_modules/events/events.js ***! + \***************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { - this.beforeCycle = function (callback) { - beforeCycleCallbacks.push(callback); - }; +"use strict"; +eval("// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n\n\nvar R = typeof Reflect === 'object' ? Reflect : null\nvar ReflectApply = R && typeof R.apply === 'function'\n ? R.apply\n : function ReflectApply(target, receiver, args) {\n return Function.prototype.apply.call(target, receiver, args);\n }\n\nvar ReflectOwnKeys\nif (R && typeof R.ownKeys === 'function') {\n ReflectOwnKeys = R.ownKeys\n} else if (Object.getOwnPropertySymbols) {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target)\n .concat(Object.getOwnPropertySymbols(target));\n };\n} else {\n ReflectOwnKeys = function ReflectOwnKeys(target) {\n return Object.getOwnPropertyNames(target);\n };\n}\n\nfunction ProcessEmitWarning(warning) {\n if (console && console.warn) console.warn(warning);\n}\n\nvar NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {\n return value !== value;\n}\n\nfunction EventEmitter() {\n EventEmitter.init.call(this);\n}\nmodule.exports = EventEmitter;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._eventsCount = 0;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nvar defaultMaxListeners = 10;\n\nObject.defineProperty(EventEmitter, 'defaultMaxListeners', {\n enumerable: true,\n get: function() {\n return defaultMaxListeners;\n },\n set: function(arg) {\n if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {\n throw new RangeError('The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received ' + arg + '.');\n }\n defaultMaxListeners = arg;\n }\n});\n\nEventEmitter.init = function() {\n\n if (this._events === undefined ||\n this._events === Object.getPrototypeOf(this)._events) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n }\n\n this._maxListeners = this._maxListeners || undefined;\n};\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {\n if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {\n throw new RangeError('The value of \"n\" is out of range. It must be a non-negative number. Received ' + n + '.');\n }\n this._maxListeners = n;\n return this;\n};\n\nfunction $getMaxListeners(that) {\n if (that._maxListeners === undefined)\n return EventEmitter.defaultMaxListeners;\n return that._maxListeners;\n}\n\nEventEmitter.prototype.getMaxListeners = function getMaxListeners() {\n return $getMaxListeners(this);\n};\n\nEventEmitter.prototype.emit = function emit(type) {\n var args = [];\n for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);\n var doError = (type === 'error');\n\n var events = this._events;\n if (events !== undefined)\n doError = (doError && events.error === undefined);\n else if (!doError)\n return false;\n\n // If there is no 'error' event listener then throw.\n if (doError) {\n var er;\n if (args.length > 0)\n er = args[0];\n if (er instanceof Error) {\n // Note: The comments on the `throw` lines are intentional, they show\n // up in Node's output if this results in an unhandled exception.\n throw er; // Unhandled 'error' event\n }\n // At least give some kind of context to the user\n var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));\n err.context = er;\n throw err; // Unhandled 'error' event\n }\n\n var handler = events[type];\n\n if (handler === undefined)\n return false;\n\n if (typeof handler === 'function') {\n ReflectApply(handler, this, args);\n } else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n ReflectApply(listeners[i], this, args);\n }\n\n return true;\n};\n\nfunction _addListener(target, type, listener, prepend) {\n var m;\n var events;\n var existing;\n\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n\n events = target._events;\n if (events === undefined) {\n events = target._events = Object.create(null);\n target._eventsCount = 0;\n } else {\n // To avoid recursion in the case that type === \"newListener\"! Before\n // adding it to the listeners, first emit \"newListener\".\n if (events.newListener !== undefined) {\n target.emit('newListener', type,\n listener.listener ? listener.listener : listener);\n\n // Re-assign `events` because a newListener handler could have caused the\n // this._events to be assigned to a new object\n events = target._events;\n }\n existing = events[type];\n }\n\n if (existing === undefined) {\n // Optimize the case of one listener. Don't need the extra array object.\n existing = events[type] = listener;\n ++target._eventsCount;\n } else {\n if (typeof existing === 'function') {\n // Adding the second element, need to change to array.\n existing = events[type] =\n prepend ? [listener, existing] : [existing, listener];\n // If we've already got an array, just append.\n } else if (prepend) {\n existing.unshift(listener);\n } else {\n existing.push(listener);\n }\n\n // Check for listener leak\n m = $getMaxListeners(target);\n if (m > 0 && existing.length > m && !existing.warned) {\n existing.warned = true;\n // No error code for this since it is a Warning\n // eslint-disable-next-line no-restricted-syntax\n var w = new Error('Possible EventEmitter memory leak detected. ' +\n existing.length + ' ' + String(type) + ' listeners ' +\n 'added. Use emitter.setMaxListeners() to ' +\n 'increase limit');\n w.name = 'MaxListenersExceededWarning';\n w.emitter = target;\n w.type = type;\n w.count = existing.length;\n ProcessEmitWarning(w);\n }\n }\n\n return target;\n}\n\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n return _addListener(this, type, listener, false);\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.prependListener =\n function prependListener(type, listener) {\n return _addListener(this, type, listener, true);\n };\n\nfunction onceWrapper() {\n var args = [];\n for (var i = 0; i < arguments.length; i++) args.push(arguments[i]);\n if (!this.fired) {\n this.target.removeListener(this.type, this.wrapFn);\n this.fired = true;\n ReflectApply(this.listener, this.target, args);\n }\n}\n\nfunction _onceWrap(target, type, listener) {\n var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };\n var wrapped = onceWrapper.bind(state);\n wrapped.listener = listener;\n state.wrapFn = wrapped;\n return wrapped;\n}\n\nEventEmitter.prototype.once = function once(type, listener) {\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n this.on(type, _onceWrap(this, type, listener));\n return this;\n};\n\nEventEmitter.prototype.prependOnceListener =\n function prependOnceListener(type, listener) {\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n this.prependListener(type, _onceWrap(this, type, listener));\n return this;\n };\n\n// Emits a 'removeListener' event if and only if the listener was removed.\nEventEmitter.prototype.removeListener =\n function removeListener(type, listener) {\n var list, events, position, i, originalListener;\n\n if (typeof listener !== 'function') {\n throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n }\n\n events = this._events;\n if (events === undefined)\n return this;\n\n list = events[type];\n if (list === undefined)\n return this;\n\n if (list === listener || list.listener === listener) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else {\n delete events[type];\n if (events.removeListener)\n this.emit('removeListener', type, list.listener || listener);\n }\n } else if (typeof list !== 'function') {\n position = -1;\n\n for (i = list.length - 1; i >= 0; i--) {\n if (list[i] === listener || list[i].listener === listener) {\n originalListener = list[i].listener;\n position = i;\n break;\n }\n }\n\n if (position < 0)\n return this;\n\n if (position === 0)\n list.shift();\n else {\n spliceOne(list, position);\n }\n\n if (list.length === 1)\n events[type] = list[0];\n\n if (events.removeListener !== undefined)\n this.emit('removeListener', type, originalListener || listener);\n }\n\n return this;\n };\n\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\n\nEventEmitter.prototype.removeAllListeners =\n function removeAllListeners(type) {\n var listeners, events, i;\n\n events = this._events;\n if (events === undefined)\n return this;\n\n // not listening for removeListener, no need to emit\n if (events.removeListener === undefined) {\n if (arguments.length === 0) {\n this._events = Object.create(null);\n this._eventsCount = 0;\n } else if (events[type] !== undefined) {\n if (--this._eventsCount === 0)\n this._events = Object.create(null);\n else\n delete events[type];\n }\n return this;\n }\n\n // emit removeListener for all listeners on all events\n if (arguments.length === 0) {\n var keys = Object.keys(events);\n var key;\n for (i = 0; i < keys.length; ++i) {\n key = keys[i];\n if (key === 'removeListener') continue;\n this.removeAllListeners(key);\n }\n this.removeAllListeners('removeListener');\n this._events = Object.create(null);\n this._eventsCount = 0;\n return this;\n }\n\n listeners = events[type];\n\n if (typeof listeners === 'function') {\n this.removeListener(type, listeners);\n } else if (listeners !== undefined) {\n // LIFO order\n for (i = listeners.length - 1; i >= 0; i--) {\n this.removeListener(type, listeners[i]);\n }\n }\n\n return this;\n };\n\nfunction _listeners(target, type, unwrap) {\n var events = target._events;\n\n if (events === undefined)\n return [];\n\n var evlistener = events[type];\n if (evlistener === undefined)\n return [];\n\n if (typeof evlistener === 'function')\n return unwrap ? [evlistener.listener || evlistener] : [evlistener];\n\n return unwrap ?\n unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);\n}\n\nEventEmitter.prototype.listeners = function listeners(type) {\n return _listeners(this, type, true);\n};\n\nEventEmitter.prototype.rawListeners = function rawListeners(type) {\n return _listeners(this, type, false);\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n if (typeof emitter.listenerCount === 'function') {\n return emitter.listenerCount(type);\n } else {\n return listenerCount.call(emitter, type);\n }\n};\n\nEventEmitter.prototype.listenerCount = listenerCount;\nfunction listenerCount(type) {\n var events = this._events;\n\n if (events !== undefined) {\n var evlistener = events[type];\n\n if (typeof evlistener === 'function') {\n return 1;\n } else if (evlistener !== undefined) {\n return evlistener.length;\n }\n }\n\n return 0;\n}\n\nEventEmitter.prototype.eventNames = function eventNames() {\n return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];\n};\n\nfunction arrayClone(arr, n) {\n var copy = new Array(n);\n for (var i = 0; i < n; ++i)\n copy[i] = arr[i];\n return copy;\n}\n\nfunction spliceOne(list, index) {\n for (; index + 1 < list.length; index++)\n list[index] = list[index + 1];\n list.pop();\n}\n\nfunction unwrapListeners(arr) {\n var ret = new Array(arr.length);\n for (var i = 0; i < ret.length; ++i) {\n ret[i] = arr[i].listener || arr[i];\n }\n return ret;\n}\n\n\n//# sourceURL=webpack:///./node_modules/events/events.js?"); - this.afterCycle = function (callback) { - afterCycleCallbacks.push(callback); - }; +/***/ }), - this.setMouseX = function (x) { - mouseX = x; - }; +/***/ "./node_modules/hammerjs/hammer.js": +/*!*****************************************!*\ + !*** ./node_modules/hammerjs/hammer.js ***! + \*****************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { - this.setMouseY = function (y) { - mouseY = y; - }; +eval("var __WEBPACK_AMD_DEFINE_RESULT__;/*! Hammer.JS - v2.0.8 - 2016-09-30\n * http://hammerjs.github.io/\n *\n * Copyright (c) Jorik Tangelder;\n * Licensed under the MIT license */\n(function(window, document, exportName, undefined) { \n'use strict';\n/**\n * @private\n * use the val2 when val1 is undefined\n * @param {*} val1\n * @param {*} val2\n * @returns {*}\n */\nfunction ifUndefined(val1, val2) {\n return val1 === undefined ? val2 : val1;\n}\n\nvar VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];\nvar TEST_ELEMENT = document.createElement('div');\n\nvar TYPE_FUNCTION = 'function';\n\nvar round = Math.round;\nvar abs = Math.abs;\nvar now = Date.now;\n\n/**\n * @private\n * get the prefixed property\n * @param {Object} obj\n * @param {String} property\n * @returns {String|Undefined} prefixed\n */\nfunction prefixed(obj, property) {\n var prefix = void 0;\n var prop = void 0;\n var camelProp = property[0].toUpperCase() + property.slice(1);\n\n var i = 0;\n while (i < VENDOR_PREFIXES.length) {\n prefix = VENDOR_PREFIXES[i];\n prop = prefix ? prefix + camelProp : property;\n\n if (prop in obj) {\n return prop;\n }\n i++;\n }\n return undefined;\n}\n\nfunction getTouchActionProps() {\n if (!NATIVE_TOUCH_ACTION) {\n return false;\n }\n var touchMap = {};\n var cssSupports = window.CSS && window.CSS.supports;\n ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function (val) {\n\n // If css.supports is not supported but there is native touch-action assume it supports\n // all values. This is the case for IE 10 and 11.\n return touchMap[val] = cssSupports ? window.CSS.supports('touch-action', val) : true;\n });\n return touchMap;\n}\n\nvar PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');\nvar NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;\n\n// magical touchAction value\nvar TOUCH_ACTION_COMPUTE = 'compute';\nvar TOUCH_ACTION_AUTO = 'auto';\nvar TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented\nvar TOUCH_ACTION_NONE = 'none';\nvar TOUCH_ACTION_PAN_X = 'pan-x';\nvar TOUCH_ACTION_PAN_Y = 'pan-y';\nvar TOUCH_ACTION_MAP = getTouchActionProps();\n\nvar MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;\n\nvar SUPPORT_TOUCH = 'ontouchstart' in window;\nvar SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined;\nvar SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);\n\nvar INPUT_TYPE_TOUCH = 'touch';\nvar INPUT_TYPE_PEN = 'pen';\nvar INPUT_TYPE_MOUSE = 'mouse';\nvar INPUT_TYPE_KINECT = 'kinect';\n\nvar COMPUTE_INTERVAL = 25;\n\nvar INPUT_START = 1;\nvar INPUT_MOVE = 2;\nvar INPUT_END = 4;\nvar INPUT_CANCEL = 8;\n\nvar DIRECTION_NONE = 1;\nvar DIRECTION_LEFT = 2;\nvar DIRECTION_RIGHT = 4;\nvar DIRECTION_UP = 8;\nvar DIRECTION_DOWN = 16;\n\nvar DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;\nvar DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;\nvar DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;\n\nvar PROPS_XY = ['x', 'y'];\nvar PROPS_CLIENT_XY = ['clientX', 'clientY'];\n\nvar STATE_POSSIBLE = 1;\nvar STATE_BEGAN = 2;\nvar STATE_CHANGED = 4;\nvar STATE_ENDED = 8;\nvar STATE_RECOGNIZED = STATE_ENDED;\nvar STATE_CANCELLED = 16;\nvar STATE_FAILED = 32;\n\n/**\n * @private\n * extend object.\n * means that properties in dest will be overwritten by the ones in src.\n * @param {Object} target\n * @param {...Object} objects_to_assign\n * @returns {Object} target\n */\nvar assign = void 0;\nif (typeof Object.assign !== 'function') {\n assign = function assign(target) {\n if (target === undefined || target === null) {\n throw new TypeError('Cannot convert undefined or null to object');\n }\n\n var output = Object(target);\n for (var index = 1; index < arguments.length; index++) {\n var source = arguments[index];\n if (source !== undefined && source !== null) {\n for (var nextKey in source) {\n if (source.hasOwnProperty(nextKey)) {\n output[nextKey] = source[nextKey];\n }\n }\n }\n }\n return output;\n };\n} else {\n assign = Object.assign;\n}\n\nvar assign$1 = assign;\n\n/**\n * @private\n * get a unique id\n * @returns {number} uniqueId\n */\nvar _uniqueId = 1;\nfunction uniqueId() {\n return _uniqueId++;\n}\n\n/**\n * @private\n * walk objects and arrays\n * @param {Object} obj\n * @param {Function} iterator\n * @param {Object} context\n */\nfunction each(obj, iterator, context) {\n var i = void 0;\n\n if (!obj) {\n return;\n }\n\n if (obj.forEach) {\n obj.forEach(iterator, context);\n } else if (obj.length !== undefined) {\n i = 0;\n while (i < obj.length) {\n iterator.call(context, obj[i], i, obj);\n i++;\n }\n } else {\n for (i in obj) {\n obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);\n }\n }\n}\n\n/**\n * @private\n * if the argument is an array, we want to execute the fn on each entry\n * if it aint an array we don't want to do a thing.\n * this is used by all the methods that accept a single and array argument.\n * @param {*|Array} arg\n * @param {String} fn\n * @param {Object} [context]\n * @returns {Boolean}\n */\nfunction invokeArrayArg(arg, fn, context) {\n if (Array.isArray(arg)) {\n each(arg, context[fn], context);\n return true;\n }\n return false;\n}\n\n/**\n * @private\n * find if a array contains the object using indexOf or a simple polyFill\n * @param {Array} src\n * @param {String} find\n * @param {String} [findByKey]\n * @return {number} -1 when not found, or the index\n */\nfunction inArray(src, find, findByKey) {\n if (src.indexOf && !findByKey) {\n return src.indexOf(find);\n } else {\n var i = 0;\n while (i < src.length) {\n if (findByKey && src[i][findByKey] == find || !findByKey && src[i] === find) {\n // do not use === here, test fails\n return i;\n }\n i++;\n }\n return -1;\n }\n}\n\nvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) {\n return typeof obj;\n} : function (obj) {\n return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj;\n};\n\nvar asyncGenerator = function () {\n function AwaitValue(value) {\n this.value = value;\n }\n\n function AsyncGenerator(gen) {\n var front, back;\n\n function send(key, arg) {\n return new Promise(function (resolve, reject) {\n var request = {\n key: key,\n arg: arg,\n resolve: resolve,\n reject: reject,\n next: null\n };\n\n if (back) {\n back = back.next = request;\n } else {\n front = back = request;\n resume(key, arg);\n }\n });\n }\n\n function resume(key, arg) {\n try {\n var result = gen[key](arg);\n var value = result.value;\n\n if (value instanceof AwaitValue) {\n Promise.resolve(value.value).then(function (arg) {\n resume(\"next\", arg);\n }, function (arg) {\n resume(\"throw\", arg);\n });\n } else {\n settle(result.done ? \"return\" : \"normal\", result.value);\n }\n } catch (err) {\n settle(\"throw\", err);\n }\n }\n\n function settle(type, value) {\n switch (type) {\n case \"return\":\n front.resolve({\n value: value,\n done: true\n });\n break;\n\n case \"throw\":\n front.reject(value);\n break;\n\n default:\n front.resolve({\n value: value,\n done: false\n });\n break;\n }\n\n front = front.next;\n\n if (front) {\n resume(front.key, front.arg);\n } else {\n back = null;\n }\n }\n\n this._invoke = send;\n\n if (typeof gen.return !== \"function\") {\n this.return = undefined;\n }\n }\n\n if (typeof Symbol === \"function\" && Symbol.asyncIterator) {\n AsyncGenerator.prototype[Symbol.asyncIterator] = function () {\n return this;\n };\n }\n\n AsyncGenerator.prototype.next = function (arg) {\n return this._invoke(\"next\", arg);\n };\n\n AsyncGenerator.prototype.throw = function (arg) {\n return this._invoke(\"throw\", arg);\n };\n\n AsyncGenerator.prototype.return = function (arg) {\n return this._invoke(\"return\", arg);\n };\n\n return {\n wrap: function (fn) {\n return function () {\n return new AsyncGenerator(fn.apply(this, arguments));\n };\n },\n await: function (value) {\n return new AwaitValue(value);\n }\n };\n}();\n\nvar classCallCheck = function (instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n};\n\nvar createClass = function () {\n function defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n }\n\n return function (Constructor, protoProps, staticProps) {\n if (protoProps) defineProperties(Constructor.prototype, protoProps);\n if (staticProps) defineProperties(Constructor, staticProps);\n return Constructor;\n };\n}();\n\nvar get = function get(object, property, receiver) {\n if (object === null) object = Function.prototype;\n var desc = Object.getOwnPropertyDescriptor(object, property);\n\n if (desc === undefined) {\n var parent = Object.getPrototypeOf(object);\n\n if (parent === null) {\n return undefined;\n } else {\n return get(parent, property, receiver);\n }\n } else if (\"value\" in desc) {\n return desc.value;\n } else {\n var getter = desc.get;\n\n if (getter === undefined) {\n return undefined;\n }\n\n return getter.call(receiver);\n }\n};\n\nvar inherits = function (subClass, superClass) {\n if (typeof superClass !== \"function\" && superClass !== null) {\n throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass);\n }\n\n subClass.prototype = Object.create(superClass && superClass.prototype, {\n constructor: {\n value: subClass,\n enumerable: false,\n writable: true,\n configurable: true\n }\n });\n if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;\n};\n\nvar possibleConstructorReturn = function (self, call) {\n if (!self) {\n throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n }\n\n return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self;\n};\n\nvar slicedToArray = function () {\n function sliceIterator(arr, i) {\n var _arr = [];\n var _n = true;\n var _d = false;\n var _e = undefined;\n\n try {\n for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {\n _arr.push(_s.value);\n\n if (i && _arr.length === i) break;\n }\n } catch (err) {\n _d = true;\n _e = err;\n } finally {\n try {\n if (!_n && _i[\"return\"]) _i[\"return\"]();\n } finally {\n if (_d) throw _e;\n }\n }\n\n return _arr;\n }\n\n return function (arr, i) {\n if (Array.isArray(arr)) {\n return arr;\n } else if (Symbol.iterator in Object(arr)) {\n return sliceIterator(arr, i);\n } else {\n throw new TypeError(\"Invalid attempt to destructure non-iterable instance\");\n }\n };\n}();\n\n/**\n * @private\n * let a boolean value also be a function that must return a boolean\n * this first item in args will be used as the context\n * @param {Boolean|Function} val\n * @param {Array} [args]\n * @returns {Boolean}\n */\nfunction boolOrFn(val, args) {\n if ((typeof val === 'undefined' ? 'undefined' : _typeof(val)) === TYPE_FUNCTION) {\n return val.apply(args ? args[0] || undefined : undefined, args);\n }\n return val;\n}\n\n/**\n * @private\n * get a recognizer by name if it is bound to a manager\n * @param {Recognizer|String} otherRecognizer\n * @param {Recognizer} recognizer\n * @returns {Recognizer}\n */\nfunction getRecognizerByNameIfManager(otherRecognizer, recognizer) {\n var manager = recognizer.manager;\n\n if (manager) {\n return manager.get(otherRecognizer);\n }\n return otherRecognizer;\n}\n\n/**\n * @private\n * get a usable string, used as event postfix\n * @param {constant} state\n * @returns {String} state\n */\nfunction stateStr(state) {\n if (state & STATE_CANCELLED) {\n return 'cancel';\n } else if (state & STATE_ENDED) {\n return 'end';\n } else if (state & STATE_CHANGED) {\n return 'move';\n } else if (state & STATE_BEGAN) {\n return 'start';\n }\n return '';\n}\n\n/**\n * @private\n * Recognizer flow explained; *\n * All recognizers have the initial state of POSSIBLE when a input session starts.\n * The definition of a input session is from the first input until the last input, with all it's movement in it. *\n * Example session for mouse-input: mousedown -> mousemove -> mouseup\n *\n * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed\n * which determines with state it should be.\n *\n * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to\n * POSSIBLE to give it another change on the next cycle.\n *\n * Possible\n * |\n * +-----+---------------+\n * | |\n * +-----+-----+ |\n * | | |\n * Failed Cancelled |\n * +-------+------+\n * | |\n * Recognized Began\n * |\n * Changed\n * |\n * Ended/Recognized\n */\n\n/**\n * @private\n * Recognizer\n * Every recognizer needs to extend from this class.\n * @constructor\n * @param {Object} options\n */\n\nvar Recognizer = function () {\n function Recognizer(options) {\n classCallCheck(this, Recognizer);\n\n this.options = assign$1({}, this.defaults, options || {});\n\n this.id = uniqueId();\n\n this.manager = null;\n\n // default is enable true\n this.options.enable = ifUndefined(this.options.enable, true);\n\n this.state = STATE_POSSIBLE;\n this.simultaneous = {};\n this.requireFail = [];\n }\n\n /**\n * @private\n * set options\n * @param {Object} options\n * @return {Recognizer}\n */\n\n\n createClass(Recognizer, [{\n key: 'set',\n value: function set(options) {\n assign$1(this.options, options);\n\n // also update the touchAction, in case something changed about the directions/enabled state\n this.manager && this.manager.touchAction.update();\n return this;\n }\n\n /**\n * @private\n * recognize simultaneous with an other recognizer.\n * @param {Recognizer} otherRecognizer\n * @returns {Recognizer} this\n */\n\n }, {\n key: 'recognizeWith',\n value: function recognizeWith(otherRecognizer) {\n if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {\n return this;\n }\n\n var simultaneous = this.simultaneous;\n\n otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);\n if (!simultaneous[otherRecognizer.id]) {\n simultaneous[otherRecognizer.id] = otherRecognizer;\n otherRecognizer.recognizeWith(this);\n }\n return this;\n }\n\n /**\n * @private\n * drop the simultaneous link. it doesnt remove the link on the other recognizer.\n * @param {Recognizer} otherRecognizer\n * @returns {Recognizer} this\n */\n\n }, {\n key: 'dropRecognizeWith',\n value: function dropRecognizeWith(otherRecognizer) {\n if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {\n return this;\n }\n\n otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);\n delete this.simultaneous[otherRecognizer.id];\n return this;\n }\n\n /**\n * @private\n * recognizer can only run when an other is failing\n * @param {Recognizer} otherRecognizer\n * @returns {Recognizer} this\n */\n\n }, {\n key: 'requireFailure',\n value: function requireFailure(otherRecognizer) {\n if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {\n return this;\n }\n\n var requireFail = this.requireFail;\n\n otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);\n if (inArray(requireFail, otherRecognizer) === -1) {\n requireFail.push(otherRecognizer);\n otherRecognizer.requireFailure(this);\n }\n return this;\n }\n\n /**\n * @private\n * drop the requireFailure link. it does not remove the link on the other recognizer.\n * @param {Recognizer} otherRecognizer\n * @returns {Recognizer} this\n */\n\n }, {\n key: 'dropRequireFailure',\n value: function dropRequireFailure(otherRecognizer) {\n if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {\n return this;\n }\n\n otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);\n var index = inArray(this.requireFail, otherRecognizer);\n if (index > -1) {\n this.requireFail.splice(index, 1);\n }\n return this;\n }\n\n /**\n * @private\n * has require failures boolean\n * @returns {boolean}\n */\n\n }, {\n key: 'hasRequireFailures',\n value: function hasRequireFailures() {\n return this.requireFail.length > 0;\n }\n\n /**\n * @private\n * if the recognizer can recognize simultaneous with an other recognizer\n * @param {Recognizer} otherRecognizer\n * @returns {Boolean}\n */\n\n }, {\n key: 'canRecognizeWith',\n value: function canRecognizeWith(otherRecognizer) {\n return !!this.simultaneous[otherRecognizer.id];\n }\n\n /**\n * @private\n * You should use `tryEmit` instead of `emit` directly to check\n * that all the needed recognizers has failed before emitting.\n * @param {Object} input\n */\n\n }, {\n key: 'emit',\n value: function emit(input) {\n var self = this;\n var state = this.state;\n\n\n function emit(event) {\n self.manager.emit(event, input);\n }\n\n // 'panstart' and 'panmove'\n if (state < STATE_ENDED) {\n emit(self.options.event + stateStr(state));\n }\n\n emit(self.options.event); // simple 'eventName' events\n\n if (input.additionalEvent) {\n // additional event(panleft, panright, pinchin, pinchout...)\n emit(input.additionalEvent);\n }\n\n // panend and pancancel\n if (state >= STATE_ENDED) {\n emit(self.options.event + stateStr(state));\n }\n }\n\n /**\n * @private\n * Check that all the require failure recognizers has failed,\n * if true, it emits a gesture event,\n * otherwise, setup the state to FAILED.\n * @param {Object} input\n */\n\n }, {\n key: 'tryEmit',\n value: function tryEmit(input) {\n if (this.canEmit()) {\n return this.emit(input);\n }\n // it's failing anyway\n this.state = STATE_FAILED;\n }\n\n /**\n * @private\n * can we emit?\n * @returns {boolean}\n */\n\n }, {\n key: 'canEmit',\n value: function canEmit() {\n var i = 0;\n while (i < this.requireFail.length) {\n if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {\n return false;\n }\n i++;\n }\n return true;\n }\n\n /**\n * @private\n * update the recognizer\n * @param {Object} inputData\n */\n\n }, {\n key: 'recognize',\n value: function recognize(inputData) {\n // make a new copy of the inputData\n // so we can change the inputData without messing up the other recognizers\n var inputDataClone = assign$1({}, inputData);\n\n // is is enabled and allow recognizing?\n if (!boolOrFn(this.options.enable, [this, inputDataClone])) {\n this.reset();\n this.state = STATE_FAILED;\n return;\n }\n\n // reset when we've reached the end\n if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {\n this.state = STATE_POSSIBLE;\n }\n\n this.state = this.process(inputDataClone);\n\n // the recognizer has recognized a gesture\n // so trigger an event\n if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {\n this.tryEmit(inputDataClone);\n }\n }\n\n /**\n * @private\n * return the state of the recognizer\n * the actual recognizing happens in this method\n * @virtual\n * @param {Object} inputData\n * @returns {constant} STATE\n */\n\n /* jshint ignore:start */\n\n }, {\n key: 'process',\n value: function process(inputData) {}\n /* jshint ignore:end */\n\n /**\n * @private\n * return the preferred touch-action\n * @virtual\n * @returns {Array}\n */\n\n }, {\n key: 'getTouchAction',\n value: function getTouchAction() {}\n\n /**\n * @private\n * called when the gesture isn't allowed to recognize\n * like when another is being recognized or it is disabled\n * @virtual\n */\n\n }, {\n key: 'reset',\n value: function reset() {}\n }]);\n return Recognizer;\n}();\n\nRecognizer.prototype.defaults = {};\n\n/**\n * @private\n * This recognizer is just used as a base for the simple attribute recognizers.\n * @constructor\n * @extends Recognizer\n */\n\nvar AttrRecognizer = function (_Recognizer) {\n inherits(AttrRecognizer, _Recognizer);\n\n function AttrRecognizer() {\n classCallCheck(this, AttrRecognizer);\n return possibleConstructorReturn(this, (AttrRecognizer.__proto__ || Object.getPrototypeOf(AttrRecognizer)).apply(this, arguments));\n }\n\n /**\n * @private\n * Used to check if it the recognizer receives valid input, like input.distance > 10.\n * @memberof AttrRecognizer\n * @param {Object} input\n * @returns {Boolean} recognized\n */\n\n\n createClass(AttrRecognizer, [{\n key: 'attrTest',\n value: function attrTest(input) {\n var optionPointers = this.options.pointers;\n return optionPointers === 0 || input.pointers.length === optionPointers;\n }\n\n /**\n * @private\n * Process the input and return the state for the recognizer\n * @memberof AttrRecognizer\n * @param {Object} input\n * @returns {*} State\n */\n\n }, {\n key: 'process',\n value: function process(input) {\n var state = this.state;\n var eventType = input.eventType;\n\n\n var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);\n var isValid = this.attrTest(input);\n\n // on cancel input and we've recognized before, return STATE_CANCELLED\n if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {\n return state | STATE_CANCELLED;\n } else if (isRecognized || isValid) {\n if (eventType & INPUT_END) {\n return state | STATE_ENDED;\n } else if (!(state & STATE_BEGAN)) {\n return STATE_BEGAN;\n }\n return state | STATE_CHANGED;\n }\n return STATE_FAILED;\n }\n }]);\n return AttrRecognizer;\n}(Recognizer);\n\nAttrRecognizer.prototype.defaults = {\n /**\n * @private\n * @type {Number}\n * @default 1\n */\n pointers: 1\n};\n\n/**\n * @private\n * Rotate\n * Recognized when two or more pointer are moving in a circular motion.\n * @constructor\n * @extends AttrRecognizer\n */\n\nvar RotateRecognizer = function (_AttrRecognizer) {\n inherits(RotateRecognizer, _AttrRecognizer);\n\n function RotateRecognizer() {\n classCallCheck(this, RotateRecognizer);\n return possibleConstructorReturn(this, (RotateRecognizer.__proto__ || Object.getPrototypeOf(RotateRecognizer)).apply(this, arguments));\n }\n\n createClass(RotateRecognizer, [{\n key: 'getTouchAction',\n value: function getTouchAction() {\n return [TOUCH_ACTION_NONE];\n }\n }, {\n key: 'attrTest',\n value: function attrTest(input) {\n return get(RotateRecognizer.prototype.__proto__ || Object.getPrototypeOf(RotateRecognizer.prototype), 'attrTest', this).call(this, input) && (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);\n }\n }]);\n return RotateRecognizer;\n}(AttrRecognizer);\n\nRotateRecognizer.prototype.defaults = {\n event: 'rotate',\n threshold: 0,\n pointers: 2\n};\n\n/**\n * @private\n * Pinch\n * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).\n * @constructor\n * @extends AttrRecognizer\n */\n\nvar PinchRecognizer = function (_AttrRecognizer) {\n inherits(PinchRecognizer, _AttrRecognizer);\n\n function PinchRecognizer() {\n classCallCheck(this, PinchRecognizer);\n return possibleConstructorReturn(this, (PinchRecognizer.__proto__ || Object.getPrototypeOf(PinchRecognizer)).apply(this, arguments));\n }\n\n createClass(PinchRecognizer, [{\n key: 'getTouchAction',\n value: function getTouchAction() {\n return [TOUCH_ACTION_NONE];\n }\n }, {\n key: 'attrTest',\n value: function attrTest(input) {\n return get(PinchRecognizer.prototype.__proto__ || Object.getPrototypeOf(PinchRecognizer.prototype), 'attrTest', this).call(this, input) && (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);\n }\n }, {\n key: 'emit',\n value: function emit(input) {\n if (input.scale !== 1) {\n var inOut = input.scale < 1 ? 'in' : 'out';\n input.additionalEvent = this.options.event + inOut;\n }\n get(PinchRecognizer.prototype.__proto__ || Object.getPrototypeOf(PinchRecognizer.prototype), 'emit', this).call(this, input);\n }\n }]);\n return PinchRecognizer;\n}(AttrRecognizer);\n\nPinchRecognizer.prototype.defaults = {\n event: 'pinch',\n threshold: 0,\n pointers: 2\n};\n\n/**\n * @private\n * direction cons to string\n * @param {constant} direction\n * @returns {String}\n */\nfunction directionStr(direction) {\n if (direction === DIRECTION_DOWN) {\n return 'down';\n } else if (direction === DIRECTION_UP) {\n return 'up';\n } else if (direction === DIRECTION_LEFT) {\n return 'left';\n } else if (direction === DIRECTION_RIGHT) {\n return 'right';\n }\n return '';\n}\n\n/**\n * @private\n * Pan\n * Recognized when the pointer is down and moved in the allowed direction.\n * @constructor\n * @extends AttrRecognizer\n */\n\nvar PanRecognizer = function (_AttrRecognizer) {\n inherits(PanRecognizer, _AttrRecognizer);\n\n function PanRecognizer() {\n classCallCheck(this, PanRecognizer);\n\n var _this = possibleConstructorReturn(this, (PanRecognizer.__proto__ || Object.getPrototypeOf(PanRecognizer)).apply(this, arguments));\n\n _this.pX = null;\n _this.pY = null;\n return _this;\n }\n\n createClass(PanRecognizer, [{\n key: 'getTouchAction',\n value: function getTouchAction() {\n var direction = this.options.direction;\n\n var actions = [];\n if (direction & DIRECTION_HORIZONTAL) {\n actions.push(TOUCH_ACTION_PAN_Y);\n }\n if (direction & DIRECTION_VERTICAL) {\n actions.push(TOUCH_ACTION_PAN_X);\n }\n return actions;\n }\n }, {\n key: 'directionTest',\n value: function directionTest(input) {\n var options = this.options;\n\n var hasMoved = true;\n var distance = input.distance;\n var direction = input.direction;\n\n var x = input.deltaX;\n var y = input.deltaY;\n\n // lock to axis?\n if (!(direction & options.direction)) {\n if (options.direction & DIRECTION_HORIZONTAL) {\n direction = x === 0 ? DIRECTION_NONE : x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;\n hasMoved = x !== this.pX;\n distance = Math.abs(input.deltaX);\n } else {\n direction = y === 0 ? DIRECTION_NONE : y < 0 ? DIRECTION_UP : DIRECTION_DOWN;\n hasMoved = y !== this.pY;\n distance = Math.abs(input.deltaY);\n }\n }\n input.direction = direction;\n return hasMoved && distance > options.threshold && direction & options.direction;\n }\n }, {\n key: 'attrTest',\n value: function attrTest(input) {\n return AttrRecognizer.prototype.attrTest.call(this, input) && ( // replace with a super call\n this.state & STATE_BEGAN || !(this.state & STATE_BEGAN) && this.directionTest(input));\n }\n }, {\n key: 'emit',\n value: function emit(input) {\n\n this.pX = input.deltaX;\n this.pY = input.deltaY;\n\n var direction = directionStr(input.direction);\n\n if (direction) {\n input.additionalEvent = this.options.event + direction;\n }\n get(PanRecognizer.prototype.__proto__ || Object.getPrototypeOf(PanRecognizer.prototype), 'emit', this).call(this, input);\n }\n }]);\n return PanRecognizer;\n}(AttrRecognizer);\n\nPanRecognizer.prototype.defaults = {\n event: 'pan',\n threshold: 10,\n pointers: 1,\n direction: DIRECTION_ALL\n};\n\n/**\n * @private\n * Swipe\n * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.\n * @constructor\n * @extends AttrRecognizer\n */\n\nvar SwipeRecognizer = function (_AttrRecognizer) {\n inherits(SwipeRecognizer, _AttrRecognizer);\n\n function SwipeRecognizer() {\n classCallCheck(this, SwipeRecognizer);\n return possibleConstructorReturn(this, (SwipeRecognizer.__proto__ || Object.getPrototypeOf(SwipeRecognizer)).apply(this, arguments));\n }\n\n createClass(SwipeRecognizer, [{\n key: 'getTouchAction',\n value: function getTouchAction() {\n return PanRecognizer.prototype.getTouchAction.call(this);\n }\n }, {\n key: 'attrTest',\n value: function attrTest(input) {\n var direction = this.options.direction;\n\n var velocity = void 0;\n\n if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {\n velocity = input.overallVelocity;\n } else if (direction & DIRECTION_HORIZONTAL) {\n velocity = input.overallVelocityX;\n } else if (direction & DIRECTION_VERTICAL) {\n velocity = input.overallVelocityY;\n }\n\n return get(SwipeRecognizer.prototype.__proto__ || Object.getPrototypeOf(SwipeRecognizer.prototype), 'attrTest', this).call(this, input) && direction & input.offsetDirection && input.distance > this.options.threshold && input.maxPointers === this.options.pointers && abs(velocity) > this.options.velocity && input.eventType & INPUT_END;\n }\n }, {\n key: 'emit',\n value: function emit(input) {\n var direction = directionStr(input.offsetDirection);\n if (direction) {\n this.manager.emit(this.options.event + direction, input);\n }\n\n this.manager.emit(this.options.event, input);\n }\n }]);\n return SwipeRecognizer;\n}(AttrRecognizer);\n\nSwipeRecognizer.prototype.defaults = {\n event: 'swipe',\n threshold: 10,\n velocity: 0.3,\n direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,\n pointers: 1\n};\n\n/**\n * @private\n * simple function bind\n * @param {Function} fn\n * @param {Object} context\n * @returns {Function}\n */\nfunction bindFn(fn, context) {\n return function boundFn() {\n return fn.apply(context, arguments);\n };\n}\n\n/**\n * @private\n * set a timeout with a given scope\n * @param {Function} fn\n * @param {Number} timeout\n * @param {Object} context\n * @returns {number}\n */\nfunction setTimeoutContext(fn, timeout, context) {\n return setTimeout(bindFn(fn, context), timeout);\n}\n\n/**\n * @private\n * calculate the absolute distance between two points\n * @param {Object} p1 {x, y}\n * @param {Object} p2 {x, y}\n * @param {Array} [props] containing x and y keys\n * @return {Number} distance\n */\nfunction getDistance(p1, p2, props) {\n if (!props) {\n props = PROPS_XY;\n }\n var x = p2[props[0]] - p1[props[0]];\n var y = p2[props[1]] - p1[props[1]];\n\n return Math.sqrt(x * x + y * y);\n}\n\n/**\n * @private\n * A tap is recognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur\n * between the given interval and position. The delay option can be used to recognize multi-taps without firing\n * a single tap.\n *\n * The eventData from the emitted event contains the property `tapCount`, which contains the amount of\n * multi-taps being recognized.\n * @constructor\n * @extends Recognizer\n */\n\nvar TapRecognizer = function (_Recognizer) {\n inherits(TapRecognizer, _Recognizer);\n\n function TapRecognizer() {\n classCallCheck(this, TapRecognizer);\n\n // previous time and center,\n // used for tap counting\n var _this = possibleConstructorReturn(this, (TapRecognizer.__proto__ || Object.getPrototypeOf(TapRecognizer)).apply(this, arguments));\n\n _this.pTime = false;\n _this.pCenter = false;\n\n _this._timer = null;\n _this._input = null;\n _this.count = 0;\n return _this;\n }\n\n createClass(TapRecognizer, [{\n key: 'getTouchAction',\n value: function getTouchAction() {\n return [TOUCH_ACTION_MANIPULATION];\n }\n }, {\n key: 'process',\n value: function process(input) {\n var _this2 = this;\n\n var options = this.options;\n\n\n var validPointers = input.pointers.length === options.pointers;\n var validMovement = input.distance < options.threshold;\n var validTouchTime = input.deltaTime < options.time;\n\n this.reset();\n\n if (input.eventType & INPUT_START && this.count === 0) {\n return this.failTimeout();\n }\n\n // we only allow little movement\n // and we've reached an end event, so a tap is possible\n if (validMovement && validTouchTime && validPointers) {\n if (input.eventType !== INPUT_END) {\n return this.failTimeout();\n }\n\n var validInterval = this.pTime ? input.timeStamp - this.pTime < options.interval : true;\n var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;\n\n this.pTime = input.timeStamp;\n this.pCenter = input.center;\n\n if (!validMultiTap || !validInterval) {\n this.count = 1;\n } else {\n this.count += 1;\n }\n\n this._input = input;\n\n // if tap count matches we have recognized it,\n // else it has began recognizing...\n var tapCount = this.count % options.taps;\n if (tapCount === 0) {\n // no failing requirements, immediately trigger the tap event\n // or wait as long as the multitap interval to trigger\n if (!this.hasRequireFailures()) {\n return STATE_RECOGNIZED;\n } else {\n this._timer = setTimeoutContext(function () {\n _this2.state = STATE_RECOGNIZED;\n _this2.tryEmit();\n }, options.interval, this);\n return STATE_BEGAN;\n }\n }\n }\n return STATE_FAILED;\n }\n }, {\n key: 'failTimeout',\n value: function failTimeout() {\n var _this3 = this;\n\n this._timer = setTimeoutContext(function () {\n _this3.state = STATE_FAILED;\n }, this.options.interval, this);\n return STATE_FAILED;\n }\n }, {\n key: 'reset',\n value: function reset() {\n clearTimeout(this._timer);\n }\n }, {\n key: 'emit',\n value: function emit() {\n if (this.state === STATE_RECOGNIZED) {\n this._input.tapCount = this.count;\n this.manager.emit(this.options.event, this._input);\n }\n }\n }]);\n return TapRecognizer;\n}(Recognizer);\n\nTapRecognizer.prototype.defaults = {\n event: 'tap',\n pointers: 1,\n taps: 1,\n interval: 300, // max time between the multi-tap taps\n time: 250, // max time of the pointer to be down (like finger on the screen)\n threshold: 9, // a minimal movement is ok, but keep it low\n posThreshold: 10 // a multi-tap can be a bit off the initial position\n};\n\n/**\n * @private\n * Press\n * Recognized when the pointer is down for x ms without any movement.\n * @constructor\n * @extends Recognizer\n */\n\nvar PressRecognizer = function (_Recognizer) {\n inherits(PressRecognizer, _Recognizer);\n\n function PressRecognizer() {\n classCallCheck(this, PressRecognizer);\n\n var _this = possibleConstructorReturn(this, (PressRecognizer.__proto__ || Object.getPrototypeOf(PressRecognizer)).apply(this, arguments));\n\n _this._timer = null;\n _this._input = null;\n return _this;\n }\n\n createClass(PressRecognizer, [{\n key: 'getTouchAction',\n value: function getTouchAction() {\n return [TOUCH_ACTION_AUTO];\n }\n }, {\n key: 'process',\n value: function process(input) {\n var _this2 = this;\n\n var options = this.options;\n\n var validPointers = input.pointers.length === options.pointers;\n var validMovement = input.distance < options.threshold;\n var validTime = input.deltaTime > options.time;\n\n this._input = input;\n\n // we only allow little movement\n // and we've reached an end event, so a tap is possible\n if (!validMovement || !validPointers || input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime) {\n this.reset();\n } else if (input.eventType & INPUT_START) {\n this.reset();\n this._timer = setTimeoutContext(function () {\n _this2.state = STATE_RECOGNIZED;\n _this2.tryEmit();\n }, options.time, this);\n } else if (input.eventType & INPUT_END) {\n return STATE_RECOGNIZED;\n }\n return STATE_FAILED;\n }\n }, {\n key: 'reset',\n value: function reset() {\n clearTimeout(this._timer);\n }\n }, {\n key: 'emit',\n value: function emit(input) {\n if (this.state !== STATE_RECOGNIZED) {\n return;\n }\n\n if (input && input.eventType & INPUT_END) {\n this.manager.emit(this.options.event + 'up', input);\n } else {\n this._input.timeStamp = now();\n this.manager.emit(this.options.event, this._input);\n }\n }\n }]);\n return PressRecognizer;\n}(Recognizer);\n\nPressRecognizer.prototype.defaults = {\n event: 'press',\n pointers: 1,\n time: 251, // minimal time of the pointer to be pressed\n threshold: 9 // a minimal movement is ok, but keep it low\n};\n\n/**\n * @private\n * small indexOf wrapper\n * @param {String} str\n * @param {String} find\n * @returns {Boolean} found\n */\nfunction inStr(str, find) {\n return str.indexOf(find) > -1;\n}\n\n/**\n * @private\n * when the touchActions are collected they are not a valid value, so we need to clean things up. *\n * @param {String} actions\n * @returns {*}\n */\nfunction cleanTouchActions(actions) {\n // none\n if (inStr(actions, TOUCH_ACTION_NONE)) {\n return TOUCH_ACTION_NONE;\n }\n\n var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);\n var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);\n\n // if both pan-x and pan-y are set (different recognizers\n // for different directions, e.g. horizontal pan but vertical swipe?)\n // we need none (as otherwise with pan-x pan-y combined none of these\n // recognizers will work, since the browser would handle all panning\n if (hasPanX && hasPanY) {\n return TOUCH_ACTION_NONE;\n }\n\n // pan-x OR pan-y\n if (hasPanX || hasPanY) {\n return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;\n }\n\n // manipulation\n if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {\n return TOUCH_ACTION_MANIPULATION;\n }\n\n return TOUCH_ACTION_AUTO;\n}\n\n/**\n * @private\n * Touch Action\n * sets the touchAction property or uses the js alternative\n * @param {Manager} manager\n * @param {String} value\n * @constructor\n */\n\nvar TouchAction = function () {\n function TouchAction(manager, value) {\n classCallCheck(this, TouchAction);\n\n this.manager = manager;\n this.set(value);\n }\n\n /**\n * @private\n * set the touchAction value on the element or enable the polyfill\n * @param {String} value\n */\n\n\n createClass(TouchAction, [{\n key: 'set',\n value: function set(value) {\n // find out the touch-action by the event handlers\n if (value === TOUCH_ACTION_COMPUTE) {\n value = this.compute();\n }\n\n if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) {\n this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;\n }\n this.actions = value.toLowerCase().trim();\n }\n\n /**\n * @private\n * just re-set the touchAction value\n */\n\n }, {\n key: 'update',\n value: function update() {\n this.set(this.manager.options.touchAction);\n }\n\n /**\n * @private\n * compute the value for the touchAction property based on the recognizer's settings\n * @returns {String} value\n */\n\n }, {\n key: 'compute',\n value: function compute() {\n var actions = [];\n each(this.manager.recognizers, function (recognizer) {\n if (boolOrFn(recognizer.options.enable, [recognizer])) {\n actions = actions.concat(recognizer.getTouchAction());\n }\n });\n return cleanTouchActions(actions.join(' '));\n }\n\n /**\n * @private\n * this method is called on each input cycle and provides the preventing of the browser behavior\n * @param {Object} input\n */\n\n }, {\n key: 'preventDefaults',\n value: function preventDefaults(input) {\n var srcEvent = input.srcEvent;\n\n var direction = input.offsetDirection;\n\n // if the touch action did prevented once this session\n if (this.manager.session.prevented) {\n srcEvent.preventDefault();\n return;\n }\n\n var actions = this.actions;\n\n var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];\n var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];\n var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];\n\n if (hasNone) {\n // do not prevent defaults if this is a tap gesture\n var isTapPointer = input.pointers.length === 1;\n var isTapMovement = input.distance < 2;\n var isTapTouchTime = input.deltaTime < 250;\n\n if (isTapPointer && isTapMovement && isTapTouchTime) {\n return;\n }\n }\n\n if (hasPanX && hasPanY) {\n // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent\n return;\n }\n\n if (hasNone || hasPanY && direction & DIRECTION_HORIZONTAL || hasPanX && direction & DIRECTION_VERTICAL) {\n return this.preventSrc(srcEvent);\n }\n }\n\n /**\n * @private\n * call preventDefault to prevent the browser's default behavior (scrolling in most cases)\n * @param {Object} srcEvent\n */\n\n }, {\n key: 'preventSrc',\n value: function preventSrc(srcEvent) {\n this.manager.session.prevented = true;\n srcEvent.preventDefault();\n }\n }]);\n return TouchAction;\n}();\n\n/**\n * @private\n * find if a node is in the given parent\n * @method hasParent\n * @param {HTMLElement} node\n * @param {HTMLElement} parent\n * @return {Boolean} found\n */\nfunction hasParent(node, parent) {\n while (node) {\n if (node === parent) {\n return true;\n }\n node = node.parentNode;\n }\n return false;\n}\n\n/**\n * @private\n * get the center of all the pointers\n * @param {Array} pointers\n * @return {Object} center contains `x` and `y` properties\n */\nfunction getCenter(pointers) {\n var pointersLength = pointers.length;\n\n // no need to loop when only one touch\n if (pointersLength === 1) {\n return {\n x: round(pointers[0].clientX),\n y: round(pointers[0].clientY)\n };\n }\n\n var x = 0;\n var y = 0;\n var i = 0;\n while (i < pointersLength) {\n x += pointers[i].clientX;\n y += pointers[i].clientY;\n i++;\n }\n\n return {\n x: round(x / pointersLength),\n y: round(y / pointersLength)\n };\n}\n\n/**\n * @private\n * create a simple clone from the input used for storage of firstInput and firstMultiple\n * @param {Object} input\n * @returns {Object} clonedInputData\n */\nfunction simpleCloneInputData(input) {\n // make a simple copy of the pointers because we will get a reference if we don't\n // we only need clientXY for the calculations\n var pointers = [];\n var i = 0;\n while (i < input.pointers.length) {\n pointers[i] = {\n clientX: round(input.pointers[i].clientX),\n clientY: round(input.pointers[i].clientY)\n };\n i++;\n }\n\n return {\n timeStamp: now(),\n pointers: pointers,\n center: getCenter(pointers),\n deltaX: input.deltaX,\n deltaY: input.deltaY\n };\n}\n\n/**\n * @private\n * calculate the angle between two coordinates\n * @param {Object} p1\n * @param {Object} p2\n * @param {Array} [props] containing x and y keys\n * @return {Number} angle\n */\nfunction getAngle(p1, p2, props) {\n if (!props) {\n props = PROPS_XY;\n }\n var x = p2[props[0]] - p1[props[0]];\n var y = p2[props[1]] - p1[props[1]];\n return Math.atan2(y, x) * 180 / Math.PI;\n}\n\n/**\n * @private\n * get the direction between two points\n * @param {Number} x\n * @param {Number} y\n * @return {Number} direction\n */\nfunction getDirection(x, y) {\n if (x === y) {\n return DIRECTION_NONE;\n }\n\n if (abs(x) >= abs(y)) {\n return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;\n }\n return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;\n}\n\nfunction computeDeltaXY(session, input) {\n var center = input.center;\n // let { offsetDelta:offset = {}, prevDelta = {}, prevInput = {} } = session;\n // jscs throwing error on defalut destructured values and without defaults tests fail\n\n var offset = session.offsetDelta || {};\n var prevDelta = session.prevDelta || {};\n var prevInput = session.prevInput || {};\n\n if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {\n prevDelta = session.prevDelta = {\n x: prevInput.deltaX || 0,\n y: prevInput.deltaY || 0\n };\n\n offset = session.offsetDelta = {\n x: center.x,\n y: center.y\n };\n }\n\n input.deltaX = prevDelta.x + (center.x - offset.x);\n input.deltaY = prevDelta.y + (center.y - offset.y);\n}\n\n/**\n * @private\n * calculate the velocity between two points. unit is in px per ms.\n * @param {Number} deltaTime\n * @param {Number} x\n * @param {Number} y\n * @return {Object} velocity `x` and `y`\n */\nfunction getVelocity(deltaTime, x, y) {\n return {\n x: x / deltaTime || 0,\n y: y / deltaTime || 0\n };\n}\n\n/**\n * @private\n * calculate the scale factor between two pointersets\n * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out\n * @param {Array} start array of pointers\n * @param {Array} end array of pointers\n * @return {Number} scale\n */\nfunction getScale(start, end) {\n return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);\n}\n\n/**\n * @private\n * calculate the rotation degrees between two pointersets\n * @param {Array} start array of pointers\n * @param {Array} end array of pointers\n * @return {Number} rotation\n */\nfunction getRotation(start, end) {\n return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);\n}\n\n/**\n * @private\n * velocity is calculated every x ms\n * @param {Object} session\n * @param {Object} input\n */\nfunction computeIntervalInputData(session, input) {\n var last = session.lastInterval || input;\n var deltaTime = input.timeStamp - last.timeStamp;\n var velocity = void 0;\n var velocityX = void 0;\n var velocityY = void 0;\n var direction = void 0;\n\n if (input.eventType !== INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {\n var deltaX = input.deltaX - last.deltaX;\n var deltaY = input.deltaY - last.deltaY;\n\n var v = getVelocity(deltaTime, deltaX, deltaY);\n velocityX = v.x;\n velocityY = v.y;\n velocity = abs(v.x) > abs(v.y) ? v.x : v.y;\n direction = getDirection(deltaX, deltaY);\n\n session.lastInterval = input;\n } else {\n // use latest velocity info if it doesn't overtake a minimum period\n velocity = last.velocity;\n velocityX = last.velocityX;\n velocityY = last.velocityY;\n direction = last.direction;\n }\n\n input.velocity = velocity;\n input.velocityX = velocityX;\n input.velocityY = velocityY;\n input.direction = direction;\n}\n\n/**\n* @private\n * extend the data with some usable properties like scale, rotate, velocity etc\n * @param {Object} manager\n * @param {Object} input\n */\nfunction computeInputData(manager, input) {\n var session = manager.session;\n var pointers = input.pointers;\n var pointersLength = pointers.length;\n\n // store the first input to calculate the distance and direction\n\n if (!session.firstInput) {\n session.firstInput = simpleCloneInputData(input);\n }\n\n // to compute scale and rotation we need to store the multiple touches\n if (pointersLength > 1 && !session.firstMultiple) {\n session.firstMultiple = simpleCloneInputData(input);\n } else if (pointersLength === 1) {\n session.firstMultiple = false;\n }\n\n var firstInput = session.firstInput;\n var firstMultiple = session.firstMultiple;\n\n var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;\n\n var center = input.center = getCenter(pointers);\n input.timeStamp = now();\n input.deltaTime = input.timeStamp - firstInput.timeStamp;\n\n input.angle = getAngle(offsetCenter, center);\n input.distance = getDistance(offsetCenter, center);\n\n computeDeltaXY(session, input);\n input.offsetDirection = getDirection(input.deltaX, input.deltaY);\n\n var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);\n input.overallVelocityX = overallVelocity.x;\n input.overallVelocityY = overallVelocity.y;\n input.overallVelocity = abs(overallVelocity.x) > abs(overallVelocity.y) ? overallVelocity.x : overallVelocity.y;\n\n input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;\n input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;\n\n input.maxPointers = !session.prevInput ? input.pointers.length : input.pointers.length > session.prevInput.maxPointers ? input.pointers.length : session.prevInput.maxPointers;\n\n computeIntervalInputData(session, input);\n\n // find the correct target\n var target = manager.element;\n if (hasParent(input.srcEvent.target, target)) {\n target = input.srcEvent.target;\n }\n input.target = target;\n}\n\n/**\n * @private\n * handle input events\n * @param {Manager} manager\n * @param {String} eventType\n * @param {Object} input\n */\nfunction inputHandler(manager, eventType, input) {\n var pointersLen = input.pointers.length;\n var changedPointersLen = input.changedPointers.length;\n var isFirst = eventType & INPUT_START && pointersLen - changedPointersLen === 0;\n var isFinal = eventType & (INPUT_END | INPUT_CANCEL) && pointersLen - changedPointersLen === 0;\n\n input.isFirst = !!isFirst;\n input.isFinal = !!isFinal;\n\n if (isFirst) {\n manager.session = {};\n }\n\n // source event is the normalized value of the domEvents\n // like 'touchstart, mouseup, pointerdown'\n input.eventType = eventType;\n\n // compute scale, rotation etc\n computeInputData(manager, input);\n\n // emit secret event\n manager.emit('hammer.input', input);\n\n manager.recognize(input);\n manager.session.prevInput = input;\n}\n\n/**\n * @private\n * split string on whitespace\n * @param {String} str\n * @returns {Array} words\n */\n\nfunction splitStr(str) {\n return str.trim().split(/\\s+/g);\n}\n\n/**\n * @private\n * addEventListener with multiple events at once\n * @param {EventTarget} target\n * @param {String} types\n * @param {Function} handler\n */\nfunction addEventListeners(target, types, handler) {\n each(splitStr(types), function (type) {\n target.addEventListener(type, handler, false);\n });\n}\n\n/**\n * @private\n * removeEventListener with multiple events at once\n * @param {EventTarget} target\n * @param {String} types\n * @param {Function} handler\n */\nfunction removeEventListeners(target, types, handler) {\n each(splitStr(types), function (type) {\n target.removeEventListener(type, handler, false);\n });\n}\n\n/**\n * @private\n * get the window object of an element\n * @param {HTMLElement} element\n * @returns {DocumentView|Window}\n */\nfunction getWindowForElement(element) {\n var doc = element.ownerDocument || element;\n return doc.defaultView || doc.parentWindow || window;\n}\n\n/**\n * @private\n * create new input type manager\n * @param {Manager} manager\n * @param {Function} callback\n * @returns {Input}\n * @constructor\n */\n\nvar Input = function () {\n function Input(manager, callback) {\n classCallCheck(this, Input);\n\n var self = this;\n this.manager = manager;\n this.callback = callback;\n this.element = manager.element;\n this.target = manager.options.inputTarget;\n\n // smaller wrapper around the handler, for the scope and the enabled state of the manager,\n // so when disabled the input events are completely bypassed.\n this.domHandler = function (ev) {\n if (boolOrFn(manager.options.enable, [manager])) {\n self.handler(ev);\n }\n };\n\n this.init();\n }\n /**\n * @private\n * should handle the inputEvent data and trigger the callback\n * @virtual\n */\n\n\n createClass(Input, [{\n key: 'handler',\n value: function handler() {}\n\n /**\n * @private\n * bind the events\n */\n\n }, {\n key: 'init',\n value: function init() {\n this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);\n this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);\n this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);\n }\n\n /**\n * @private\n * unbind the events\n */\n\n }, {\n key: 'destroy',\n value: function destroy() {\n this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);\n this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);\n this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);\n }\n }]);\n return Input;\n}();\n\nvar POINTER_INPUT_MAP = {\n pointerdown: INPUT_START,\n pointermove: INPUT_MOVE,\n pointerup: INPUT_END,\n pointercancel: INPUT_CANCEL,\n pointerout: INPUT_CANCEL\n};\n\n// in IE10 the pointer types is defined as an enum\nvar IE10_POINTER_TYPE_ENUM = {\n 2: INPUT_TYPE_TOUCH,\n 3: INPUT_TYPE_PEN,\n 4: INPUT_TYPE_MOUSE,\n 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816\n};\n\nvar POINTER_ELEMENT_EVENTS = 'pointerdown';\nvar POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel';\n\n// IE10 has prefixed support, and case-sensitive\nif (window.MSPointerEvent && !window.PointerEvent) {\n POINTER_ELEMENT_EVENTS = 'MSPointerDown';\n POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';\n}\n\n/**\n * @private\n * Pointer events input\n * @constructor\n * @extends Input\n */\n\nvar PointerEventInput = function (_Input) {\n inherits(PointerEventInput, _Input);\n\n function PointerEventInput() {\n classCallCheck(this, PointerEventInput);\n\n var _this = possibleConstructorReturn(this, (PointerEventInput.__proto__ || Object.getPrototypeOf(PointerEventInput)).apply(this, arguments));\n\n _this.evEl = POINTER_ELEMENT_EVENTS;\n _this.evWin = POINTER_WINDOW_EVENTS;\n\n _this.store = _this.manager.session.pointerEvents = [];\n return _this;\n }\n\n /**\n * @private\n * handle mouse events\n * @param {Object} ev\n */\n\n\n createClass(PointerEventInput, [{\n key: 'handler',\n value: function handler(ev) {\n var store = this.store;\n\n var removePointer = false;\n\n var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');\n var eventType = POINTER_INPUT_MAP[eventTypeNormalized];\n var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;\n\n var isTouch = pointerType === INPUT_TYPE_TOUCH;\n\n // get index of the event in the store\n var storeIndex = inArray(store, ev.pointerId, 'pointerId');\n\n // start and mouse must be down\n if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {\n if (storeIndex < 0) {\n store.push(ev);\n storeIndex = store.length - 1;\n }\n } else if (eventType & (INPUT_END | INPUT_CANCEL)) {\n removePointer = true;\n }\n\n // it not found, so the pointer hasn't been down (so it's probably a hover)\n if (storeIndex < 0) {\n return;\n }\n\n // update the event in the store\n store[storeIndex] = ev;\n\n this.callback(this.manager, eventType, {\n pointers: store,\n changedPointers: [ev],\n pointerType: pointerType,\n srcEvent: ev\n });\n\n if (removePointer) {\n // remove from the store\n store.splice(storeIndex, 1);\n }\n }\n }]);\n return PointerEventInput;\n}(Input);\n\n/**\n * @private\n * convert array-like objects to real arrays\n * @param {Object} obj\n * @returns {Array}\n */\nfunction toArray$1(obj) {\n return Array.prototype.slice.call(obj, 0);\n}\n\n/**\n * @private\n * unique array with objects based on a key (like 'id') or just by the array's value\n * @param {Array} src [{id:1},{id:2},{id:1}]\n * @param {String} [key]\n * @param {Boolean} [sort=False]\n * @returns {Array} [{id:1},{id:2}]\n */\nfunction uniqueArray(src, key, sort) {\n var results = [];\n var values = [];\n var i = 0;\n\n while (i < src.length) {\n var val = key ? src[i][key] : src[i];\n if (inArray(values, val) < 0) {\n results.push(src[i]);\n }\n values[i] = val;\n i++;\n }\n\n if (sort) {\n if (!key) {\n results = results.sort();\n } else {\n results = results.sort(function (a, b) {\n return a[key] > b[key];\n });\n }\n }\n\n return results;\n}\n\nvar TOUCH_INPUT_MAP = {\n touchstart: INPUT_START,\n touchmove: INPUT_MOVE,\n touchend: INPUT_END,\n touchcancel: INPUT_CANCEL\n};\n\nvar TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';\n\n/**\n * @private\n * Multi-user touch events input\n * @constructor\n * @extends Input\n */\n\nvar TouchInput = function (_Input) {\n inherits(TouchInput, _Input);\n\n function TouchInput() {\n classCallCheck(this, TouchInput);\n\n TouchInput.prototype.evTarget = TOUCH_TARGET_EVENTS;\n TouchInput.prototype.targetIds = {};\n\n var _this = possibleConstructorReturn(this, (TouchInput.__proto__ || Object.getPrototypeOf(TouchInput)).apply(this, arguments));\n\n _this.evTarget = TOUCH_TARGET_EVENTS;\n _this.targetIds = {};\n return _this;\n }\n\n createClass(TouchInput, [{\n key: 'handler',\n value: function handler(ev) {\n var type = TOUCH_INPUT_MAP[ev.type];\n var touches = getTouches.call(this, ev, type);\n if (!touches) {\n return;\n }\n\n this.callback(this.manager, type, {\n pointers: touches[0],\n changedPointers: touches[1],\n pointerType: INPUT_TYPE_TOUCH,\n srcEvent: ev\n });\n }\n }]);\n return TouchInput;\n}(Input);\n\nfunction getTouches(ev, type) {\n var allTouches = toArray$1(ev.touches);\n var targetIds = this.targetIds;\n\n // when there is only one touch, the process can be simplified\n\n if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {\n targetIds[allTouches[0].identifier] = true;\n return [allTouches, allTouches];\n }\n\n var i = void 0;\n var targetTouches = void 0;\n var changedTouches = toArray$1(ev.changedTouches);\n var changedTargetTouches = [];\n var target = this.target;\n\n // get target touches from touches\n\n targetTouches = allTouches.filter(function (touch) {\n return hasParent(touch.target, target);\n });\n\n // collect touches\n if (type === INPUT_START) {\n i = 0;\n while (i < targetTouches.length) {\n targetIds[targetTouches[i].identifier] = true;\n i++;\n }\n }\n\n // filter changed touches to only contain touches that exist in the collected target ids\n i = 0;\n while (i < changedTouches.length) {\n if (targetIds[changedTouches[i].identifier]) {\n changedTargetTouches.push(changedTouches[i]);\n }\n\n // cleanup removed touches\n if (type & (INPUT_END | INPUT_CANCEL)) {\n delete targetIds[changedTouches[i].identifier];\n }\n i++;\n }\n\n if (!changedTargetTouches.length) {\n return;\n }\n\n return [\n // merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'\n uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true), changedTargetTouches];\n}\n\nvar MOUSE_INPUT_MAP = {\n mousedown: INPUT_START,\n mousemove: INPUT_MOVE,\n mouseup: INPUT_END\n};\n\nvar MOUSE_ELEMENT_EVENTS = 'mousedown';\nvar MOUSE_WINDOW_EVENTS = 'mousemove mouseup';\n\n/**\n * @private\n * Mouse events input\n * @constructor\n * @extends Input\n */\n\nvar MouseInput = function (_Input) {\n inherits(MouseInput, _Input);\n\n function MouseInput() {\n classCallCheck(this, MouseInput);\n\n var _this = possibleConstructorReturn(this, (MouseInput.__proto__ || Object.getPrototypeOf(MouseInput)).apply(this, arguments));\n\n _this.evEl = MOUSE_ELEMENT_EVENTS;\n _this.evWin = MOUSE_WINDOW_EVENTS;\n\n _this.pressed = false; // mousedown state\n return _this;\n }\n\n /**\n * @private\n * handle mouse events\n * @param {Object} ev\n */\n\n\n createClass(MouseInput, [{\n key: 'handler',\n value: function handler(ev) {\n var eventType = MOUSE_INPUT_MAP[ev.type];\n\n // on start we want to have the left mouse button down\n if (eventType & INPUT_START && ev.button === 0) {\n this.pressed = true;\n }\n\n if (eventType & INPUT_MOVE && ev.which !== 1) {\n eventType = INPUT_END;\n }\n\n // mouse must be down\n if (!this.pressed) {\n return;\n }\n\n if (eventType & INPUT_END) {\n this.pressed = false;\n }\n\n this.callback(this.manager, eventType, {\n pointers: [ev],\n changedPointers: [ev],\n pointerType: INPUT_TYPE_MOUSE,\n srcEvent: ev\n });\n }\n }]);\n return MouseInput;\n}(Input);\n\n/**\n * @private\n * Combined touch and mouse input\n *\n * Touch has a higher priority then mouse, and while touching no mouse events are allowed.\n * This because touch devices also emit mouse events while doing a touch.\n *\n * @constructor\n * @extends Input\n */\n\nvar DEDUP_TIMEOUT = 2500;\nvar DEDUP_DISTANCE = 25;\n\nvar TouchMouseInput = function (_Input) {\n inherits(TouchMouseInput, _Input);\n\n function TouchMouseInput() {\n classCallCheck(this, TouchMouseInput);\n\n var _this = possibleConstructorReturn(this, (TouchMouseInput.__proto__ || Object.getPrototypeOf(TouchMouseInput)).apply(this, arguments));\n\n var handler = bindFn(_this.handler, _this);\n _this.touch = new TouchInput(_this.manager, handler);\n _this.mouse = new MouseInput(_this.manager, handler);\n\n _this.primaryTouch = null;\n _this.lastTouches = [];\n return _this;\n }\n\n /**\n * @private\n * handle mouse and touch events\n * @param {Hammer} manager\n * @param {String} inputEvent\n * @param {Object} inputData\n */\n\n\n createClass(TouchMouseInput, [{\n key: 'handler',\n value: function handler(manager, inputEvent, inputData) {\n var isTouch = inputData.pointerType === INPUT_TYPE_TOUCH;\n var isMouse = inputData.pointerType === INPUT_TYPE_MOUSE;\n\n if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) {\n return;\n }\n\n // when we're in a touch event, record touches to de-dupe synthetic mouse event\n if (isTouch) {\n recordTouches.call(this, inputEvent, inputData);\n } else if (isMouse && isSyntheticEvent.call(this, inputData)) {\n return;\n }\n\n this.callback(manager, inputEvent, inputData);\n }\n\n /**\n * @private\n * remove the event listeners\n */\n\n }, {\n key: 'destroy',\n value: function destroy() {\n this.touch.destroy();\n this.mouse.destroy();\n }\n }]);\n return TouchMouseInput;\n}(Input);\n\nfunction recordTouches(eventType, eventData) {\n if (eventType & INPUT_START) {\n this.primaryTouch = eventData.changedPointers[0].identifier;\n setLastTouch.call(this, eventData);\n } else if (eventType & (INPUT_END | INPUT_CANCEL)) {\n setLastTouch.call(this, eventData);\n }\n}\n\nfunction setLastTouch(eventData) {\n var _this2 = this;\n\n var _eventData$changedPoi = slicedToArray(eventData.changedPointers, 1);\n\n var touch = _eventData$changedPoi[0];\n\n if (touch.identifier === this.primaryTouch) {\n (function () {\n var lastTouch = { x: touch.clientX, y: touch.clientY };\n _this2.lastTouches.push(lastTouch);\n var lts = _this2.lastTouches;\n var removeLastTouch = function removeLastTouch() {\n var i = lts.indexOf(lastTouch);\n if (i > -1) {\n lts.splice(i, 1);\n }\n };\n setTimeout(removeLastTouch, DEDUP_TIMEOUT);\n })();\n }\n}\n\nfunction isSyntheticEvent(eventData) {\n var x = eventData.srcEvent.clientX;\n var y = eventData.srcEvent.clientY;\n for (var i = 0; i < this.lastTouches.length; i++) {\n var t = this.lastTouches[i];\n var dx = Math.abs(x - t.x);\n var dy = Math.abs(y - t.y);\n if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * @private\n * create new input type manager\n * called by the Manager constructor\n * @param {Hammer} manager\n * @returns {Input}\n */\nfunction createInputInstance(manager) {\n var Type = void 0;\n // let inputClass = manager.options.inputClass;\n var inputClass = manager.options.inputClass;\n\n if (inputClass) {\n Type = inputClass;\n } else if (SUPPORT_POINTER_EVENTS) {\n Type = PointerEventInput;\n } else if (SUPPORT_ONLY_TOUCH) {\n Type = TouchInput;\n } else if (!SUPPORT_TOUCH) {\n Type = MouseInput;\n } else {\n Type = TouchMouseInput;\n }\n return new Type(manager, inputHandler);\n}\n\nvar STOP = 1;\nvar FORCED_STOP = 2;\n\n/**\n* @private\n * Manager\n * @param {HTMLElement} element\n * @param {Object} [options]\n * @constructor\n */\n\nvar Manager = function () {\n function Manager(element, options) {\n var _this = this;\n\n classCallCheck(this, Manager);\n\n this.options = assign$1({}, Hammer.defaults, options || {});\n\n this.options.inputTarget = this.options.inputTarget || element;\n\n this.handlers = {};\n this.session = {};\n this.recognizers = [];\n this.oldCssProps = {};\n\n this.element = element;\n this.input = createInputInstance(this);\n this.touchAction = new TouchAction(this, this.options.touchAction);\n\n toggleCssProps(this, true);\n\n each(this.options.recognizers, function (item) {\n var recognizer = _this.add(new item[0](item[1]));\n item[2] && recognizer.recognizeWith(item[2]);\n item[3] && recognizer.requireFailure(item[3]);\n }, this);\n }\n\n /**\n * @private\n * set options\n * @param {Object} options\n * @returns {Manager}\n */\n\n\n createClass(Manager, [{\n key: 'set',\n value: function set(options) {\n assign$1(this.options, options);\n\n // Options that need a little more setup\n if (options.touchAction) {\n this.touchAction.update();\n }\n if (options.inputTarget) {\n // Clean up existing event listeners and reinitialize\n this.input.destroy();\n this.input.target = options.inputTarget;\n this.input.init();\n }\n return this;\n }\n\n /**\n * @private\n * stop recognizing for this session.\n * This session will be discarded, when a new [input]start event is fired.\n * When forced, the recognizer cycle is stopped immediately.\n * @param {Boolean} [force]\n */\n\n }, {\n key: 'stop',\n value: function stop(force) {\n this.session.stopped = force ? FORCED_STOP : STOP;\n }\n\n /**\n * @private\n * run the recognizers!\n * called by the inputHandler function on every movement of the pointers (touches)\n * it walks through all the recognizers and tries to detect the gesture that is being made\n * @param {Object} inputData\n */\n\n }, {\n key: 'recognize',\n value: function recognize(inputData) {\n var session = this.session;\n\n if (session.stopped) {\n return;\n }\n\n // run the touch-action polyfill\n this.touchAction.preventDefaults(inputData);\n\n var recognizer = void 0;\n var recognizers = this.recognizers;\n\n // this holds the recognizer that is being recognized.\n // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED\n // if no recognizer is detecting a thing, it is set to `null`\n\n var curRecognizer = session.curRecognizer;\n\n // reset when the last recognizer is recognized\n // or when we're in a new session\n\n if (!curRecognizer || curRecognizer && curRecognizer.state & STATE_RECOGNIZED) {\n curRecognizer = session.curRecognizer = null;\n }\n\n var i = 0;\n while (i < recognizers.length) {\n recognizer = recognizers[i];\n\n // find out if we are allowed try to recognize the input for this one.\n // 1. allow if the session is NOT forced stopped (see the .stop() method)\n // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one\n // that is being recognized.\n // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.\n // this can be setup with the `recognizeWith()` method on the recognizer.\n if (session.stopped !== FORCED_STOP && ( // 1\n !curRecognizer || recognizer === curRecognizer || // 2\n recognizer.canRecognizeWith(curRecognizer))) {\n // 3\n recognizer.recognize(inputData);\n } else {\n recognizer.reset();\n }\n\n // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the\n // current active recognizer. but only if we don't already have an active recognizer\n if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {\n curRecognizer = session.curRecognizer = recognizer;\n }\n i++;\n }\n }\n\n /**\n * @private\n * get a recognizer by its event name.\n * @param {Recognizer|String} recognizer\n * @returns {Recognizer|Null}\n */\n\n }, {\n key: 'get',\n value: function get(recognizer) {\n if (recognizer instanceof Recognizer) {\n return recognizer;\n }\n\n var recognizers = this.recognizers;\n\n for (var i = 0; i < recognizers.length; i++) {\n if (recognizers[i].options.event === recognizer) {\n return recognizers[i];\n }\n }\n return null;\n }\n\n /**\n * @private add a recognizer to the manager\n * existing recognizers with the same event name will be removed\n * @param {Recognizer} recognizer\n * @returns {Recognizer|Manager}\n */\n\n }, {\n key: 'add',\n value: function add(recognizer) {\n if (invokeArrayArg(recognizer, 'add', this)) {\n return this;\n }\n\n // remove existing\n var existing = this.get(recognizer.options.event);\n if (existing) {\n this.remove(existing);\n }\n\n this.recognizers.push(recognizer);\n recognizer.manager = this;\n\n this.touchAction.update();\n return recognizer;\n }\n\n /**\n * @private\n * remove a recognizer by name or instance\n * @param {Recognizer|String} recognizer\n * @returns {Manager}\n */\n\n }, {\n key: 'remove',\n value: function remove(recognizer) {\n if (invokeArrayArg(recognizer, 'remove', this)) {\n return this;\n }\n\n recognizer = this.get(recognizer);\n\n // let's make sure this recognizer exists\n if (recognizer) {\n var recognizers = this.recognizers;\n\n var index = inArray(recognizers, recognizer);\n\n if (index !== -1) {\n recognizers.splice(index, 1);\n this.touchAction.update();\n }\n }\n\n return this;\n }\n\n /**\n * @private\n * bind event\n * @param {String} events\n * @param {Function} handler\n * @returns {EventEmitter} this\n */\n\n }, {\n key: 'on',\n value: function on(events, handler) {\n if (events === undefined) {\n return;\n }\n if (handler === undefined) {\n return;\n }\n\n var handlers = this.handlers;\n\n each(splitStr(events), function (event) {\n handlers[event] = handlers[event] || [];\n handlers[event].push(handler);\n });\n return this;\n }\n\n /**\n * @private unbind event, leave emit blank to remove all handlers\n * @param {String} events\n * @param {Function} [handler]\n * @returns {EventEmitter} this\n */\n\n }, {\n key: 'off',\n value: function off(events, handler) {\n if (events === undefined) {\n return;\n }\n\n var handlers = this.handlers;\n\n each(splitStr(events), function (event) {\n if (!handler) {\n delete handlers[event];\n } else {\n handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);\n }\n });\n return this;\n }\n\n /**\n * @private emit event to the listeners\n * @param {String} event\n * @param {Object} data\n */\n\n }, {\n key: 'emit',\n value: function emit(event, data) {\n // we also want to trigger dom events\n if (this.options.domEvents) {\n triggerDomEvent(event, data);\n }\n\n // no handlers, so skip it all\n var handlers = this.handlers[event] && this.handlers[event].slice();\n if (!handlers || !handlers.length) {\n return;\n }\n\n data.type = event;\n data.preventDefault = function () {\n data.srcEvent.preventDefault();\n };\n\n var i = 0;\n while (i < handlers.length) {\n handlers[i](data);\n i++;\n }\n }\n\n /**\n * @private\n * destroy the manager and unbinds all events\n * it doesn't unbind dom events, that is the user own responsibility\n */\n\n }, {\n key: 'destroy',\n value: function destroy() {\n this.element && toggleCssProps(this, false);\n\n this.handlers = {};\n this.session = {};\n this.input.destroy();\n this.element = null;\n }\n }]);\n return Manager;\n}();\n\nfunction toggleCssProps(manager, add) {\n var element = manager.element;\n\n if (!element.style) {\n return;\n }\n var prop = void 0;\n each(manager.options.cssProps, function (value, name) {\n prop = prefixed(element.style, name);\n if (add) {\n manager.oldCssProps[prop] = element.style[prop];\n element.style[prop] = value;\n } else {\n element.style[prop] = manager.oldCssProps[prop] || '';\n }\n });\n if (!add) {\n manager.oldCssProps = {};\n }\n}\n\n/**\n * @private\n * trigger dom event\n * @param {String} event\n * @param {Object} data\n */\nfunction triggerDomEvent(event, data) {\n var gestureEvent = document.createEvent('Event');\n gestureEvent.initEvent(event, true, true);\n gestureEvent.gesture = data;\n data.target.dispatchEvent(gestureEvent);\n}\n\n/**\n * @private\n * Simple way to create a manager with a default set of recognizers.\n * @param {HTMLElement} element\n * @param {Object} [options]\n * @constructor\n */\n\nvar Hammer = function Hammer(element, options) {\n classCallCheck(this, Hammer);\n\n options = options || {};\n options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);\n return new Manager(element, options);\n};\n\nHammer.VERSION = '2.0.8';\n\n/**\n * @private\n * default settings\n * @namespace\n */\nHammer.defaults = {\n /**\n * @private\n * set if DOM events are being triggered.\n * But this is slower and unused by simple implementations, so disabled by default.\n * @type {Boolean}\n * @default false\n */\n domEvents: false,\n\n /**\n * @private\n * The value for the touchAction property/fallback.\n * When set to `compute` it will magically set the correct value based on the added recognizers.\n * @type {String}\n * @default compute\n */\n touchAction: TOUCH_ACTION_COMPUTE,\n\n /**\n * @private\n * @type {Boolean}\n * @default true\n */\n enable: true,\n\n /**\n * @private\n * EXPERIMENTAL FEATURE -- can be removed/changed\n * Change the parent input target element.\n * If Null, then it is being set the to main element.\n * @type {Null|EventTarget}\n * @default null\n */\n inputTarget: null,\n\n /**\n * @private\n * force an input class\n * @type {Null|Function}\n * @default null\n */\n inputClass: null,\n\n /**\n * @private\n * Default recognizer setup when calling `Hammer()`\n * When creating a new Manager these will be skipped.\n * @type {Array}\n */\n preset: [\n // RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]\n [RotateRecognizer, { enable: false }], [PinchRecognizer, { enable: false }, ['rotate']], [SwipeRecognizer, { direction: DIRECTION_HORIZONTAL }], [PanRecognizer, { direction: DIRECTION_HORIZONTAL }, ['swipe']], [TapRecognizer], [TapRecognizer, { event: 'doubletap', taps: 2 }, ['tap']], [PressRecognizer]],\n\n /**\n * @private\n * Some CSS properties can be used to improve the working of Hammer.\n * Add them to this method and they will be set when creating a new Manager.\n * @namespace\n */\n cssProps: {\n /**\n * @private\n * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.\n * @type {String}\n * @default 'none'\n */\n userSelect: 'none',\n\n /**\n * @private\n * Disable the Windows Phone grippers when pressing an element.\n * @type {String}\n * @default 'none'\n */\n touchSelect: 'none',\n\n /**\n * @private\n * Disables the default callout shown when you touch and hold a touch target.\n * On iOS, when you touch and hold a touch target such as a link, Safari displays\n * a callout containing information about the link. This property allows you to disable that callout.\n * @type {String}\n * @default 'none'\n */\n touchCallout: 'none',\n\n /**\n * @private\n * Specifies whether zooming is enabled. Used by IE10>\n * @type {String}\n * @default 'none'\n */\n contentZooming: 'none',\n\n /**\n * @private\n * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.\n * @type {String}\n * @default 'none'\n */\n userDrag: 'none',\n\n /**\n * @private\n * Overrides the highlight color shown when the user taps a link or a JavaScript\n * clickable element in iOS. This property obeys the alpha value, if specified.\n * @type {String}\n * @default 'rgba(0,0,0,0)'\n */\n tapHighlightColor: 'rgba(0,0,0,0)'\n }\n};\n\nvar SINGLE_TOUCH_INPUT_MAP = {\n touchstart: INPUT_START,\n touchmove: INPUT_MOVE,\n touchend: INPUT_END,\n touchcancel: INPUT_CANCEL\n};\n\nvar SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';\nvar SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';\n\n/**\n * @private\n * Touch events input\n * @constructor\n * @extends Input\n */\n\nvar SingleTouchInput = function (_Input) {\n inherits(SingleTouchInput, _Input);\n\n function SingleTouchInput() {\n classCallCheck(this, SingleTouchInput);\n\n var _this = possibleConstructorReturn(this, (SingleTouchInput.__proto__ || Object.getPrototypeOf(SingleTouchInput)).apply(this, arguments));\n\n _this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;\n _this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;\n _this.started = false;\n\n Input.apply(_this, arguments);\n return _this;\n }\n\n createClass(SingleTouchInput, [{\n key: 'handler',\n value: function handler(ev) {\n var type = SINGLE_TOUCH_INPUT_MAP[ev.type];\n\n // should we handle the touch events?\n if (type === INPUT_START) {\n this.started = true;\n }\n\n if (!this.started) {\n return;\n }\n\n var touches = normalizeSingleTouches.call(this, ev, type);\n\n // when done, reset the started state\n if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {\n this.started = false;\n }\n\n this.callback(this.manager, type, {\n pointers: touches[0],\n changedPointers: touches[1],\n pointerType: INPUT_TYPE_TOUCH,\n srcEvent: ev\n });\n }\n }]);\n return SingleTouchInput;\n}(Input);\n\nfunction normalizeSingleTouches(ev, type) {\n var all = toArray$1(ev.touches);\n var changed = toArray$1(ev.changedTouches);\n\n if (type & (INPUT_END | INPUT_CANCEL)) {\n all = uniqueArray(all.concat(changed), 'identifier', true);\n }\n\n return [all, changed];\n}\n\n/**\n * @private\n * wrap a method with a deprecation warning and stack trace\n * @param {Function} method\n * @param {String} name\n * @param {String} message\n * @returns {Function} A new function wrapping the supplied method.\n */\nfunction deprecate(method, name, message) {\n var deprecationMessage = 'DEPRECATED METHOD: ' + name + '\\n' + message + ' AT \\n';\n return function () {\n var e = new Error('get-stack-trace');\n var stack = e && e.stack ? e.stack.replace(/^[^\\(]+?[\\n$]/gm, '').replace(/^\\s+at\\s+/gm, '').replace(/^Object.\\s*\\(/gm, '{anonymous}()@') : 'Unknown Stack Trace';\n\n var log = window.console && (window.console.warn || window.console.log);\n if (log) {\n log.call(window.console, deprecationMessage, stack);\n }\n return method.apply(this, arguments);\n };\n}\n\n/**\n * @private\n * extend object.\n * means that properties in dest will be overwritten by the ones in src.\n * @param {Object} dest\n * @param {Object} src\n * @param {Boolean} [merge=false]\n * @returns {Object} dest\n */\nvar extend = deprecate(function (dest, src, merge) {\n var keys = Object.keys(src);\n var i = 0;\n while (i < keys.length) {\n if (!merge || merge && dest[keys[i]] === undefined) {\n dest[keys[i]] = src[keys[i]];\n }\n i++;\n }\n return dest;\n}, 'extend', 'Use `assign`.');\n\n/**\n * @private\n * merge the values from src in the dest.\n * means that properties that exist in dest will not be overwritten by src\n * @param {Object} dest\n * @param {Object} src\n * @returns {Object} dest\n */\nvar merge = deprecate(function (dest, src) {\n return extend(dest, src, true);\n}, 'merge', 'Use `assign`.');\n\n/**\n * @private\n * simple class inheritance\n * @param {Function} child\n * @param {Function} base\n * @param {Object} [properties]\n */\nfunction inherit(child, base, properties) {\n var baseP = base.prototype;\n var childP = void 0;\n\n childP = child.prototype = Object.create(baseP);\n childP.constructor = child;\n childP._super = baseP;\n\n if (properties) {\n assign$1(childP, properties);\n }\n}\n\n// this prevents errors when Hammer is loaded in the presence of an AMD\n// style loader but by script tag, not by the loader.\n\nassign$1(Hammer, {\n INPUT_START: INPUT_START,\n INPUT_MOVE: INPUT_MOVE,\n INPUT_END: INPUT_END,\n INPUT_CANCEL: INPUT_CANCEL,\n\n STATE_POSSIBLE: STATE_POSSIBLE,\n STATE_BEGAN: STATE_BEGAN,\n STATE_CHANGED: STATE_CHANGED,\n STATE_ENDED: STATE_ENDED,\n STATE_RECOGNIZED: STATE_RECOGNIZED,\n STATE_CANCELLED: STATE_CANCELLED,\n STATE_FAILED: STATE_FAILED,\n\n DIRECTION_NONE: DIRECTION_NONE,\n DIRECTION_LEFT: DIRECTION_LEFT,\n DIRECTION_RIGHT: DIRECTION_RIGHT,\n DIRECTION_UP: DIRECTION_UP,\n DIRECTION_DOWN: DIRECTION_DOWN,\n DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL,\n DIRECTION_VERTICAL: DIRECTION_VERTICAL,\n DIRECTION_ALL: DIRECTION_ALL,\n\n Manager: Manager,\n Input: Input,\n TouchAction: TouchAction,\n\n TouchInput: TouchInput,\n MouseInput: MouseInput,\n PointerEventInput: PointerEventInput,\n TouchMouseInput: TouchMouseInput,\n SingleTouchInput: SingleTouchInput,\n\n Recognizer: Recognizer,\n AttrRecognizer: AttrRecognizer,\n Tap: TapRecognizer,\n Pan: PanRecognizer,\n Swipe: SwipeRecognizer,\n Pinch: PinchRecognizer,\n Rotate: RotateRecognizer,\n Press: PressRecognizer,\n\n on: addEventListeners,\n off: removeEventListeners,\n each: each,\n merge: merge,\n extend: extend,\n assign: assign$1,\n inherit: inherit,\n bindFn: bindFn,\n prefixed: prefixed,\n toArray: toArray$1,\n inArray: inArray,\n uniqueArray: uniqueArray,\n splitStr: splitStr,\n boolOrFn: boolOrFn,\n hasParent: hasParent,\n addEventListeners: addEventListeners,\n removeEventListeners: removeEventListeners\n});\n\n/* jshint ignore:start */\nif (true) {\n !(__WEBPACK_AMD_DEFINE_RESULT__ = (function () {\n return Hammer;\n }).call(exports, __webpack_require__, exports, module),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n} else {}\n/* jshint ignore:end */\n})(window, document, 'Hammer');\n\n\n//# sourceURL=webpack:///./node_modules/hammerjs/hammer.js?"); - player.setMapPosition(0, 0); - player.setMapPositionTarget(0, -10); - dContext.followSprite(player); +/***/ }), - var intervalNum = 0; +/***/ "./node_modules/underscore/underscore.js": +/*!***********************************************!*\ + !*** ./node_modules/underscore/underscore.js ***! + \***********************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { - this.cycle = function () { - beforeCycleCallbacks.each(function(c) { - c(); - }); +eval("var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// Underscore.js 1.6.0\n// http://underscorejs.org\n// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n// Underscore may be freely distributed under the MIT license.\n\n(function() {\n\n // Baseline setup\n // --------------\n\n // Establish the root object, `window` in the browser, or `exports` on the server.\n var root = this;\n\n // Save the previous value of the `_` variable.\n var previousUnderscore = root._;\n\n // Establish the object that gets returned to break out of a loop iteration.\n var breaker = {};\n\n // Save bytes in the minified (but not gzipped) version:\n var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;\n\n // Create quick reference variables for speed access to core prototypes.\n var\n push = ArrayProto.push,\n slice = ArrayProto.slice,\n concat = ArrayProto.concat,\n toString = ObjProto.toString,\n hasOwnProperty = ObjProto.hasOwnProperty;\n\n // All **ECMAScript 5** native function implementations that we hope to use\n // are declared here.\n var\n nativeForEach = ArrayProto.forEach,\n nativeMap = ArrayProto.map,\n nativeReduce = ArrayProto.reduce,\n nativeReduceRight = ArrayProto.reduceRight,\n nativeFilter = ArrayProto.filter,\n nativeEvery = ArrayProto.every,\n nativeSome = ArrayProto.some,\n nativeIndexOf = ArrayProto.indexOf,\n nativeLastIndexOf = ArrayProto.lastIndexOf,\n nativeIsArray = Array.isArray,\n nativeKeys = Object.keys,\n nativeBind = FuncProto.bind;\n\n // Create a safe reference to the Underscore object for use below.\n var _ = function(obj) {\n if (obj instanceof _) return obj;\n if (!(this instanceof _)) return new _(obj);\n this._wrapped = obj;\n };\n\n // Export the Underscore object for **Node.js**, with\n // backwards-compatibility for the old `require()` API. If we're in\n // the browser, add `_` as a global object via a string identifier,\n // for Closure Compiler \"advanced\" mode.\n if (true) {\n if ( true && module.exports) {\n exports = module.exports = _;\n }\n exports._ = _;\n } else {}\n\n // Current version.\n _.VERSION = '1.6.0';\n\n // Collection Functions\n // --------------------\n\n // The cornerstone, an `each` implementation, aka `forEach`.\n // Handles objects with the built-in `forEach`, arrays, and raw objects.\n // Delegates to **ECMAScript 5**'s native `forEach` if available.\n var each = _.each = _.forEach = function(obj, iterator, context) {\n if (obj == null) return obj;\n if (nativeForEach && obj.forEach === nativeForEach) {\n obj.forEach(iterator, context);\n } else if (obj.length === +obj.length) {\n for (var i = 0, length = obj.length; i < length; i++) {\n if (iterator.call(context, obj[i], i, obj) === breaker) return;\n }\n } else {\n var keys = _.keys(obj);\n for (var i = 0, length = keys.length; i < length; i++) {\n if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;\n }\n }\n return obj;\n };\n\n // Return the results of applying the iterator to each element.\n // Delegates to **ECMAScript 5**'s native `map` if available.\n _.map = _.collect = function(obj, iterator, context) {\n var results = [];\n if (obj == null) return results;\n if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);\n each(obj, function(value, index, list) {\n results.push(iterator.call(context, value, index, list));\n });\n return results;\n };\n\n var reduceError = 'Reduce of empty array with no initial value';\n\n // **Reduce** builds up a single result from a list of values, aka `inject`,\n // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.\n _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {\n var initial = arguments.length > 2;\n if (obj == null) obj = [];\n if (nativeReduce && obj.reduce === nativeReduce) {\n if (context) iterator = _.bind(iterator, context);\n return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);\n }\n each(obj, function(value, index, list) {\n if (!initial) {\n memo = value;\n initial = true;\n } else {\n memo = iterator.call(context, memo, value, index, list);\n }\n });\n if (!initial) throw new TypeError(reduceError);\n return memo;\n };\n\n // The right-associative version of reduce, also known as `foldr`.\n // Delegates to **ECMAScript 5**'s native `reduceRight` if available.\n _.reduceRight = _.foldr = function(obj, iterator, memo, context) {\n var initial = arguments.length > 2;\n if (obj == null) obj = [];\n if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {\n if (context) iterator = _.bind(iterator, context);\n return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);\n }\n var length = obj.length;\n if (length !== +length) {\n var keys = _.keys(obj);\n length = keys.length;\n }\n each(obj, function(value, index, list) {\n index = keys ? keys[--length] : --length;\n if (!initial) {\n memo = obj[index];\n initial = true;\n } else {\n memo = iterator.call(context, memo, obj[index], index, list);\n }\n });\n if (!initial) throw new TypeError(reduceError);\n return memo;\n };\n\n // Return the first value which passes a truth test. Aliased as `detect`.\n _.find = _.detect = function(obj, predicate, context) {\n var result;\n any(obj, function(value, index, list) {\n if (predicate.call(context, value, index, list)) {\n result = value;\n return true;\n }\n });\n return result;\n };\n\n // Return all the elements that pass a truth test.\n // Delegates to **ECMAScript 5**'s native `filter` if available.\n // Aliased as `select`.\n _.filter = _.select = function(obj, predicate, context) {\n var results = [];\n if (obj == null) return results;\n if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context);\n each(obj, function(value, index, list) {\n if (predicate.call(context, value, index, list)) results.push(value);\n });\n return results;\n };\n\n // Return all the elements for which a truth test fails.\n _.reject = function(obj, predicate, context) {\n return _.filter(obj, function(value, index, list) {\n return !predicate.call(context, value, index, list);\n }, context);\n };\n\n // Determine whether all of the elements match a truth test.\n // Delegates to **ECMAScript 5**'s native `every` if available.\n // Aliased as `all`.\n _.every = _.all = function(obj, predicate, context) {\n predicate || (predicate = _.identity);\n var result = true;\n if (obj == null) return result;\n if (nativeEvery && obj.every === nativeEvery) return obj.every(predicate, context);\n each(obj, function(value, index, list) {\n if (!(result = result && predicate.call(context, value, index, list))) return breaker;\n });\n return !!result;\n };\n\n // Determine if at least one element in the object matches a truth test.\n // Delegates to **ECMAScript 5**'s native `some` if available.\n // Aliased as `any`.\n var any = _.some = _.any = function(obj, predicate, context) {\n predicate || (predicate = _.identity);\n var result = false;\n if (obj == null) return result;\n if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context);\n each(obj, function(value, index, list) {\n if (result || (result = predicate.call(context, value, index, list))) return breaker;\n });\n return !!result;\n };\n\n // Determine if the array or object contains a given value (using `===`).\n // Aliased as `include`.\n _.contains = _.include = function(obj, target) {\n if (obj == null) return false;\n if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;\n return any(obj, function(value) {\n return value === target;\n });\n };\n\n // Invoke a method (with arguments) on every item in a collection.\n _.invoke = function(obj, method) {\n var args = slice.call(arguments, 2);\n var isFunc = _.isFunction(method);\n return _.map(obj, function(value) {\n return (isFunc ? method : value[method]).apply(value, args);\n });\n };\n\n // Convenience version of a common use case of `map`: fetching a property.\n _.pluck = function(obj, key) {\n return _.map(obj, _.property(key));\n };\n\n // Convenience version of a common use case of `filter`: selecting only objects\n // containing specific `key:value` pairs.\n _.where = function(obj, attrs) {\n return _.filter(obj, _.matches(attrs));\n };\n\n // Convenience version of a common use case of `find`: getting the first object\n // containing specific `key:value` pairs.\n _.findWhere = function(obj, attrs) {\n return _.find(obj, _.matches(attrs));\n };\n\n // Return the maximum element or (element-based computation).\n // Can't optimize arrays of integers longer than 65,535 elements.\n // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)\n _.max = function(obj, iterator, context) {\n if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {\n return Math.max.apply(Math, obj);\n }\n var result = -Infinity, lastComputed = -Infinity;\n each(obj, function(value, index, list) {\n var computed = iterator ? iterator.call(context, value, index, list) : value;\n if (computed > lastComputed) {\n result = value;\n lastComputed = computed;\n }\n });\n return result;\n };\n\n // Return the minimum element (or element-based computation).\n _.min = function(obj, iterator, context) {\n if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {\n return Math.min.apply(Math, obj);\n }\n var result = Infinity, lastComputed = Infinity;\n each(obj, function(value, index, list) {\n var computed = iterator ? iterator.call(context, value, index, list) : value;\n if (computed < lastComputed) {\n result = value;\n lastComputed = computed;\n }\n });\n return result;\n };\n\n // Shuffle an array, using the modern version of the\n // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).\n _.shuffle = function(obj) {\n var rand;\n var index = 0;\n var shuffled = [];\n each(obj, function(value) {\n rand = _.random(index++);\n shuffled[index - 1] = shuffled[rand];\n shuffled[rand] = value;\n });\n return shuffled;\n };\n\n // Sample **n** random values from a collection.\n // If **n** is not specified, returns a single random element.\n // The internal `guard` argument allows it to work with `map`.\n _.sample = function(obj, n, guard) {\n if (n == null || guard) {\n if (obj.length !== +obj.length) obj = _.values(obj);\n return obj[_.random(obj.length - 1)];\n }\n return _.shuffle(obj).slice(0, Math.max(0, n));\n };\n\n // An internal function to generate lookup iterators.\n var lookupIterator = function(value) {\n if (value == null) return _.identity;\n if (_.isFunction(value)) return value;\n return _.property(value);\n };\n\n // Sort the object's values by a criterion produced by an iterator.\n _.sortBy = function(obj, iterator, context) {\n iterator = lookupIterator(iterator);\n return _.pluck(_.map(obj, function(value, index, list) {\n return {\n value: value,\n index: index,\n criteria: iterator.call(context, value, index, list)\n };\n }).sort(function(left, right) {\n var a = left.criteria;\n var b = right.criteria;\n if (a !== b) {\n if (a > b || a === void 0) return 1;\n if (a < b || b === void 0) return -1;\n }\n return left.index - right.index;\n }), 'value');\n };\n\n // An internal function used for aggregate \"group by\" operations.\n var group = function(behavior) {\n return function(obj, iterator, context) {\n var result = {};\n iterator = lookupIterator(iterator);\n each(obj, function(value, index) {\n var key = iterator.call(context, value, index, obj);\n behavior(result, key, value);\n });\n return result;\n };\n };\n\n // Groups the object's values by a criterion. Pass either a string attribute\n // to group by, or a function that returns the criterion.\n _.groupBy = group(function(result, key, value) {\n _.has(result, key) ? result[key].push(value) : result[key] = [value];\n });\n\n // Indexes the object's values by a criterion, similar to `groupBy`, but for\n // when you know that your index values will be unique.\n _.indexBy = group(function(result, key, value) {\n result[key] = value;\n });\n\n // Counts instances of an object that group by a certain criterion. Pass\n // either a string attribute to count by, or a function that returns the\n // criterion.\n _.countBy = group(function(result, key) {\n _.has(result, key) ? result[key]++ : result[key] = 1;\n });\n\n // Use a comparator function to figure out the smallest index at which\n // an object should be inserted so as to maintain order. Uses binary search.\n _.sortedIndex = function(array, obj, iterator, context) {\n iterator = lookupIterator(iterator);\n var value = iterator.call(context, obj);\n var low = 0, high = array.length;\n while (low < high) {\n var mid = (low + high) >>> 1;\n iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;\n }\n return low;\n };\n\n // Safely create a real, live array from anything iterable.\n _.toArray = function(obj) {\n if (!obj) return [];\n if (_.isArray(obj)) return slice.call(obj);\n if (obj.length === +obj.length) return _.map(obj, _.identity);\n return _.values(obj);\n };\n\n // Return the number of elements in an object.\n _.size = function(obj) {\n if (obj == null) return 0;\n return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;\n };\n\n // Array Functions\n // ---------------\n\n // Get the first element of an array. Passing **n** will return the first N\n // values in the array. Aliased as `head` and `take`. The **guard** check\n // allows it to work with `_.map`.\n _.first = _.head = _.take = function(array, n, guard) {\n if (array == null) return void 0;\n if ((n == null) || guard) return array[0];\n if (n < 0) return [];\n return slice.call(array, 0, n);\n };\n\n // Returns everything but the last entry of the array. Especially useful on\n // the arguments object. Passing **n** will return all the values in\n // the array, excluding the last N. The **guard** check allows it to work with\n // `_.map`.\n _.initial = function(array, n, guard) {\n return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));\n };\n\n // Get the last element of an array. Passing **n** will return the last N\n // values in the array. The **guard** check allows it to work with `_.map`.\n _.last = function(array, n, guard) {\n if (array == null) return void 0;\n if ((n == null) || guard) return array[array.length - 1];\n return slice.call(array, Math.max(array.length - n, 0));\n };\n\n // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.\n // Especially useful on the arguments object. Passing an **n** will return\n // the rest N values in the array. The **guard**\n // check allows it to work with `_.map`.\n _.rest = _.tail = _.drop = function(array, n, guard) {\n return slice.call(array, (n == null) || guard ? 1 : n);\n };\n\n // Trim out all falsy values from an array.\n _.compact = function(array) {\n return _.filter(array, _.identity);\n };\n\n // Internal implementation of a recursive `flatten` function.\n var flatten = function(input, shallow, output) {\n if (shallow && _.every(input, _.isArray)) {\n return concat.apply(output, input);\n }\n each(input, function(value) {\n if (_.isArray(value) || _.isArguments(value)) {\n shallow ? push.apply(output, value) : flatten(value, shallow, output);\n } else {\n output.push(value);\n }\n });\n return output;\n };\n\n // Flatten out an array, either recursively (by default), or just one level.\n _.flatten = function(array, shallow) {\n return flatten(array, shallow, []);\n };\n\n // Return a version of the array that does not contain the specified value(s).\n _.without = function(array) {\n return _.difference(array, slice.call(arguments, 1));\n };\n\n // Split an array into two arrays: one whose elements all satisfy the given\n // predicate, and one whose elements all do not satisfy the predicate.\n _.partition = function(array, predicate) {\n var pass = [], fail = [];\n each(array, function(elem) {\n (predicate(elem) ? pass : fail).push(elem);\n });\n return [pass, fail];\n };\n\n // Produce a duplicate-free version of the array. If the array has already\n // been sorted, you have the option of using a faster algorithm.\n // Aliased as `unique`.\n _.uniq = _.unique = function(array, isSorted, iterator, context) {\n if (_.isFunction(isSorted)) {\n context = iterator;\n iterator = isSorted;\n isSorted = false;\n }\n var initial = iterator ? _.map(array, iterator, context) : array;\n var results = [];\n var seen = [];\n each(initial, function(value, index) {\n if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {\n seen.push(value);\n results.push(array[index]);\n }\n });\n return results;\n };\n\n // Produce an array that contains the union: each distinct element from all of\n // the passed-in arrays.\n _.union = function() {\n return _.uniq(_.flatten(arguments, true));\n };\n\n // Produce an array that contains every item shared between all the\n // passed-in arrays.\n _.intersection = function(array) {\n var rest = slice.call(arguments, 1);\n return _.filter(_.uniq(array), function(item) {\n return _.every(rest, function(other) {\n return _.contains(other, item);\n });\n });\n };\n\n // Take the difference between one array and a number of other arrays.\n // Only the elements present in just the first array will remain.\n _.difference = function(array) {\n var rest = concat.apply(ArrayProto, slice.call(arguments, 1));\n return _.filter(array, function(value){ return !_.contains(rest, value); });\n };\n\n // Zip together multiple lists into a single array -- elements that share\n // an index go together.\n _.zip = function() {\n var length = _.max(_.pluck(arguments, 'length').concat(0));\n var results = new Array(length);\n for (var i = 0; i < length; i++) {\n results[i] = _.pluck(arguments, '' + i);\n }\n return results;\n };\n\n // Converts lists into objects. Pass either a single array of `[key, value]`\n // pairs, or two parallel arrays of the same length -- one of keys, and one of\n // the corresponding values.\n _.object = function(list, values) {\n if (list == null) return {};\n var result = {};\n for (var i = 0, length = list.length; i < length; i++) {\n if (values) {\n result[list[i]] = values[i];\n } else {\n result[list[i][0]] = list[i][1];\n }\n }\n return result;\n };\n\n // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),\n // we need this function. Return the position of the first occurrence of an\n // item in an array, or -1 if the item is not included in the array.\n // Delegates to **ECMAScript 5**'s native `indexOf` if available.\n // If the array is large and already in sort order, pass `true`\n // for **isSorted** to use binary search.\n _.indexOf = function(array, item, isSorted) {\n if (array == null) return -1;\n var i = 0, length = array.length;\n if (isSorted) {\n if (typeof isSorted == 'number') {\n i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);\n } else {\n i = _.sortedIndex(array, item);\n return array[i] === item ? i : -1;\n }\n }\n if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);\n for (; i < length; i++) if (array[i] === item) return i;\n return -1;\n };\n\n // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.\n _.lastIndexOf = function(array, item, from) {\n if (array == null) return -1;\n var hasIndex = from != null;\n if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {\n return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);\n }\n var i = (hasIndex ? from : array.length);\n while (i--) if (array[i] === item) return i;\n return -1;\n };\n\n // Generate an integer Array containing an arithmetic progression. A port of\n // the native Python `range()` function. See\n // [the Python documentation](http://docs.python.org/library/functions.html#range).\n _.range = function(start, stop, step) {\n if (arguments.length <= 1) {\n stop = start || 0;\n start = 0;\n }\n step = arguments[2] || 1;\n\n var length = Math.max(Math.ceil((stop - start) / step), 0);\n var idx = 0;\n var range = new Array(length);\n\n while(idx < length) {\n range[idx++] = start;\n start += step;\n }\n\n return range;\n };\n\n // Function (ahem) Functions\n // ------------------\n\n // Reusable constructor function for prototype setting.\n var ctor = function(){};\n\n // Create a function bound to a given object (assigning `this`, and arguments,\n // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if\n // available.\n _.bind = function(func, context) {\n var args, bound;\n if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));\n if (!_.isFunction(func)) throw new TypeError;\n args = slice.call(arguments, 2);\n return bound = function() {\n if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));\n ctor.prototype = func.prototype;\n var self = new ctor;\n ctor.prototype = null;\n var result = func.apply(self, args.concat(slice.call(arguments)));\n if (Object(result) === result) return result;\n return self;\n };\n };\n\n // Partially apply a function by creating a version that has had some of its\n // arguments pre-filled, without changing its dynamic `this` context. _ acts\n // as a placeholder, allowing any combination of arguments to be pre-filled.\n _.partial = function(func) {\n var boundArgs = slice.call(arguments, 1);\n return function() {\n var position = 0;\n var args = boundArgs.slice();\n for (var i = 0, length = args.length; i < length; i++) {\n if (args[i] === _) args[i] = arguments[position++];\n }\n while (position < arguments.length) args.push(arguments[position++]);\n return func.apply(this, args);\n };\n };\n\n // Bind a number of an object's methods to that object. Remaining arguments\n // are the method names to be bound. Useful for ensuring that all callbacks\n // defined on an object belong to it.\n _.bindAll = function(obj) {\n var funcs = slice.call(arguments, 1);\n if (funcs.length === 0) throw new Error('bindAll must be passed function names');\n each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });\n return obj;\n };\n\n // Memoize an expensive function by storing its results.\n _.memoize = function(func, hasher) {\n var memo = {};\n hasher || (hasher = _.identity);\n return function() {\n var key = hasher.apply(this, arguments);\n return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));\n };\n };\n\n // Delays a function for the given number of milliseconds, and then calls\n // it with the arguments supplied.\n _.delay = function(func, wait) {\n var args = slice.call(arguments, 2);\n return setTimeout(function(){ return func.apply(null, args); }, wait);\n };\n\n // Defers a function, scheduling it to run after the current call stack has\n // cleared.\n _.defer = function(func) {\n return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));\n };\n\n // Returns a function, that, when invoked, will only be triggered at most once\n // during a given window of time. Normally, the throttled function will run\n // as much as it can, without ever going more than once per `wait` duration;\n // but if you'd like to disable the execution on the leading edge, pass\n // `{leading: false}`. To disable execution on the trailing edge, ditto.\n _.throttle = function(func, wait, options) {\n var context, args, result;\n var timeout = null;\n var previous = 0;\n options || (options = {});\n var later = function() {\n previous = options.leading === false ? 0 : _.now();\n timeout = null;\n result = func.apply(context, args);\n context = args = null;\n };\n return function() {\n var now = _.now();\n if (!previous && options.leading === false) previous = now;\n var remaining = wait - (now - previous);\n context = this;\n args = arguments;\n if (remaining <= 0) {\n clearTimeout(timeout);\n timeout = null;\n previous = now;\n result = func.apply(context, args);\n context = args = null;\n } else if (!timeout && options.trailing !== false) {\n timeout = setTimeout(later, remaining);\n }\n return result;\n };\n };\n\n // Returns a function, that, as long as it continues to be invoked, will not\n // be triggered. The function will be called after it stops being called for\n // N milliseconds. If `immediate` is passed, trigger the function on the\n // leading edge, instead of the trailing.\n _.debounce = function(func, wait, immediate) {\n var timeout, args, context, timestamp, result;\n\n var later = function() {\n var last = _.now() - timestamp;\n if (last < wait) {\n timeout = setTimeout(later, wait - last);\n } else {\n timeout = null;\n if (!immediate) {\n result = func.apply(context, args);\n context = args = null;\n }\n }\n };\n\n return function() {\n context = this;\n args = arguments;\n timestamp = _.now();\n var callNow = immediate && !timeout;\n if (!timeout) {\n timeout = setTimeout(later, wait);\n }\n if (callNow) {\n result = func.apply(context, args);\n context = args = null;\n }\n\n return result;\n };\n };\n\n // Returns a function that will be executed at most one time, no matter how\n // often you call it. Useful for lazy initialization.\n _.once = function(func) {\n var ran = false, memo;\n return function() {\n if (ran) return memo;\n ran = true;\n memo = func.apply(this, arguments);\n func = null;\n return memo;\n };\n };\n\n // Returns the first function passed as an argument to the second,\n // allowing you to adjust arguments, run code before and after, and\n // conditionally execute the original function.\n _.wrap = function(func, wrapper) {\n return _.partial(wrapper, func);\n };\n\n // Returns a function that is the composition of a list of functions, each\n // consuming the return value of the function that follows.\n _.compose = function() {\n var funcs = arguments;\n return function() {\n var args = arguments;\n for (var i = funcs.length - 1; i >= 0; i--) {\n args = [funcs[i].apply(this, args)];\n }\n return args[0];\n };\n };\n\n // Returns a function that will only be executed after being called N times.\n _.after = function(times, func) {\n return function() {\n if (--times < 1) {\n return func.apply(this, arguments);\n }\n };\n };\n\n // Object Functions\n // ----------------\n\n // Retrieve the names of an object's properties.\n // Delegates to **ECMAScript 5**'s native `Object.keys`\n _.keys = function(obj) {\n if (!_.isObject(obj)) return [];\n if (nativeKeys) return nativeKeys(obj);\n var keys = [];\n for (var key in obj) if (_.has(obj, key)) keys.push(key);\n return keys;\n };\n\n // Retrieve the values of an object's properties.\n _.values = function(obj) {\n var keys = _.keys(obj);\n var length = keys.length;\n var values = new Array(length);\n for (var i = 0; i < length; i++) {\n values[i] = obj[keys[i]];\n }\n return values;\n };\n\n // Convert an object into a list of `[key, value]` pairs.\n _.pairs = function(obj) {\n var keys = _.keys(obj);\n var length = keys.length;\n var pairs = new Array(length);\n for (var i = 0; i < length; i++) {\n pairs[i] = [keys[i], obj[keys[i]]];\n }\n return pairs;\n };\n\n // Invert the keys and values of an object. The values must be serializable.\n _.invert = function(obj) {\n var result = {};\n var keys = _.keys(obj);\n for (var i = 0, length = keys.length; i < length; i++) {\n result[obj[keys[i]]] = keys[i];\n }\n return result;\n };\n\n // Return a sorted list of the function names available on the object.\n // Aliased as `methods`\n _.functions = _.methods = function(obj) {\n var names = [];\n for (var key in obj) {\n if (_.isFunction(obj[key])) names.push(key);\n }\n return names.sort();\n };\n\n // Extend a given object with all the properties in passed-in object(s).\n _.extend = function(obj) {\n each(slice.call(arguments, 1), function(source) {\n if (source) {\n for (var prop in source) {\n obj[prop] = source[prop];\n }\n }\n });\n return obj;\n };\n\n // Return a copy of the object only containing the whitelisted properties.\n _.pick = function(obj) {\n var copy = {};\n var keys = concat.apply(ArrayProto, slice.call(arguments, 1));\n each(keys, function(key) {\n if (key in obj) copy[key] = obj[key];\n });\n return copy;\n };\n\n // Return a copy of the object without the blacklisted properties.\n _.omit = function(obj) {\n var copy = {};\n var keys = concat.apply(ArrayProto, slice.call(arguments, 1));\n for (var key in obj) {\n if (!_.contains(keys, key)) copy[key] = obj[key];\n }\n return copy;\n };\n\n // Fill in a given object with default properties.\n _.defaults = function(obj) {\n each(slice.call(arguments, 1), function(source) {\n if (source) {\n for (var prop in source) {\n if (obj[prop] === void 0) obj[prop] = source[prop];\n }\n }\n });\n return obj;\n };\n\n // Create a (shallow-cloned) duplicate of an object.\n _.clone = function(obj) {\n if (!_.isObject(obj)) return obj;\n return _.isArray(obj) ? obj.slice() : _.extend({}, obj);\n };\n\n // Invokes interceptor with the obj, and then returns obj.\n // The primary purpose of this method is to \"tap into\" a method chain, in\n // order to perform operations on intermediate results within the chain.\n _.tap = function(obj, interceptor) {\n interceptor(obj);\n return obj;\n };\n\n // Internal recursive comparison function for `isEqual`.\n var eq = function(a, b, aStack, bStack) {\n // Identical objects are equal. `0 === -0`, but they aren't identical.\n // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).\n if (a === b) return a !== 0 || 1 / a == 1 / b;\n // A strict comparison is necessary because `null == undefined`.\n if (a == null || b == null) return a === b;\n // Unwrap any wrapped objects.\n if (a instanceof _) a = a._wrapped;\n if (b instanceof _) b = b._wrapped;\n // Compare `[[Class]]` names.\n var className = toString.call(a);\n if (className != toString.call(b)) return false;\n switch (className) {\n // Strings, numbers, dates, and booleans are compared by value.\n case '[object String]':\n // Primitives and their corresponding object wrappers are equivalent; thus, `\"5\"` is\n // equivalent to `new String(\"5\")`.\n return a == String(b);\n case '[object Number]':\n // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for\n // other numeric values.\n return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);\n case '[object Date]':\n case '[object Boolean]':\n // Coerce dates and booleans to numeric primitive values. Dates are compared by their\n // millisecond representations. Note that invalid dates with millisecond representations\n // of `NaN` are not equivalent.\n return +a == +b;\n // RegExps are compared by their source patterns and flags.\n case '[object RegExp]':\n return a.source == b.source &&\n a.global == b.global &&\n a.multiline == b.multiline &&\n a.ignoreCase == b.ignoreCase;\n }\n if (typeof a != 'object' || typeof b != 'object') return false;\n // Assume equality for cyclic structures. The algorithm for detecting cyclic\n // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.\n var length = aStack.length;\n while (length--) {\n // Linear search. Performance is inversely proportional to the number of\n // unique nested structures.\n if (aStack[length] == a) return bStack[length] == b;\n }\n // Objects with different constructors are not equivalent, but `Object`s\n // from different frames are.\n var aCtor = a.constructor, bCtor = b.constructor;\n if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&\n _.isFunction(bCtor) && (bCtor instanceof bCtor))\n && ('constructor' in a && 'constructor' in b)) {\n return false;\n }\n // Add the first object to the stack of traversed objects.\n aStack.push(a);\n bStack.push(b);\n var size = 0, result = true;\n // Recursively compare objects and arrays.\n if (className == '[object Array]') {\n // Compare array lengths to determine if a deep comparison is necessary.\n size = a.length;\n result = size == b.length;\n if (result) {\n // Deep compare the contents, ignoring non-numeric properties.\n while (size--) {\n if (!(result = eq(a[size], b[size], aStack, bStack))) break;\n }\n }\n } else {\n // Deep compare objects.\n for (var key in a) {\n if (_.has(a, key)) {\n // Count the expected number of properties.\n size++;\n // Deep compare each member.\n if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;\n }\n }\n // Ensure that both objects contain the same number of properties.\n if (result) {\n for (key in b) {\n if (_.has(b, key) && !(size--)) break;\n }\n result = !size;\n }\n }\n // Remove the first object from the stack of traversed objects.\n aStack.pop();\n bStack.pop();\n return result;\n };\n\n // Perform a deep comparison to check if two objects are equal.\n _.isEqual = function(a, b) {\n return eq(a, b, [], []);\n };\n\n // Is a given array, string, or object empty?\n // An \"empty\" object has no enumerable own-properties.\n _.isEmpty = function(obj) {\n if (obj == null) return true;\n if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;\n for (var key in obj) if (_.has(obj, key)) return false;\n return true;\n };\n\n // Is a given value a DOM element?\n _.isElement = function(obj) {\n return !!(obj && obj.nodeType === 1);\n };\n\n // Is a given value an array?\n // Delegates to ECMA5's native Array.isArray\n _.isArray = nativeIsArray || function(obj) {\n return toString.call(obj) == '[object Array]';\n };\n\n // Is a given variable an object?\n _.isObject = function(obj) {\n return obj === Object(obj);\n };\n\n // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.\n each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {\n _['is' + name] = function(obj) {\n return toString.call(obj) == '[object ' + name + ']';\n };\n });\n\n // Define a fallback version of the method in browsers (ahem, IE), where\n // there isn't any inspectable \"Arguments\" type.\n if (!_.isArguments(arguments)) {\n _.isArguments = function(obj) {\n return !!(obj && _.has(obj, 'callee'));\n };\n }\n\n // Optimize `isFunction` if appropriate.\n if (true) {\n _.isFunction = function(obj) {\n return typeof obj === 'function';\n };\n }\n\n // Is a given object a finite number?\n _.isFinite = function(obj) {\n return isFinite(obj) && !isNaN(parseFloat(obj));\n };\n\n // Is the given value `NaN`? (NaN is the only number which does not equal itself).\n _.isNaN = function(obj) {\n return _.isNumber(obj) && obj != +obj;\n };\n\n // Is a given value a boolean?\n _.isBoolean = function(obj) {\n return obj === true || obj === false || toString.call(obj) == '[object Boolean]';\n };\n\n // Is a given value equal to null?\n _.isNull = function(obj) {\n return obj === null;\n };\n\n // Is a given variable undefined?\n _.isUndefined = function(obj) {\n return obj === void 0;\n };\n\n // Shortcut function for checking if an object has a given property directly\n // on itself (in other words, not on a prototype).\n _.has = function(obj, key) {\n return hasOwnProperty.call(obj, key);\n };\n\n // Utility Functions\n // -----------------\n\n // Run Underscore.js in *noConflict* mode, returning the `_` variable to its\n // previous owner. Returns a reference to the Underscore object.\n _.noConflict = function() {\n root._ = previousUnderscore;\n return this;\n };\n\n // Keep the identity function around for default iterators.\n _.identity = function(value) {\n return value;\n };\n\n _.constant = function(value) {\n return function () {\n return value;\n };\n };\n\n _.property = function(key) {\n return function(obj) {\n return obj[key];\n };\n };\n\n // Returns a predicate for checking whether an object has a given set of `key:value` pairs.\n _.matches = function(attrs) {\n return function(obj) {\n if (obj === attrs) return true; //avoid comparing an object to itself.\n for (var key in attrs) {\n if (attrs[key] !== obj[key])\n return false;\n }\n return true;\n }\n };\n\n // Run a function **n** times.\n _.times = function(n, iterator, context) {\n var accum = Array(Math.max(0, n));\n for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);\n return accum;\n };\n\n // Return a random integer between min and max (inclusive).\n _.random = function(min, max) {\n if (max == null) {\n max = min;\n min = 0;\n }\n return min + Math.floor(Math.random() * (max - min + 1));\n };\n\n // A (possibly faster) way to get the current timestamp as an integer.\n _.now = Date.now || function() { return new Date().getTime(); };\n\n // List of HTML entities for escaping.\n var entityMap = {\n escape: {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''\n }\n };\n entityMap.unescape = _.invert(entityMap.escape);\n\n // Regexes containing the keys and values listed immediately above.\n var entityRegexes = {\n escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),\n unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')\n };\n\n // Functions for escaping and unescaping strings to/from HTML interpolation.\n _.each(['escape', 'unescape'], function(method) {\n _[method] = function(string) {\n if (string == null) return '';\n return ('' + string).replace(entityRegexes[method], function(match) {\n return entityMap[method][match];\n });\n };\n });\n\n // If the value of the named `property` is a function then invoke it with the\n // `object` as context; otherwise, return it.\n _.result = function(object, property) {\n if (object == null) return void 0;\n var value = object[property];\n return _.isFunction(value) ? value.call(object) : value;\n };\n\n // Add your own custom functions to the Underscore object.\n _.mixin = function(obj) {\n each(_.functions(obj), function(name) {\n var func = _[name] = obj[name];\n _.prototype[name] = function() {\n var args = [this._wrapped];\n push.apply(args, arguments);\n return result.call(this, func.apply(_, args));\n };\n });\n };\n\n // Generate a unique integer id (unique within the entire client session).\n // Useful for temporary DOM ids.\n var idCounter = 0;\n _.uniqueId = function(prefix) {\n var id = ++idCounter + '';\n return prefix ? prefix + id : id;\n };\n\n // By default, Underscore uses ERB-style template delimiters, change the\n // following template settings to use alternative delimiters.\n _.templateSettings = {\n evaluate : /<%([\\s\\S]+?)%>/g,\n interpolate : /<%=([\\s\\S]+?)%>/g,\n escape : /<%-([\\s\\S]+?)%>/g\n };\n\n // When customizing `templateSettings`, if you don't want to define an\n // interpolation, evaluation or escaping regex, we need one that is\n // guaranteed not to match.\n var noMatch = /(.)^/;\n\n // Certain characters need to be escaped so that they can be put into a\n // string literal.\n var escapes = {\n \"'\": \"'\",\n '\\\\': '\\\\',\n '\\r': 'r',\n '\\n': 'n',\n '\\t': 't',\n '\\u2028': 'u2028',\n '\\u2029': 'u2029'\n };\n\n var escaper = /\\\\|'|\\r|\\n|\\t|\\u2028|\\u2029/g;\n\n // JavaScript micro-templating, similar to John Resig's implementation.\n // Underscore templating handles arbitrary delimiters, preserves whitespace,\n // and correctly escapes quotes within interpolated code.\n _.template = function(text, data, settings) {\n var render;\n settings = _.defaults({}, settings, _.templateSettings);\n\n // Combine delimiters into one regular expression via alternation.\n var matcher = new RegExp([\n (settings.escape || noMatch).source,\n (settings.interpolate || noMatch).source,\n (settings.evaluate || noMatch).source\n ].join('|') + '|$', 'g');\n\n // Compile the template source, escaping string literals appropriately.\n var index = 0;\n var source = \"__p+='\";\n text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {\n source += text.slice(index, offset)\n .replace(escaper, function(match) { return '\\\\' + escapes[match]; });\n\n if (escape) {\n source += \"'+\\n((__t=(\" + escape + \"))==null?'':_.escape(__t))+\\n'\";\n }\n if (interpolate) {\n source += \"'+\\n((__t=(\" + interpolate + \"))==null?'':__t)+\\n'\";\n }\n if (evaluate) {\n source += \"';\\n\" + evaluate + \"\\n__p+='\";\n }\n index = offset + match.length;\n return match;\n });\n source += \"';\\n\";\n\n // If a variable is not specified, place data values in local scope.\n if (!settings.variable) source = 'with(obj||{}){\\n' + source + '}\\n';\n\n source = \"var __t,__p='',__j=Array.prototype.join,\" +\n \"print=function(){__p+=__j.call(arguments,'');};\\n\" +\n source + \"return __p;\\n\";\n\n try {\n render = new Function(settings.variable || 'obj', '_', source);\n } catch (e) {\n e.source = source;\n throw e;\n }\n\n if (data) return render(data, _);\n var template = function(data) {\n return render.call(this, data, _);\n };\n\n // Provide the compiled function source as a convenience for precompilation.\n template.source = 'function(' + (settings.variable || 'obj') + '){\\n' + source + '}';\n\n return template;\n };\n\n // Add a \"chain\" function, which will delegate to the wrapper.\n _.chain = function(obj) {\n return _(obj).chain();\n };\n\n // OOP\n // ---------------\n // If Underscore is called as a function, it returns a wrapped object that\n // can be used OO-style. This wrapper holds altered versions of all the\n // underscore functions. Wrapped objects may be chained.\n\n // Helper function to continue chaining intermediate results.\n var result = function(obj) {\n return this._chain ? _(obj).chain() : obj;\n };\n\n // Add all of the Underscore functions to the wrapper object.\n _.mixin(_);\n\n // Add all mutator Array functions to the wrapper.\n each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {\n var method = ArrayProto[name];\n _.prototype[name] = function() {\n var obj = this._wrapped;\n method.apply(obj, arguments);\n if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];\n return result.call(this, obj);\n };\n });\n\n // Add all accessor Array functions to the wrapper.\n each(['concat', 'join', 'slice'], function(name) {\n var method = ArrayProto[name];\n _.prototype[name] = function() {\n return result.call(this, method.apply(this._wrapped, arguments));\n };\n });\n\n _.extend(_.prototype, {\n\n // Start chaining a wrapped Underscore object.\n chain: function() {\n this._chain = true;\n return this;\n },\n\n // Extracts the result from a wrapped and chained object.\n value: function() {\n return this._wrapped;\n }\n\n });\n\n // AMD registration happens at the end for compatibility with AMD loaders\n // that may not enforce next-turn semantics on modules. Even though general\n // practice for AMD registration is to be anonymous, underscore registers\n // as a named module because, like jQuery, it is a base library that is\n // popular enough to be bundled in a third party lib, but not be part of\n // an AMD load request. Those cases could generate an error when an\n // anonymous define() is called outside of a loader request.\n if (true) {\n !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = (function() {\n return _;\n }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n }\n}).call(this);\n\n\n//# sourceURL=webpack:///./node_modules/underscore/underscore.js?"); - // Clear canvas - var mouseMapPosition = dContext.canvasPositionToMapPosition([mouseX, mouseY]); +/***/ }), - if (!player.isJumping) { - player.setMapPositionTarget(mouseMapPosition[0], mouseMapPosition[1]); - } +/***/ "./node_modules/webpack/buildin/global.js": +/*!***********************************!*\ + !*** (webpack)/buildin/global.js ***! + \***********************************/ +/*! no static exports found */ +/***/ (function(module, exports) { - intervalNum++; +eval("var g;\n\n// This works in non-strict mode\ng = (function() {\n\treturn this;\n})();\n\ntry {\n\t// This works if eval is allowed (see CSP)\n\tg = g || new Function(\"return this\")();\n} catch (e) {\n\t// This works if the window reference is available\n\tif (typeof window === \"object\") g = window;\n}\n\n// g can still be undefined, but nothing to do about it...\n// We return undefined, instead of nothing here, so it's\n// easier to handle this case. if(!global) { ...}\n\nmodule.exports = g;\n\n\n//# sourceURL=webpack:///(webpack)/buildin/global.js?"); - player.cycle(); +/***/ }) - movingObjects.each(function (movingObject, i) { - movingObject.cycle(dContext); - }); - - staticObjects.cull(); - staticObjects.each(function (staticObject, i) { - if (staticObject.cycle) { - staticObject.cycle(); - } - }); - - uiElements.each(function (uiElement, i) { - if (uiElement.cycle) { - uiElement.cycle(); - } - }); - - afterCycleCallbacks.each(function(c) { - c(); - }); - }; - - that.draw = function () { - // Clear canvas - mainCanvas.width = mainCanvas.width; - - player.draw(dContext); - - player.cycle(); - - movingObjects.each(function (movingObject, i) { - movingObject.draw(dContext); - }); - - staticObjects.each(function (staticObject, i) { - if (staticObject.draw) { - staticObject.draw(dContext, 'main'); - } - }); - - uiElements.each(function (uiElement, i) { - if (uiElement.draw) { - uiElement.draw(dContext, 'main'); - } - }); - }; - - this.start = function () { - gameLoop.start(); - }; - - this.pause = function () { - paused = true; - gameLoop.stop(); - }; - - this.isPaused = function () { - return paused; - }; - - this.reset = function () { - paused = false; - staticObjects = new SpriteArray(); - movingObjects = new SpriteArray(); - mouseX = dContext.getCentreOfViewport(); - mouseY = 0; - player.reset(); - player.setMapPosition(0, 0, 0); - this.start(); - }.bind(this); - - gameLoop.on('20', this.cycle); - gameLoop.on('20', this.draw); - } - - global.game = Game; -})( this ); - - -if (typeof module !== 'undefined') { - module.exports = this.game; -} -},{"./spriteArray":12,"eventedloop":16}],4:[function(require,module,exports){ -// Creates a random ID string -(function(global) { - function guid () - { - var S4 = function () - { - return Math.floor( - Math.random() * 0x10000 /* 65536 */ - ).toString(16); - }; - - return ( - S4() + S4() + "-" + - S4() + "-" + - S4() + "-" + - S4() + "-" + - S4() + S4() + S4() - ); - } - global.guid = guid; -})(this); - -if (typeof module !== 'undefined') { - module.exports = this.guid; -} -},{}],5:[function(require,module,exports){ -function InfoBox(data) { - var that = this; - - that.lines = data.initialLines; - - that.top = data.position.top; - that.right = data.position.right; - that.bottom = data.position.bottom; - that.left = data.position.left; - - that.width = data.width; - that.height = data.height; - - that.setLines = function (lines) { - that.lines = lines; - }; - - that.draw = function (dContext) { - dContext.font = '11px monospace'; - var yOffset = 0; - that.lines.each(function (line) { - var fontSize = +dContext.font.slice(0,2); - var textWidth = dContext.measureText(line).width; - var textHeight = fontSize * 1.5; - var xPos, yPos; - if (that.top) { - yPos = that.top + yOffset; - } else if (that.bottom) { - yPos = dContext.canvas.height - that.top - textHeight + yOffset; - } - - if (that.right) { - xPos = dContext.canvas.width - that.right - textWidth; - } else if (that.left) { - xPos = that.left; - } - - yOffset += textHeight; - - - dContext.fillText(line, xPos, yPos); - }); - }; - - return that; -} - -if (typeof module !== 'undefined') { - module.exports = InfoBox; -} - -},{}],6:[function(require,module,exports){ -function isMobileDevice() { - if(navigator.userAgent.match(/Android/i) || - navigator.userAgent.match(/webOS/i) || - navigator.userAgent.match(/iPhone/i) || - navigator.userAgent.match(/iPad/i) || - navigator.userAgent.match(/iPod/i) || - navigator.userAgent.match(/BlackBerry/i) || - navigator.userAgent.match(/Windows Phone/i) - ) { - return true; - } - else { - return false; - } -} - -module.exports = isMobileDevice; -},{}],7:[function(require,module,exports){ -var Sprite = require('./sprite'); - -(function(global) { - function Monster(data) { - var that = new Sprite(data); - var super_draw = that.superior('draw'); - var spriteVersion = 1; - var eatingStage = 0; - var standardSpeed = 6; - - that.isEating = false; - that.isFull = false; - that.setSpeed(standardSpeed); - - that.draw = function(dContext) { - var spritePartToUse = function () { - var xDiff = that.movingToward[0] - that.canvasX; - - if (that.isEating) { - return 'eating' + eatingStage; - } - - if (spriteVersion + 0.1 > 2) { - spriteVersion = 0.1; - } else { - spriteVersion += 0.1; - } - if (xDiff >= 0) { - return 'sEast' + Math.ceil(spriteVersion); - } else if (xDiff < 0) { - return 'sWest' + Math.ceil(spriteVersion); - } - }; - - return super_draw(dContext, spritePartToUse()); - }; - - function startEating (whenDone) { - eatingStage += 1; - that.isEating = true; - that.isMoving = false; - if (eatingStage < 6) { - setTimeout(function () { - startEating(whenDone); - }, 300); - } else { - eatingStage = 0; - that.isEating = false; - that.isMoving = true; - whenDone(); - } - } - - that.startEating = startEating; - - return that; - } - - global.monster = Monster; -})( this ); - - -if (typeof module !== 'undefined') { - module.exports = this.monster; -} -},{"./sprite":11}],8:[function(require,module,exports){ -// Avoid `console` errors in browsers that lack a console. -(function() { - var method; - var noop = function noop() {}; - var methods = [ - 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', - 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', - 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', - 'timeStamp', 'trace', 'warn' - ]; - var length = methods.length; - var console = (window.console = window.console || {}); - - while (length--) { - method = methods[length]; - - // Only stub undefined methods. - if (!console[method]) { - console[method] = noop; - } - } -}()); -},{}],9:[function(require,module,exports){ -var Sprite = require('./sprite'); -if (typeof navigator !== 'undefined') { - navigator.vibrate = navigator.vibrate || - navigator.webkitVibrate || - navigator.mozVibrate || - navigator.msVibrate; -} else { - navigator = { - vibrate: false - }; -} - -(function(global) { - function Skier(data) { - var discreteDirections = { - 'west': 270, - 'wsWest': 240, - 'sWest': 195, - 'south': 180, - 'sEast': 165, - 'esEast': 120, - 'east': 90 - }; - var that = new Sprite(data); - var sup = { - draw: that.superior('draw'), - cycle: that.superior('cycle'), - getSpeedX: that.superior('getSpeedX'), - getSpeedY: that.superior('getSpeedY'), - hits: that.superior('hits') - }; - var directions = { - esEast: function(xDiff) { return xDiff > 300; }, - sEast: function(xDiff) { return xDiff > 75; }, - wsWest: function(xDiff) { return xDiff < -300; }, - sWest: function(xDiff) { return xDiff < -75; } - }; - - var cancelableStateTimeout; - var cancelableStateInterval; - - var canSpeedBoost = true; - - var obstaclesHit = []; - var pixelsTravelled = 0; - var standardSpeed = 5; - var boostMultiplier = 2; - var turnEaseCycles = 70; - var speedX = 0; - var speedXFactor = 0; - var speedY = 0; - var speedYFactor = 1; - var trickStep = 0; // There are three of these - - that.isMoving = true; - that.hasBeenHit = false; - that.isJumping = false; - that.isPerformingTrick = false; - that.onHitObstacleCb = function() {}; - that.setSpeed(standardSpeed); - - that.reset = function () { - obstaclesHit = []; - pixelsTravelled = 0; - that.isMoving = true; - that.hasBeenHit = false; - canSpeedBoost = true; - setNormal(); - }; - - function setNormal() { - that.setSpeed(standardSpeed); - that.isMoving = true; - that.hasBeenHit = false; - that.isJumping = false; - that.isPerformingTrick = false; - if (cancelableStateInterval) { - clearInterval(cancelableStateInterval); - } - that.setMapPosition(undefined, undefined, 0); - } - - function setCrashed() { - that.isMoving = false; - that.hasBeenHit = true; - that.isJumping = false; - that.isPerformingTrick = false; - if (cancelableStateInterval) { - clearInterval(cancelableStateInterval); - } - that.setMapPosition(undefined, undefined, 0); - } - - function setJumping() { - var currentSpeed = that.getSpeed(); - that.setSpeed(currentSpeed + 2); - that.setSpeedY(currentSpeed + 2); - that.isMoving = true; - that.hasBeenHit = false; - that.isJumping = true; - that.setMapPosition(undefined, undefined, 1); - } - - function getDiscreteDirection() { - if (that.direction) { - if (that.direction <= 90) { - return 'east'; - } else if (that.direction > 90 && that.direction < 150) { - return 'esEast'; - } else if (that.direction >= 150 && that.direction < 180) { - return 'sEast'; - } else if (that.direction === 180) { - return 'south'; - } else if (that.direction > 180 && that.direction <= 210) { - return 'sWest'; - } else if (that.direction > 210 && that.direction < 270) { - return 'wsWest'; - } else if (that.direction >= 270) { - return 'west'; - } else { - return 'south'; - } - } else { - var xDiff = that.movingToward[0] - that.mapPosition[0]; - var yDiff = that.movingToward[1] - that.mapPosition[1]; - if (yDiff <= 0) { - if (xDiff > 0) { - return 'east'; - } else { - return 'west'; - } - } - - if (directions.esEast(xDiff)) { - return 'esEast'; - } else if (directions.sEast(xDiff)) { - return 'sEast'; - } else if (directions.wsWest(xDiff)) { - return 'wsWest'; - } else if (directions.sWest(xDiff)) { - return 'sWest'; - } - } - return 'south'; - } - - function setDiscreteDirection(d) { - if (discreteDirections[d]) { - that.setDirection(discreteDirections[d]); - } - - if (d === 'west' || d === 'east') { - that.isMoving = false; - } else { - that.isMoving = true; - } - } - - function getBeingEatenSprite() { - return 'blank'; - } - - function getJumpingSprite() { - return 'jumping'; - } - - function getTrickSprite() { - console.log('Trick step is', trickStep); - if (trickStep === 0) { - return 'jumping'; - } else if (trickStep === 1) { - return 'somersault1'; - } else { - return 'somersault2'; - } - } - - that.stop = function () { - if (that.direction > 180) { - setDiscreteDirection('west'); - } else { - setDiscreteDirection('east'); - } - }; - - that.turnEast = function () { - var discreteDirection = getDiscreteDirection(); - - switch (discreteDirection) { - case 'west': - setDiscreteDirection('wsWest'); - break; - case 'wsWest': - setDiscreteDirection('sWest'); - break; - case 'sWest': - setDiscreteDirection('south'); - break; - case 'south': - setDiscreteDirection('sEast'); - break; - case 'sEast': - setDiscreteDirection('esEast'); - break; - case 'esEast': - setDiscreteDirection('east'); - break; - default: - setDiscreteDirection('south'); - break; - } - }; - - that.turnWest = function () { - var discreteDirection = getDiscreteDirection(); - - switch (discreteDirection) { - case 'east': - setDiscreteDirection('esEast'); - break; - case 'esEast': - setDiscreteDirection('sEast'); - break; - case 'sEast': - setDiscreteDirection('south'); - break; - case 'south': - setDiscreteDirection('sWest'); - break; - case 'sWest': - setDiscreteDirection('wsWest'); - break; - case 'wsWest': - setDiscreteDirection('west'); - break; - default: - setDiscreteDirection('south'); - break; - } - }; - - that.stepWest = function () { - that.mapPosition[0] -= that.speed * 2; - }; - - that.stepEast = function () { - that.mapPosition[0] += that.speed * 2; - }; - - that.setMapPositionTarget = function (x, y) { - if (that.hasBeenHit) return; - - if (Math.abs(that.mapPosition[0] - x) <= 75) { - x = that.mapPosition[0]; - } - - that.movingToward = [ x, y ]; - - // that.resetDirection(); - }; - - that.startMovingIfPossible = function () { - if (!that.hasBeenHit && !that.isBeingEaten) { - that.isMoving = true; - } - }; - - that.setTurnEaseCycles = function (c) { - turnEaseCycles = c; - }; - - that.getPixelsTravelledDownMountain = function () { - return pixelsTravelled; - }; - - that.resetSpeed = function () { - that.setSpeed(standardSpeed); - }; - - that.cycle = function () { - if ( that.getSpeedX() <= 0 && that.getSpeedY() <= 0 ) { - that.isMoving = false; - } - if (that.isMoving) { - pixelsTravelled += that.speed; - } - - if (that.isJumping) { - that.setMapPositionTarget(undefined, that.mapPosition[1] + that.getSpeed()); - } - - sup.cycle(); - - that.checkHittableObjects(); - }; - - that.draw = function(dContext) { - var spritePartToUse = function () { - if (that.isBeingEaten) { - return getBeingEatenSprite(); - } - - if (that.isJumping) { - if (that.isPerformingTrick) { - return getTrickSprite(); - } - return getJumpingSprite(); - } - - if (that.hasBeenHit) { - return 'hit'; - } - - return getDiscreteDirection(); - }; - - return sup.draw(dContext, spritePartToUse()); - }; - - that.hits = function (obs) { - if (obstaclesHit.indexOf(obs.id) !== -1) { - return false; - } - - if (!obs.occupiesZIndex(that.mapPosition[2])) { - return false; - } - - if (sup.hits(obs)) { - return true; - } - - return false; - }; - - that.speedBoost = function () { - var originalSpeed = that.speed; - if (canSpeedBoost) { - canSpeedBoost = false; - that.setSpeed(that.speed * boostMultiplier); - setTimeout(function () { - that.setSpeed(originalSpeed); - setTimeout(function () { - canSpeedBoost = true; - }, 10000); - }, 2000); - } - }; - - that.attemptTrick = function () { - if (that.isJumping) { - that.isPerformingTrick = true; - cancelableStateInterval = setInterval(function () { - if (trickStep >= 2) { - trickStep = 0; - } else { - trickStep += 1; - } - }, 300); - } - }; - - that.getStandardSpeed = function () { - return standardSpeed; - }; - - function easeSpeedToTargetUsingFactor(sp, targetSpeed, f) { - if (f === 0 || f === 1) { - return targetSpeed; - } - - if (sp < targetSpeed) { - sp += that.getSpeed() * (f / turnEaseCycles); - } - - if (sp > targetSpeed) { - sp -= that.getSpeed() * (f / turnEaseCycles); - } - - return sp; - } - - that.getSpeedX = function () { - if (getDiscreteDirection() === 'esEast' || getDiscreteDirection() === 'wsWest') { - speedXFactor = 0.5; - speedX = easeSpeedToTargetUsingFactor(speedX, that.getSpeed() * speedXFactor, speedXFactor); - - return speedX; - } - - if (getDiscreteDirection() === 'sEast' || getDiscreteDirection() === 'sWest') { - speedXFactor = 0.33; - speedX = easeSpeedToTargetUsingFactor(speedX, that.getSpeed() * speedXFactor, speedXFactor); - - return speedX; - } - - // So it must be south - - speedX = easeSpeedToTargetUsingFactor(speedX, 0, speedXFactor); - - return speedX; - }; - - that.setSpeedY = function(sy) { - speedY = sy; - }; - - that.getSpeedY = function () { - var targetSpeed; - - if (that.isJumping) { - return speedY; - } - - if (getDiscreteDirection() === 'esEast' || getDiscreteDirection() === 'wsWest') { - speedYFactor = 0.6; - speedY = easeSpeedToTargetUsingFactor(speedY, that.getSpeed() * 0.6, 0.6); - - return speedY; - } - - if (getDiscreteDirection() === 'sEast' || getDiscreteDirection() === 'sWest') { - speedYFactor = 0.85; - speedY = easeSpeedToTargetUsingFactor(speedY, that.getSpeed() * 0.85, 0.85); - - return speedY; - } - - if (getDiscreteDirection() === 'east' || getDiscreteDirection() === 'west') { - speedYFactor = 1; - speedY = 0; - - return speedY; - } - - // So it must be south - - speedY = easeSpeedToTargetUsingFactor(speedY, that.getSpeed(), speedYFactor); - - return speedY; - }; - - that.hasHitObstacle = function (obs) { - setCrashed(); - - if (navigator.vibrate) { - navigator.vibrate(500); - } - - obstaclesHit.push(obs.id); - - that.resetSpeed(); - that.onHitObstacleCb(obs); - - if (cancelableStateTimeout) { - clearTimeout(cancelableStateTimeout); - } - cancelableStateTimeout = setTimeout(function() { - setNormal(); - }, 1500); - }; - - that.hasHitJump = function () { - setJumping(); - - if (cancelableStateTimeout) { - clearTimeout(cancelableStateTimeout); - } - cancelableStateTimeout = setTimeout(function() { - setNormal(); - }, 1000); - }; - - that.isEatenBy = function (monster, whenEaten) { - that.hasHitObstacle(monster); - monster.startEating(whenEaten); - obstaclesHit.push(monster.id); - that.isMoving = false; - that.isBeingEaten = true; - }; - - that.reset = function () { - obstaclesHit = []; - pixelsTravelled = 0; - that.isMoving = true; - that.isJumping = false; - that.hasBeenHit = false; - canSpeedBoost = true; - }; - - that.setHitObstacleCb = function (fn) { - that.onHitObstacleCb = fn || function() {}; - }; - return that; - } - - global.skier = Skier; -})(this); - -if (typeof module !== 'undefined') { - module.exports = this.skier; -} - -},{"./sprite":11}],10:[function(require,module,exports){ -var Sprite = require('./sprite'); - -(function(global) { - function Snowboarder(data) { - var that = new Sprite(data); - var sup = { - draw: that.superior('draw'), - cycle: that.superior('cycle') - }; - var directions = { - sEast: function(xDiff) { return xDiff > 0; }, - sWest: function(xDiff) { return xDiff <= 0; } - }; - var standardSpeed = 3; - - that.setSpeed(standardSpeed); - - function getDirection() { - var xDiff = that.movingToward[0] - that.mapPosition[0]; - var yDiff = that.movingToward[1] - that.mapPosition[1]; - - if (directions.sEast(xDiff)) { - return 'sEast'; - } else { - return 'sWest'; - } - } - - that.cycle = function (dContext) { - if (Number.random(10) === 1) { - that.setMapPositionTarget(dContext.getRandomlyInTheCentreOfMap()); - that.setSpeed(standardSpeed + Number.random(-1, 1)); - } - - that.setMapPositionTarget(undefined, dContext.getMapBelowViewport() + 600); - - sup.cycle(); - }; - - that.draw = function(dContext) { - var spritePartToUse = function () { - return getDirection(); - }; - - return sup.draw(dContext, spritePartToUse()); - }; - - return that; - } - - global.snowboarder = Snowboarder; -})( this ); - - -if (typeof module !== 'undefined') { - module.exports = this.snowboarder; -} -},{"./sprite":11}],11:[function(require,module,exports){ -(function (global) { - var GUID = require('./guid'); - function Sprite (data) { - var hittableObjects = {}; - var zIndexesOccupied = [ 0 ]; - var that = this; - var trackedSpriteToMoveToward; - that.direction = undefined; - that.mapPosition = [0, 0, 0]; - that.id = GUID(); - that.canvasX = 0; - that.canvasY = 0; - that.canvasZ = 0; - that.height = 0; - that.speed = 0; - that.data = data || { parts : {} }; - that.movingToward = [ 0, 0 ]; - that.metresDownTheMountain = 0; - that.movingWithConviction = false; - that.deleted = false; - that.maxHeight = (function () { - return Object.values(that.data.parts).map(function (p) { return p[3]; }).max(); - }()); - that.isMoving = true; - - if (!that.data.parts) { - that.data.parts = {}; - } - - if (data && data.id){ - that.id = data.id; - } - - if (data && data.zIndexesOccupied) { - zIndexesOccupied = data.zIndexesOccupied; - } - - function incrementX(amount) { - that.canvasX += amount.toNumber(); - } - - function incrementY(amount) { - that.canvasY += amount.toNumber(); - } - - function getHitBox(forZIndex) { - if (that.data.hitBoxes) { - if (data.hitBoxes[forZIndex]) { - return data.hitBoxes[forZIndex]; - } - } - } - - function roundHalf(num) { - num = Math.round(num*2)/2; - return num; - } - - function move() { - if (!that.isMoving) { - return; - } - - var currentX = that.mapPosition[0]; - var currentY = that.mapPosition[1]; - - if (typeof that.direction !== 'undefined') { - // For this we need to modify the that.direction so it relates to the horizontal - var d = that.direction - 90; - if (d < 0) d = 360 + d; - currentX += roundHalf(that.speed * Math.cos(d * (Math.PI / 180))); - currentY += roundHalf(that.speed * Math.sin(d * (Math.PI / 180))); - } else { - if (typeof that.movingToward[0] !== 'undefined') { - if (currentX > that.movingToward[0]) { - currentX -= Math.min(that.getSpeedX(), Math.abs(currentX - that.movingToward[0])); - } else if (currentX < that.movingToward[0]) { - currentX += Math.min(that.getSpeedX(), Math.abs(currentX - that.movingToward[0])); - } - } - - if (typeof that.movingToward[1] !== 'undefined') { - if (currentY > that.movingToward[1]) { - currentY -= Math.min(that.getSpeedY(), Math.abs(currentY - that.movingToward[1])); - } else if (currentY < that.movingToward[1]) { - currentY += Math.min(that.getSpeedY(), Math.abs(currentY - that.movingToward[1])); - } - } - } - - that.setMapPosition(currentX, currentY); - } - - this.draw = function (dCtx, spriteFrame) { - var fr = that.data.parts[spriteFrame]; - that.height = fr[3]; - that.width = fr[2]; - - var newCanvasPosition = dCtx.mapPositionToCanvasPosition(that.mapPosition); - that.setCanvasPosition(newCanvasPosition[0], newCanvasPosition[1]); - - dCtx.drawImage(dCtx.getLoadedImage(that.data.$imageFile), fr[0], fr[1], fr[2], fr[3], that.canvasX, that.canvasY, fr[2], fr[3]); - }; - - this.setMapPosition = function (x, y, z) { - if (typeof x === 'undefined') { - x = that.mapPosition[0]; - } - if (typeof y === 'undefined') { - y = that.mapPosition[1]; - } - if (typeof z === 'undefined') { - z = that.mapPosition[2]; - } else { - that.zIndexesOccupied = [ z ]; - } - that.mapPosition = [x, y, z]; - }; - - this.setCanvasPosition = function (cx, cy) { - if (cx) { - if (Object.isString(cx) && (cx.first() === '+' || cx.first() === '-')) incrementX(cx); - else that.canvasX = cx; - } - - if (cy) { - if (Object.isString(cy) && (cy.first() === '+' || cy.first() === '-')) incrementY(cy); - else that.canvasY = cy; - } - }; - - this.getCanvasPositionX = function () { - return that.canvasX; - }; - - this.getCanvasPositionY = function () { - return that.canvasY; - }; - - this.getLeftHitBoxEdge = function (zIndex) { - zIndex = zIndex || 0; - var lhbe = this.getCanvasPositionX(); - if (getHitBox(zIndex)) { - lhbe += getHitBox(zIndex)[0]; - } - return lhbe; - }; - - this.getTopHitBoxEdge = function (zIndex) { - zIndex = zIndex || 0; - var thbe = this.getCanvasPositionY(); - if (getHitBox(zIndex)) { - thbe += getHitBox(zIndex)[1]; - } - return thbe; - }; - - this.getRightHitBoxEdge = function (zIndex) { - zIndex = zIndex || 0; - - if (getHitBox(zIndex)) { - return that.canvasX + getHitBox(zIndex)[2]; - } - - return that.canvasX + that.width; - }; - - this.getBottomHitBoxEdge = function (zIndex) { - zIndex = zIndex || 0; - - if (getHitBox(zIndex)) { - return that.canvasY + getHitBox(zIndex)[3]; - } - - return that.canvasY + that.height; - }; - - this.getPositionInFrontOf = function () { - return [that.canvasX, that.canvasY + that.height]; - }; - - this.setSpeed = function (s) { - that.speed = s; - that.speedX = s; - that.speedY = s; - }; - - this.incrementSpeedBy = function (s) { - that.speed += s; - }; - - that.getSpeed = function getSpeed () { - return that.speed; - }; - - that.getSpeedX = function () { - return that.speed; - }; - - that.getSpeedY = function () { - return that.speed; - }; - - this.setHeight = function (h) { - that.height = h; - }; - - this.setWidth = function (w) { - that.width = w; - }; - - this.getMaxHeight = function () { - return that.maxHeight; - }; - - that.getMovingTowardOpposite = function () { - if (!that.isMoving) { - return [0, 0]; - } - - var dx = (that.movingToward[0] - that.mapPosition[0]); - var dy = (that.movingToward[1] - that.mapPosition[1]); - - var oppositeX = (Math.abs(dx) > 75 ? 0 - dx : 0); - var oppositeY = -dy; - - return [ oppositeX, oppositeY ]; - }; - - this.checkHittableObjects = function () { - Object.keys(hittableObjects, function (k, objectData) { - if (objectData.object.deleted) { - delete hittableObjects[k]; - } else { - if (objectData.object.hits(that)) { - objectData.callbacks.each(function (callback) { - callback(that, objectData.object); - }); - } - } - }); - }; - - this.cycle = function () { - that.checkHittableObjects(); - - if (trackedSpriteToMoveToward) { - that.setMapPositionTarget(trackedSpriteToMoveToward.mapPosition[0], trackedSpriteToMoveToward.mapPosition[1], true); - } - - move(); - }; - - this.setMapPositionTarget = function (x, y, override) { - if (override) { - that.movingWithConviction = false; - } - - if (!that.movingWithConviction) { - if (typeof x === 'undefined') { - x = that.movingToward[0]; - } - - if (typeof y === 'undefined') { - y = that.movingToward[1]; - } - - that.movingToward = [ x, y ]; - - that.movingWithConviction = false; - } - - // that.resetDirection(); - }; - - this.setDirection = function (angle) { - if (angle >= 360) { - angle = 360 - angle; - } - that.direction = angle; - that.movingToward = undefined; - }; - - this.resetDirection = function () { - that.direction = undefined; - }; - - this.setMapPositionTargetWithConviction = function (cx, cy) { - that.setMapPositionTarget(cx, cy); - that.movingWithConviction = true; - // that.resetDirection(); - }; - - this.follow = function (sprite) { - trackedSpriteToMoveToward = sprite; - // that.resetDirection(); - }; - - this.stopFollowing = function () { - trackedSpriteToMoveToward = false; - }; - - this.onHitting = function (objectToHit, callback) { - if (hittableObjects[objectToHit.id]) { - return hittableObjects[objectToHit.id].callbacks.push(callback); - } - - hittableObjects[objectToHit.id] = { - object: objectToHit, - callbacks: [ callback ] - }; - }; - - this.deleteOnNextCycle = function () { - that.deleted = true; - }; - - this.occupiesZIndex = function (z) { - return zIndexesOccupied.indexOf(z) >= 0; - }; - - this.hits = function (other) { - var verticalIntersect = false; - var horizontalIntersect = false; - - // Test that THIS has a bottom edge inside of the other object - if (other.getTopHitBoxEdge(that.mapPosition[2]) <= that.getBottomHitBoxEdge(that.mapPosition[2]) && other.getBottomHitBoxEdge(that.mapPosition[2]) >= that.getBottomHitBoxEdge(that.mapPosition[2])) { - verticalIntersect = true; - } - - // Test that THIS has a top edge inside of the other object - if (other.getTopHitBoxEdge(that.mapPosition[2]) <= that.getTopHitBoxEdge(that.mapPosition[2]) && other.getBottomHitBoxEdge(that.mapPosition[2]) >= that.getTopHitBoxEdge(that.mapPosition[2])) { - verticalIntersect = true; - } - - // Test that THIS has a right edge inside of the other object - if (other.getLeftHitBoxEdge(that.mapPosition[2]) <= that.getRightHitBoxEdge(that.mapPosition[2]) && other.getRightHitBoxEdge(that.mapPosition[2]) >= that.getRightHitBoxEdge(that.mapPosition[2])) { - horizontalIntersect = true; - } - - // Test that THIS has a left edge inside of the other object - if (other.getLeftHitBoxEdge(that.mapPosition[2]) <= that.getLeftHitBoxEdge(that.mapPosition[2]) && other.getRightHitBoxEdge(that.mapPosition[2]) >= that.getLeftHitBoxEdge(that.mapPosition[2])) { - horizontalIntersect = true; - } - - return verticalIntersect && horizontalIntersect; - }; - - this.isAboveOnCanvas = function (cy) { - return (that.canvasY + that.height) < cy; - }; - - this.isBelowOnCanvas = function (cy) { - return (that.canvasY) > cy; - }; - - return that; - } - - Sprite.createObjects = function createObjects(spriteInfoArray, opts) { - if (!Array.isArray(spriteInfoArray)) spriteInfoArray = [ spriteInfoArray ]; - opts = Object.merge(opts, { - rateModifier: 0, - dropRate: 1, - position: [0, 0] - }, false, false); - - function createOne (spriteInfo) { - var position = opts.position; - if (Number.random(100 + opts.rateModifier) <= spriteInfo.dropRate) { - var sprite = new Sprite(spriteInfo.sprite); - sprite.setSpeed(0); - - if (Object.isFunction(position)) { - position = position(); - } - - sprite.setMapPosition(position[0], position[1]); - - if (spriteInfo.sprite.hitBehaviour && spriteInfo.sprite.hitBehaviour.skier && opts.player) { - sprite.onHitting(opts.player, spriteInfo.sprite.hitBehaviour.skier); - } - - return sprite; - } - } - - var objects = spriteInfoArray.map(createOne).remove(undefined); - - return objects; - }; - - global.sprite = Sprite; -})( this ); - - -if (typeof module !== 'undefined') { - module.exports = this.sprite; -} -},{"./guid":4}],12:[function(require,module,exports){ -(function (global) { - function SpriteArray() { - this.pushHandlers = []; - - return this; - } - - SpriteArray.prototype = Object.create(Array.prototype); - - SpriteArray.prototype.onPush = function(f, retroactive) { - this.pushHandlers.push(f); - - if (retroactive) { - this.each(f); - } - }; - - SpriteArray.prototype.push = function(obj) { - Array.prototype.push.call(this, obj); - this.pushHandlers.each(function(handler) { - handler(obj); - }); - }; - - SpriteArray.prototype.cull = function() { - this.each(function (obj, i) { - if (obj.deleted) { - return (delete this[i]); - } - }); - }; - - global.spriteArray = SpriteArray; -})(this); - - -if (typeof module !== 'undefined') { - module.exports = this.spriteArray; -} -},{}],13:[function(require,module,exports){ -// Global dependencies which return no modules -require('./lib/canvasRenderingContext2DExtensions'); -require('./lib/extenders'); -require('./lib/plugins'); - -// External dependencies -var Hammer = require('hammerjs'); -var Mousetrap = require('br-mousetrap'); - -// Method modules -var isMobileDevice = require('./lib/isMobileDevice'); - -// Game Objects -var SpriteArray = require('./lib/spriteArray'); -var Monster = require('./lib/monster'); -var Sprite = require('./lib/sprite'); -var Snowboarder = require('./lib/snowboarder'); -var Skier = require('./lib/skier'); -var InfoBox = require('./lib/infoBox'); -var Game = require('./lib/game'); - -// Local variables for starting the game -var mainCanvas = document.getElementById('skifree-canvas'); -var dContext = mainCanvas.getContext('2d'); -var imageSources = [ 'sprite-characters.png', 'skifree-objects.png' ]; -var global = this; -var infoBoxControls = 'Use the mouse or WASD to control the player'; -if (isMobileDevice()) infoBoxControls = 'Tap or drag on the piste to control the player'; -var sprites = require('./spriteInfo'); - -var pixelsPerMetre = 18; -var distanceTravelledInMetres = 0; -var monsterDistanceThreshold = 2000; -var livesLeft = 5; -var highScore = 0; -var loseLifeOnObstacleHit = false; -var dropRates = {smallTree: 4, tallTree: 2, jump: 1, thickSnow: 1, rock: 1}; -if (localStorage.getItem('highScore')) highScore = localStorage.getItem('highScore'); - -function loadImages (sources, next) { - var loaded = 0; - var images = {}; - - function finish () { - loaded += 1; - if (loaded === sources.length) { - next(images); - } - } - - sources.each(function (src) { - var im = new Image(); - im.onload = finish; - im.src = src; - dContext.storeLoadedImage(src, im); - }); -} - -function monsterHitsSkierBehaviour(monster, skier) { - skier.isEatenBy(monster, function () { - livesLeft -= 1; - monster.isFull = true; - monster.isEating = false; - skier.isBeingEaten = false; - monster.setSpeed(skier.getSpeed()); - monster.stopFollowing(); - var randomPositionAbove = dContext.getRandomMapPositionAboveViewport(); - monster.setMapPositionTarget(randomPositionAbove[0], randomPositionAbove[1]); - }); -} - -function startNeverEndingGame (images) { - var player; - var startSign; - var infoBox; - var game; - - function resetGame () { - distanceTravelledInMetres = 0; - livesLeft = 5; - highScore = localStorage.getItem('highScore'); - game.reset(); - game.addStaticObject(startSign); - } - - function detectEnd () { - if (!game.isPaused()) { - highScore = localStorage.setItem('highScore', distanceTravelledInMetres); - infoBox.setLines([ - 'Game over!', - 'Hit space to restart' - ]); - game.pause(); - game.cycle(); - } - } - - function randomlySpawnNPC(spawnFunction, dropRate) { - var rateModifier = Math.max(800 - mainCanvas.width, 0); - if (Number.random(1000 + rateModifier) <= dropRate) { - spawnFunction(); - } - } - - function spawnMonster () { - var newMonster = new Monster(sprites.monster); - var randomPosition = dContext.getRandomMapPositionAboveViewport(); - newMonster.setMapPosition(randomPosition[0], randomPosition[1]); - newMonster.follow(player); - newMonster.setSpeed(player.getStandardSpeed()); - newMonster.onHitting(player, monsterHitsSkierBehaviour); - - game.addMovingObject(newMonster, 'monster'); - } - - function spawnBoarder () { - var newBoarder = new Snowboarder(sprites.snowboarder); - var randomPositionAbove = dContext.getRandomMapPositionAboveViewport(); - var randomPositionBelow = dContext.getRandomMapPositionBelowViewport(); - newBoarder.setMapPosition(randomPositionAbove[0], randomPositionAbove[1]); - newBoarder.setMapPositionTarget(randomPositionBelow[0], randomPositionBelow[1]); - newBoarder.onHitting(player, sprites.snowboarder.hitBehaviour.skier); - - game.addMovingObject(newBoarder); - } - - player = new Skier(sprites.skier); - player.setMapPosition(0, 0); - player.setMapPositionTarget(0, -10); - if ( loseLifeOnObstacleHit ) { - player.setHitObstacleCb(function() { - livesLeft -= 1; - }); - } - - game = new Game(mainCanvas, player); - - startSign = new Sprite(sprites.signStart); - game.addStaticObject(startSign); - startSign.setMapPosition(-50, 0); - dContext.followSprite(player); - - infoBox = new InfoBox({ - initialLines : [ - 'SkiFree.js', - infoBoxControls, - 'Travelled 0m', - 'High Score: ' + highScore, - 'Skiers left: ' + livesLeft, - 'Created by Dan Hough (@basicallydan)' - ], - position: { - top: 15, - right: 10 - } - }); - - game.beforeCycle(function () { - var newObjects = []; - if (player.isMoving) { - newObjects = Sprite.createObjects([ - { sprite: sprites.smallTree, dropRate: dropRates.smallTree }, - { sprite: sprites.tallTree, dropRate: dropRates.tallTree }, - { sprite: sprites.jump, dropRate: dropRates.jump }, - { sprite: sprites.thickSnow, dropRate: dropRates.thickSnow }, - { sprite: sprites.rock, dropRate: dropRates.rock }, - ], { - rateModifier: Math.max(800 - mainCanvas.width, 0), - position: function () { - return dContext.getRandomMapPositionBelowViewport(); - }, - player: player - }); - } - if (!game.isPaused()) { - game.addStaticObjects(newObjects); - - randomlySpawnNPC(spawnBoarder, 0.1); - distanceTravelledInMetres = parseFloat(player.getPixelsTravelledDownMountain() / pixelsPerMetre).toFixed(1); - - if (distanceTravelledInMetres > monsterDistanceThreshold) { - randomlySpawnNPC(spawnMonster, 0.001); - } - - infoBox.setLines([ - 'SkiFree.js', - infoBoxControls, - 'Travelled ' + distanceTravelledInMetres + 'm', - 'Skiers left: ' + livesLeft, - 'High Score: ' + highScore, - 'Created by Dan Hough (@basicallydan)', - 'Current Speed: ' + player.getSpeed()/*, - 'Skier Map Position: ' + player.mapPosition[0].toFixed(1) + ', ' + player.mapPosition[1].toFixed(1), - 'Mouse Map Position: ' + mouseMapPosition[0].toFixed(1) + ', ' + mouseMapPosition[1].toFixed(1)*/ - ]); - } - }); - - game.afterCycle(function() { - if (livesLeft === 0) { - detectEnd(); - } - }); - - game.addUIElement(infoBox); - - $(mainCanvas) - .mousemove(function (e) { - game.setMouseX(e.pageX); - game.setMouseY(e.pageY); - player.resetDirection(); - player.startMovingIfPossible(); - }) - .bind('click', function (e) { - game.setMouseX(e.pageX); - game.setMouseY(e.pageY); - player.resetDirection(); - player.startMovingIfPossible(); - }) - .focus(); // So we can listen to events immediately - - Mousetrap.bind('f', player.speedBoost); - Mousetrap.bind('t', player.attemptTrick); - Mousetrap.bind(['w', 'up'], function () { - player.stop(); - }); - Mousetrap.bind(['a', 'left'], function () { - if (player.direction === 270) { - player.stepWest(); - } else { - player.turnWest(); - } - }); - Mousetrap.bind(['s', 'down'], function () { - player.setDirection(180); - player.startMovingIfPossible(); - }); - Mousetrap.bind(['d', 'right'], function () { - if (player.direction === 90) { - player.stepEast(); - } else { - player.turnEast(); - } - }); - Mousetrap.bind('m', spawnMonster); - Mousetrap.bind('b', spawnBoarder); - Mousetrap.bind('space', resetGame); - - var hammertime = Hammer(mainCanvas).on('press', function (e) { - e.preventDefault(); - game.setMouseX(e.center.x); - game.setMouseY(e.center.y); - }).on('tap', function (e) { - game.setMouseX(e.center.x); - game.setMouseY(e.center.y); - }).on('pan', function (e) { - game.setMouseX(e.center.x); - game.setMouseY(e.center.y); - player.resetDirection(); - player.startMovingIfPossible(); - }).on('doubletap', function (e) { - player.speedBoost(); - }); - - player.isMoving = false; - player.setDirection(270); - - game.start(); -} - -function resizeCanvas() { - mainCanvas.width = window.innerWidth; - mainCanvas.height = window.innerHeight; -} - -window.addEventListener('resize', resizeCanvas, false); - -resizeCanvas(); - -loadImages(imageSources, startNeverEndingGame); - -this.exports = window; - -},{"./lib/canvasRenderingContext2DExtensions":1,"./lib/extenders":2,"./lib/game":3,"./lib/infoBox":5,"./lib/isMobileDevice":6,"./lib/monster":7,"./lib/plugins":8,"./lib/skier":9,"./lib/snowboarder":10,"./lib/sprite":11,"./lib/spriteArray":12,"./spriteInfo":14,"br-mousetrap":15,"hammerjs":18}],14:[function(require,module,exports){ -(function (global) { - var sprites = { - 'skier' : { - $imageFile : 'sprite-characters.png', - parts : { - blank : [ 0, 0, 0, 0 ], - east : [ 0, 0, 24, 34 ], - esEast : [ 24, 0, 24, 34 ], - sEast : [ 49, 0, 17, 34 ], - south : [ 65, 0, 17, 34 ], - sWest : [ 49, 37, 17, 34 ], - wsWest : [ 24, 37, 24, 34 ], - west : [ 0, 37, 24, 34 ], - hit : [ 0, 78, 31, 31 ], - jumping : [ 84, 0, 32, 34 ], - somersault1 : [ 116, 0, 32, 34 ], - somersault2 : [ 148, 0, 32, 34 ] - }, - hitBoxes: { - 0: [ 7, 20, 27, 34 ] - }, - id : 'player', - hitBehaviour: {} - }, - 'smallTree' : { - $imageFile : 'skifree-objects.png', - parts : { - main : [ 0, 28, 30, 34 ] - }, - hitBoxes: { - 0: [ 0, 18, 30, 34 ] - }, - hitBehaviour: {} - }, - 'tallTree' : { - $imageFile : 'skifree-objects.png', - parts : { - main : [ 95, 66, 32, 64 ] - }, - zIndexesOccupied : [0, 1], - hitBoxes: { - 0: [0, 54, 32, 64], - 1: [0, 10, 32, 54] - }, - hitBehaviour: {} - }, - 'thickSnow' : { - $imageFile : 'skifree-objects.png', - parts : { - main : [ 143, 53, 43, 10 ] - }, - hitBehaviour: {} - }, - 'rock' : { - $imageFile : 'skifree-objects.png', - parts : { - main : [ 30, 52, 23, 11 ] - }, - hitBehaviour: {} - }, - 'monster' : { - $imageFile : 'sprite-characters.png', - parts : { - sEast1 : [ 64, 112, 26, 43 ], - sEast2 : [ 90, 112, 32, 43 ], - sWest1 : [ 64, 158, 26, 43 ], - sWest2 : [ 90, 158, 32, 43 ], - eating1 : [ 122, 112, 34, 43 ], - eating2 : [ 156, 112, 31, 43 ], - eating3 : [ 187, 112, 31, 43 ], - eating4 : [ 219, 112, 25, 43 ], - eating5 : [ 243, 112, 26, 43 ] - }, - hitBehaviour: {} - }, - 'jump' : { - $imageFile : 'skifree-objects.png', - parts : { - main : [ 109, 55, 32, 8 ] - }, - hitBehaviour: {} - }, - 'signStart' : { - $imageFile : 'skifree-objects.png', - parts : { - main : [ 260, 103, 42, 27 ] - }, - hitBehaviour: {} - }, - 'snowboarder' : { - $imageFile : 'sprite-characters.png', - parts : { - sEast : [ 73, 229, 20, 29 ], - sWest : [ 95, 228, 26, 30 ] - }, - hitBehaviour: {} - }, - 'emptyChairLift': { - $imageFile : 'skifree-objects.png', - parts: { - main : [ 92, 136, 26, 30 ] - }, - zIndexesOccupied : [1], - } - }; - - function monsterHitsTreeBehaviour(monster) { - monster.deleteOnNextCycle(); - } - - sprites.monster.hitBehaviour.tree = monsterHitsTreeBehaviour; - - function treeHitsMonsterBehaviour(tree, monster) { - monster.deleteOnNextCycle(); - } - - sprites.smallTree.hitBehaviour.monster = treeHitsMonsterBehaviour; - sprites.tallTree.hitBehaviour.monster = treeHitsMonsterBehaviour; - - function skierHitsTreeBehaviour(skier, tree) { - skier.hasHitObstacle(tree); - } - - function treeHitsSkierBehaviour(tree, skier) { - skier.hasHitObstacle(tree); - } - - sprites.smallTree.hitBehaviour.skier = treeHitsSkierBehaviour; - sprites.tallTree.hitBehaviour.skier = treeHitsSkierBehaviour; - - function rockHitsSkierBehaviour(rock, skier) { - skier.hasHitObstacle(rock); - } - - sprites.rock.hitBehaviour.skier = rockHitsSkierBehaviour; - - function skierHitsJumpBehaviour(skier, jump) { - skier.hasHitJump(jump); - } - - function jumpHitsSkierBehaviour(jump, skier) { - skier.hasHitJump(jump); - } - - sprites.jump.hitBehaviour.skier = jumpHitsSkierBehaviour; - -// Really not a fan of this behaviour. -/* function skierHitsThickSnowBehaviour(skier, thickSnow) { - // Need to implement this properly - skier.setSpeed(2); - setTimeout(function() { - skier.resetSpeed(); - }, 700); - } - - function thickSnowHitsSkierBehaviour(thickSnow, skier) { - // Need to implement this properly - skier.setSpeed(2); - setTimeout(function() { - skier.resetSpeed(); - }, 300); - }*/ - - // sprites.thickSnow.hitBehaviour.skier = thickSnowHitsSkierBehaviour; - - function snowboarderHitsSkierBehaviour(snowboarder, skier) { - skier.hasHitObstacle(snowboarder); - } - - sprites.snowboarder.hitBehaviour.skier = snowboarderHitsSkierBehaviour; - - global.spriteInfo = sprites; -})( this ); - - -if (typeof module !== 'undefined') { - module.exports = this.spriteInfo; -} -},{}],15:[function(require,module,exports){ -/** - * Copyright 2012 Craig Campbell - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Mousetrap is a simple keyboard shortcut library for Javascript with - * no external dependencies - * - * @version 1.1.3 - * @url craig.is/killing/mice - */ -(function() { - - /** - * mapping of special keycodes to their corresponding keys - * - * everything in this dictionary cannot use keypress events - * so it has to be here to map to the correct keycodes for - * keyup/keydown events - * - * @type {Object} - */ - var _MAP = { - 8: 'backspace', - 9: 'tab', - 13: 'enter', - 16: 'shift', - 17: 'ctrl', - 18: 'alt', - 20: 'capslock', - 27: 'esc', - 32: 'space', - 33: 'pageup', - 34: 'pagedown', - 35: 'end', - 36: 'home', - 37: 'left', - 38: 'up', - 39: 'right', - 40: 'down', - 45: 'ins', - 46: 'del', - 91: 'meta', - 93: 'meta', - 224: 'meta' - }, - - /** - * mapping for special characters so they can support - * - * this dictionary is only used incase you want to bind a - * keyup or keydown event to one of these keys - * - * @type {Object} - */ - _KEYCODE_MAP = { - 106: '*', - 107: '+', - 109: '-', - 110: '.', - 111 : '/', - 186: ';', - 187: '=', - 188: ',', - 189: '-', - 190: '.', - 191: '/', - 192: '`', - 219: '[', - 220: '\\', - 221: ']', - 222: '\'' - }, - - /** - * this is a mapping of keys that require shift on a US keypad - * back to the non shift equivelents - * - * this is so you can use keyup events with these keys - * - * note that this will only work reliably on US keyboards - * - * @type {Object} - */ - _SHIFT_MAP = { - '~': '`', - '!': '1', - '@': '2', - '#': '3', - '$': '4', - '%': '5', - '^': '6', - '&': '7', - '*': '8', - '(': '9', - ')': '0', - '_': '-', - '+': '=', - ':': ';', - '\"': '\'', - '<': ',', - '>': '.', - '?': '/', - '|': '\\' - }, - - /** - * this is a list of special strings you can use to map - * to modifier keys when you specify your keyboard shortcuts - * - * @type {Object} - */ - _SPECIAL_ALIASES = { - 'option': 'alt', - 'command': 'meta', - 'return': 'enter', - 'escape': 'esc' - }, - - /** - * variable to store the flipped version of _MAP from above - * needed to check if we should use keypress or not when no action - * is specified - * - * @type {Object|undefined} - */ - _REVERSE_MAP, - - /** - * a list of all the callbacks setup via Mousetrap.bind() - * - * @type {Object} - */ - _callbacks = {}, - - /** - * direct map of string combinations to callbacks used for trigger() - * - * @type {Object} - */ - _direct_map = {}, - - /** - * keeps track of what level each sequence is at since multiple - * sequences can start out with the same sequence - * - * @type {Object} - */ - _sequence_levels = {}, - - /** - * variable to store the setTimeout call - * - * @type {null|number} - */ - _reset_timer, - - /** - * temporary state where we will ignore the next keyup - * - * @type {boolean|string} - */ - _ignore_next_keyup = false, - - /** - * are we currently inside of a sequence? - * type of action ("keyup" or "keydown" or "keypress") or false - * - * @type {boolean|string} - */ - _inside_sequence = false; - - /** - * loop through the f keys, f1 to f19 and add them to the map - * programatically - */ - for (var i = 1; i < 20; ++i) { - _MAP[111 + i] = 'f' + i; - } - - /** - * loop through to map numbers on the numeric keypad - */ - for (i = 0; i <= 9; ++i) { - _MAP[i + 96] = i; - } - - /** - * cross browser add event method - * - * @param {Element|HTMLDocument} object - * @param {string} type - * @param {Function} callback - * @returns void - */ - function _addEvent(object, type, callback) { - if (object.addEventListener) { - object.addEventListener(type, callback, false); - return; - } - - object.attachEvent('on' + type, callback); - } - - /** - * takes the event and returns the key character - * - * @param {Event} e - * @return {string} - */ - function _characterFromEvent(e) { - - // for keypress events we should return the character as is - if (e.type == 'keypress') { - return String.fromCharCode(e.which); - } - - // for non keypress events the special maps are needed - if (_MAP[e.which]) { - return _MAP[e.which]; - } - - if (_KEYCODE_MAP[e.which]) { - return _KEYCODE_MAP[e.which]; - } - - // if it is not in the special map - return String.fromCharCode(e.which).toLowerCase(); - } - - /** - * checks if two arrays are equal - * - * @param {Array} modifiers1 - * @param {Array} modifiers2 - * @returns {boolean} - */ - function _modifiersMatch(modifiers1, modifiers2) { - return modifiers1.sort().join(',') === modifiers2.sort().join(','); - } - - /** - * resets all sequence counters except for the ones passed in - * - * @param {Object} do_not_reset - * @returns void - */ - function _resetSequences(do_not_reset) { - do_not_reset = do_not_reset || {}; - - var active_sequences = false, - key; - - for (key in _sequence_levels) { - if (do_not_reset[key]) { - active_sequences = true; - continue; - } - _sequence_levels[key] = 0; - } - - if (!active_sequences) { - _inside_sequence = false; - } - } - - /** - * finds all callbacks that match based on the keycode, modifiers, - * and action - * - * @param {string} character - * @param {Array} modifiers - * @param {Event|Object} e - * @param {boolean=} remove - should we remove any matches - * @param {string=} combination - * @returns {Array} - */ - function _getMatches(character, modifiers, e, remove, combination) { - var i, - callback, - matches = [], - action = e.type; - - // if there are no events related to this keycode - if (!_callbacks[character]) { - return []; - } - - // if a modifier key is coming up on its own we should allow it - if (action == 'keyup' && _isModifier(character)) { - modifiers = [character]; - } - - // loop through all callbacks for the key that was pressed - // and see if any of them match - for (i = 0; i < _callbacks[character].length; ++i) { - callback = _callbacks[character][i]; - - // if this is a sequence but it is not at the right level - // then move onto the next match - if (callback.seq && _sequence_levels[callback.seq] != callback.level) { - continue; - } - - // if the action we are looking for doesn't match the action we got - // then we should keep going - if (action != callback.action) { - continue; - } - - // if this is a keypress event and the meta key and control key - // are not pressed that means that we need to only look at the - // character, otherwise check the modifiers as well - // - // chrome will not fire a keypress if meta or control is down - // safari will fire a keypress if meta or meta+shift is down - // firefox will fire a keypress if meta or control is down - if ((action == 'keypress' && !e.metaKey && !e.ctrlKey) || _modifiersMatch(modifiers, callback.modifiers)) { - - // remove is used so if you change your mind and call bind a - // second time with a new function the first one is overwritten - if (remove && callback.combo == combination) { - _callbacks[character].splice(i, 1); - } - - matches.push(callback); - } - } - - return matches; - } - - /** - * takes a key event and figures out what the modifiers are - * - * @param {Event} e - * @returns {Array} - */ - function _eventModifiers(e) { - var modifiers = []; - - if (e.shiftKey) { - modifiers.push('shift'); - } - - if (e.altKey) { - modifiers.push('alt'); - } - - if (e.ctrlKey) { - modifiers.push('ctrl'); - } - - if (e.metaKey) { - modifiers.push('meta'); - } - - return modifiers; - } - - /** - * actually calls the callback function - * - * if your callback function returns false this will use the jquery - * convention - prevent default and stop propogation on the event - * - * @param {Function} callback - * @param {Event} e - * @returns void - */ - function _fireCallback(callback, e) { - if (callback(e) === false) { - if (e.preventDefault) { - e.preventDefault(); - } - - if (e.stopPropagation) { - e.stopPropagation(); - } - - e.returnValue = false; - e.cancelBubble = true; - } - } - - /** - * handles a character key event - * - * @param {string} character - * @param {Event} e - * @returns void - */ - function _handleCharacter(character, e) { - - // if this event should not happen stop here - if (Mousetrap.stopCallback(e, e.target || e.srcElement)) { - return; - } - - var callbacks = _getMatches(character, _eventModifiers(e), e), - i, - do_not_reset = {}, - processed_sequence_callback = false; - - // loop through matching callbacks for this key event - for (i = 0; i < callbacks.length; ++i) { - - // fire for all sequence callbacks - // this is because if for example you have multiple sequences - // bound such as "g i" and "g t" they both need to fire the - // callback for matching g cause otherwise you can only ever - // match the first one - if (callbacks[i].seq) { - processed_sequence_callback = true; - - // keep a list of which sequences were matches for later - do_not_reset[callbacks[i].seq] = 1; - _fireCallback(callbacks[i].callback, e); - continue; - } - - // if there were no sequence matches but we are still here - // that means this is a regular match so we should fire that - if (!processed_sequence_callback && !_inside_sequence) { - _fireCallback(callbacks[i].callback, e); - } - } - - // if you are inside of a sequence and the key you are pressing - // is not a modifier key then we should reset all sequences - // that were not matched by this key event - if (e.type == _inside_sequence && !_isModifier(character)) { - _resetSequences(do_not_reset); - } - } - - /** - * handles a keydown event - * - * @param {Event} e - * @returns void - */ - function _handleKey(e) { - - // normalize e.which for key events - // @see http://stackoverflow.com/questions/4285627/javascript-keycode-vs-charcode-utter-confusion - e.which = typeof e.which == "number" ? e.which : e.keyCode; - - var character = _characterFromEvent(e); - - // no character found then stop - if (!character) { - return; - } - - if (e.type == 'keyup' && _ignore_next_keyup == character) { - _ignore_next_keyup = false; - return; - } - - _handleCharacter(character, e); - } - - /** - * determines if the keycode specified is a modifier key or not - * - * @param {string} key - * @returns {boolean} - */ - function _isModifier(key) { - return key == 'shift' || key == 'ctrl' || key == 'alt' || key == 'meta'; - } - - /** - * called to set a 1 second timeout on the specified sequence - * - * this is so after each key press in the sequence you have 1 second - * to press the next key before you have to start over - * - * @returns void - */ - function _resetSequenceTimer() { - clearTimeout(_reset_timer); - _reset_timer = setTimeout(_resetSequences, 1000); - } - - /** - * reverses the map lookup so that we can look for specific keys - * to see what can and can't use keypress - * - * @return {Object} - */ - function _getReverseMap() { - if (!_REVERSE_MAP) { - _REVERSE_MAP = {}; - for (var key in _MAP) { - - // pull out the numeric keypad from here cause keypress should - // be able to detect the keys from the character - if (key > 95 && key < 112) { - continue; - } - - if (_MAP.hasOwnProperty(key)) { - _REVERSE_MAP[_MAP[key]] = key; - } - } - } - return _REVERSE_MAP; - } - - /** - * picks the best action based on the key combination - * - * @param {string} key - character for key - * @param {Array} modifiers - * @param {string=} action passed in - */ - function _pickBestAction(key, modifiers, action) { - - // if no action was picked in we should try to pick the one - // that we think would work best for this key - if (!action) { - action = _getReverseMap()[key] ? 'keydown' : 'keypress'; - } - - // modifier keys don't work as expected with keypress, - // switch to keydown - if (action == 'keypress' && modifiers.length) { - action = 'keydown'; - } - - return action; - } - - /** - * binds a key sequence to an event - * - * @param {string} combo - combo specified in bind call - * @param {Array} keys - * @param {Function} callback - * @param {string=} action - * @returns void - */ - function _bindSequence(combo, keys, callback, action) { - - // start off by adding a sequence level record for this combination - // and setting the level to 0 - _sequence_levels[combo] = 0; - - // if there is no action pick the best one for the first key - // in the sequence - if (!action) { - action = _pickBestAction(keys[0], []); - } - - /** - * callback to increase the sequence level for this sequence and reset - * all other sequences that were active - * - * @param {Event} e - * @returns void - */ - var _increaseSequence = function(e) { - _inside_sequence = action; - ++_sequence_levels[combo]; - _resetSequenceTimer(); - }, - - /** - * wraps the specified callback inside of another function in order - * to reset all sequence counters as soon as this sequence is done - * - * @param {Event} e - * @returns void - */ - _callbackAndReset = function(e) { - _fireCallback(callback, e); - - // we should ignore the next key up if the action is key down - // or keypress. this is so if you finish a sequence and - // release the key the final key will not trigger a keyup - if (action !== 'keyup') { - _ignore_next_keyup = _characterFromEvent(e); - } - - // weird race condition if a sequence ends with the key - // another sequence begins with - setTimeout(_resetSequences, 10); - }, - i; - - // loop through keys one at a time and bind the appropriate callback - // function. for any key leading up to the final one it should - // increase the sequence. after the final, it should reset all sequences - for (i = 0; i < keys.length; ++i) { - _bindSingle(keys[i], i < keys.length - 1 ? _increaseSequence : _callbackAndReset, action, combo, i); - } - } - - /** - * binds a single keyboard combination - * - * @param {string} combination - * @param {Function} callback - * @param {string=} action - * @param {string=} sequence_name - name of sequence if part of sequence - * @param {number=} level - what part of the sequence the command is - * @returns void - */ - function _bindSingle(combination, callback, action, sequence_name, level) { - - // make sure multiple spaces in a row become a single space - combination = combination.replace(/\s+/g, ' '); - - var sequence = combination.split(' '), - i, - key, - keys, - modifiers = []; - - // if this pattern is a sequence of keys then run through this method - // to reprocess each pattern one key at a time - if (sequence.length > 1) { - _bindSequence(combination, sequence, callback, action); - return; - } - - // take the keys from this pattern and figure out what the actual - // pattern is all about - keys = combination === '+' ? ['+'] : combination.split('+'); - - for (i = 0; i < keys.length; ++i) { - key = keys[i]; - - // normalize key names - if (_SPECIAL_ALIASES[key]) { - key = _SPECIAL_ALIASES[key]; - } - - // if this is not a keypress event then we should - // be smart about using shift keys - // this will only work for US keyboards however - if (action && action != 'keypress' && _SHIFT_MAP[key]) { - key = _SHIFT_MAP[key]; - modifiers.push('shift'); - } - - // if this key is a modifier then add it to the list of modifiers - if (_isModifier(key)) { - modifiers.push(key); - } - } - - // depending on what the key combination is - // we will try to pick the best event for it - action = _pickBestAction(key, modifiers, action); - - // make sure to initialize array if this is the first time - // a callback is added for this key - if (!_callbacks[key]) { - _callbacks[key] = []; - } - - // remove an existing match if there is one - _getMatches(key, modifiers, {type: action}, !sequence_name, combination); - - // add this call back to the array - // if it is a sequence put it at the beginning - // if not put it at the end - // - // this is important because the way these are processed expects - // the sequence ones to come first - _callbacks[key][sequence_name ? 'unshift' : 'push']({ - callback: callback, - modifiers: modifiers, - action: action, - seq: sequence_name, - level: level, - combo: combination - }); - } - - /** - * binds multiple combinations to the same callback - * - * @param {Array} combinations - * @param {Function} callback - * @param {string|undefined} action - * @returns void - */ - function _bindMultiple(combinations, callback, action) { - for (var i = 0; i < combinations.length; ++i) { - _bindSingle(combinations[i], callback, action); - } - } - - // start! - _addEvent(document, 'keypress', _handleKey); - _addEvent(document, 'keydown', _handleKey); - _addEvent(document, 'keyup', _handleKey); - - var Mousetrap = { - - /** - * binds an event to mousetrap - * - * can be a single key, a combination of keys separated with +, - * an array of keys, or a sequence of keys separated by spaces - * - * be sure to list the modifier keys first to make sure that the - * correct key ends up getting bound (the last key in the pattern) - * - * @param {string|Array} keys - * @param {Function} callback - * @param {string=} action - 'keypress', 'keydown', or 'keyup' - * @returns void - */ - bind: function(keys, callback, action) { - _bindMultiple(keys instanceof Array ? keys : [keys], callback, action); - _direct_map[keys + ':' + action] = callback; - return this; - }, - - /** - * unbinds an event to mousetrap - * - * the unbinding sets the callback function of the specified key combo - * to an empty function and deletes the corresponding key in the - * _direct_map dict. - * - * the keycombo+action has to be exactly the same as - * it was defined in the bind method - * - * TODO: actually remove this from the _callbacks dictionary instead - * of binding an empty function - * - * @param {string|Array} keys - * @param {string} action - * @returns void - */ - unbind: function(keys, action) { - if (_direct_map[keys + ':' + action]) { - delete _direct_map[keys + ':' + action]; - this.bind(keys, function() {}, action); - } - return this; - }, - - /** - * triggers an event that has already been bound - * - * @param {string} keys - * @param {string=} action - * @returns void - */ - trigger: function(keys, action) { - _direct_map[keys + ':' + action](); - return this; - }, - - /** - * resets the library back to its initial state. this is useful - * if you want to clear out the current keyboard shortcuts and bind - * new ones - for example if you switch to another page - * - * @returns void - */ - reset: function() { - _callbacks = {}; - _direct_map = {}; - return this; - }, - - /** - * should we stop this event before firing off callbacks - * - * @param {Event} e - * @param {Element} element - * @return {boolean} - */ - stopCallback: function(e, element) { - - // if the element has the class "mousetrap" then no need to stop - if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) { - return false; - } - - // stop for input, select, and textarea - return element.tagName == 'INPUT' || element.tagName == 'SELECT' || element.tagName == 'TEXTAREA' || (element.contentEditable && element.contentEditable == 'true'); - } - }; - - // expose mousetrap to the global object - window.Mousetrap = Mousetrap; - - // expose mousetrap as an AMD module - if (typeof define == 'function' && define.amd) { - define('mousetrap', function() { return Mousetrap; }); - } - // browserify support - if(typeof module === 'object' && module.exports) { - module.exports = Mousetrap; - } -}) (); - -},{}],16:[function(require,module,exports){ -(function (global){ -(function() { - var root = this; - var EventEmitter = require('events').EventEmitter; - var _ = require('underscore'); - var intervalParser = /([0-9\.]+)(ms|s|m|h)?/; - var root = global || window; - - // Lil bit of useful polyfill... - if (typeof(Function.prototype.inherits) === 'undefined') { - Function.prototype.inherits = function(parent) { - this.prototype = Object.create(parent.prototype); - }; - } - - if (typeof(Array.prototype.removeOne) === 'undefined') { - Array.prototype.removeOne = function() { - var what, a = arguments, L = a.length, ax; - while (L && this.length) { - what = a[--L]; - while ((ax = this.indexOf(what)) !== -1) { - return this.splice(ax, 1); - } - } - }; - } - - function greatestCommonFactor(intervals) { - var sumOfModuli = 1; - var interval = _.min(intervals); - while (sumOfModuli !== 0) { - sumOfModuli = _.reduce(intervals, function(memo, i){ return memo + (i % interval); }, 0); - if (sumOfModuli !== 0) { - interval -= 10; - } - } - return interval; - } - - function parseEvent(e) { - var intervalGroups = intervalParser.exec(e); - if (!intervalGroups) { - throw new Error('I don\'t understand that particular interval'); - } - var intervalAmount = +intervalGroups[1]; - var intervalType = intervalGroups[2] || 'ms'; - if (intervalType === 's') { - intervalAmount = intervalAmount * 1000; - } else if (intervalType === 'm') { - intervalAmount = intervalAmount * 1000 * 60; - } else if (intervalType === 'h') { - intervalAmount = intervalAmount * 1000 * 60 * 60; - } else if (!!intervalType && intervalType !== 'ms') { - throw new Error('You can only specify intervals of ms, s, m, or h'); - } - if (intervalAmount < 10 || intervalAmount % 10 !== 0) { - // We only deal in 10's of milliseconds for simplicity - throw new Error('You can only specify 10s of milliseconds, trust me on this one'); - } - return { - amount:intervalAmount, - type:intervalType - }; - } - - function EventedLoop() { - this.intervalId = undefined; - this.intervalLength = undefined; - this.intervalsToEmit = {}; - this.currentTick = 1; - this.maxTicks = 0; - this.listeningForFocus = false; - - // Private method - var determineIntervalLength = function () { - var potentialIntervalLength = greatestCommonFactor(_.keys(this.intervalsToEmit)); - var changed = false; - - if (this.intervalLength) { - if (potentialIntervalLength !== this.intervalLength) { - // Looks like we need a new interval - this.intervalLength = potentialIntervalLength; - changed = true; - } - } else { - this.intervalLength = potentialIntervalLength; - } - - this.maxTicks = _.max(_.map(_.keys(this.intervalsToEmit), function(a) { return +a; })) / this.intervalLength; - return changed; - }.bind(this); - - this.on('newListener', function (e) { - if (e === 'removeListener' || e === 'newListener') return; // We don't care about that one - var intervalInfo = parseEvent(e); - var intervalAmount = intervalInfo.amount; - - this.intervalsToEmit[+intervalAmount] = _.union(this.intervalsToEmit[+intervalAmount] || [], [e]); - - if (determineIntervalLength() && this.isStarted()) { - this.stop().start(); - } - }); - - this.on('removeListener', function (e) { - if (EventEmitter.listenerCount(this, e) > 0) return; - var intervalInfo = parseEvent(e); - var intervalAmount = intervalInfo.amount; - - var removedEvent = this.intervalsToEmit[+intervalAmount].removeOne(e); - if (this.intervalsToEmit[+intervalAmount].length === 0) { - delete this.intervalsToEmit[+intervalAmount]; - } - console.log('Determining interval length after removal of', removedEvent); - determineIntervalLength(); - - if (determineIntervalLength() && this.isStarted()) { - this.stop().start(); - } - }); - } - - EventedLoop.inherits(EventEmitter); - - // Public methods - EventedLoop.prototype.tick = function () { - var milliseconds = this.currentTick * this.intervalLength; - _.each(this.intervalsToEmit, function (events, key) { - if (milliseconds % key === 0) { - _.each(events, function(e) { this.emit(e, e, key); }.bind(this)); - } - }.bind(this)); - this.currentTick += 1; - if (this.currentTick > this.maxTicks) { - this.currentTick = 1; - } - return this; - }; - - EventedLoop.prototype.start = function () { - if (!this.intervalLength) { - throw new Error('You haven\'t specified any interval callbacks. Use EventedLoop.on(\'500ms\', function () { ... }) to do so, and then you can start'); - } - if (this.intervalId) { - return console.log('No need to start the loop again, it\'s already started.'); - } - - this.intervalId = setInterval(this.tick.bind(this), this.intervalLength); - - if (root && !this.listeningForFocus && root.addEventListener) { - root.addEventListener('focus', function() { - this.start(); - }.bind(this)); - - root.addEventListener('blur', function() { - this.stop(); - }.bind(this)); - - this.listeningForFocus = true; - } - return this; - }; - - EventedLoop.prototype.stop = function () { - clearInterval(this.intervalId); - this.intervalId = undefined; - return this; - }; - - EventedLoop.prototype.isStarted = function () { - return !!this.intervalId; - }; - - EventedLoop.prototype.every = EventedLoop.prototype.on; - - // Export the EventedLoop object for **Node.js** or other - // commonjs systems. Otherwise, add it as a global object to the root - if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) { - exports = module.exports = EventedLoop; - } - exports.EventedLoop = EventedLoop; - } - if (typeof window !== 'undefined') { - window.EventedLoop = EventedLoop; - } -}).call(this); -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"events":19,"underscore":17}],17:[function(require,module,exports){ -// Underscore.js 1.6.0 -// http://underscorejs.org -// (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors -// Underscore may be freely distributed under the MIT license. - -(function() { - - // Baseline setup - // -------------- - - // Establish the root object, `window` in the browser, or `exports` on the server. - var root = this; - - // Save the previous value of the `_` variable. - var previousUnderscore = root._; - - // Establish the object that gets returned to break out of a loop iteration. - var breaker = {}; - - // Save bytes in the minified (but not gzipped) version: - var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; - - // Create quick reference variables for speed access to core prototypes. - var - push = ArrayProto.push, - slice = ArrayProto.slice, - concat = ArrayProto.concat, - toString = ObjProto.toString, - hasOwnProperty = ObjProto.hasOwnProperty; - - // All **ECMAScript 5** native function implementations that we hope to use - // are declared here. - var - nativeForEach = ArrayProto.forEach, - nativeMap = ArrayProto.map, - nativeReduce = ArrayProto.reduce, - nativeReduceRight = ArrayProto.reduceRight, - nativeFilter = ArrayProto.filter, - nativeEvery = ArrayProto.every, - nativeSome = ArrayProto.some, - nativeIndexOf = ArrayProto.indexOf, - nativeLastIndexOf = ArrayProto.lastIndexOf, - nativeIsArray = Array.isArray, - nativeKeys = Object.keys, - nativeBind = FuncProto.bind; - - // Create a safe reference to the Underscore object for use below. - var _ = function(obj) { - if (obj instanceof _) return obj; - if (!(this instanceof _)) return new _(obj); - this._wrapped = obj; - }; - - // Export the Underscore object for **Node.js**, with - // backwards-compatibility for the old `require()` API. If we're in - // the browser, add `_` as a global object via a string identifier, - // for Closure Compiler "advanced" mode. - if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) { - exports = module.exports = _; - } - exports._ = _; - } else { - root._ = _; - } - - // Current version. - _.VERSION = '1.6.0'; - - // Collection Functions - // -------------------- - - // The cornerstone, an `each` implementation, aka `forEach`. - // Handles objects with the built-in `forEach`, arrays, and raw objects. - // Delegates to **ECMAScript 5**'s native `forEach` if available. - var each = _.each = _.forEach = function(obj, iterator, context) { - if (obj == null) return obj; - if (nativeForEach && obj.forEach === nativeForEach) { - obj.forEach(iterator, context); - } else if (obj.length === +obj.length) { - for (var i = 0, length = obj.length; i < length; i++) { - if (iterator.call(context, obj[i], i, obj) === breaker) return; - } - } else { - var keys = _.keys(obj); - for (var i = 0, length = keys.length; i < length; i++) { - if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return; - } - } - return obj; - }; - - // Return the results of applying the iterator to each element. - // Delegates to **ECMAScript 5**'s native `map` if available. - _.map = _.collect = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); - each(obj, function(value, index, list) { - results.push(iterator.call(context, value, index, list)); - }); - return results; - }; - - var reduceError = 'Reduce of empty array with no initial value'; - - // **Reduce** builds up a single result from a list of values, aka `inject`, - // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. - _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { - var initial = arguments.length > 2; - if (obj == null) obj = []; - if (nativeReduce && obj.reduce === nativeReduce) { - if (context) iterator = _.bind(iterator, context); - return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); - } - each(obj, function(value, index, list) { - if (!initial) { - memo = value; - initial = true; - } else { - memo = iterator.call(context, memo, value, index, list); - } - }); - if (!initial) throw new TypeError(reduceError); - return memo; - }; - - // The right-associative version of reduce, also known as `foldr`. - // Delegates to **ECMAScript 5**'s native `reduceRight` if available. - _.reduceRight = _.foldr = function(obj, iterator, memo, context) { - var initial = arguments.length > 2; - if (obj == null) obj = []; - if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { - if (context) iterator = _.bind(iterator, context); - return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); - } - var length = obj.length; - if (length !== +length) { - var keys = _.keys(obj); - length = keys.length; - } - each(obj, function(value, index, list) { - index = keys ? keys[--length] : --length; - if (!initial) { - memo = obj[index]; - initial = true; - } else { - memo = iterator.call(context, memo, obj[index], index, list); - } - }); - if (!initial) throw new TypeError(reduceError); - return memo; - }; - - // Return the first value which passes a truth test. Aliased as `detect`. - _.find = _.detect = function(obj, predicate, context) { - var result; - any(obj, function(value, index, list) { - if (predicate.call(context, value, index, list)) { - result = value; - return true; - } - }); - return result; - }; - - // Return all the elements that pass a truth test. - // Delegates to **ECMAScript 5**'s native `filter` if available. - // Aliased as `select`. - _.filter = _.select = function(obj, predicate, context) { - var results = []; - if (obj == null) return results; - if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context); - each(obj, function(value, index, list) { - if (predicate.call(context, value, index, list)) results.push(value); - }); - return results; - }; - - // Return all the elements for which a truth test fails. - _.reject = function(obj, predicate, context) { - return _.filter(obj, function(value, index, list) { - return !predicate.call(context, value, index, list); - }, context); - }; - - // Determine whether all of the elements match a truth test. - // Delegates to **ECMAScript 5**'s native `every` if available. - // Aliased as `all`. - _.every = _.all = function(obj, predicate, context) { - predicate || (predicate = _.identity); - var result = true; - if (obj == null) return result; - if (nativeEvery && obj.every === nativeEvery) return obj.every(predicate, context); - each(obj, function(value, index, list) { - if (!(result = result && predicate.call(context, value, index, list))) return breaker; - }); - return !!result; - }; - - // Determine if at least one element in the object matches a truth test. - // Delegates to **ECMAScript 5**'s native `some` if available. - // Aliased as `any`. - var any = _.some = _.any = function(obj, predicate, context) { - predicate || (predicate = _.identity); - var result = false; - if (obj == null) return result; - if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context); - each(obj, function(value, index, list) { - if (result || (result = predicate.call(context, value, index, list))) return breaker; - }); - return !!result; - }; - - // Determine if the array or object contains a given value (using `===`). - // Aliased as `include`. - _.contains = _.include = function(obj, target) { - if (obj == null) return false; - if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; - return any(obj, function(value) { - return value === target; - }); - }; - - // Invoke a method (with arguments) on every item in a collection. - _.invoke = function(obj, method) { - var args = slice.call(arguments, 2); - var isFunc = _.isFunction(method); - return _.map(obj, function(value) { - return (isFunc ? method : value[method]).apply(value, args); - }); - }; - - // Convenience version of a common use case of `map`: fetching a property. - _.pluck = function(obj, key) { - return _.map(obj, _.property(key)); - }; - - // Convenience version of a common use case of `filter`: selecting only objects - // containing specific `key:value` pairs. - _.where = function(obj, attrs) { - return _.filter(obj, _.matches(attrs)); - }; - - // Convenience version of a common use case of `find`: getting the first object - // containing specific `key:value` pairs. - _.findWhere = function(obj, attrs) { - return _.find(obj, _.matches(attrs)); - }; - - // Return the maximum element or (element-based computation). - // Can't optimize arrays of integers longer than 65,535 elements. - // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797) - _.max = function(obj, iterator, context) { - if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { - return Math.max.apply(Math, obj); - } - var result = -Infinity, lastComputed = -Infinity; - each(obj, function(value, index, list) { - var computed = iterator ? iterator.call(context, value, index, list) : value; - if (computed > lastComputed) { - result = value; - lastComputed = computed; - } - }); - return result; - }; - - // Return the minimum element (or element-based computation). - _.min = function(obj, iterator, context) { - if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { - return Math.min.apply(Math, obj); - } - var result = Infinity, lastComputed = Infinity; - each(obj, function(value, index, list) { - var computed = iterator ? iterator.call(context, value, index, list) : value; - if (computed < lastComputed) { - result = value; - lastComputed = computed; - } - }); - return result; - }; - - // Shuffle an array, using the modern version of the - // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle). - _.shuffle = function(obj) { - var rand; - var index = 0; - var shuffled = []; - each(obj, function(value) { - rand = _.random(index++); - shuffled[index - 1] = shuffled[rand]; - shuffled[rand] = value; - }); - return shuffled; - }; - - // Sample **n** random values from a collection. - // If **n** is not specified, returns a single random element. - // The internal `guard` argument allows it to work with `map`. - _.sample = function(obj, n, guard) { - if (n == null || guard) { - if (obj.length !== +obj.length) obj = _.values(obj); - return obj[_.random(obj.length - 1)]; - } - return _.shuffle(obj).slice(0, Math.max(0, n)); - }; - - // An internal function to generate lookup iterators. - var lookupIterator = function(value) { - if (value == null) return _.identity; - if (_.isFunction(value)) return value; - return _.property(value); - }; - - // Sort the object's values by a criterion produced by an iterator. - _.sortBy = function(obj, iterator, context) { - iterator = lookupIterator(iterator); - return _.pluck(_.map(obj, function(value, index, list) { - return { - value: value, - index: index, - criteria: iterator.call(context, value, index, list) - }; - }).sort(function(left, right) { - var a = left.criteria; - var b = right.criteria; - if (a !== b) { - if (a > b || a === void 0) return 1; - if (a < b || b === void 0) return -1; - } - return left.index - right.index; - }), 'value'); - }; - - // An internal function used for aggregate "group by" operations. - var group = function(behavior) { - return function(obj, iterator, context) { - var result = {}; - iterator = lookupIterator(iterator); - each(obj, function(value, index) { - var key = iterator.call(context, value, index, obj); - behavior(result, key, value); - }); - return result; - }; - }; - - // Groups the object's values by a criterion. Pass either a string attribute - // to group by, or a function that returns the criterion. - _.groupBy = group(function(result, key, value) { - _.has(result, key) ? result[key].push(value) : result[key] = [value]; - }); - - // Indexes the object's values by a criterion, similar to `groupBy`, but for - // when you know that your index values will be unique. - _.indexBy = group(function(result, key, value) { - result[key] = value; - }); - - // Counts instances of an object that group by a certain criterion. Pass - // either a string attribute to count by, or a function that returns the - // criterion. - _.countBy = group(function(result, key) { - _.has(result, key) ? result[key]++ : result[key] = 1; - }); - - // Use a comparator function to figure out the smallest index at which - // an object should be inserted so as to maintain order. Uses binary search. - _.sortedIndex = function(array, obj, iterator, context) { - iterator = lookupIterator(iterator); - var value = iterator.call(context, obj); - var low = 0, high = array.length; - while (low < high) { - var mid = (low + high) >>> 1; - iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid; - } - return low; - }; - - // Safely create a real, live array from anything iterable. - _.toArray = function(obj) { - if (!obj) return []; - if (_.isArray(obj)) return slice.call(obj); - if (obj.length === +obj.length) return _.map(obj, _.identity); - return _.values(obj); - }; - - // Return the number of elements in an object. - _.size = function(obj) { - if (obj == null) return 0; - return (obj.length === +obj.length) ? obj.length : _.keys(obj).length; - }; - - // Array Functions - // --------------- - - // Get the first element of an array. Passing **n** will return the first N - // values in the array. Aliased as `head` and `take`. The **guard** check - // allows it to work with `_.map`. - _.first = _.head = _.take = function(array, n, guard) { - if (array == null) return void 0; - if ((n == null) || guard) return array[0]; - if (n < 0) return []; - return slice.call(array, 0, n); - }; - - // Returns everything but the last entry of the array. Especially useful on - // the arguments object. Passing **n** will return all the values in - // the array, excluding the last N. The **guard** check allows it to work with - // `_.map`. - _.initial = function(array, n, guard) { - return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); - }; - - // Get the last element of an array. Passing **n** will return the last N - // values in the array. The **guard** check allows it to work with `_.map`. - _.last = function(array, n, guard) { - if (array == null) return void 0; - if ((n == null) || guard) return array[array.length - 1]; - return slice.call(array, Math.max(array.length - n, 0)); - }; - - // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. - // Especially useful on the arguments object. Passing an **n** will return - // the rest N values in the array. The **guard** - // check allows it to work with `_.map`. - _.rest = _.tail = _.drop = function(array, n, guard) { - return slice.call(array, (n == null) || guard ? 1 : n); - }; - - // Trim out all falsy values from an array. - _.compact = function(array) { - return _.filter(array, _.identity); - }; - - // Internal implementation of a recursive `flatten` function. - var flatten = function(input, shallow, output) { - if (shallow && _.every(input, _.isArray)) { - return concat.apply(output, input); - } - each(input, function(value) { - if (_.isArray(value) || _.isArguments(value)) { - shallow ? push.apply(output, value) : flatten(value, shallow, output); - } else { - output.push(value); - } - }); - return output; - }; - - // Flatten out an array, either recursively (by default), or just one level. - _.flatten = function(array, shallow) { - return flatten(array, shallow, []); - }; - - // Return a version of the array that does not contain the specified value(s). - _.without = function(array) { - return _.difference(array, slice.call(arguments, 1)); - }; - - // Split an array into two arrays: one whose elements all satisfy the given - // predicate, and one whose elements all do not satisfy the predicate. - _.partition = function(array, predicate) { - var pass = [], fail = []; - each(array, function(elem) { - (predicate(elem) ? pass : fail).push(elem); - }); - return [pass, fail]; - }; - - // Produce a duplicate-free version of the array. If the array has already - // been sorted, you have the option of using a faster algorithm. - // Aliased as `unique`. - _.uniq = _.unique = function(array, isSorted, iterator, context) { - if (_.isFunction(isSorted)) { - context = iterator; - iterator = isSorted; - isSorted = false; - } - var initial = iterator ? _.map(array, iterator, context) : array; - var results = []; - var seen = []; - each(initial, function(value, index) { - if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) { - seen.push(value); - results.push(array[index]); - } - }); - return results; - }; - - // Produce an array that contains the union: each distinct element from all of - // the passed-in arrays. - _.union = function() { - return _.uniq(_.flatten(arguments, true)); - }; - - // Produce an array that contains every item shared between all the - // passed-in arrays. - _.intersection = function(array) { - var rest = slice.call(arguments, 1); - return _.filter(_.uniq(array), function(item) { - return _.every(rest, function(other) { - return _.contains(other, item); - }); - }); - }; - - // Take the difference between one array and a number of other arrays. - // Only the elements present in just the first array will remain. - _.difference = function(array) { - var rest = concat.apply(ArrayProto, slice.call(arguments, 1)); - return _.filter(array, function(value){ return !_.contains(rest, value); }); - }; - - // Zip together multiple lists into a single array -- elements that share - // an index go together. - _.zip = function() { - var length = _.max(_.pluck(arguments, 'length').concat(0)); - var results = new Array(length); - for (var i = 0; i < length; i++) { - results[i] = _.pluck(arguments, '' + i); - } - return results; - }; - - // Converts lists into objects. Pass either a single array of `[key, value]` - // pairs, or two parallel arrays of the same length -- one of keys, and one of - // the corresponding values. - _.object = function(list, values) { - if (list == null) return {}; - var result = {}; - for (var i = 0, length = list.length; i < length; i++) { - if (values) { - result[list[i]] = values[i]; - } else { - result[list[i][0]] = list[i][1]; - } - } - return result; - }; - - // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), - // we need this function. Return the position of the first occurrence of an - // item in an array, or -1 if the item is not included in the array. - // Delegates to **ECMAScript 5**'s native `indexOf` if available. - // If the array is large and already in sort order, pass `true` - // for **isSorted** to use binary search. - _.indexOf = function(array, item, isSorted) { - if (array == null) return -1; - var i = 0, length = array.length; - if (isSorted) { - if (typeof isSorted == 'number') { - i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted); - } else { - i = _.sortedIndex(array, item); - return array[i] === item ? i : -1; - } - } - if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); - for (; i < length; i++) if (array[i] === item) return i; - return -1; - }; - - // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. - _.lastIndexOf = function(array, item, from) { - if (array == null) return -1; - var hasIndex = from != null; - if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) { - return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item); - } - var i = (hasIndex ? from : array.length); - while (i--) if (array[i] === item) return i; - return -1; - }; - - // Generate an integer Array containing an arithmetic progression. A port of - // the native Python `range()` function. See - // [the Python documentation](http://docs.python.org/library/functions.html#range). - _.range = function(start, stop, step) { - if (arguments.length <= 1) { - stop = start || 0; - start = 0; - } - step = arguments[2] || 1; - - var length = Math.max(Math.ceil((stop - start) / step), 0); - var idx = 0; - var range = new Array(length); - - while(idx < length) { - range[idx++] = start; - start += step; - } - - return range; - }; - - // Function (ahem) Functions - // ------------------ - - // Reusable constructor function for prototype setting. - var ctor = function(){}; - - // Create a function bound to a given object (assigning `this`, and arguments, - // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if - // available. - _.bind = function(func, context) { - var args, bound; - if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); - if (!_.isFunction(func)) throw new TypeError; - args = slice.call(arguments, 2); - return bound = function() { - if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); - ctor.prototype = func.prototype; - var self = new ctor; - ctor.prototype = null; - var result = func.apply(self, args.concat(slice.call(arguments))); - if (Object(result) === result) return result; - return self; - }; - }; - - // Partially apply a function by creating a version that has had some of its - // arguments pre-filled, without changing its dynamic `this` context. _ acts - // as a placeholder, allowing any combination of arguments to be pre-filled. - _.partial = function(func) { - var boundArgs = slice.call(arguments, 1); - return function() { - var position = 0; - var args = boundArgs.slice(); - for (var i = 0, length = args.length; i < length; i++) { - if (args[i] === _) args[i] = arguments[position++]; - } - while (position < arguments.length) args.push(arguments[position++]); - return func.apply(this, args); - }; - }; - - // Bind a number of an object's methods to that object. Remaining arguments - // are the method names to be bound. Useful for ensuring that all callbacks - // defined on an object belong to it. - _.bindAll = function(obj) { - var funcs = slice.call(arguments, 1); - if (funcs.length === 0) throw new Error('bindAll must be passed function names'); - each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); - return obj; - }; - - // Memoize an expensive function by storing its results. - _.memoize = function(func, hasher) { - var memo = {}; - hasher || (hasher = _.identity); - return function() { - var key = hasher.apply(this, arguments); - return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); - }; - }; - - // Delays a function for the given number of milliseconds, and then calls - // it with the arguments supplied. - _.delay = function(func, wait) { - var args = slice.call(arguments, 2); - return setTimeout(function(){ return func.apply(null, args); }, wait); - }; - - // Defers a function, scheduling it to run after the current call stack has - // cleared. - _.defer = function(func) { - return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); - }; - - // Returns a function, that, when invoked, will only be triggered at most once - // during a given window of time. Normally, the throttled function will run - // as much as it can, without ever going more than once per `wait` duration; - // but if you'd like to disable the execution on the leading edge, pass - // `{leading: false}`. To disable execution on the trailing edge, ditto. - _.throttle = function(func, wait, options) { - var context, args, result; - var timeout = null; - var previous = 0; - options || (options = {}); - var later = function() { - previous = options.leading === false ? 0 : _.now(); - timeout = null; - result = func.apply(context, args); - context = args = null; - }; - return function() { - var now = _.now(); - if (!previous && options.leading === false) previous = now; - var remaining = wait - (now - previous); - context = this; - args = arguments; - if (remaining <= 0) { - clearTimeout(timeout); - timeout = null; - previous = now; - result = func.apply(context, args); - context = args = null; - } else if (!timeout && options.trailing !== false) { - timeout = setTimeout(later, remaining); - } - return result; - }; - }; - - // Returns a function, that, as long as it continues to be invoked, will not - // be triggered. The function will be called after it stops being called for - // N milliseconds. If `immediate` is passed, trigger the function on the - // leading edge, instead of the trailing. - _.debounce = function(func, wait, immediate) { - var timeout, args, context, timestamp, result; - - var later = function() { - var last = _.now() - timestamp; - if (last < wait) { - timeout = setTimeout(later, wait - last); - } else { - timeout = null; - if (!immediate) { - result = func.apply(context, args); - context = args = null; - } - } - }; - - return function() { - context = this; - args = arguments; - timestamp = _.now(); - var callNow = immediate && !timeout; - if (!timeout) { - timeout = setTimeout(later, wait); - } - if (callNow) { - result = func.apply(context, args); - context = args = null; - } - - return result; - }; - }; - - // Returns a function that will be executed at most one time, no matter how - // often you call it. Useful for lazy initialization. - _.once = function(func) { - var ran = false, memo; - return function() { - if (ran) return memo; - ran = true; - memo = func.apply(this, arguments); - func = null; - return memo; - }; - }; - - // Returns the first function passed as an argument to the second, - // allowing you to adjust arguments, run code before and after, and - // conditionally execute the original function. - _.wrap = function(func, wrapper) { - return _.partial(wrapper, func); - }; - - // Returns a function that is the composition of a list of functions, each - // consuming the return value of the function that follows. - _.compose = function() { - var funcs = arguments; - return function() { - var args = arguments; - for (var i = funcs.length - 1; i >= 0; i--) { - args = [funcs[i].apply(this, args)]; - } - return args[0]; - }; - }; - - // Returns a function that will only be executed after being called N times. - _.after = function(times, func) { - return function() { - if (--times < 1) { - return func.apply(this, arguments); - } - }; - }; - - // Object Functions - // ---------------- - - // Retrieve the names of an object's properties. - // Delegates to **ECMAScript 5**'s native `Object.keys` - _.keys = function(obj) { - if (!_.isObject(obj)) return []; - if (nativeKeys) return nativeKeys(obj); - var keys = []; - for (var key in obj) if (_.has(obj, key)) keys.push(key); - return keys; - }; - - // Retrieve the values of an object's properties. - _.values = function(obj) { - var keys = _.keys(obj); - var length = keys.length; - var values = new Array(length); - for (var i = 0; i < length; i++) { - values[i] = obj[keys[i]]; - } - return values; - }; - - // Convert an object into a list of `[key, value]` pairs. - _.pairs = function(obj) { - var keys = _.keys(obj); - var length = keys.length; - var pairs = new Array(length); - for (var i = 0; i < length; i++) { - pairs[i] = [keys[i], obj[keys[i]]]; - } - return pairs; - }; - - // Invert the keys and values of an object. The values must be serializable. - _.invert = function(obj) { - var result = {}; - var keys = _.keys(obj); - for (var i = 0, length = keys.length; i < length; i++) { - result[obj[keys[i]]] = keys[i]; - } - return result; - }; - - // Return a sorted list of the function names available on the object. - // Aliased as `methods` - _.functions = _.methods = function(obj) { - var names = []; - for (var key in obj) { - if (_.isFunction(obj[key])) names.push(key); - } - return names.sort(); - }; - - // Extend a given object with all the properties in passed-in object(s). - _.extend = function(obj) { - each(slice.call(arguments, 1), function(source) { - if (source) { - for (var prop in source) { - obj[prop] = source[prop]; - } - } - }); - return obj; - }; - - // Return a copy of the object only containing the whitelisted properties. - _.pick = function(obj) { - var copy = {}; - var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); - each(keys, function(key) { - if (key in obj) copy[key] = obj[key]; - }); - return copy; - }; - - // Return a copy of the object without the blacklisted properties. - _.omit = function(obj) { - var copy = {}; - var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); - for (var key in obj) { - if (!_.contains(keys, key)) copy[key] = obj[key]; - } - return copy; - }; - - // Fill in a given object with default properties. - _.defaults = function(obj) { - each(slice.call(arguments, 1), function(source) { - if (source) { - for (var prop in source) { - if (obj[prop] === void 0) obj[prop] = source[prop]; - } - } - }); - return obj; - }; - - // Create a (shallow-cloned) duplicate of an object. - _.clone = function(obj) { - if (!_.isObject(obj)) return obj; - return _.isArray(obj) ? obj.slice() : _.extend({}, obj); - }; - - // Invokes interceptor with the obj, and then returns obj. - // The primary purpose of this method is to "tap into" a method chain, in - // order to perform operations on intermediate results within the chain. - _.tap = function(obj, interceptor) { - interceptor(obj); - return obj; - }; - - // Internal recursive comparison function for `isEqual`. - var eq = function(a, b, aStack, bStack) { - // Identical objects are equal. `0 === -0`, but they aren't identical. - // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). - if (a === b) return a !== 0 || 1 / a == 1 / b; - // A strict comparison is necessary because `null == undefined`. - if (a == null || b == null) return a === b; - // Unwrap any wrapped objects. - if (a instanceof _) a = a._wrapped; - if (b instanceof _) b = b._wrapped; - // Compare `[[Class]]` names. - var className = toString.call(a); - if (className != toString.call(b)) return false; - switch (className) { - // Strings, numbers, dates, and booleans are compared by value. - case '[object String]': - // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is - // equivalent to `new String("5")`. - return a == String(b); - case '[object Number]': - // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for - // other numeric values. - return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); - case '[object Date]': - case '[object Boolean]': - // Coerce dates and booleans to numeric primitive values. Dates are compared by their - // millisecond representations. Note that invalid dates with millisecond representations - // of `NaN` are not equivalent. - return +a == +b; - // RegExps are compared by their source patterns and flags. - case '[object RegExp]': - return a.source == b.source && - a.global == b.global && - a.multiline == b.multiline && - a.ignoreCase == b.ignoreCase; - } - if (typeof a != 'object' || typeof b != 'object') return false; - // Assume equality for cyclic structures. The algorithm for detecting cyclic - // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. - var length = aStack.length; - while (length--) { - // Linear search. Performance is inversely proportional to the number of - // unique nested structures. - if (aStack[length] == a) return bStack[length] == b; - } - // Objects with different constructors are not equivalent, but `Object`s - // from different frames are. - var aCtor = a.constructor, bCtor = b.constructor; - if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && - _.isFunction(bCtor) && (bCtor instanceof bCtor)) - && ('constructor' in a && 'constructor' in b)) { - return false; - } - // Add the first object to the stack of traversed objects. - aStack.push(a); - bStack.push(b); - var size = 0, result = true; - // Recursively compare objects and arrays. - if (className == '[object Array]') { - // Compare array lengths to determine if a deep comparison is necessary. - size = a.length; - result = size == b.length; - if (result) { - // Deep compare the contents, ignoring non-numeric properties. - while (size--) { - if (!(result = eq(a[size], b[size], aStack, bStack))) break; - } - } - } else { - // Deep compare objects. - for (var key in a) { - if (_.has(a, key)) { - // Count the expected number of properties. - size++; - // Deep compare each member. - if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break; - } - } - // Ensure that both objects contain the same number of properties. - if (result) { - for (key in b) { - if (_.has(b, key) && !(size--)) break; - } - result = !size; - } - } - // Remove the first object from the stack of traversed objects. - aStack.pop(); - bStack.pop(); - return result; - }; - - // Perform a deep comparison to check if two objects are equal. - _.isEqual = function(a, b) { - return eq(a, b, [], []); - }; - - // Is a given array, string, or object empty? - // An "empty" object has no enumerable own-properties. - _.isEmpty = function(obj) { - if (obj == null) return true; - if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; - for (var key in obj) if (_.has(obj, key)) return false; - return true; - }; - - // Is a given value a DOM element? - _.isElement = function(obj) { - return !!(obj && obj.nodeType === 1); - }; - - // Is a given value an array? - // Delegates to ECMA5's native Array.isArray - _.isArray = nativeIsArray || function(obj) { - return toString.call(obj) == '[object Array]'; - }; - - // Is a given variable an object? - _.isObject = function(obj) { - return obj === Object(obj); - }; - - // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp. - each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) { - _['is' + name] = function(obj) { - return toString.call(obj) == '[object ' + name + ']'; - }; - }); - - // Define a fallback version of the method in browsers (ahem, IE), where - // there isn't any inspectable "Arguments" type. - if (!_.isArguments(arguments)) { - _.isArguments = function(obj) { - return !!(obj && _.has(obj, 'callee')); - }; - } - - // Optimize `isFunction` if appropriate. - if (typeof (/./) !== 'function') { - _.isFunction = function(obj) { - return typeof obj === 'function'; - }; - } - - // Is a given object a finite number? - _.isFinite = function(obj) { - return isFinite(obj) && !isNaN(parseFloat(obj)); - }; - - // Is the given value `NaN`? (NaN is the only number which does not equal itself). - _.isNaN = function(obj) { - return _.isNumber(obj) && obj != +obj; - }; - - // Is a given value a boolean? - _.isBoolean = function(obj) { - return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; - }; - - // Is a given value equal to null? - _.isNull = function(obj) { - return obj === null; - }; - - // Is a given variable undefined? - _.isUndefined = function(obj) { - return obj === void 0; - }; - - // Shortcut function for checking if an object has a given property directly - // on itself (in other words, not on a prototype). - _.has = function(obj, key) { - return hasOwnProperty.call(obj, key); - }; - - // Utility Functions - // ----------------- - - // Run Underscore.js in *noConflict* mode, returning the `_` variable to its - // previous owner. Returns a reference to the Underscore object. - _.noConflict = function() { - root._ = previousUnderscore; - return this; - }; - - // Keep the identity function around for default iterators. - _.identity = function(value) { - return value; - }; - - _.constant = function(value) { - return function () { - return value; - }; - }; - - _.property = function(key) { - return function(obj) { - return obj[key]; - }; - }; - - // Returns a predicate for checking whether an object has a given set of `key:value` pairs. - _.matches = function(attrs) { - return function(obj) { - if (obj === attrs) return true; //avoid comparing an object to itself. - for (var key in attrs) { - if (attrs[key] !== obj[key]) - return false; - } - return true; - } - }; - - // Run a function **n** times. - _.times = function(n, iterator, context) { - var accum = Array(Math.max(0, n)); - for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i); - return accum; - }; - - // Return a random integer between min and max (inclusive). - _.random = function(min, max) { - if (max == null) { - max = min; - min = 0; - } - return min + Math.floor(Math.random() * (max - min + 1)); - }; - - // A (possibly faster) way to get the current timestamp as an integer. - _.now = Date.now || function() { return new Date().getTime(); }; - - // List of HTML entities for escaping. - var entityMap = { - escape: { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''' - } - }; - entityMap.unescape = _.invert(entityMap.escape); - - // Regexes containing the keys and values listed immediately above. - var entityRegexes = { - escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'), - unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g') - }; - - // Functions for escaping and unescaping strings to/from HTML interpolation. - _.each(['escape', 'unescape'], function(method) { - _[method] = function(string) { - if (string == null) return ''; - return ('' + string).replace(entityRegexes[method], function(match) { - return entityMap[method][match]; - }); - }; - }); - - // If the value of the named `property` is a function then invoke it with the - // `object` as context; otherwise, return it. - _.result = function(object, property) { - if (object == null) return void 0; - var value = object[property]; - return _.isFunction(value) ? value.call(object) : value; - }; - - // Add your own custom functions to the Underscore object. - _.mixin = function(obj) { - each(_.functions(obj), function(name) { - var func = _[name] = obj[name]; - _.prototype[name] = function() { - var args = [this._wrapped]; - push.apply(args, arguments); - return result.call(this, func.apply(_, args)); - }; - }); - }; - - // Generate a unique integer id (unique within the entire client session). - // Useful for temporary DOM ids. - var idCounter = 0; - _.uniqueId = function(prefix) { - var id = ++idCounter + ''; - return prefix ? prefix + id : id; - }; - - // By default, Underscore uses ERB-style template delimiters, change the - // following template settings to use alternative delimiters. - _.templateSettings = { - evaluate : /<%([\s\S]+?)%>/g, - interpolate : /<%=([\s\S]+?)%>/g, - escape : /<%-([\s\S]+?)%>/g - }; - - // When customizing `templateSettings`, if you don't want to define an - // interpolation, evaluation or escaping regex, we need one that is - // guaranteed not to match. - var noMatch = /(.)^/; - - // Certain characters need to be escaped so that they can be put into a - // string literal. - var escapes = { - "'": "'", - '\\': '\\', - '\r': 'r', - '\n': 'n', - '\t': 't', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; - - var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; - - // JavaScript micro-templating, similar to John Resig's implementation. - // Underscore templating handles arbitrary delimiters, preserves whitespace, - // and correctly escapes quotes within interpolated code. - _.template = function(text, data, settings) { - var render; - settings = _.defaults({}, settings, _.templateSettings); - - // Combine delimiters into one regular expression via alternation. - var matcher = new RegExp([ - (settings.escape || noMatch).source, - (settings.interpolate || noMatch).source, - (settings.evaluate || noMatch).source - ].join('|') + '|$', 'g'); - - // Compile the template source, escaping string literals appropriately. - var index = 0; - var source = "__p+='"; - text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { - source += text.slice(index, offset) - .replace(escaper, function(match) { return '\\' + escapes[match]; }); - - if (escape) { - source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; - } - if (interpolate) { - source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; - } - if (evaluate) { - source += "';\n" + evaluate + "\n__p+='"; - } - index = offset + match.length; - return match; - }); - source += "';\n"; - - // If a variable is not specified, place data values in local scope. - if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; - - source = "var __t,__p='',__j=Array.prototype.join," + - "print=function(){__p+=__j.call(arguments,'');};\n" + - source + "return __p;\n"; - - try { - render = new Function(settings.variable || 'obj', '_', source); - } catch (e) { - e.source = source; - throw e; - } - - if (data) return render(data, _); - var template = function(data) { - return render.call(this, data, _); - }; - - // Provide the compiled function source as a convenience for precompilation. - template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; - - return template; - }; - - // Add a "chain" function, which will delegate to the wrapper. - _.chain = function(obj) { - return _(obj).chain(); - }; - - // OOP - // --------------- - // If Underscore is called as a function, it returns a wrapped object that - // can be used OO-style. This wrapper holds altered versions of all the - // underscore functions. Wrapped objects may be chained. - - // Helper function to continue chaining intermediate results. - var result = function(obj) { - return this._chain ? _(obj).chain() : obj; - }; - - // Add all of the Underscore functions to the wrapper object. - _.mixin(_); - - // Add all mutator Array functions to the wrapper. - each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { - var method = ArrayProto[name]; - _.prototype[name] = function() { - var obj = this._wrapped; - method.apply(obj, arguments); - if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0]; - return result.call(this, obj); - }; - }); - - // Add all accessor Array functions to the wrapper. - each(['concat', 'join', 'slice'], function(name) { - var method = ArrayProto[name]; - _.prototype[name] = function() { - return result.call(this, method.apply(this._wrapped, arguments)); - }; - }); - - _.extend(_.prototype, { - - // Start chaining a wrapped Underscore object. - chain: function() { - this._chain = true; - return this; - }, - - // Extracts the result from a wrapped and chained object. - value: function() { - return this._wrapped; - } - - }); - - // AMD registration happens at the end for compatibility with AMD loaders - // that may not enforce next-turn semantics on modules. Even though general - // practice for AMD registration is to be anonymous, underscore registers - // as a named module because, like jQuery, it is a base library that is - // popular enough to be bundled in a third party lib, but not be part of - // an AMD load request. Those cases could generate an error when an - // anonymous define() is called outside of a loader request. - if (typeof define === 'function' && define.amd) { - define('underscore', [], function() { - return _; - }); - } -}).call(this); - -},{}],18:[function(require,module,exports){ -/*! Hammer.JS - v1.0.7dev - 2014-02-18 - * http://eightmedia.github.com/hammer.js - * - * Copyright (c) 2014 Jorik Tangelder ; - * Licensed under the MIT license */ - -(function(window, undefined) { - 'use strict'; - -/** - * Hammer - * use this to create instances - * @param {HTMLElement} element - * @param {Object} options - * @returns {Hammer.Instance} - * @constructor - */ -var Hammer = function(element, options) { - return new Hammer.Instance(element, options || {}); -}; - -// default settings -Hammer.defaults = { - // add styles and attributes to the element to prevent the browser from doing - // its native behavior. this doesnt prevent the scrolling, but cancels - // the contextmenu, tap highlighting etc - // set to false to disable this - stop_browser_behavior: { - // this also triggers onselectstart=false for IE - userSelect : 'none', - // this makes the element blocking in IE10 >, you could experiment with the value - // see for more options this issue; https://github.com/EightMedia/hammer.js/issues/241 - touchAction : 'none', - touchCallout : 'none', - contentZooming : 'none', - userDrag : 'none', - tapHighlightColor: 'rgba(0,0,0,0)' - } - - // - // more settings are defined per gesture at gestures.js - // -}; - -// detect touchevents -Hammer.HAS_POINTEREVENTS = window.navigator.pointerEnabled || window.navigator.msPointerEnabled; -Hammer.HAS_TOUCHEVENTS = ('ontouchstart' in window); - -// dont use mouseevents on mobile devices -Hammer.MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android|silk/i; -Hammer.NO_MOUSEEVENTS = Hammer.HAS_TOUCHEVENTS && window.navigator.userAgent.match(Hammer.MOBILE_REGEX); - -// eventtypes per touchevent (start, move, end) -// are filled by Hammer.event.determineEventTypes on setup -Hammer.EVENT_TYPES = {}; - -// direction defines -Hammer.DIRECTION_DOWN = 'down'; -Hammer.DIRECTION_LEFT = 'left'; -Hammer.DIRECTION_UP = 'up'; -Hammer.DIRECTION_RIGHT = 'right'; - -// pointer type -Hammer.POINTER_MOUSE = 'mouse'; -Hammer.POINTER_TOUCH = 'touch'; -Hammer.POINTER_PEN = 'pen'; - -// interval in which Hammer recalculates current velocity in ms -Hammer.UPDATE_VELOCITY_INTERVAL = 20; - -// touch event defines -Hammer.EVENT_START = 'start'; -Hammer.EVENT_MOVE = 'move'; -Hammer.EVENT_END = 'end'; - -// hammer document where the base events are added at -Hammer.DOCUMENT = window.document; - -// plugins and gestures namespaces -Hammer.plugins = Hammer.plugins || {}; -Hammer.gestures = Hammer.gestures || {}; - - -// if the window events are set... -Hammer.READY = false; - -/** - * setup events to detect gestures on the document - */ -function setup() { - if(Hammer.READY) { - return; - } - - // find what eventtypes we add listeners to - Hammer.event.determineEventTypes(); - - // Register all gestures inside Hammer.gestures - Hammer.utils.each(Hammer.gestures, function(gesture){ - Hammer.detection.register(gesture); - }); - - // Add touch events on the document - Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_MOVE, Hammer.detection.detect); - Hammer.event.onTouch(Hammer.DOCUMENT, Hammer.EVENT_END, Hammer.detection.detect); - - // Hammer is ready...! - Hammer.READY = true; -} - -Hammer.utils = { - /** - * extend method, - * also used for cloning when dest is an empty object - * @param {Object} dest - * @param {Object} src - * @parm {Boolean} merge do a merge - * @returns {Object} dest - */ - extend: function extend(dest, src, merge) { - for(var key in src) { - if(dest[key] !== undefined && merge) { - continue; - } - dest[key] = src[key]; - } - return dest; - }, - - - /** - * for each - * @param obj - * @param iterator - */ - each: function(obj, iterator, context) { - var i, length; - // native forEach on arrays - if ('forEach' in obj) { - obj.forEach(iterator, context); - } - // arrays - else if(obj.length !== undefined) { - for (i = 0, length = obj.length; i < length; i++) { - if (iterator.call(context, obj[i], i, obj) === false) { - return; - } - } - } - // objects - else { - for (i in obj) { - if (obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj) === false) { - return; - } - } - } - }, - - /** - * find if a node is in the given parent - * used for event delegation tricks - * @param {HTMLElement} node - * @param {HTMLElement} parent - * @returns {boolean} has_parent - */ - hasParent: function(node, parent) { - while(node) { - if(node == parent) { - return true; - } - node = node.parentNode; - } - return false; - }, - - - /** - * get the center of all the touches - * @param {Array} touches - * @returns {Object} center - */ - getCenter: function getCenter(touches) { - var valuesX = [], valuesY = []; - - Hammer.utils.each(touches, function(touch) { - // I prefer clientX because it ignore the scrolling position - valuesX.push(typeof touch.clientX !== 'undefined' ? touch.clientX : touch.pageX ); - valuesY.push(typeof touch.clientY !== 'undefined' ? touch.clientY : touch.pageY ); - }); - - return { - pageX: ((Math.min.apply(Math, valuesX) + Math.max.apply(Math, valuesX)) / 2), - pageY: ((Math.min.apply(Math, valuesY) + Math.max.apply(Math, valuesY)) / 2) - }; - }, - - - /** - * calculate the velocity between two points - * @param {Number} delta_time - * @param {Number} delta_x - * @param {Number} delta_y - * @returns {Object} velocity - */ - getVelocity: function getVelocity(delta_time, delta_x, delta_y) { - return { - x: Math.abs(delta_x / delta_time) || 0, - y: Math.abs(delta_y / delta_time) || 0 - }; - }, - - - /** - * calculate the angle between two coordinates - * @param {Touch} touch1 - * @param {Touch} touch2 - * @returns {Number} angle - */ - getAngle: function getAngle(touch1, touch2) { - var y = touch2.pageY - touch1.pageY, - x = touch2.pageX - touch1.pageX; - return Math.atan2(y, x) * 180 / Math.PI; - }, - - - /** - * angle to direction define - * @param {Touch} touch1 - * @param {Touch} touch2 - * @returns {String} direction constant, like Hammer.DIRECTION_LEFT - */ - getDirection: function getDirection(touch1, touch2) { - var x = Math.abs(touch1.pageX - touch2.pageX), - y = Math.abs(touch1.pageY - touch2.pageY); - - if(x >= y) { - return touch1.pageX - touch2.pageX > 0 ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT; - } - else { - return touch1.pageY - touch2.pageY > 0 ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN; - } - }, - - - /** - * calculate the distance between two touches - * @param {Touch} touch1 - * @param {Touch} touch2 - * @returns {Number} distance - */ - getDistance: function getDistance(touch1, touch2) { - var x = touch2.pageX - touch1.pageX, - y = touch2.pageY - touch1.pageY; - return Math.sqrt((x * x) + (y * y)); - }, - - - /** - * calculate the scale factor between two touchLists (fingers) - * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out - * @param {Array} start - * @param {Array} end - * @returns {Number} scale - */ - getScale: function getScale(start, end) { - // need two fingers... - if(start.length >= 2 && end.length >= 2) { - return this.getDistance(end[0], end[1]) / - this.getDistance(start[0], start[1]); - } - return 1; - }, - - - /** - * calculate the rotation degrees between two touchLists (fingers) - * @param {Array} start - * @param {Array} end - * @returns {Number} rotation - */ - getRotation: function getRotation(start, end) { - // need two fingers - if(start.length >= 2 && end.length >= 2) { - return this.getAngle(end[1], end[0]) - - this.getAngle(start[1], start[0]); - } - return 0; - }, - - - /** - * boolean if the direction is vertical - * @param {String} direction - * @returns {Boolean} is_vertical - */ - isVertical: function isVertical(direction) { - return (direction == Hammer.DIRECTION_UP || direction == Hammer.DIRECTION_DOWN); - }, - - - /** - * stop browser default behavior with css props - * @param {HtmlElement} element - * @param {Object} css_props - */ - stopDefaultBrowserBehavior: function stopDefaultBrowserBehavior(element, css_props) { - if(!css_props || !element || !element.style) { - return; - } - - // with css properties for modern browsers - Hammer.utils.each(['webkit', 'khtml', 'moz', 'Moz', 'ms', 'o', ''], function(vendor) { - Hammer.utils.each(css_props, function(value, prop) { - // vender prefix at the property - if(vendor) { - prop = vendor + prop.substring(0, 1).toUpperCase() + prop.substring(1); - } - // set the style - if(prop in element.style) { - element.style[prop] = value; - } - }); - }); - - // also the disable onselectstart - if(css_props.userSelect == 'none') { - element.onselectstart = function() { - return false; - }; - } - - // and disable ondragstart - if(css_props.userDrag == 'none') { - element.ondragstart = function() { - return false; - }; - } - }, - - - /** - * reverts all changes made by 'stopDefaultBrowserBehavior' - * @param {HtmlElement} element - * @param {Object} css_props - */ - startDefaultBrowserBehavior: function startDefaultBrowserBehavior(element, css_props) { - if(!css_props || !element || !element.style) { - return; - } - - // with css properties for modern browsers - Hammer.utils.each(['webkit', 'khtml', 'moz', 'Moz', 'ms', 'o', ''], function(vendor) { - Hammer.utils.each(css_props, function(value, prop) { - // vender prefix at the property - if(vendor) { - prop = vendor + prop.substring(0, 1).toUpperCase() + prop.substring(1); - } - // reset the style - if(prop in element.style) { - element.style[prop] = ''; - } - }); - }); - - // also the enable onselectstart - if(css_props.userSelect == 'none') { - element.onselectstart = null; - } - - // and enable ondragstart - if(css_props.userDrag == 'none') { - element.ondragstart = null; - } - } -}; - - -/** - * create new hammer instance - * all methods should return the instance itself, so it is chainable. - * @param {HTMLElement} element - * @param {Object} [options={}] - * @returns {Hammer.Instance} - * @constructor - */ -Hammer.Instance = function(element, options) { - var self = this; - - // setup HammerJS window events and register all gestures - // this also sets up the default options - setup(); - - this.element = element; - - // start/stop detection option - this.enabled = true; - - // merge options - this.options = Hammer.utils.extend( - Hammer.utils.extend({}, Hammer.defaults), - options || {}); - - // add some css to the element to prevent the browser from doing its native behavoir - if(this.options.stop_browser_behavior) { - Hammer.utils.stopDefaultBrowserBehavior(this.element, this.options.stop_browser_behavior); - } - - // start detection on touchstart - this._eventStartHandler = Hammer.event.onTouch(element, Hammer.EVENT_START, function(ev) { - if(self.enabled) { - Hammer.detection.startDetect(self, ev); - } - }); - - // keep a list of user event handlers which needs to be removed when calling 'dispose' - this._eventHandler = []; - - // return instance - return this; -}; - - -Hammer.Instance.prototype = { - /** - * bind events to the instance - * @param {String} gesture - * @param {Function} handler - * @returns {Hammer.Instance} - */ - on: function onEvent(gesture, handler) { - var gestures = gesture.split(' '); - Hammer.utils.each(gestures, function(gesture) { - this.element.addEventListener(gesture, handler, false); - this._eventHandler.push({ gesture: gesture, handler: handler }); - }, this); - return this; - }, - - - /** - * unbind events to the instance - * @param {String} gesture - * @param {Function} handler - * @returns {Hammer.Instance} - */ - off: function offEvent(gesture, handler) { - var gestures = gesture.split(' '); - Hammer.utils.each(gestures, function(gesture) { - this.element.removeEventListener(gesture, handler, false); - - // remove the event handler from the internal list - var index = -1; - Hammer.utils.each(this._eventHandler, function(eventHandler, i) { - if (index === -1 && eventHandler.gesture === gesture && eventHandler.handler === handler) { - index = i; - } - }, this); - - if (index > -1) { - this._eventHandler.splice(index, 1); - } - }, this); - return this; - }, - - - /** - * trigger gesture event - * @param {String} gesture - * @param {Object} [eventData] - * @returns {Hammer.Instance} - */ - trigger: function triggerEvent(gesture, eventData) { - // optional - if(!eventData) { - eventData = {}; - } - - // create DOM event - var event = Hammer.DOCUMENT.createEvent('Event'); - event.initEvent(gesture, true, true); - event.gesture = eventData; - - // trigger on the target if it is in the instance element, - // this is for event delegation tricks - var element = this.element; - if(Hammer.utils.hasParent(eventData.target, element)) { - element = eventData.target; - } - - element.dispatchEvent(event); - return this; - }, - - - /** - * enable of disable hammer.js detection - * @param {Boolean} state - * @returns {Hammer.Instance} - */ - enable: function enable(state) { - this.enabled = state; - return this; - }, - - - /** - * dispose this hammer instance - * @returns {Hammer.Instance} - */ - dispose: function dispose() { - - // undo all changes made by stop_browser_behavior - if(this.options.stop_browser_behavior) { - Hammer.utils.startDefaultBrowserBehavior(this.element, this.options.stop_browser_behavior); - } - - // unbind all custom event handlers - Hammer.utils.each(this._eventHandler, function(eventHandler) { - this.element.removeEventListener(eventHandler.gesture, eventHandler.handler, false); - }, this); - this._eventHandler.length = 0; - - // unbind the start event listener - Hammer.event.unbindDom(this.element, Hammer.EVENT_TYPES[Hammer.EVENT_START], this._eventStartHandler); - return this; - } -}; - - -/** - * this holds the last move event, - * used to fix empty touchend issue - * see the onTouch event for an explanation - * @type {Object} - */ -var last_move_event = null; - - -/** - * when the mouse is hold down, this is true - * @type {Boolean} - */ -var enable_detect = false; - - -/** - * when touch events have been fired, this is true - * @type {Boolean} - */ -var touch_triggered = false; - - -Hammer.event = { - /** - * simple addEventListener - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - */ - bindDom: function(element, type, handler) { - var types = type.split(' '); - Hammer.utils.each(types, function(type){ - element.addEventListener(type, handler, false); - }); - }, - - - /** - * simple removeEventListener - * @param {HTMLElement} element - * @param {String} type - * @param {Function} handler - */ - unbindDom: function(element, type, handler) { - var types = type.split(' '); - Hammer.utils.each(types, function(type){ - element.removeEventListener(type, handler, false); - }); - }, - - - /** - * touch events with mouse fallback - * @param {HTMLElement} element - * @param {String} eventType like Hammer.EVENT_MOVE - * @param {Function} handler - */ - onTouch: function onTouch(element, eventType, handler) { - var self = this; - - var fn = function bindDomOnTouch(ev) { - var sourceEventType = ev.type.toLowerCase(); - - // onmouseup, but when touchend has been fired we do nothing. - // this is for touchdevices which also fire a mouseup on touchend - if(sourceEventType.match(/mouse/) && touch_triggered) { - return; - } - - // mousebutton must be down or a touch event - else if(sourceEventType.match(/touch/) || // touch events are always on screen - sourceEventType.match(/pointerdown/) || // pointerevents touch - (sourceEventType.match(/mouse/) && ev.which === 1) // mouse is pressed - ) { - enable_detect = true; - } - - // mouse isn't pressed - else if(sourceEventType.match(/mouse/) && !ev.which) { - enable_detect = false; - } - - - // we are in a touch event, set the touch triggered bool to true, - // this for the conflicts that may occur on ios and android - if(sourceEventType.match(/touch|pointer/)) { - touch_triggered = true; - } - - // count the total touches on the screen - var count_touches = 0; - - // when touch has been triggered in this detection session - // and we are now handling a mouse event, we stop that to prevent conflicts - if(enable_detect) { - // update pointerevent - if(Hammer.HAS_POINTEREVENTS && eventType != Hammer.EVENT_END) { - count_touches = Hammer.PointerEvent.updatePointer(eventType, ev); - } - // touch - else if(sourceEventType.match(/touch/)) { - count_touches = ev.touches.length; - } - // mouse - else if(!touch_triggered) { - count_touches = sourceEventType.match(/up/) ? 0 : 1; - } - - // if we are in a end event, but when we remove one touch and - // we still have enough, set eventType to move - if(count_touches > 0 && eventType == Hammer.EVENT_END) { - eventType = Hammer.EVENT_MOVE; - } - // no touches, force the end event - else if(!count_touches) { - eventType = Hammer.EVENT_END; - } - - // store the last move event - if(count_touches || last_move_event === null) { - last_move_event = ev; - } - - // trigger the handler - handler.call(Hammer.detection, self.collectEventData(element, eventType, self.getTouchList(last_move_event, eventType), ev)); - - // remove pointerevent from list - if(Hammer.HAS_POINTEREVENTS && eventType == Hammer.EVENT_END) { - count_touches = Hammer.PointerEvent.updatePointer(eventType, ev); - } - } - - // on the end we reset everything - if(!count_touches) { - last_move_event = null; - enable_detect = false; - touch_triggered = false; - Hammer.PointerEvent.reset(); - } - }; - - this.bindDom(element, Hammer.EVENT_TYPES[eventType], fn); - - // return the bound function to be able to unbind it later - return fn; - }, - - - /** - * we have different events for each device/browser - * determine what we need and set them in the Hammer.EVENT_TYPES constant - */ - determineEventTypes: function determineEventTypes() { - // determine the eventtype we want to set - var types; - - // pointerEvents magic - if(Hammer.HAS_POINTEREVENTS) { - types = Hammer.PointerEvent.getEvents(); - } - // on Android, iOS, blackberry, windows mobile we dont want any mouseevents - else if(Hammer.NO_MOUSEEVENTS) { - types = [ - 'touchstart', - 'touchmove', - 'touchend touchcancel']; - } - // for non pointer events browsers and mixed browsers, - // like chrome on windows8 touch laptop - else { - types = [ - 'touchstart mousedown', - 'touchmove mousemove', - 'touchend touchcancel mouseup']; - } - - Hammer.EVENT_TYPES[Hammer.EVENT_START] = types[0]; - Hammer.EVENT_TYPES[Hammer.EVENT_MOVE] = types[1]; - Hammer.EVENT_TYPES[Hammer.EVENT_END] = types[2]; - }, - - - /** - * create touchlist depending on the event - * @param {Object} ev - * @param {String} eventType used by the fakemultitouch plugin - */ - getTouchList: function getTouchList(ev/*, eventType*/) { - // get the fake pointerEvent touchlist - if(Hammer.HAS_POINTEREVENTS) { - return Hammer.PointerEvent.getTouchList(); - } - // get the touchlist - else if(ev.touches) { - return ev.touches; - } - // make fake touchlist from mouse position - else { - ev.identifier = 1; - return [ev]; - } - }, - - - /** - * collect event data for Hammer js - * @param {HTMLElement} element - * @param {String} eventType like Hammer.EVENT_MOVE - * @param {Object} eventData - */ - collectEventData: function collectEventData(element, eventType, touches, ev) { - // find out pointerType - var pointerType = Hammer.POINTER_TOUCH; - if(ev.type.match(/mouse/) || Hammer.PointerEvent.matchType(Hammer.POINTER_MOUSE, ev)) { - pointerType = Hammer.POINTER_MOUSE; - } - - return { - center : Hammer.utils.getCenter(touches), - timeStamp : new Date().getTime(), - target : ev.target, - touches : touches, - eventType : eventType, - pointerType: pointerType, - srcEvent : ev, - - /** - * prevent the browser default actions - * mostly used to disable scrolling of the browser - */ - preventDefault: function() { - if(this.srcEvent.preventManipulation) { - this.srcEvent.preventManipulation(); - } - - if(this.srcEvent.preventDefault) { - this.srcEvent.preventDefault(); - } - }, - - /** - * stop bubbling the event up to its parents - */ - stopPropagation: function() { - this.srcEvent.stopPropagation(); - }, - - /** - * immediately stop gesture detection - * might be useful after a swipe was detected - * @return {*} - */ - stopDetect: function() { - return Hammer.detection.stopDetect(); - } - }; - } -}; - -Hammer.PointerEvent = { - /** - * holds all pointers - * @type {Object} - */ - pointers: {}, - - /** - * get a list of pointers - * @returns {Array} touchlist - */ - getTouchList: function() { - var self = this; - var touchlist = []; - - // we can use forEach since pointerEvents only is in IE10 - Hammer.utils.each(self.pointers, function(pointer){ - touchlist.push(pointer); - }); - - return touchlist; - }, - - /** - * update the position of a pointer - * @param {String} type Hammer.EVENT_END - * @param {Object} pointerEvent - */ - updatePointer: function(type, pointerEvent) { - if(type == Hammer.EVENT_END) { - delete this.pointers[pointerEvent.pointerId]; - } - else { - pointerEvent.identifier = pointerEvent.pointerId; - this.pointers[pointerEvent.pointerId] = pointerEvent; - } - - return Object.keys(this.pointers).length; - }, - - /** - * check if ev matches pointertype - * @param {String} pointerType Hammer.POINTER_MOUSE - * @param {PointerEvent} ev - */ - matchType: function(pointerType, ev) { - if(!ev.pointerType) { - return false; - } - - var pt = ev.pointerType, - types = {}; - types[Hammer.POINTER_MOUSE] = (pt === ev.MSPOINTER_TYPE_MOUSE || pt === Hammer.POINTER_MOUSE); - types[Hammer.POINTER_TOUCH] = (pt === ev.MSPOINTER_TYPE_TOUCH || pt === Hammer.POINTER_TOUCH); - types[Hammer.POINTER_PEN] = (pt === ev.MSPOINTER_TYPE_PEN || pt === Hammer.POINTER_PEN); - return types[pointerType]; - }, - - - /** - * get events - */ - getEvents: function() { - return [ - 'pointerdown MSPointerDown', - 'pointermove MSPointerMove', - 'pointerup pointercancel MSPointerUp MSPointerCancel' - ]; - }, - - /** - * reset the list - */ - reset: function() { - this.pointers = {}; - } -}; - - -Hammer.detection = { - // contains all registred Hammer.gestures in the correct order - gestures: [], - - // data of the current Hammer.gesture detection session - current : null, - - // the previous Hammer.gesture session data - // is a full clone of the previous gesture.current object - previous: null, - - // when this becomes true, no gestures are fired - stopped : false, - - - /** - * start Hammer.gesture detection - * @param {Hammer.Instance} inst - * @param {Object} eventData - */ - startDetect: function startDetect(inst, eventData) { - // already busy with a Hammer.gesture detection on an element - if(this.current) { - return; - } - - this.stopped = false; - - this.current = { - inst : inst, // reference to HammerInstance we're working for - startEvent: Hammer.utils.extend({}, eventData), // start eventData for distances, timing etc - lastEvent : false, // last eventData - lastVEvent: false, // last eventData for velocity. - velocity : false, // current velocity - name : '' // current gesture we're in/detected, can be 'tap', 'hold' etc - }; - - this.detect(eventData); - }, - - - /** - * Hammer.gesture detection - * @param {Object} eventData - */ - detect: function detect(eventData) { - if(!this.current || this.stopped) { - return; - } - - // extend event data with calculations about scale, distance etc - eventData = this.extendEventData(eventData); - - // instance options - var inst_options = this.current.inst.options; - - // call Hammer.gesture handlers - Hammer.utils.each(this.gestures, function(gesture) { - // only when the instance options have enabled this gesture - if(!this.stopped && inst_options[gesture.name] !== false) { - // if a handler returns false, we stop with the detection - if(gesture.handler.call(gesture, eventData, this.current.inst) === false) { - this.stopDetect(); - return false; - } - } - }, this); - - // store as previous event event - if(this.current) { - this.current.lastEvent = eventData; - } - - // endevent, but not the last touch, so dont stop - if(eventData.eventType == Hammer.EVENT_END && !eventData.touches.length - 1) { - this.stopDetect(); - } - - return eventData; - }, - - - /** - * clear the Hammer.gesture vars - * this is called on endDetect, but can also be used when a final Hammer.gesture has been detected - * to stop other Hammer.gestures from being fired - */ - stopDetect: function stopDetect() { - // clone current data to the store as the previous gesture - // used for the double tap gesture, since this is an other gesture detect session - this.previous = Hammer.utils.extend({}, this.current); - - // reset the current - this.current = null; - - // stopped! - this.stopped = true; - }, - - - /** - * extend eventData for Hammer.gestures - * @param {Object} ev - * @returns {Object} ev - */ - extendEventData: function extendEventData(ev) { - var startEv = this.current.startEvent, - lastVEv = this.current.lastVEvent; - - // if the touches change, set the new touches over the startEvent touches - // this because touchevents don't have all the touches on touchstart, or the - // user must place his fingers at the EXACT same time on the screen, which is not realistic - // but, sometimes it happens that both fingers are touching at the EXACT same time - if(startEv && (ev.touches.length != startEv.touches.length || ev.touches === startEv.touches)) { - // extend 1 level deep to get the touchlist with the touch objects - startEv.touches = []; - Hammer.utils.each(ev.touches, function(touch) { - startEv.touches.push(Hammer.utils.extend({}, touch)); - }); - } - - var delta_time = ev.timeStamp - startEv.timeStamp - , delta_x = ev.center.pageX - startEv.center.pageX - , delta_y = ev.center.pageY - startEv.center.pageY - , interimAngle - , interimDirection - , velocity = this.current.velocity; - - if (lastVEv !== false && ev.timeStamp - lastVEv.timeStamp > Hammer.UPDATE_VELOCITY_INTERVAL) { - - velocity = Hammer.utils.getVelocity(ev.timeStamp - lastVEv.timeStamp, ev.center.pageX - lastVEv.center.pageX, ev.center.pageY - lastVEv.center.pageY); - this.current.lastVEvent = ev; - - if (velocity.x > 0 && velocity.y > 0) { - this.current.velocity = velocity; - } - - } else if(this.current.velocity === false) { - velocity = Hammer.utils.getVelocity(delta_time, delta_x, delta_y); - this.current.velocity = velocity; - this.current.lastVEvent = ev; - } - - // end events (e.g. dragend) don't have useful values for interimDirection & interimAngle - // because the previous event has exactly the same coordinates - // so for end events, take the previous values of interimDirection & interimAngle - // instead of recalculating them and getting a spurious '0' - if(ev.eventType === 'end') { - interimAngle = this.current.lastEvent && this.current.lastEvent.interimAngle; - interimDirection = this.current.lastEvent && this.current.lastEvent.interimDirection; - } - else { - interimAngle = this.current.lastEvent && Hammer.utils.getAngle(this.current.lastEvent.center, ev.center); - interimDirection = this.current.lastEvent && Hammer.utils.getDirection(this.current.lastEvent.center, ev.center); - } - - Hammer.utils.extend(ev, { - deltaTime: delta_time, - - deltaX: delta_x, - deltaY: delta_y, - - velocityX: velocity.x, - velocityY: velocity.y, - - distance: Hammer.utils.getDistance(startEv.center, ev.center), - - angle: Hammer.utils.getAngle(startEv.center, ev.center), - interimAngle: interimAngle, - - direction: Hammer.utils.getDirection(startEv.center, ev.center), - interimDirection: interimDirection, - - scale: Hammer.utils.getScale(startEv.touches, ev.touches), - rotation: Hammer.utils.getRotation(startEv.touches, ev.touches), - - startEvent: startEv - }); - - return ev; - }, - - - /** - * register new gesture - * @param {Object} gesture object, see gestures.js for documentation - * @returns {Array} gestures - */ - register: function register(gesture) { - // add an enable gesture options if there is no given - var options = gesture.defaults || {}; - if(options[gesture.name] === undefined) { - options[gesture.name] = true; - } - - // extend Hammer default options with the Hammer.gesture options - Hammer.utils.extend(Hammer.defaults, options, true); - - // set its index - gesture.index = gesture.index || 1000; - - // add Hammer.gesture to the list - this.gestures.push(gesture); - - // sort the list by index - this.gestures.sort(function(a, b) { - if(a.index < b.index) { return -1; } - if(a.index > b.index) { return 1; } - return 0; - }); - - return this.gestures; - } -}; - - -/** - * Drag - * Move with x fingers (default 1) around on the page. Blocking the scrolling when - * moving left and right is a good practice. When all the drag events are blocking - * you disable scrolling on that area. - * @events drag, drapleft, dragright, dragup, dragdown - */ -Hammer.gestures.Drag = { - name : 'drag', - index : 50, - defaults : { - drag_min_distance : 10, - - // Set correct_for_drag_min_distance to true to make the starting point of the drag - // be calculated from where the drag was triggered, not from where the touch started. - // Useful to avoid a jerk-starting drag, which can make fine-adjustments - // through dragging difficult, and be visually unappealing. - correct_for_drag_min_distance: true, - - // set 0 for unlimited, but this can conflict with transform - drag_max_touches : 1, - - // prevent default browser behavior when dragging occurs - // be careful with it, it makes the element a blocking element - // when you are using the drag gesture, it is a good practice to set this true - drag_block_horizontal : false, - drag_block_vertical : false, - - // drag_lock_to_axis keeps the drag gesture on the axis that it started on, - // It disallows vertical directions if the initial direction was horizontal, and vice versa. - drag_lock_to_axis : false, - - // drag lock only kicks in when distance > drag_lock_min_distance - // This way, locking occurs only when the distance has become large enough to reliably determine the direction - drag_lock_min_distance : 25 - }, - - triggered: false, - handler : function dragGesture(ev, inst) { - // current gesture isnt drag, but dragged is true - // this means an other gesture is busy. now call dragend - if(Hammer.detection.current.name != this.name && this.triggered) { - inst.trigger(this.name + 'end', ev); - this.triggered = false; - return; - } - - // max touches - if(inst.options.drag_max_touches > 0 && - ev.touches.length > inst.options.drag_max_touches) { - return; - } - - switch(ev.eventType) { - case Hammer.EVENT_START: - this.triggered = false; - break; - - case Hammer.EVENT_MOVE: - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.distance < inst.options.drag_min_distance && - Hammer.detection.current.name != this.name) { - return; - } - - // we are dragging! - if(Hammer.detection.current.name != this.name) { - Hammer.detection.current.name = this.name; - if(inst.options.correct_for_drag_min_distance && ev.distance > 0) { - // When a drag is triggered, set the event center to drag_min_distance pixels from the original event center. - // Without this correction, the dragged distance would jumpstart at drag_min_distance pixels instead of at 0. - // It might be useful to save the original start point somewhere - var factor = Math.abs(inst.options.drag_min_distance / ev.distance); - Hammer.detection.current.startEvent.center.pageX += ev.deltaX * factor; - Hammer.detection.current.startEvent.center.pageY += ev.deltaY * factor; - - // recalculate event data using new start point - ev = Hammer.detection.extendEventData(ev); - } - } - - // lock drag to axis? - if(Hammer.detection.current.lastEvent.drag_locked_to_axis || (inst.options.drag_lock_to_axis && inst.options.drag_lock_min_distance <= ev.distance)) { - ev.drag_locked_to_axis = true; - } - var last_direction = Hammer.detection.current.lastEvent.direction; - if(ev.drag_locked_to_axis && last_direction !== ev.direction) { - // keep direction on the axis that the drag gesture started on - if(Hammer.utils.isVertical(last_direction)) { - ev.direction = (ev.deltaY < 0) ? Hammer.DIRECTION_UP : Hammer.DIRECTION_DOWN; - } - else { - ev.direction = (ev.deltaX < 0) ? Hammer.DIRECTION_LEFT : Hammer.DIRECTION_RIGHT; - } - } - - // first time, trigger dragstart event - if(!this.triggered) { - inst.trigger(this.name + 'start', ev); - this.triggered = true; - } - - // trigger normal event - inst.trigger(this.name, ev); - - // direction event, like dragdown - inst.trigger(this.name + ev.direction, ev); - - // block the browser events - if((inst.options.drag_block_vertical && Hammer.utils.isVertical(ev.direction)) || - (inst.options.drag_block_horizontal && !Hammer.utils.isVertical(ev.direction))) { - ev.preventDefault(); - } - break; - - case Hammer.EVENT_END: - // trigger dragend - if(this.triggered) { - inst.trigger(this.name + 'end', ev); - } - - this.triggered = false; - break; - } - } -}; - -/** - * Hold - * Touch stays at the same place for x time - * @events hold - */ -Hammer.gestures.Hold = { - name : 'hold', - index : 10, - defaults: { - hold_timeout : 500, - hold_threshold: 1 - }, - timer : null, - handler : function holdGesture(ev, inst) { - switch(ev.eventType) { - case Hammer.EVENT_START: - // clear any running timers - clearTimeout(this.timer); - - // set the gesture so we can check in the timeout if it still is - Hammer.detection.current.name = this.name; - - // set timer and if after the timeout it still is hold, - // we trigger the hold event - this.timer = setTimeout(function() { - if(Hammer.detection.current.name == 'hold') { - inst.trigger('hold', ev); - } - }, inst.options.hold_timeout); - break; - - // when you move or end we clear the timer - case Hammer.EVENT_MOVE: - if(ev.distance > inst.options.hold_threshold) { - clearTimeout(this.timer); - } - break; - - case Hammer.EVENT_END: - clearTimeout(this.timer); - break; - } - } -}; - -/** - * Release - * Called as last, tells the user has released the screen - * @events release - */ -Hammer.gestures.Release = { - name : 'release', - index : Infinity, - handler: function releaseGesture(ev, inst) { - if(ev.eventType == Hammer.EVENT_END) { - inst.trigger(this.name, ev); - } - } -}; - -/** - * Swipe - * triggers swipe events when the end velocity is above the threshold - * @events swipe, swipeleft, swiperight, swipeup, swipedown - */ -Hammer.gestures.Swipe = { - name : 'swipe', - index : 40, - defaults: { - // set 0 for unlimited, but this can conflict with transform - swipe_min_touches: 1, - swipe_max_touches: 1, - swipe_velocity : 0.7 - }, - handler : function swipeGesture(ev, inst) { - if(ev.eventType == Hammer.EVENT_END) { - // max touches - if(inst.options.swipe_max_touches > 0 && - ev.touches.length < inst.options.swipe_min_touches && - ev.touches.length > inst.options.swipe_max_touches) { - return; - } - - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(ev.velocityX > inst.options.swipe_velocity || - ev.velocityY > inst.options.swipe_velocity) { - // trigger swipe events - inst.trigger(this.name, ev); - inst.trigger(this.name + ev.direction, ev); - } - } - } -}; - -/** - * Tap/DoubleTap - * Quick touch at a place or double at the same place - * @events tap, doubletap - */ -Hammer.gestures.Tap = { - name : 'tap', - index : 100, - defaults: { - tap_max_touchtime : 250, - tap_max_distance : 10, - tap_always : true, - doubletap_distance: 20, - doubletap_interval: 300 - }, - handler : function tapGesture(ev, inst) { - if(ev.eventType == Hammer.EVENT_MOVE && !Hammer.detection.current.reachedTapMaxDistance) { - //Track the distance we've moved. If it's above the max ONCE, remember that (fixes #406). - Hammer.detection.current.reachedTapMaxDistance = (ev.distance > inst.options.tap_max_distance); - } else if(ev.eventType == Hammer.EVENT_END && ev.srcEvent.type != 'touchcancel') { - // previous gesture, for the double tap since these are two different gesture detections - var prev = Hammer.detection.previous, - did_doubletap = false; - - // when the touchtime is higher then the max touch time - // or when the moving distance is too much - if(Hammer.detection.current.reachedTapMaxDistance || ev.deltaTime > inst.options.tap_max_touchtime) { - return; - } - - // check if double tap - if(prev && prev.name == 'tap' && - (ev.timeStamp - prev.lastEvent.timeStamp) < inst.options.doubletap_interval && - ev.distance < inst.options.doubletap_distance) { - inst.trigger('doubletap', ev); - did_doubletap = true; - } - - // do a single tap - if(!did_doubletap || inst.options.tap_always) { - Hammer.detection.current.name = 'tap'; - inst.trigger(Hammer.detection.current.name, ev); - } - } - } -}; - -/** - * Touch - * Called as first, tells the user has touched the screen - * @events touch - */ -Hammer.gestures.Touch = { - name : 'touch', - index : -Infinity, - defaults: { - // call preventDefault at touchstart, and makes the element blocking by - // disabling the scrolling of the page, but it improves gestures like - // transforming and dragging. - // be careful with using this, it can be very annoying for users to be stuck - // on the page - prevent_default : false, - - // disable mouse events, so only touch (or pen!) input triggers events - prevent_mouseevents: false - }, - handler : function touchGesture(ev, inst) { - if(inst.options.prevent_mouseevents && ev.pointerType == Hammer.POINTER_MOUSE) { - ev.stopDetect(); - return; - } - - if(inst.options.prevent_default) { - ev.preventDefault(); - } - - if(ev.eventType == Hammer.EVENT_START) { - inst.trigger(this.name, ev); - } - } -}; - - -/** - * Transform - * User want to scale or rotate with 2 fingers - * @events transform, pinch, pinchin, pinchout, rotate - */ -Hammer.gestures.Transform = { - name : 'transform', - index : 45, - defaults : { - // factor, no scale is 1, zoomin is to 0 and zoomout until higher then 1 - transform_min_scale : 0.01, - // rotation in degrees - transform_min_rotation: 1, - // prevent default browser behavior when two touches are on the screen - // but it makes the element a blocking element - // when you are using the transform gesture, it is a good practice to set this true - transform_always_block: false - }, - triggered: false, - handler : function transformGesture(ev, inst) { - // current gesture isnt drag, but dragged is true - // this means an other gesture is busy. now call dragend - if(Hammer.detection.current.name != this.name && this.triggered) { - inst.trigger(this.name + 'end', ev); - this.triggered = false; - return; - } - - // atleast multitouch - if(ev.touches.length < 2) { - return; - } - - // prevent default when two fingers are on the screen - if(inst.options.transform_always_block) { - ev.preventDefault(); - } - - switch(ev.eventType) { - case Hammer.EVENT_START: - this.triggered = false; - break; - - case Hammer.EVENT_MOVE: - var scale_threshold = Math.abs(1 - ev.scale); - var rotation_threshold = Math.abs(ev.rotation); - - // when the distance we moved is too small we skip this gesture - // or we can be already in dragging - if(scale_threshold < inst.options.transform_min_scale && - rotation_threshold < inst.options.transform_min_rotation) { - return; - } - - // we are transforming! - Hammer.detection.current.name = this.name; - - // first time, trigger dragstart event - if(!this.triggered) { - inst.trigger(this.name + 'start', ev); - this.triggered = true; - } - - inst.trigger(this.name, ev); // basic transform event - - // trigger rotate event - if(rotation_threshold > inst.options.transform_min_rotation) { - inst.trigger('rotate', ev); - } - - // trigger pinch event - if(scale_threshold > inst.options.transform_min_scale) { - inst.trigger('pinch', ev); - inst.trigger('pinch' + ((ev.scale < 1) ? 'in' : 'out'), ev); - } - break; - - case Hammer.EVENT_END: - // trigger dragend - if(this.triggered) { - inst.trigger(this.name + 'end', ev); - } - - this.triggered = false; - break; - } - } -}; - - // Based off Lo-Dash's excellent UMD wrapper (slightly modified) - https://github.com/bestiejs/lodash/blob/master/lodash.js#L5515-L5543 - // some AMD build optimizers, like r.js, check for specific condition patterns like the following: - if(typeof define == 'function' && define.amd) { - // define as an anonymous module - define(function() { return Hammer; }); - } - - // check for `exports` after `define` in case a build optimizer adds an `exports` object - else if(typeof module === 'object' && module.exports) { - module.exports = Hammer; - } - - else { - window.Hammer = Hammer; - } - -})(window); - -},{}],19:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; -} -module.exports = EventEmitter; - -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; - -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; - -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; - -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); - this._maxListeners = n; - return this; -}; - -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; - - if (!this._events) - this._events = {}; - - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } - throw TypeError('Uncaught, unspecified "error" event.'); - } - } - - handler = this._events[type]; - - if (isUndefined(handler)) - return false; - - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - handler.apply(this, args); - } - } else if (isObject(handler)) { - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); - } - - return true; -}; - -EventEmitter.prototype.addListener = function(type, listener) { - var m; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events) - this._events = {}; - - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); - - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - var m; - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } - - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } - - return this; -}; - -EventEmitter.prototype.on = EventEmitter.prototype.addListener; - -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - var fired = false; - - function g() { - this.removeListener(type, g); - - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } - - g.listener = listener; - this.on(type, g); - - return this; -}; - -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events || !this._events[type]) - return this; - - list = this._events[type]; - length = list.length; - position = -1; - - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } - - if (position < 0) - return this; - - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } - - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } - - return this; -}; - -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; - - if (!this._events) - return this; - - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } - - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } - - listeners = this._events[type]; - - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; - - return this; -}; - -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; - -EventEmitter.listenerCount = function(emitter, type) { - var ret; - if (!emitter._events || !emitter._events[type]) - ret = 0; - else if (isFunction(emitter._events[type])) - ret = 1; - else - ret = emitter._events[type].length; - return ret; -}; - -function isFunction(arg) { - return typeof arg === 'function'; -} - -function isNumber(arg) { - return typeof arg === 'number'; -} - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} - -function isUndefined(arg) { - return arg === void 0; -} - -},{}]},{},[13]) -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi91c3IvbG9jYWwvbGliL25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCIvVXNlcnMvZGFuL0RldmVsb3BtZW50L3NraWZyZWUtanMvanMvbGliL2NhbnZhc1JlbmRlcmluZ0NvbnRleHQyREV4dGVuc2lvbnMuanMiLCIvVXNlcnMvZGFuL0RldmVsb3BtZW50L3NraWZyZWUtanMvanMvbGliL2V4dGVuZGVycy5qcyIsIi9Vc2Vycy9kYW4vRGV2ZWxvcG1lbnQvc2tpZnJlZS1qcy9qcy9saWIvZ2FtZS5qcyIsIi9Vc2Vycy9kYW4vRGV2ZWxvcG1lbnQvc2tpZnJlZS1qcy9qcy9saWIvZ3VpZC5qcyIsIi9Vc2Vycy9kYW4vRGV2ZWxvcG1lbnQvc2tpZnJlZS1qcy9qcy9saWIvaW5mb0JveC5qcyIsIi9Vc2Vycy9kYW4vRGV2ZWxvcG1lbnQvc2tpZnJlZS1qcy9qcy9saWIvaXNNb2JpbGVEZXZpY2UuanMiLCIvVXNlcnMvZGFuL0RldmVsb3BtZW50L3NraWZyZWUtanMvanMvbGliL21vbnN0ZXIuanMiLCIvVXNlcnMvZGFuL0RldmVsb3BtZW50L3NraWZyZWUtanMvanMvbGliL3BsdWdpbnMuanMiLCIvVXNlcnMvZGFuL0RldmVsb3BtZW50L3NraWZyZWUtanMvanMvbGliL3NraWVyLmpzIiwiL1VzZXJzL2Rhbi9EZXZlbG9wbWVudC9za2lmcmVlLWpzL2pzL2xpYi9zbm93Ym9hcmRlci5qcyIsIi9Vc2Vycy9kYW4vRGV2ZWxvcG1lbnQvc2tpZnJlZS1qcy9qcy9saWIvc3ByaXRlLmpzIiwiL1VzZXJzL2Rhbi9EZXZlbG9wbWVudC9za2lmcmVlLWpzL2pzL2xpYi9zcHJpdGVBcnJheS5qcyIsIi9Vc2Vycy9kYW4vRGV2ZWxvcG1lbnQvc2tpZnJlZS1qcy9qcy9tYWluLmpzIiwiL1VzZXJzL2Rhbi9EZXZlbG9wbWVudC9za2lmcmVlLWpzL2pzL3Nwcml0ZUluZm8uanMiLCIvVXNlcnMvZGFuL0RldmVsb3BtZW50L3NraWZyZWUtanMvbm9kZV9tb2R1bGVzL2JyLW1vdXNldHJhcC9tb3VzZXRyYXAuanMiLCIvVXNlcnMvZGFuL0RldmVsb3BtZW50L3NraWZyZWUtanMvbm9kZV9tb2R1bGVzL2V2ZW50ZWRsb29wL2xpYi9tYWluLmpzIiwiL1VzZXJzL2Rhbi9EZXZlbG9wbWVudC9za2lmcmVlLWpzL25vZGVfbW9kdWxlcy9ldmVudGVkbG9vcC9ub2RlX21vZHVsZXMvdW5kZXJzY29yZS91bmRlcnNjb3JlLmpzIiwiL1VzZXJzL2Rhbi9EZXZlbG9wbWVudC9za2lmcmVlLWpzL25vZGVfbW9kdWxlcy9oYW1tZXJqcy9oYW1tZXIuanMiLCIvdXNyL2xvY2FsL2xpYi9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvZXZlbnRzL2V2ZW50cy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbERBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdmZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4REE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlZQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy95QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy96Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxOUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiQ2FudmFzUmVuZGVyaW5nQ29udGV4dDJELnByb3RvdHlwZS5zdG9yZUxvYWRlZEltYWdlID0gZnVuY3Rpb24gKGtleSwgaW1hZ2UpIHtcblx0aWYgKCF0aGlzLmltYWdlcykge1xuXHRcdHRoaXMuaW1hZ2VzID0ge307XG5cdH1cblxuXHR0aGlzLmltYWdlc1trZXldID0gaW1hZ2U7XG59O1xuXG5DYW52YXNSZW5kZXJpbmdDb250ZXh0MkQucHJvdG90eXBlLmdldExvYWRlZEltYWdlID0gZnVuY3Rpb24gKGtleSkge1xuXHRpZiAodGhpcy5pbWFnZXNba2V5XSkge1xuXHRcdHJldHVybiB0aGlzLmltYWdlc1trZXldO1xuXHR9XG59O1xuXG5DYW52YXNSZW5kZXJpbmdDb250ZXh0MkQucHJvdG90eXBlLmZvbGxvd1Nwcml0ZSA9IGZ1bmN0aW9uIChzcHJpdGUpIHtcblx0dGhpcy5jZW50cmFsU3ByaXRlID0gc3ByaXRlO1xufTtcblxuQ2FudmFzUmVuZGVyaW5nQ29udGV4dDJELnByb3RvdHlwZS5nZXRDZW50cmFsUG9zaXRpb24gPSBmdW5jdGlvbiAoKSB7XG5cdHJldHVybiB7XG5cdFx0bWFwOiB0aGlzLmNlbnRyYWxTcHJpdGUubWFwUG9zaXRpb24sXG5cdFx0Y2FudmFzOiBbIE1hdGgucm91bmQodGhpcy5jYW52YXMud2lkdGggKiAwLjUpLCBNYXRoLnJvdW5kKHRoaXMuY2FudmFzLmhlaWdodCAqIDAuNSksIDBdXG5cdH07XG59O1xuXG5DYW52YXNSZW5kZXJpbmdDb250ZXh0MkQucHJvdG90eXBlLm1hcFBvc2l0aW9uVG9DYW52YXNQb3NpdGlvbiA9IGZ1bmN0aW9uIChwb3NpdGlvbikge1xuXHR2YXIgY2VudHJhbCA9IHRoaXMuZ2V0Q2VudHJhbFBvc2l0aW9uKCk7XG5cdHZhciBjZW50cmFsTWFwUG9zaXRpb24gPSBjZW50cmFsLm1hcDtcblx0dmFyIGNlbnRyYWxDYW52YXNQb3NpdGlvbiA9IGNlbnRyYWwuY2FudmFzO1xuXHR2YXIgbWFwRGlmZmVyZW5jZVggPSBjZW50cmFsTWFwUG9zaXRpb25bMF0gLSBwb3NpdGlvblswXTtcblx0dmFyIG1hcERpZmZlcmVuY2VZID0gY2VudHJhbE1hcFBvc2l0aW9uWzFdIC0gcG9zaXRpb25bMV07XG5cdHJldHVybiBbIGNlbnRyYWxDYW52YXNQb3NpdGlvblswXSAtIG1hcERpZmZlcmVuY2VYLCBjZW50cmFsQ2FudmFzUG9zaXRpb25bMV0gLSBtYXBEaWZmZXJlbmNlWSBdO1xufTtcblxuQ2FudmFzUmVuZGVyaW5nQ29udGV4dDJELnByb3RvdHlwZS5jYW52YXNQb3NpdGlvblRvTWFwUG9zaXRpb24gPSBmdW5jdGlvbiAocG9zaXRpb24pIHtcblx0dmFyIGNlbnRyYWwgPSB0aGlzLmdldENlbnRyYWxQb3NpdGlvbigpO1xuXHR2YXIgY2VudHJhbE1hcFBvc2l0aW9uID0gY2VudHJhbC5tYXA7XG5cdHZhciBjZW50cmFsQ2FudmFzUG9zaXRpb24gPSBjZW50cmFsLmNhbnZhcztcblx0dmFyIG1hcERpZmZlcmVuY2VYID0gY2VudHJhbENhbnZhc1Bvc2l0aW9uWzBdIC0gcG9zaXRpb25bMF07XG5cdHZhciBtYXBEaWZmZXJlbmNlWSA9IGNlbnRyYWxDYW52YXNQb3NpdGlvblsxXSAtIHBvc2l0aW9uWzFdO1xuXHRyZXR1cm4gWyBjZW50cmFsTWFwUG9zaXRpb25bMF0gLSBtYXBEaWZmZXJlbmNlWCwgY2VudHJhbE1hcFBvc2l0aW9uWzFdIC0gbWFwRGlmZmVyZW5jZVkgXTtcbn07XG5cbkNhbnZhc1JlbmRlcmluZ0NvbnRleHQyRC5wcm90b3R5cGUuZ2V0Q2VudHJlT2ZWaWV3cG9ydCA9IGZ1bmN0aW9uICgpIHtcblx0cmV0dXJuICh0aGlzLmNhbnZhcy53aWR0aCAvIDIpLmZsb29yKCk7XG59O1xuXG4vLyBZLXBvcyBjYW52YXMgZnVuY3Rpb25zXG5DYW52YXNSZW5kZXJpbmdDb250ZXh0MkQucHJvdG90eXBlLmdldE1pZGRsZU9mVmlld3BvcnQgPSBmdW5jdGlvbiAoKSB7XG5cdHJldHVybiAodGhpcy5jYW52YXMuaGVpZ2h0IC8gMikuZmxvb3IoKTtcbn07XG5cbkNhbnZhc1JlbmRlcmluZ0NvbnRleHQyRC5wcm90b3R5cGUuZ2V0QmVsb3dWaWV3cG9ydCA9IGZ1bmN0aW9uICgpIHtcblx0cmV0dXJuIHRoaXMuY2FudmFzLmhlaWdodC5mbG9vcigpO1xufTtcblxuQ2FudmFzUmVuZGVyaW5nQ29udGV4dDJELnByb3RvdHlwZS5nZXRNYXBCZWxvd1ZpZXdwb3J0ID0gZnVuY3Rpb24gKCkge1xuXHR2YXIgYmVsb3cgPSB0aGlzLmdldEJlbG93Vmlld3BvcnQoKTtcblx0cmV0dXJuIHRoaXMuY2FudmFzUG9zaXRpb25Ub01hcFBvc2l0aW9uKFsgMCwgYmVsb3cgXSlbMV07XG59O1xuXG5DYW52YXNSZW5kZXJpbmdDb250ZXh0MkQucHJvdG90eXBlLmdldFJhbmRvbWx5SW5UaGVDZW50cmVPZkNhbnZhcyA9IGZ1bmN0aW9uIChidWZmZXIpIHtcblx0dmFyIG1pbiA9IDA7XG5cdHZhciBtYXggPSB0aGlzLmNhbnZhcy53aWR0aDtcblxuXHRpZiAoYnVmZmVyKSB7XG5cdFx0bWluIC09IGJ1ZmZlcjtcblx0XHRtYXggKz0gYnVmZmVyO1xuXHR9XG5cblx0cmV0dXJuIE51bWJlci5yYW5kb20obWluLCBtYXgpO1xufTtcblxuQ2FudmFzUmVuZGVyaW5nQ29udGV4dDJELnByb3RvdHlwZS5nZXRSYW5kb21seUluVGhlQ2VudHJlT2ZNYXAgPSBmdW5jdGlvbiAoYnVmZmVyKSB7XG5cdHZhciByYW5kb20gPSB0aGlzLmdldFJhbmRvbWx5SW5UaGVDZW50cmVPZkNhbnZhcyhidWZmZXIpO1xuXHRyZXR1cm4gdGhpcy5jYW52YXNQb3NpdGlvblRvTWFwUG9zaXRpb24oWyByYW5kb20sIDAgXSlbMF07XG59O1xuXG5DYW52YXNSZW5kZXJpbmdDb250ZXh0MkQucHJvdG90eXBlLmdldFJhbmRvbU1hcFBvc2l0aW9uQmVsb3dWaWV3cG9ydCA9IGZ1bmN0aW9uICgpIHtcblx0dmFyIHhDYW52YXMgPSB0aGlzLmdldFJhbmRvbWx5SW5UaGVDZW50cmVPZkNhbnZhcygpO1xuXHR2YXIgeUNhbnZhcyA9IHRoaXMuZ2V0QmVsb3dWaWV3cG9ydCgpO1xuXHRyZXR1cm4gdGhpcy5jYW52YXNQb3NpdGlvblRvTWFwUG9zaXRpb24oWyB4Q2FudmFzLCB5Q2FudmFzIF0pO1xufTtcblxuQ2FudmFzUmVuZGVyaW5nQ29udGV4dDJELnByb3RvdHlwZS5nZXRSYW5kb21NYXBQb3NpdGlvbkFib3ZlVmlld3BvcnQgPSBmdW5jdGlvbiAoKSB7XG5cdHZhciB4Q2FudmFzID0gdGhpcy5nZXRSYW5kb21seUluVGhlQ2VudHJlT2ZDYW52YXMoKTtcblx0dmFyIHlDYW52YXMgPSB0aGlzLmdldEFib3ZlVmlld3BvcnQoKTtcblx0cmV0dXJuIHRoaXMuY2FudmFzUG9zaXRpb25Ub01hcFBvc2l0aW9uKFsgeENhbnZhcywgeUNhbnZhcyBdKTtcbn07XG5cbkNhbnZhc1JlbmRlcmluZ0NvbnRleHQyRC5wcm90b3R5cGUuZ2V0VG9wT2ZWaWV3cG9ydCA9IGZ1bmN0aW9uICgpIHtcblx0cmV0dXJuIHRoaXMuY2FudmFzUG9zaXRpb25Ub01hcFBvc2l0aW9uKFsgMCwgMCBdKVsxXTtcbn07XG5cbkNhbnZhc1JlbmRlcmluZ0NvbnRleHQyRC5wcm90b3R5cGUuZ2V0QWJvdmVWaWV3cG9ydCA9IGZ1bmN0aW9uICgpIHtcblx0cmV0dXJuIDAgLSAodGhpcy5jYW52YXMuaGVpZ2h0IC8gNCkuZmxvb3IoKTtcbn07IiwiLy8gRXh0ZW5kcyBmdW5jdGlvbiBzbyB0aGF0IG5ldy1hYmxlIG9iamVjdHMgY2FuIGJlIGdpdmVuIG5ldyBtZXRob2RzIGVhc2lseVxuRnVuY3Rpb24ucHJvdG90eXBlLm1ldGhvZCA9IGZ1bmN0aW9uIChuYW1lLCBmdW5jKSB7XG4gICAgdGhpcy5wcm90b3R5cGVbbmFtZV0gPSBmdW5jO1xuICAgIHJldHVybiB0aGlzO1xufTtcblxuLy8gV2lsbCByZXR1cm4gdGhlIG9yaWdpbmFsIG1ldGhvZCBvZiBhbiBvYmplY3Qgd2hlbiBpbmhlcml0aW5nIGZyb20gYW5vdGhlclxuT2JqZWN0Lm1ldGhvZCgnc3VwZXJpb3InLCBmdW5jdGlvbiAobmFtZSkge1xuICAgIHZhciB0aGF0ID0gdGhpcztcbiAgICB2YXIgbWV0aG9kID0gdGhhdFtuYW1lXTtcbiAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiBtZXRob2QuYXBwbHkodGhhdCwgYXJndW1lbnRzKTtcbiAgICB9O1xufSk7IiwidmFyIFNwcml0ZUFycmF5ID0gcmVxdWlyZSgnLi9zcHJpdGVBcnJheScpO1xudmFyIEV2ZW50ZWRMb29wID0gcmVxdWlyZSgnZXZlbnRlZGxvb3AnKTtcblxuKGZ1bmN0aW9uIChnbG9iYWwpIHtcblx0ZnVuY3Rpb24gR2FtZSAobWFpbkNhbnZhcywgcGxheWVyKSB7XG5cdFx0dmFyIHN0YXRpY09iamVjdHMgPSBuZXcgU3ByaXRlQXJyYXkoKTtcblx0XHR2YXIgbW92aW5nT2JqZWN0cyA9IG5ldyBTcHJpdGVBcnJheSgpO1xuXHRcdHZhciB1aUVsZW1lbnRzID0gbmV3IFNwcml0ZUFycmF5KCk7XG5cdFx0dmFyIGRDb250ZXh0ID0gbWFpbkNhbnZhcy5nZXRDb250ZXh0KCcyZCcpO1xuXHRcdHZhciBtb3VzZVggPSBkQ29udGV4dC5nZXRDZW50cmVPZlZpZXdwb3J0KCk7XG5cdFx0dmFyIG1vdXNlWSA9IDA7XG5cdFx0dmFyIHBhdXNlZCA9IGZhbHNlO1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblx0XHR2YXIgYmVmb3JlQ3ljbGVDYWxsYmFja3MgPSBbXTtcblx0XHR2YXIgYWZ0ZXJDeWNsZUNhbGxiYWNrcyA9IFtdO1xuXHRcdHZhciBnYW1lTG9vcCA9IG5ldyBFdmVudGVkTG9vcCgpO1xuXG5cdFx0dGhpcy5hZGRTdGF0aWNPYmplY3QgPSBmdW5jdGlvbiAoc3ByaXRlKSB7XG5cdFx0XHRzdGF0aWNPYmplY3RzLnB1c2goc3ByaXRlKTtcblx0XHR9O1xuXG5cdFx0dGhpcy5hZGRTdGF0aWNPYmplY3RzID0gZnVuY3Rpb24gKHNwcml0ZXMpIHtcblx0XHRcdHNwcml0ZXMuZm9yRWFjaCh0aGlzLmFkZFN0YXRpY09iamVjdC5iaW5kKHRoaXMpKTtcblx0XHR9O1xuXG5cdFx0dGhpcy5hZGRNb3ZpbmdPYmplY3QgPSBmdW5jdGlvbiAobW92aW5nT2JqZWN0LCBtb3ZpbmdPYmplY3RUeXBlKSB7XG5cdFx0XHRpZiAobW92aW5nT2JqZWN0VHlwZSkge1xuXHRcdFx0XHRzdGF0aWNPYmplY3RzLm9uUHVzaChmdW5jdGlvbiAob2JqKSB7XG5cdFx0XHRcdFx0aWYgKG9iai5kYXRhICYmIG9iai5kYXRhLmhpdEJlaGF2aW91clttb3ZpbmdPYmplY3RUeXBlXSkge1xuXHRcdFx0XHRcdFx0b2JqLm9uSGl0dGluZyhtb3ZpbmdPYmplY3QsIG9iai5kYXRhLmhpdEJlaGF2aW91clttb3ZpbmdPYmplY3RUeXBlXSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9LCB0cnVlKTtcblx0XHRcdH1cblxuXHRcdFx0bW92aW5nT2JqZWN0cy5wdXNoKG1vdmluZ09iamVjdCk7XG5cdFx0fTtcblxuXHRcdHRoaXMuYWRkVUlFbGVtZW50ID0gZnVuY3Rpb24gKGVsZW1lbnQpIHtcblx0XHRcdHVpRWxlbWVudHMucHVzaChlbGVtZW50KTtcblx0XHR9O1xuXG5cdFx0dGhpcy5iZWZvcmVDeWNsZSA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuXHRcdFx0YmVmb3JlQ3ljbGVDYWxsYmFja3MucHVzaChjYWxsYmFjayk7XG5cdFx0fTtcblxuXHRcdHRoaXMuYWZ0ZXJDeWNsZSA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuXHRcdFx0YWZ0ZXJDeWNsZUNhbGxiYWNrcy5wdXNoKGNhbGxiYWNrKTtcblx0XHR9O1xuXG5cdFx0dGhpcy5zZXRNb3VzZVggPSBmdW5jdGlvbiAoeCkge1xuXHRcdFx0bW91c2VYID0geDtcblx0XHR9O1xuXG5cdFx0dGhpcy5zZXRNb3VzZVkgPSBmdW5jdGlvbiAoeSkge1xuXHRcdFx0bW91c2VZID0geTtcblx0XHR9O1xuXG5cdFx0cGxheWVyLnNldE1hcFBvc2l0aW9uKDAsIDApO1xuXHRcdHBsYXllci5zZXRNYXBQb3NpdGlvblRhcmdldCgwLCAtMTApO1xuXHRcdGRDb250ZXh0LmZvbGxvd1Nwcml0ZShwbGF5ZXIpO1xuXG5cdFx0dmFyIGludGVydmFsTnVtID0gMDtcblxuXHRcdHRoaXMuY3ljbGUgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRiZWZvcmVDeWNsZUNhbGxiYWNrcy5lYWNoKGZ1bmN0aW9uKGMpIHtcblx0XHRcdFx0YygpO1xuXHRcdFx0fSk7XG5cblx0XHRcdC8vIENsZWFyIGNhbnZhc1xuXHRcdFx0dmFyIG1vdXNlTWFwUG9zaXRpb24gPSBkQ29udGV4dC5jYW52YXNQb3NpdGlvblRvTWFwUG9zaXRpb24oW21vdXNlWCwgbW91c2VZXSk7XG5cblx0XHRcdGlmICghcGxheWVyLmlzSnVtcGluZykge1xuXHRcdFx0XHRwbGF5ZXIuc2V0TWFwUG9zaXRpb25UYXJnZXQobW91c2VNYXBQb3NpdGlvblswXSwgbW91c2VNYXBQb3NpdGlvblsxXSk7XG5cdFx0XHR9XG5cblx0XHRcdGludGVydmFsTnVtKys7XG5cblx0XHRcdHBsYXllci5jeWNsZSgpO1xuXG5cdFx0XHRtb3ZpbmdPYmplY3RzLmVhY2goZnVuY3Rpb24gKG1vdmluZ09iamVjdCwgaSkge1xuXHRcdFx0XHRtb3ZpbmdPYmplY3QuY3ljbGUoZENvbnRleHQpO1xuXHRcdFx0fSk7XG5cdFx0XHRcblx0XHRcdHN0YXRpY09iamVjdHMuY3VsbCgpO1xuXHRcdFx0c3RhdGljT2JqZWN0cy5lYWNoKGZ1bmN0aW9uIChzdGF0aWNPYmplY3QsIGkpIHtcblx0XHRcdFx0aWYgKHN0YXRpY09iamVjdC5jeWNsZSkge1xuXHRcdFx0XHRcdHN0YXRpY09iamVjdC5jeWNsZSgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblxuXHRcdFx0dWlFbGVtZW50cy5lYWNoKGZ1bmN0aW9uICh1aUVsZW1lbnQsIGkpIHtcblx0XHRcdFx0aWYgKHVpRWxlbWVudC5jeWNsZSkge1xuXHRcdFx0XHRcdHVpRWxlbWVudC5jeWNsZSgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblxuXHRcdFx0YWZ0ZXJDeWNsZUNhbGxiYWNrcy5lYWNoKGZ1bmN0aW9uKGMpIHtcblx0XHRcdFx0YygpO1xuXHRcdFx0fSk7XG5cdFx0fTtcblxuXHRcdHRoYXQuZHJhdyA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdC8vIENsZWFyIGNhbnZhc1xuXHRcdFx0bWFpbkNhbnZhcy53aWR0aCA9IG1haW5DYW52YXMud2lkdGg7XG5cblx0XHRcdHBsYXllci5kcmF3KGRDb250ZXh0KTtcblxuXHRcdFx0cGxheWVyLmN5Y2xlKCk7XG5cblx0XHRcdG1vdmluZ09iamVjdHMuZWFjaChmdW5jdGlvbiAobW92aW5nT2JqZWN0LCBpKSB7XG5cdFx0XHRcdG1vdmluZ09iamVjdC5kcmF3KGRDb250ZXh0KTtcblx0XHRcdH0pO1xuXHRcdFx0XG5cdFx0XHRzdGF0aWNPYmplY3RzLmVhY2goZnVuY3Rpb24gKHN0YXRpY09iamVjdCwgaSkge1xuXHRcdFx0XHRpZiAoc3RhdGljT2JqZWN0LmRyYXcpIHtcblx0XHRcdFx0XHRzdGF0aWNPYmplY3QuZHJhdyhkQ29udGV4dCwgJ21haW4nKTtcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cblx0XHRcdHVpRWxlbWVudHMuZWFjaChmdW5jdGlvbiAodWlFbGVtZW50LCBpKSB7XG5cdFx0XHRcdGlmICh1aUVsZW1lbnQuZHJhdykge1xuXHRcdFx0XHRcdHVpRWxlbWVudC5kcmF3KGRDb250ZXh0LCAnbWFpbicpO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHR9O1xuXG5cdFx0dGhpcy5zdGFydCA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdGdhbWVMb29wLnN0YXJ0KCk7XG5cdFx0fTtcblxuXHRcdHRoaXMucGF1c2UgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRwYXVzZWQgPSB0cnVlO1xuXHRcdFx0Z2FtZUxvb3Auc3RvcCgpO1xuXHRcdH07XG5cblx0XHR0aGlzLmlzUGF1c2VkID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0cmV0dXJuIHBhdXNlZDtcblx0XHR9O1xuXG5cdFx0dGhpcy5yZXNldCA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdHBhdXNlZCA9IGZhbHNlO1xuXHRcdFx0c3RhdGljT2JqZWN0cyA9IG5ldyBTcHJpdGVBcnJheSgpO1xuXHRcdFx0bW92aW5nT2JqZWN0cyA9IG5ldyBTcHJpdGVBcnJheSgpO1xuXHRcdFx0bW91c2VYID0gZENvbnRleHQuZ2V0Q2VudHJlT2ZWaWV3cG9ydCgpO1xuXHRcdFx0bW91c2VZID0gMDtcblx0XHRcdHBsYXllci5yZXNldCgpO1xuXHRcdFx0cGxheWVyLnNldE1hcFBvc2l0aW9uKDAsIDAsIDApO1xuXHRcdFx0dGhpcy5zdGFydCgpO1xuXHRcdH0uYmluZCh0aGlzKTtcblxuXHRcdGdhbWVMb29wLm9uKCcyMCcsIHRoaXMuY3ljbGUpO1xuXHRcdGdhbWVMb29wLm9uKCcyMCcsIHRoaXMuZHJhdyk7XG5cdH1cblxuXHRnbG9iYWwuZ2FtZSA9IEdhbWU7XG59KSggdGhpcyApO1xuXG5cbmlmICh0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJykge1xuXHRtb2R1bGUuZXhwb3J0cyA9IHRoaXMuZ2FtZTtcbn0iLCIvLyBDcmVhdGVzIGEgcmFuZG9tIElEIHN0cmluZ1xuKGZ1bmN0aW9uKGdsb2JhbCkge1xuICAgIGZ1bmN0aW9uIGd1aWQgKClcbiAgICB7XG4gICAgICAgIHZhciBTNCA9IGZ1bmN0aW9uICgpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHJldHVybiBNYXRoLmZsb29yKFxuICAgICAgICAgICAgICAgICAgICBNYXRoLnJhbmRvbSgpICogMHgxMDAwMCAvKiA2NTUzNiAqL1xuICAgICAgICAgICAgICAgICkudG9TdHJpbmcoMTYpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICAgICAgUzQoKSArIFM0KCkgKyBcIi1cIiArXG4gICAgICAgICAgICAgICAgUzQoKSArIFwiLVwiICtcbiAgICAgICAgICAgICAgICBTNCgpICsgXCItXCIgK1xuICAgICAgICAgICAgICAgIFM0KCkgKyBcIi1cIiArXG4gICAgICAgICAgICAgICAgUzQoKSArIFM0KCkgKyBTNCgpXG4gICAgICAgICAgICApO1xuICAgIH1cbiAgICBnbG9iYWwuZ3VpZCA9IGd1aWQ7XG59KSh0aGlzKTtcblxuaWYgKHR5cGVvZiBtb2R1bGUgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgbW9kdWxlLmV4cG9ydHMgPSB0aGlzLmd1aWQ7XG59IiwiZnVuY3Rpb24gSW5mb0JveChkYXRhKSB7XG5cdHZhciB0aGF0ID0gdGhpcztcblxuXHR0aGF0LmxpbmVzID0gZGF0YS5pbml0aWFsTGluZXM7XG5cblx0dGhhdC50b3AgPSBkYXRhLnBvc2l0aW9uLnRvcDtcblx0dGhhdC5yaWdodCA9IGRhdGEucG9zaXRpb24ucmlnaHQ7XG5cdHRoYXQuYm90dG9tID0gZGF0YS5wb3NpdGlvbi5ib3R0b207XG5cdHRoYXQubGVmdCA9IGRhdGEucG9zaXRpb24ubGVmdDtcblxuXHR0aGF0LndpZHRoID0gZGF0YS53aWR0aDtcblx0dGhhdC5oZWlnaHQgPSBkYXRhLmhlaWdodDtcblxuXHR0aGF0LnNldExpbmVzID0gZnVuY3Rpb24gKGxpbmVzKSB7XG5cdFx0dGhhdC5saW5lcyA9IGxpbmVzO1xuXHR9O1xuXG5cdHRoYXQuZHJhdyA9IGZ1bmN0aW9uIChkQ29udGV4dCkge1xuXHRcdGRDb250ZXh0LmZvbnQgPSAnMTFweCBtb25vc3BhY2UnO1xuXHRcdHZhciB5T2Zmc2V0ID0gMDtcblx0XHR0aGF0LmxpbmVzLmVhY2goZnVuY3Rpb24gKGxpbmUpIHtcblx0XHRcdHZhciBmb250U2l6ZSA9ICtkQ29udGV4dC5mb250LnNsaWNlKDAsMik7XG5cdFx0XHR2YXIgdGV4dFdpZHRoID0gZENvbnRleHQubWVhc3VyZVRleHQobGluZSkud2lkdGg7XG5cdFx0XHR2YXIgdGV4dEhlaWdodCA9IGZvbnRTaXplICogMS41O1xuXHRcdFx0dmFyIHhQb3MsIHlQb3M7XG5cdFx0XHRpZiAodGhhdC50b3ApIHtcblx0XHRcdFx0eVBvcyA9IHRoYXQudG9wICsgeU9mZnNldDtcblx0XHRcdH0gZWxzZSBpZiAodGhhdC5ib3R0b20pIHtcblx0XHRcdFx0eVBvcyA9IGRDb250ZXh0LmNhbnZhcy5oZWlnaHQgLSB0aGF0LnRvcCAtIHRleHRIZWlnaHQgKyB5T2Zmc2V0O1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAodGhhdC5yaWdodCkge1xuXHRcdFx0XHR4UG9zID0gZENvbnRleHQuY2FudmFzLndpZHRoIC0gdGhhdC5yaWdodCAtIHRleHRXaWR0aDtcblx0XHRcdH0gZWxzZSBpZiAodGhhdC5sZWZ0KSB7XG5cdFx0XHRcdHhQb3MgPSB0aGF0LmxlZnQ7XG5cdFx0XHR9XG5cblx0XHRcdHlPZmZzZXQgKz0gdGV4dEhlaWdodDtcblxuXG5cdFx0XHRkQ29udGV4dC5maWxsVGV4dChsaW5lLCB4UG9zLCB5UG9zKTtcblx0XHR9KTtcblx0fTtcblxuXHRyZXR1cm4gdGhhdDtcbn1cblxuaWYgKHR5cGVvZiBtb2R1bGUgIT09ICd1bmRlZmluZWQnKSB7XG5cdG1vZHVsZS5leHBvcnRzID0gSW5mb0JveDtcbn1cbiIsImZ1bmN0aW9uIGlzTW9iaWxlRGV2aWNlKCkge1xuXHRpZihuYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKC9BbmRyb2lkL2kpIHx8XG5cdFx0bmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgvd2ViT1MvaSkgfHxcblx0XHRuYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKC9pUGhvbmUvaSkgfHxcblx0XHRuYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKC9pUGFkL2kpIHx8XG5cdFx0bmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgvaVBvZC9pKSB8fFxuXHRcdG5hdmlnYXRvci51c2VyQWdlbnQubWF0Y2goL0JsYWNrQmVycnkvaSkgfHxcblx0XHRuYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKC9XaW5kb3dzIFBob25lL2kpXG5cdCkge1xuXHRcdHJldHVybiB0cnVlO1xuXHR9XG5cdGVsc2Uge1xuXHRcdHJldHVybiBmYWxzZTtcblx0fVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGlzTW9iaWxlRGV2aWNlOyIsInZhciBTcHJpdGUgPSByZXF1aXJlKCcuL3Nwcml0ZScpO1xuXG4oZnVuY3Rpb24oZ2xvYmFsKSB7XG5cdGZ1bmN0aW9uIE1vbnN0ZXIoZGF0YSkge1xuXHRcdHZhciB0aGF0ID0gbmV3IFNwcml0ZShkYXRhKTtcblx0XHR2YXIgc3VwZXJfZHJhdyA9IHRoYXQuc3VwZXJpb3IoJ2RyYXcnKTtcblx0XHR2YXIgc3ByaXRlVmVyc2lvbiA9IDE7XG5cdFx0dmFyIGVhdGluZ1N0YWdlID0gMDtcblx0XHR2YXIgc3RhbmRhcmRTcGVlZCA9IDY7XG5cblx0XHR0aGF0LmlzRWF0aW5nID0gZmFsc2U7XG5cdFx0dGhhdC5pc0Z1bGwgPSBmYWxzZTtcblx0XHR0aGF0LnNldFNwZWVkKHN0YW5kYXJkU3BlZWQpO1xuXG5cdFx0dGhhdC5kcmF3ID0gZnVuY3Rpb24oZENvbnRleHQpIHtcblx0XHRcdHZhciBzcHJpdGVQYXJ0VG9Vc2UgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdHZhciB4RGlmZiA9IHRoYXQubW92aW5nVG93YXJkWzBdIC0gdGhhdC5jYW52YXNYO1xuXG5cdFx0XHRcdGlmICh0aGF0LmlzRWF0aW5nKSB7XG5cdFx0XHRcdFx0cmV0dXJuICdlYXRpbmcnICsgZWF0aW5nU3RhZ2U7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoc3ByaXRlVmVyc2lvbiArIDAuMSA+IDIpIHtcblx0XHRcdFx0XHRzcHJpdGVWZXJzaW9uID0gMC4xO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHNwcml0ZVZlcnNpb24gKz0gMC4xO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICh4RGlmZiA+PSAwKSB7XG5cdFx0XHRcdFx0cmV0dXJuICdzRWFzdCcgKyBNYXRoLmNlaWwoc3ByaXRlVmVyc2lvbik7XG5cdFx0XHRcdH0gZWxzZSBpZiAoeERpZmYgPCAwKSB7XG5cdFx0XHRcdFx0cmV0dXJuICdzV2VzdCcgKyBNYXRoLmNlaWwoc3ByaXRlVmVyc2lvbik7XG5cdFx0XHRcdH1cblx0XHRcdH07XG5cblx0XHRcdHJldHVybiBzdXBlcl9kcmF3KGRDb250ZXh0LCBzcHJpdGVQYXJ0VG9Vc2UoKSk7XG5cdFx0fTtcblxuXHRcdGZ1bmN0aW9uIHN0YXJ0RWF0aW5nICh3aGVuRG9uZSkge1xuXHRcdFx0ZWF0aW5nU3RhZ2UgKz0gMTtcblx0XHRcdHRoYXQuaXNFYXRpbmcgPSB0cnVlO1xuXHRcdFx0dGhhdC5pc01vdmluZyA9IGZhbHNlO1xuXHRcdFx0aWYgKGVhdGluZ1N0YWdlIDwgNikge1xuXHRcdFx0XHRzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRzdGFydEVhdGluZyh3aGVuRG9uZSk7XG5cdFx0XHRcdH0sIDMwMCk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRlYXRpbmdTdGFnZSA9IDA7XG5cdFx0XHRcdHRoYXQuaXNFYXRpbmcgPSBmYWxzZTtcblx0XHRcdFx0dGhhdC5pc01vdmluZyA9IHRydWU7XG5cdFx0XHRcdHdoZW5Eb25lKCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhhdC5zdGFydEVhdGluZyA9IHN0YXJ0RWF0aW5nO1xuXG5cdFx0cmV0dXJuIHRoYXQ7XG5cdH1cblxuXHRnbG9iYWwubW9uc3RlciA9IE1vbnN0ZXI7XG59KSggdGhpcyApO1xuXG5cbmlmICh0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJykge1xuXHRtb2R1bGUuZXhwb3J0cyA9IHRoaXMubW9uc3Rlcjtcbn0iLCIvLyBBdm9pZCBgY29uc29sZWAgZXJyb3JzIGluIGJyb3dzZXJzIHRoYXQgbGFjayBhIGNvbnNvbGUuXG4oZnVuY3Rpb24oKSB7XG4gICAgdmFyIG1ldGhvZDtcbiAgICB2YXIgbm9vcCA9IGZ1bmN0aW9uIG5vb3AoKSB7fTtcbiAgICB2YXIgbWV0aG9kcyA9IFtcbiAgICAgICAgJ2Fzc2VydCcsICdjbGVhcicsICdjb3VudCcsICdkZWJ1ZycsICdkaXInLCAnZGlyeG1sJywgJ2Vycm9yJyxcbiAgICAgICAgJ2V4Y2VwdGlvbicsICdncm91cCcsICdncm91cENvbGxhcHNlZCcsICdncm91cEVuZCcsICdpbmZvJywgJ2xvZycsXG4gICAgICAgICdtYXJrVGltZWxpbmUnLCAncHJvZmlsZScsICdwcm9maWxlRW5kJywgJ3RhYmxlJywgJ3RpbWUnLCAndGltZUVuZCcsXG4gICAgICAgICd0aW1lU3RhbXAnLCAndHJhY2UnLCAnd2FybidcbiAgICBdO1xuICAgIHZhciBsZW5ndGggPSBtZXRob2RzLmxlbmd0aDtcbiAgICB2YXIgY29uc29sZSA9ICh3aW5kb3cuY29uc29sZSA9IHdpbmRvdy5jb25zb2xlIHx8IHt9KTtcblxuICAgIHdoaWxlIChsZW5ndGgtLSkge1xuICAgICAgICBtZXRob2QgPSBtZXRob2RzW2xlbmd0aF07XG5cbiAgICAgICAgLy8gT25seSBzdHViIHVuZGVmaW5lZCBtZXRob2RzLlxuICAgICAgICBpZiAoIWNvbnNvbGVbbWV0aG9kXSkge1xuICAgICAgICAgICAgY29uc29sZVttZXRob2RdID0gbm9vcDtcbiAgICAgICAgfVxuICAgIH1cbn0oKSk7IiwidmFyIFNwcml0ZSA9IHJlcXVpcmUoJy4vc3ByaXRlJyk7XG5pZiAodHlwZW9mIG5hdmlnYXRvciAhPT0gJ3VuZGVmaW5lZCcpIHtcblx0bmF2aWdhdG9yLnZpYnJhdGUgPSBuYXZpZ2F0b3IudmlicmF0ZSB8fFxuXHRcdG5hdmlnYXRvci53ZWJraXRWaWJyYXRlIHx8XG5cdFx0bmF2aWdhdG9yLm1velZpYnJhdGUgfHxcblx0XHRuYXZpZ2F0b3IubXNWaWJyYXRlO1xufSBlbHNlIHtcblx0bmF2aWdhdG9yID0ge1xuXHRcdHZpYnJhdGU6IGZhbHNlXG5cdH07XG59XG5cbihmdW5jdGlvbihnbG9iYWwpIHtcblx0ZnVuY3Rpb24gU2tpZXIoZGF0YSkge1xuXHRcdHZhciBkaXNjcmV0ZURpcmVjdGlvbnMgPSB7XG5cdFx0XHQnd2VzdCc6IDI3MCxcblx0XHRcdCd3c1dlc3QnOiAyNDAsXG5cdFx0XHQnc1dlc3QnOiAxOTUsXG5cdFx0XHQnc291dGgnOiAxODAsXG5cdFx0XHQnc0Vhc3QnOiAxNjUsXG5cdFx0XHQnZXNFYXN0JzogMTIwLFxuXHRcdFx0J2Vhc3QnOiA5MFxuXHRcdH07XG5cdFx0dmFyIHRoYXQgPSBuZXcgU3ByaXRlKGRhdGEpO1xuXHRcdHZhciBzdXAgPSB7XG5cdFx0XHRkcmF3OiB0aGF0LnN1cGVyaW9yKCdkcmF3JyksXG5cdFx0XHRjeWNsZTogdGhhdC5zdXBlcmlvcignY3ljbGUnKSxcblx0XHRcdGdldFNwZWVkWDogdGhhdC5zdXBlcmlvcignZ2V0U3BlZWRYJyksXG5cdFx0XHRnZXRTcGVlZFk6IHRoYXQuc3VwZXJpb3IoJ2dldFNwZWVkWScpLFxuXHRcdFx0aGl0czogdGhhdC5zdXBlcmlvcignaGl0cycpXG5cdFx0fTtcblx0XHR2YXIgZGlyZWN0aW9ucyA9IHtcblx0XHRcdGVzRWFzdDogZnVuY3Rpb24oeERpZmYpIHsgcmV0dXJuIHhEaWZmID4gMzAwOyB9LFxuXHRcdFx0c0Vhc3Q6IGZ1bmN0aW9uKHhEaWZmKSB7IHJldHVybiB4RGlmZiA+IDc1OyB9LFxuXHRcdFx0d3NXZXN0OiBmdW5jdGlvbih4RGlmZikgeyByZXR1cm4geERpZmYgPCAtMzAwOyB9LFxuXHRcdFx0c1dlc3Q6IGZ1bmN0aW9uKHhEaWZmKSB7IHJldHVybiB4RGlmZiA8IC03NTsgfVxuXHRcdH07XG5cblx0XHR2YXIgY2FuY2VsYWJsZVN0YXRlVGltZW91dDtcblx0XHR2YXIgY2FuY2VsYWJsZVN0YXRlSW50ZXJ2YWw7XG5cblx0XHR2YXIgY2FuU3BlZWRCb29zdCA9IHRydWU7XG5cblx0XHR2YXIgb2JzdGFjbGVzSGl0ID0gW107XG5cdFx0dmFyIHBpeGVsc1RyYXZlbGxlZCA9IDA7XG5cdFx0dmFyIHN0YW5kYXJkU3BlZWQgPSA1O1xuXHRcdHZhciBib29zdE11bHRpcGxpZXIgPSAyO1xuXHRcdHZhciB0dXJuRWFzZUN5Y2xlcyA9IDcwO1xuXHRcdHZhciBzcGVlZFggPSAwO1xuXHRcdHZhciBzcGVlZFhGYWN0b3IgPSAwO1xuXHRcdHZhciBzcGVlZFkgPSAwO1xuXHRcdHZhciBzcGVlZFlGYWN0b3IgPSAxO1xuXHRcdHZhciB0cmlja1N0ZXAgPSAwOyAvLyBUaGVyZSBhcmUgdGhyZWUgb2YgdGhlc2VcblxuXHRcdHRoYXQuaXNNb3ZpbmcgPSB0cnVlO1xuXHRcdHRoYXQuaGFzQmVlbkhpdCA9IGZhbHNlO1xuXHRcdHRoYXQuaXNKdW1waW5nID0gZmFsc2U7XG5cdFx0dGhhdC5pc1BlcmZvcm1pbmdUcmljayA9IGZhbHNlO1xuXHRcdHRoYXQub25IaXRPYnN0YWNsZUNiID0gZnVuY3Rpb24oKSB7fTtcblx0XHR0aGF0LnNldFNwZWVkKHN0YW5kYXJkU3BlZWQpO1xuXG5cdFx0dGhhdC5yZXNldCA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdG9ic3RhY2xlc0hpdCA9IFtdO1xuXHRcdFx0cGl4ZWxzVHJhdmVsbGVkID0gMDtcblx0XHRcdHRoYXQuaXNNb3ZpbmcgPSB0cnVlO1xuXHRcdFx0dGhhdC5oYXNCZWVuSGl0ID0gZmFsc2U7XG5cdFx0XHRjYW5TcGVlZEJvb3N0ID0gdHJ1ZTtcblx0XHRcdHNldE5vcm1hbCgpO1xuXHRcdH07XG5cblx0XHRmdW5jdGlvbiBzZXROb3JtYWwoKSB7XG5cdFx0XHR0aGF0LnNldFNwZWVkKHN0YW5kYXJkU3BlZWQpO1xuXHRcdFx0dGhhdC5pc01vdmluZyA9IHRydWU7XG5cdFx0XHR0aGF0Lmhhc0JlZW5IaXQgPSBmYWxzZTtcblx0XHRcdHRoYXQuaXNKdW1waW5nID0gZmFsc2U7XG5cdFx0XHR0aGF0LmlzUGVyZm9ybWluZ1RyaWNrID0gZmFsc2U7XG5cdFx0XHRpZiAoY2FuY2VsYWJsZVN0YXRlSW50ZXJ2YWwpIHtcblx0XHRcdFx0Y2xlYXJJbnRlcnZhbChjYW5jZWxhYmxlU3RhdGVJbnRlcnZhbCk7XG5cdFx0XHR9XG5cdFx0XHR0aGF0LnNldE1hcFBvc2l0aW9uKHVuZGVmaW5lZCwgdW5kZWZpbmVkLCAwKTtcblx0XHR9XG5cblx0XHRmdW5jdGlvbiBzZXRDcmFzaGVkKCkge1xuXHRcdFx0dGhhdC5pc01vdmluZyA9IGZhbHNlO1xuXHRcdFx0dGhhdC5oYXNCZWVuSGl0ID0gdHJ1ZTtcblx0XHRcdHRoYXQuaXNKdW1waW5nID0gZmFsc2U7XG5cdFx0XHR0aGF0LmlzUGVyZm9ybWluZ1RyaWNrID0gZmFsc2U7XG5cdFx0XHRpZiAoY2FuY2VsYWJsZVN0YXRlSW50ZXJ2YWwpIHtcblx0XHRcdFx0Y2xlYXJJbnRlcnZhbChjYW5jZWxhYmxlU3RhdGVJbnRlcnZhbCk7XG5cdFx0XHR9XG5cdFx0XHR0aGF0LnNldE1hcFBvc2l0aW9uKHVuZGVmaW5lZCwgdW5kZWZpbmVkLCAwKTtcblx0XHR9XG5cblx0XHRmdW5jdGlvbiBzZXRKdW1waW5nKCkge1xuXHRcdFx0dmFyIGN1cnJlbnRTcGVlZCA9IHRoYXQuZ2V0U3BlZWQoKTtcblx0XHRcdHRoYXQuc2V0U3BlZWQoY3VycmVudFNwZWVkICsgMik7XG5cdFx0XHR0aGF0LnNldFNwZWVkWShjdXJyZW50U3BlZWQgKyAyKTtcblx0XHRcdHRoYXQuaXNNb3ZpbmcgPSB0cnVlO1xuXHRcdFx0dGhhdC5oYXNCZWVuSGl0ID0gZmFsc2U7XG5cdFx0XHR0aGF0LmlzSnVtcGluZyA9IHRydWU7XG5cdFx0XHR0aGF0LnNldE1hcFBvc2l0aW9uKHVuZGVmaW5lZCwgdW5kZWZpbmVkLCAxKTtcblx0XHR9XG5cblx0XHRmdW5jdGlvbiBnZXREaXNjcmV0ZURpcmVjdGlvbigpIHtcblx0XHRcdGlmICh0aGF0LmRpcmVjdGlvbikge1xuXHRcdFx0XHRpZiAodGhhdC5kaXJlY3Rpb24gPD0gOTApIHtcblx0XHRcdFx0XHRyZXR1cm4gJ2Vhc3QnO1xuXHRcdFx0XHR9IGVsc2UgaWYgKHRoYXQuZGlyZWN0aW9uID4gOTAgJiYgdGhhdC5kaXJlY3Rpb24gPCAxNTApIHtcblx0XHRcdFx0XHRyZXR1cm4gJ2VzRWFzdCc7XG5cdFx0XHRcdH0gZWxzZSBpZiAodGhhdC5kaXJlY3Rpb24gPj0gMTUwICYmIHRoYXQuZGlyZWN0aW9uIDwgMTgwKSB7XG5cdFx0XHRcdFx0cmV0dXJuICdzRWFzdCc7XG5cdFx0XHRcdH0gZWxzZSBpZiAodGhhdC5kaXJlY3Rpb24gPT09IDE4MCkge1xuXHRcdFx0XHRcdHJldHVybiAnc291dGgnO1xuXHRcdFx0XHR9IGVsc2UgaWYgKHRoYXQuZGlyZWN0aW9uID4gMTgwICYmIHRoYXQuZGlyZWN0aW9uIDw9IDIxMCkge1xuXHRcdFx0XHRcdHJldHVybiAnc1dlc3QnO1xuXHRcdFx0XHR9IGVsc2UgaWYgKHRoYXQuZGlyZWN0aW9uID4gMjEwICYmIHRoYXQuZGlyZWN0aW9uIDwgMjcwKSB7XG5cdFx0XHRcdFx0cmV0dXJuICd3c1dlc3QnO1xuXHRcdFx0XHR9IGVsc2UgaWYgKHRoYXQuZGlyZWN0aW9uID49IDI3MCkge1xuXHRcdFx0XHRcdHJldHVybiAnd2VzdCc7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0cmV0dXJuICdzb3V0aCc7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHZhciB4RGlmZiA9IHRoYXQubW92aW5nVG93YXJkWzBdIC0gdGhhdC5tYXBQb3NpdGlvblswXTtcblx0XHRcdFx0dmFyIHlEaWZmID0gdGhhdC5tb3ZpbmdUb3dhcmRbMV0gLSB0aGF0Lm1hcFBvc2l0aW9uWzFdO1xuXHRcdFx0XHRpZiAoeURpZmYgPD0gMCkge1xuXHRcdFx0XHRcdGlmICh4RGlmZiA+IDApIHtcblx0XHRcdFx0XHRcdHJldHVybiAnZWFzdCc7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHJldHVybiAnd2VzdCc7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKGRpcmVjdGlvbnMuZXNFYXN0KHhEaWZmKSkge1xuXHRcdFx0XHRcdHJldHVybiAnZXNFYXN0Jztcblx0XHRcdFx0fSBlbHNlIGlmIChkaXJlY3Rpb25zLnNFYXN0KHhEaWZmKSkge1xuXHRcdFx0XHRcdHJldHVybiAnc0Vhc3QnO1xuXHRcdFx0XHR9IGVsc2UgaWYgKGRpcmVjdGlvbnMud3NXZXN0KHhEaWZmKSkge1xuXHRcdFx0XHRcdHJldHVybiAnd3NXZXN0Jztcblx0XHRcdFx0fSBlbHNlIGlmIChkaXJlY3Rpb25zLnNXZXN0KHhEaWZmKSkge1xuXHRcdFx0XHRcdHJldHVybiAnc1dlc3QnO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gJ3NvdXRoJztcblx0XHR9XG5cblx0XHRmdW5jdGlvbiBzZXREaXNjcmV0ZURpcmVjdGlvbihkKSB7XG5cdFx0XHRpZiAoZGlzY3JldGVEaXJlY3Rpb25zW2RdKSB7XG5cdFx0XHRcdHRoYXQuc2V0RGlyZWN0aW9uKGRpc2NyZXRlRGlyZWN0aW9uc1tkXSk7XG5cdFx0XHR9XG5cblx0XHRcdGlmIChkID09PSAnd2VzdCcgfHwgZCA9PT0gJ2Vhc3QnKSB7XG5cdFx0XHRcdHRoYXQuaXNNb3ZpbmcgPSBmYWxzZTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoYXQuaXNNb3ZpbmcgPSB0cnVlO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGdldEJlaW5nRWF0ZW5TcHJpdGUoKSB7XG5cdFx0XHRyZXR1cm4gJ2JsYW5rJztcblx0XHR9XG5cblx0XHRmdW5jdGlvbiBnZXRKdW1waW5nU3ByaXRlKCkge1xuXHRcdFx0cmV0dXJuICdqdW1waW5nJztcblx0XHR9XG5cblx0XHRmdW5jdGlvbiBnZXRUcmlja1Nwcml0ZSgpIHtcblx0XHRcdGNvbnNvbGUubG9nKCdUcmljayBzdGVwIGlzJywgdHJpY2tTdGVwKTtcblx0XHRcdGlmICh0cmlja1N0ZXAgPT09IDApIHtcblx0XHRcdFx0cmV0dXJuICdqdW1waW5nJztcblx0XHRcdH0gZWxzZSBpZiAodHJpY2tTdGVwID09PSAxKSB7XG5cdFx0XHRcdHJldHVybiAnc29tZXJzYXVsdDEnO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cmV0dXJuICdzb21lcnNhdWx0Mic7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhhdC5zdG9wID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0aWYgKHRoYXQuZGlyZWN0aW9uID4gMTgwKSB7XG5cdFx0XHRcdHNldERpc2NyZXRlRGlyZWN0aW9uKCd3ZXN0Jyk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRzZXREaXNjcmV0ZURpcmVjdGlvbignZWFzdCcpO1xuXHRcdFx0fVxuXHRcdH07XG5cblx0XHR0aGF0LnR1cm5FYXN0ID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0dmFyIGRpc2NyZXRlRGlyZWN0aW9uID0gZ2V0RGlzY3JldGVEaXJlY3Rpb24oKTtcblxuXHRcdFx0c3dpdGNoIChkaXNjcmV0ZURpcmVjdGlvbikge1xuXHRcdFx0XHRjYXNlICd3ZXN0Jzpcblx0XHRcdFx0XHRzZXREaXNjcmV0ZURpcmVjdGlvbignd3NXZXN0Jyk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgJ3dzV2VzdCc6XG5cdFx0XHRcdFx0c2V0RGlzY3JldGVEaXJlY3Rpb24oJ3NXZXN0Jyk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgJ3NXZXN0Jzpcblx0XHRcdFx0XHRzZXREaXNjcmV0ZURpcmVjdGlvbignc291dGgnKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAnc291dGgnOlxuXHRcdFx0XHRcdHNldERpc2NyZXRlRGlyZWN0aW9uKCdzRWFzdCcpO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlICdzRWFzdCc6XG5cdFx0XHRcdFx0c2V0RGlzY3JldGVEaXJlY3Rpb24oJ2VzRWFzdCcpO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlICdlc0Vhc3QnOlxuXHRcdFx0XHRcdHNldERpc2NyZXRlRGlyZWN0aW9uKCdlYXN0Jyk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdFx0c2V0RGlzY3JldGVEaXJlY3Rpb24oJ3NvdXRoJyk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdHRoYXQudHVybldlc3QgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHR2YXIgZGlzY3JldGVEaXJlY3Rpb24gPSBnZXREaXNjcmV0ZURpcmVjdGlvbigpO1xuXG5cdFx0XHRzd2l0Y2ggKGRpc2NyZXRlRGlyZWN0aW9uKSB7XG5cdFx0XHRcdGNhc2UgJ2Vhc3QnOlxuXHRcdFx0XHRcdHNldERpc2NyZXRlRGlyZWN0aW9uKCdlc0Vhc3QnKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAnZXNFYXN0Jzpcblx0XHRcdFx0XHRzZXREaXNjcmV0ZURpcmVjdGlvbignc0Vhc3QnKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAnc0Vhc3QnOlxuXHRcdFx0XHRcdHNldERpc2NyZXRlRGlyZWN0aW9uKCdzb3V0aCcpO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlICdzb3V0aCc6XG5cdFx0XHRcdFx0c2V0RGlzY3JldGVEaXJlY3Rpb24oJ3NXZXN0Jyk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgJ3NXZXN0Jzpcblx0XHRcdFx0XHRzZXREaXNjcmV0ZURpcmVjdGlvbignd3NXZXN0Jyk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgJ3dzV2VzdCc6XG5cdFx0XHRcdFx0c2V0RGlzY3JldGVEaXJlY3Rpb24oJ3dlc3QnKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0XHRzZXREaXNjcmV0ZURpcmVjdGlvbignc291dGgnKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdH1cblx0XHR9O1xuXG5cdFx0dGhhdC5zdGVwV2VzdCA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdHRoYXQubWFwUG9zaXRpb25bMF0gLT0gdGhhdC5zcGVlZCAqIDI7XG5cdFx0fTtcblxuXHRcdHRoYXQuc3RlcEVhc3QgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHR0aGF0Lm1hcFBvc2l0aW9uWzBdICs9IHRoYXQuc3BlZWQgKiAyO1xuXHRcdH07XG5cblx0XHR0aGF0LnNldE1hcFBvc2l0aW9uVGFyZ2V0ID0gZnVuY3Rpb24gKHgsIHkpIHtcblx0XHRcdGlmICh0aGF0Lmhhc0JlZW5IaXQpIHJldHVybjtcblxuXHRcdFx0aWYgKE1hdGguYWJzKHRoYXQubWFwUG9zaXRpb25bMF0gLSB4KSA8PSA3NSkge1xuXHRcdFx0XHR4ID0gdGhhdC5tYXBQb3NpdGlvblswXTtcblx0XHRcdH1cblxuXHRcdFx0dGhhdC5tb3ZpbmdUb3dhcmQgPSBbIHgsIHkgXTtcblxuXHRcdFx0Ly8gdGhhdC5yZXNldERpcmVjdGlvbigpO1xuXHRcdH07XG5cblx0XHR0aGF0LnN0YXJ0TW92aW5nSWZQb3NzaWJsZSA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdGlmICghdGhhdC5oYXNCZWVuSGl0ICYmICF0aGF0LmlzQmVpbmdFYXRlbikge1xuXHRcdFx0XHR0aGF0LmlzTW92aW5nID0gdHJ1ZTtcblx0XHRcdH1cblx0XHR9O1xuXG5cdFx0dGhhdC5zZXRUdXJuRWFzZUN5Y2xlcyA9IGZ1bmN0aW9uIChjKSB7XG5cdFx0XHR0dXJuRWFzZUN5Y2xlcyA9IGM7XG5cdFx0fTtcblxuXHRcdHRoYXQuZ2V0UGl4ZWxzVHJhdmVsbGVkRG93bk1vdW50YWluID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0cmV0dXJuIHBpeGVsc1RyYXZlbGxlZDtcblx0XHR9O1xuXG5cdFx0dGhhdC5yZXNldFNwZWVkID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0dGhhdC5zZXRTcGVlZChzdGFuZGFyZFNwZWVkKTtcblx0XHR9O1xuXG5cdFx0dGhhdC5jeWNsZSA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdGlmICggdGhhdC5nZXRTcGVlZFgoKSA8PSAwICYmIHRoYXQuZ2V0U3BlZWRZKCkgPD0gMCApIHtcblx0XHRcdFx0XHRcdHRoYXQuaXNNb3ZpbmcgPSBmYWxzZTtcblx0XHRcdH1cblx0XHRcdGlmICh0aGF0LmlzTW92aW5nKSB7XG5cdFx0XHRcdHBpeGVsc1RyYXZlbGxlZCArPSB0aGF0LnNwZWVkO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAodGhhdC5pc0p1bXBpbmcpIHtcblx0XHRcdFx0dGhhdC5zZXRNYXBQb3NpdGlvblRhcmdldCh1bmRlZmluZWQsIHRoYXQubWFwUG9zaXRpb25bMV0gKyB0aGF0LmdldFNwZWVkKCkpO1xuXHRcdFx0fVxuXG5cdFx0XHRzdXAuY3ljbGUoKTtcblx0XHRcdFxuXHRcdFx0dGhhdC5jaGVja0hpdHRhYmxlT2JqZWN0cygpO1xuXHRcdH07XG5cblx0XHR0aGF0LmRyYXcgPSBmdW5jdGlvbihkQ29udGV4dCkge1xuXHRcdFx0dmFyIHNwcml0ZVBhcnRUb1VzZSA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0aWYgKHRoYXQuaXNCZWluZ0VhdGVuKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGdldEJlaW5nRWF0ZW5TcHJpdGUoKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICh0aGF0LmlzSnVtcGluZykge1xuXHRcdFx0XHRcdGlmICh0aGF0LmlzUGVyZm9ybWluZ1RyaWNrKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZ2V0VHJpY2tTcHJpdGUoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cmV0dXJuIGdldEp1bXBpbmdTcHJpdGUoKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICh0aGF0Lmhhc0JlZW5IaXQpIHtcblx0XHRcdFx0XHRyZXR1cm4gJ2hpdCc7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXR1cm4gZ2V0RGlzY3JldGVEaXJlY3Rpb24oKTtcblx0XHRcdH07XG5cblx0XHRcdHJldHVybiBzdXAuZHJhdyhkQ29udGV4dCwgc3ByaXRlUGFydFRvVXNlKCkpO1xuXHRcdH07XG5cblx0XHR0aGF0LmhpdHMgPSBmdW5jdGlvbiAob2JzKSB7XG5cdFx0XHRpZiAob2JzdGFjbGVzSGl0LmluZGV4T2Yob2JzLmlkKSAhPT0gLTEpIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIW9icy5vY2N1cGllc1pJbmRleCh0aGF0Lm1hcFBvc2l0aW9uWzJdKSkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cblx0XHRcdGlmIChzdXAuaGl0cyhvYnMpKSB7XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fTtcblxuXHRcdHRoYXQuc3BlZWRCb29zdCA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdHZhciBvcmlnaW5hbFNwZWVkID0gdGhhdC5zcGVlZDtcblx0XHRcdGlmIChjYW5TcGVlZEJvb3N0KSB7XG5cdFx0XHRcdGNhblNwZWVkQm9vc3QgPSBmYWxzZTtcblx0XHRcdFx0dGhhdC5zZXRTcGVlZCh0aGF0LnNwZWVkICogYm9vc3RNdWx0aXBsaWVyKTtcblx0XHRcdFx0c2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0dGhhdC5zZXRTcGVlZChvcmlnaW5hbFNwZWVkKTtcblx0XHRcdFx0XHRzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRcdGNhblNwZWVkQm9vc3QgPSB0cnVlO1xuXHRcdFx0XHRcdH0sIDEwMDAwKTtcblx0XHRcdFx0fSwgMjAwMCk7XG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdHRoYXQuYXR0ZW1wdFRyaWNrID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0aWYgKHRoYXQuaXNKdW1waW5nKSB7XG5cdFx0XHRcdHRoYXQuaXNQZXJmb3JtaW5nVHJpY2sgPSB0cnVlO1xuXHRcdFx0XHRjYW5jZWxhYmxlU3RhdGVJbnRlcnZhbCA9IHNldEludGVydmFsKGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRpZiAodHJpY2tTdGVwID49IDIpIHtcblx0XHRcdFx0XHRcdHRyaWNrU3RlcCA9IDA7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHRyaWNrU3RlcCArPSAxO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSwgMzAwKTtcblx0XHRcdH1cblx0XHR9O1xuXG5cdFx0dGhhdC5nZXRTdGFuZGFyZFNwZWVkID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0cmV0dXJuIHN0YW5kYXJkU3BlZWQ7XG5cdFx0fTtcblxuXHRcdGZ1bmN0aW9uIGVhc2VTcGVlZFRvVGFyZ2V0VXNpbmdGYWN0b3Ioc3AsIHRhcmdldFNwZWVkLCBmKSB7XG5cdFx0XHRpZiAoZiA9PT0gMCB8fCBmID09PSAxKSB7XG5cdFx0XHRcdHJldHVybiB0YXJnZXRTcGVlZDtcblx0XHRcdH1cblxuXHRcdFx0aWYgKHNwIDwgdGFyZ2V0U3BlZWQpIHtcblx0XHRcdFx0c3AgKz0gdGhhdC5nZXRTcGVlZCgpICogKGYgLyB0dXJuRWFzZUN5Y2xlcyk7XG5cdFx0XHR9XG5cblx0XHRcdGlmIChzcCA+IHRhcmdldFNwZWVkKSB7XG5cdFx0XHRcdHNwIC09IHRoYXQuZ2V0U3BlZWQoKSAqIChmIC8gdHVybkVhc2VDeWNsZXMpO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gc3A7XG5cdFx0fVxuXG5cdFx0dGhhdC5nZXRTcGVlZFggPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRpZiAoZ2V0RGlzY3JldGVEaXJlY3Rpb24oKSA9PT0gJ2VzRWFzdCcgfHwgZ2V0RGlzY3JldGVEaXJlY3Rpb24oKSA9PT0gJ3dzV2VzdCcpIHtcblx0XHRcdFx0c3BlZWRYRmFjdG9yID0gMC41O1xuXHRcdFx0XHRzcGVlZFggPSBlYXNlU3BlZWRUb1RhcmdldFVzaW5nRmFjdG9yKHNwZWVkWCwgdGhhdC5nZXRTcGVlZCgpICogc3BlZWRYRmFjdG9yLCBzcGVlZFhGYWN0b3IpO1xuXG5cdFx0XHRcdHJldHVybiBzcGVlZFg7XG5cdFx0XHR9XG5cblx0XHRcdGlmIChnZXREaXNjcmV0ZURpcmVjdGlvbigpID09PSAnc0Vhc3QnIHx8IGdldERpc2NyZXRlRGlyZWN0aW9uKCkgPT09ICdzV2VzdCcpIHtcblx0XHRcdFx0c3BlZWRYRmFjdG9yID0gMC4zMztcblx0XHRcdFx0c3BlZWRYID0gZWFzZVNwZWVkVG9UYXJnZXRVc2luZ0ZhY3RvcihzcGVlZFgsIHRoYXQuZ2V0U3BlZWQoKSAqIHNwZWVkWEZhY3Rvciwgc3BlZWRYRmFjdG9yKTtcblxuXHRcdFx0XHRyZXR1cm4gc3BlZWRYO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTbyBpdCBtdXN0IGJlIHNvdXRoXG5cblx0XHRcdHNwZWVkWCA9IGVhc2VTcGVlZFRvVGFyZ2V0VXNpbmdGYWN0b3Ioc3BlZWRYLCAwLCBzcGVlZFhGYWN0b3IpO1xuXG5cdFx0XHRyZXR1cm4gc3BlZWRYO1xuXHRcdH07XG5cblx0XHR0aGF0LnNldFNwZWVkWSA9IGZ1bmN0aW9uKHN5KSB7XG5cdFx0XHRzcGVlZFkgPSBzeTtcblx0XHR9O1xuXG5cdFx0dGhhdC5nZXRTcGVlZFkgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHR2YXIgdGFyZ2V0U3BlZWQ7XG5cblx0XHRcdGlmICh0aGF0LmlzSnVtcGluZykge1xuXHRcdFx0XHRyZXR1cm4gc3BlZWRZO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoZ2V0RGlzY3JldGVEaXJlY3Rpb24oKSA9PT0gJ2VzRWFzdCcgfHwgZ2V0RGlzY3JldGVEaXJlY3Rpb24oKSA9PT0gJ3dzV2VzdCcpIHtcblx0XHRcdFx0c3BlZWRZRmFjdG9yID0gMC42O1xuXHRcdFx0XHRzcGVlZFkgPSBlYXNlU3BlZWRUb1RhcmdldFVzaW5nRmFjdG9yKHNwZWVkWSwgdGhhdC5nZXRTcGVlZCgpICogMC42LCAwLjYpO1xuXG5cdFx0XHRcdHJldHVybiBzcGVlZFk7XG5cdFx0XHR9XG5cblx0XHRcdGlmIChnZXREaXNjcmV0ZURpcmVjdGlvbigpID09PSAnc0Vhc3QnIHx8IGdldERpc2NyZXRlRGlyZWN0aW9uKCkgPT09ICdzV2VzdCcpIHtcblx0XHRcdFx0c3BlZWRZRmFjdG9yID0gMC44NTtcblx0XHRcdFx0c3BlZWRZID0gZWFzZVNwZWVkVG9UYXJnZXRVc2luZ0ZhY3RvcihzcGVlZFksIHRoYXQuZ2V0U3BlZWQoKSAqIDAuODUsIDAuODUpO1xuXG5cdFx0XHRcdHJldHVybiBzcGVlZFk7XG5cdFx0XHR9XG5cblx0XHRcdGlmIChnZXREaXNjcmV0ZURpcmVjdGlvbigpID09PSAnZWFzdCcgfHwgZ2V0RGlzY3JldGVEaXJlY3Rpb24oKSA9PT0gJ3dlc3QnKSB7XG5cdFx0XHRcdHNwZWVkWUZhY3RvciA9IDE7XG5cdFx0XHRcdHNwZWVkWSA9IDA7XG5cblx0XHRcdFx0cmV0dXJuIHNwZWVkWTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gU28gaXQgbXVzdCBiZSBzb3V0aFxuXG5cdFx0XHRzcGVlZFkgPSBlYXNlU3BlZWRUb1RhcmdldFVzaW5nRmFjdG9yKHNwZWVkWSwgdGhhdC5nZXRTcGVlZCgpLCBzcGVlZFlGYWN0b3IpO1xuXG5cdFx0XHRyZXR1cm4gc3BlZWRZO1xuXHRcdH07XG5cblx0XHR0aGF0Lmhhc0hpdE9ic3RhY2xlID0gZnVuY3Rpb24gKG9icykge1xuXHRcdFx0c2V0Q3Jhc2hlZCgpO1xuXG5cdFx0XHRpZiAobmF2aWdhdG9yLnZpYnJhdGUpIHtcblx0XHRcdFx0bmF2aWdhdG9yLnZpYnJhdGUoNTAwKTtcblx0XHRcdH1cblxuXHRcdFx0b2JzdGFjbGVzSGl0LnB1c2gob2JzLmlkKTtcblxuXHRcdFx0dGhhdC5yZXNldFNwZWVkKCk7XG5cdFx0XHR0aGF0Lm9uSGl0T2JzdGFjbGVDYihvYnMpO1xuXG5cdFx0XHRpZiAoY2FuY2VsYWJsZVN0YXRlVGltZW91dCkge1xuXHRcdFx0XHRjbGVhclRpbWVvdXQoY2FuY2VsYWJsZVN0YXRlVGltZW91dCk7XG5cdFx0XHR9XG5cdFx0XHRjYW5jZWxhYmxlU3RhdGVUaW1lb3V0ID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcblx0XHRcdFx0c2V0Tm9ybWFsKCk7XG5cdFx0XHR9LCAxNTAwKTtcblx0XHR9O1xuXG5cdFx0dGhhdC5oYXNIaXRKdW1wID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0c2V0SnVtcGluZygpO1xuXG5cdFx0XHRpZiAoY2FuY2VsYWJsZVN0YXRlVGltZW91dCkge1xuXHRcdFx0XHRjbGVhclRpbWVvdXQoY2FuY2VsYWJsZVN0YXRlVGltZW91dCk7XG5cdFx0XHR9XG5cdFx0XHRjYW5jZWxhYmxlU3RhdGVUaW1lb3V0ID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcblx0XHRcdFx0c2V0Tm9ybWFsKCk7XG5cdFx0XHR9LCAxMDAwKTtcblx0XHR9O1xuXG5cdFx0dGhhdC5pc0VhdGVuQnkgPSBmdW5jdGlvbiAobW9uc3Rlciwgd2hlbkVhdGVuKSB7XG5cdFx0XHR0aGF0Lmhhc0hpdE9ic3RhY2xlKG1vbnN0ZXIpO1xuXHRcdFx0bW9uc3Rlci5zdGFydEVhdGluZyh3aGVuRWF0ZW4pO1xuXHRcdFx0b2JzdGFjbGVzSGl0LnB1c2gobW9uc3Rlci5pZCk7XG5cdFx0XHR0aGF0LmlzTW92aW5nID0gZmFsc2U7XG5cdFx0XHR0aGF0LmlzQmVpbmdFYXRlbiA9IHRydWU7XG5cdFx0fTtcblxuXHRcdHRoYXQucmVzZXQgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRvYnN0YWNsZXNIaXQgPSBbXTtcblx0XHRcdHBpeGVsc1RyYXZlbGxlZCA9IDA7XG5cdFx0XHR0aGF0LmlzTW92aW5nID0gdHJ1ZTtcblx0XHRcdHRoYXQuaXNKdW1waW5nID0gZmFsc2U7XG5cdFx0XHR0aGF0Lmhhc0JlZW5IaXQgPSBmYWxzZTtcblx0XHRcdGNhblNwZWVkQm9vc3QgPSB0cnVlO1xuXHRcdH07XG5cblx0XHR0aGF0LnNldEhpdE9ic3RhY2xlQ2IgPSBmdW5jdGlvbiAoZm4pIHtcblx0XHRcdHRoYXQub25IaXRPYnN0YWNsZUNiID0gZm4gfHwgZnVuY3Rpb24oKSB7fTtcblx0XHR9O1xuXHRcdHJldHVybiB0aGF0O1xuXHR9XG5cblx0Z2xvYmFsLnNraWVyID0gU2tpZXI7XG59KSh0aGlzKTtcblxuaWYgKHR5cGVvZiBtb2R1bGUgIT09ICd1bmRlZmluZWQnKSB7XG5cdG1vZHVsZS5leHBvcnRzID0gdGhpcy5za2llcjtcbn1cbiIsInZhciBTcHJpdGUgPSByZXF1aXJlKCcuL3Nwcml0ZScpO1xuXG4oZnVuY3Rpb24oZ2xvYmFsKSB7XG5cdGZ1bmN0aW9uIFNub3dib2FyZGVyKGRhdGEpIHtcblx0XHR2YXIgdGhhdCA9IG5ldyBTcHJpdGUoZGF0YSk7XG5cdFx0dmFyIHN1cCA9IHtcblx0XHRcdGRyYXc6IHRoYXQuc3VwZXJpb3IoJ2RyYXcnKSxcblx0XHRcdGN5Y2xlOiB0aGF0LnN1cGVyaW9yKCdjeWNsZScpXG5cdFx0fTtcblx0XHR2YXIgZGlyZWN0aW9ucyA9IHtcblx0XHRcdHNFYXN0OiBmdW5jdGlvbih4RGlmZikgeyByZXR1cm4geERpZmYgPiAwOyB9LFxuXHRcdFx0c1dlc3Q6IGZ1bmN0aW9uKHhEaWZmKSB7IHJldHVybiB4RGlmZiA8PSAwOyB9XG5cdFx0fTtcblx0XHR2YXIgc3RhbmRhcmRTcGVlZCA9IDM7XG5cblx0XHR0aGF0LnNldFNwZWVkKHN0YW5kYXJkU3BlZWQpO1xuXG5cdFx0ZnVuY3Rpb24gZ2V0RGlyZWN0aW9uKCkge1xuXHRcdFx0dmFyIHhEaWZmID0gdGhhdC5tb3ZpbmdUb3dhcmRbMF0gLSB0aGF0Lm1hcFBvc2l0aW9uWzBdO1xuXHRcdFx0dmFyIHlEaWZmID0gdGhhdC5tb3ZpbmdUb3dhcmRbMV0gLSB0aGF0Lm1hcFBvc2l0aW9uWzFdO1xuXG5cdFx0XHRpZiAoZGlyZWN0aW9ucy5zRWFzdCh4RGlmZikpIHtcblx0XHRcdFx0cmV0dXJuICdzRWFzdCc7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRyZXR1cm4gJ3NXZXN0Jztcblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aGF0LmN5Y2xlID0gZnVuY3Rpb24gKGRDb250ZXh0KSB7XG5cdFx0XHRpZiAoTnVtYmVyLnJhbmRvbSgxMCkgPT09IDEpIHtcblx0XHRcdFx0dGhhdC5zZXRNYXBQb3NpdGlvblRhcmdldChkQ29udGV4dC5nZXRSYW5kb21seUluVGhlQ2VudHJlT2ZNYXAoKSk7XG5cdFx0XHRcdHRoYXQuc2V0U3BlZWQoc3RhbmRhcmRTcGVlZCArIE51bWJlci5yYW5kb20oLTEsIDEpKTtcblx0XHRcdH1cblxuXHRcdFx0dGhhdC5zZXRNYXBQb3NpdGlvblRhcmdldCh1bmRlZmluZWQsIGRDb250ZXh0LmdldE1hcEJlbG93Vmlld3BvcnQoKSArIDYwMCk7XG5cblx0XHRcdHN1cC5jeWNsZSgpO1xuXHRcdH07XG5cblx0XHR0aGF0LmRyYXcgPSBmdW5jdGlvbihkQ29udGV4dCkge1xuXHRcdFx0dmFyIHNwcml0ZVBhcnRUb1VzZSA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0cmV0dXJuIGdldERpcmVjdGlvbigpO1xuXHRcdFx0fTtcblxuXHRcdFx0cmV0dXJuIHN1cC5kcmF3KGRDb250ZXh0LCBzcHJpdGVQYXJ0VG9Vc2UoKSk7XG5cdFx0fTtcblxuXHRcdHJldHVybiB0aGF0O1xuXHR9XG5cblx0Z2xvYmFsLnNub3dib2FyZGVyID0gU25vd2JvYXJkZXI7XG59KSggdGhpcyApO1xuXG5cbmlmICh0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJykge1xuXHRtb2R1bGUuZXhwb3J0cyA9IHRoaXMuc25vd2JvYXJkZXI7XG59IiwiKGZ1bmN0aW9uIChnbG9iYWwpIHtcblx0dmFyIEdVSUQgPSByZXF1aXJlKCcuL2d1aWQnKTtcblx0ZnVuY3Rpb24gU3ByaXRlIChkYXRhKSB7XG5cdFx0dmFyIGhpdHRhYmxlT2JqZWN0cyA9IHt9O1xuXHRcdHZhciB6SW5kZXhlc09jY3VwaWVkID0gWyAwIF07XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXHRcdHZhciB0cmFja2VkU3ByaXRlVG9Nb3ZlVG93YXJkO1xuXHRcdHRoYXQuZGlyZWN0aW9uID0gdW5kZWZpbmVkO1xuXHRcdHRoYXQubWFwUG9zaXRpb24gPSBbMCwgMCwgMF07XG5cdFx0dGhhdC5pZCA9IEdVSUQoKTtcblx0XHR0aGF0LmNhbnZhc1ggPSAwO1xuXHRcdHRoYXQuY2FudmFzWSA9IDA7XG5cdFx0dGhhdC5jYW52YXNaID0gMDtcblx0XHR0aGF0LmhlaWdodCA9IDA7XG5cdFx0dGhhdC5zcGVlZCA9IDA7XG5cdFx0dGhhdC5kYXRhID0gZGF0YSB8fCB7IHBhcnRzIDoge30gfTtcblx0XHR0aGF0Lm1vdmluZ1Rvd2FyZCA9IFsgMCwgMCBdO1xuXHRcdHRoYXQubWV0cmVzRG93blRoZU1vdW50YWluID0gMDtcblx0XHR0aGF0Lm1vdmluZ1dpdGhDb252aWN0aW9uID0gZmFsc2U7XG5cdFx0dGhhdC5kZWxldGVkID0gZmFsc2U7XG5cdFx0dGhhdC5tYXhIZWlnaHQgPSAoZnVuY3Rpb24gKCkge1xuXHRcdFx0cmV0dXJuIE9iamVjdC52YWx1ZXModGhhdC5kYXRhLnBhcnRzKS5tYXAoZnVuY3Rpb24gKHApIHsgcmV0dXJuIHBbM107IH0pLm1heCgpO1xuXHRcdH0oKSk7XG5cdFx0dGhhdC5pc01vdmluZyA9IHRydWU7XG5cblx0XHRpZiAoIXRoYXQuZGF0YS5wYXJ0cykge1xuXHRcdFx0dGhhdC5kYXRhLnBhcnRzID0ge307XG5cdFx0fVxuXG5cdFx0aWYgKGRhdGEgJiYgZGF0YS5pZCl7XG5cdFx0XHR0aGF0LmlkID0gZGF0YS5pZDtcblx0XHR9XG5cblx0XHRpZiAoZGF0YSAmJiBkYXRhLnpJbmRleGVzT2NjdXBpZWQpIHtcblx0XHRcdHpJbmRleGVzT2NjdXBpZWQgPSBkYXRhLnpJbmRleGVzT2NjdXBpZWQ7XG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gaW5jcmVtZW50WChhbW91bnQpIHtcblx0XHRcdHRoYXQuY2FudmFzWCArPSBhbW91bnQudG9OdW1iZXIoKTtcblx0XHR9XG5cblx0XHRmdW5jdGlvbiBpbmNyZW1lbnRZKGFtb3VudCkge1xuXHRcdFx0dGhhdC5jYW52YXNZICs9IGFtb3VudC50b051bWJlcigpO1xuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGdldEhpdEJveChmb3JaSW5kZXgpIHtcblx0XHRcdGlmICh0aGF0LmRhdGEuaGl0Qm94ZXMpIHtcblx0XHRcdFx0aWYgKGRhdGEuaGl0Qm94ZXNbZm9yWkluZGV4XSkge1xuXHRcdFx0XHRcdHJldHVybiBkYXRhLmhpdEJveGVzW2ZvclpJbmRleF07XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRmdW5jdGlvbiByb3VuZEhhbGYobnVtKSB7XG5cdFx0XHRudW0gPSBNYXRoLnJvdW5kKG51bSoyKS8yO1xuXHRcdFx0cmV0dXJuIG51bTtcblx0XHR9XG5cblx0XHRmdW5jdGlvbiBtb3ZlKCkge1xuXHRcdFx0aWYgKCF0aGF0LmlzTW92aW5nKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0dmFyIGN1cnJlbnRYID0gdGhhdC5tYXBQb3NpdGlvblswXTtcblx0XHRcdHZhciBjdXJyZW50WSA9IHRoYXQubWFwUG9zaXRpb25bMV07XG5cblx0XHRcdGlmICh0eXBlb2YgdGhhdC5kaXJlY3Rpb24gIT09ICd1bmRlZmluZWQnKSB7XG5cdFx0XHRcdC8vIEZvciB0aGlzIHdlIG5lZWQgdG8gbW9kaWZ5IHRoZSB0aGF0LmRpcmVjdGlvbiBzbyBpdCByZWxhdGVzIHRvIHRoZSBob3Jpem9udGFsXG5cdFx0XHRcdHZhciBkID0gdGhhdC5kaXJlY3Rpb24gLSA5MDtcblx0XHRcdFx0aWYgKGQgPCAwKSBkID0gMzYwICsgZDtcblx0XHRcdFx0Y3VycmVudFggKz0gcm91bmRIYWxmKHRoYXQuc3BlZWQgKiBNYXRoLmNvcyhkICogKE1hdGguUEkgLyAxODApKSk7XG5cdFx0XHRcdGN1cnJlbnRZICs9IHJvdW5kSGFsZih0aGF0LnNwZWVkICogTWF0aC5zaW4oZCAqIChNYXRoLlBJIC8gMTgwKSkpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0aWYgKHR5cGVvZiB0aGF0Lm1vdmluZ1Rvd2FyZFswXSAhPT0gJ3VuZGVmaW5lZCcpIHtcblx0XHRcdFx0XHRpZiAoY3VycmVudFggPiB0aGF0Lm1vdmluZ1Rvd2FyZFswXSkge1xuXHRcdFx0XHRcdFx0Y3VycmVudFggLT0gTWF0aC5taW4odGhhdC5nZXRTcGVlZFgoKSwgTWF0aC5hYnMoY3VycmVudFggLSB0aGF0Lm1vdmluZ1Rvd2FyZFswXSkpO1xuXHRcdFx0XHRcdH0gZWxzZSBpZiAoY3VycmVudFggPCB0aGF0Lm1vdmluZ1Rvd2FyZFswXSkge1xuXHRcdFx0XHRcdFx0Y3VycmVudFggKz0gTWF0aC5taW4odGhhdC5nZXRTcGVlZFgoKSwgTWF0aC5hYnMoY3VycmVudFggLSB0aGF0Lm1vdmluZ1Rvd2FyZFswXSkpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XHRcblx0XHRcdFx0aWYgKHR5cGVvZiB0aGF0Lm1vdmluZ1Rvd2FyZFsxXSAhPT0gJ3VuZGVmaW5lZCcpIHtcblx0XHRcdFx0XHRpZiAoY3VycmVudFkgPiB0aGF0Lm1vdmluZ1Rvd2FyZFsxXSkge1xuXHRcdFx0XHRcdFx0Y3VycmVudFkgLT0gTWF0aC5taW4odGhhdC5nZXRTcGVlZFkoKSwgTWF0aC5hYnMoY3VycmVudFkgLSB0aGF0Lm1vdmluZ1Rvd2FyZFsxXSkpO1xuXHRcdFx0XHRcdH0gZWxzZSBpZiAoY3VycmVudFkgPCB0aGF0Lm1vdmluZ1Rvd2FyZFsxXSkge1xuXHRcdFx0XHRcdFx0Y3VycmVudFkgKz0gTWF0aC5taW4odGhhdC5nZXRTcGVlZFkoKSwgTWF0aC5hYnMoY3VycmVudFkgLSB0aGF0Lm1vdmluZ1Rvd2FyZFsxXSkpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHR0aGF0LnNldE1hcFBvc2l0aW9uKGN1cnJlbnRYLCBjdXJyZW50WSk7XG5cdFx0fVxuXG5cdFx0dGhpcy5kcmF3ID0gZnVuY3Rpb24gKGRDdHgsIHNwcml0ZUZyYW1lKSB7XG5cdFx0XHR2YXIgZnIgPSB0aGF0LmRhdGEucGFydHNbc3ByaXRlRnJhbWVdO1xuXHRcdFx0dGhhdC5oZWlnaHQgPSBmclszXTtcblx0XHRcdHRoYXQud2lkdGggPSBmclsyXTtcblxuXHRcdFx0dmFyIG5ld0NhbnZhc1Bvc2l0aW9uID0gZEN0eC5tYXBQb3NpdGlvblRvQ2FudmFzUG9zaXRpb24odGhhdC5tYXBQb3NpdGlvbik7XG5cdFx0XHR0aGF0LnNldENhbnZhc1Bvc2l0aW9uKG5ld0NhbnZhc1Bvc2l0aW9uWzBdLCBuZXdDYW52YXNQb3NpdGlvblsxXSk7XG5cblx0XHRcdGRDdHguZHJhd0ltYWdlKGRDdHguZ2V0TG9hZGVkSW1hZ2UodGhhdC5kYXRhLiRpbWFnZUZpbGUpLCBmclswXSwgZnJbMV0sIGZyWzJdLCBmclszXSwgdGhhdC5jYW52YXNYLCB0aGF0LmNhbnZhc1ksIGZyWzJdLCBmclszXSk7XG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0TWFwUG9zaXRpb24gPSBmdW5jdGlvbiAoeCwgeSwgeikge1xuXHRcdFx0aWYgKHR5cGVvZiB4ID09PSAndW5kZWZpbmVkJykge1xuXHRcdFx0XHR4ID0gdGhhdC5tYXBQb3NpdGlvblswXTtcblx0XHRcdH1cblx0XHRcdGlmICh0eXBlb2YgeSA9PT0gJ3VuZGVmaW5lZCcpIHtcblx0XHRcdFx0eSA9IHRoYXQubWFwUG9zaXRpb25bMV07XG5cdFx0XHR9XG5cdFx0XHRpZiAodHlwZW9mIHogPT09ICd1bmRlZmluZWQnKSB7XG5cdFx0XHRcdHogPSB0aGF0Lm1hcFBvc2l0aW9uWzJdO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGhhdC56SW5kZXhlc09jY3VwaWVkID0gWyB6IF07XG5cdFx0XHR9XG5cdFx0XHR0aGF0Lm1hcFBvc2l0aW9uID0gW3gsIHksIHpdO1xuXHRcdH07XG5cblx0XHR0aGlzLnNldENhbnZhc1Bvc2l0aW9uID0gZnVuY3Rpb24gKGN4LCBjeSkge1xuXHRcdFx0aWYgKGN4KSB7XG5cdFx0XHRcdGlmIChPYmplY3QuaXNTdHJpbmcoY3gpICYmIChjeC5maXJzdCgpID09PSAnKycgfHwgY3guZmlyc3QoKSA9PT0gJy0nKSkgaW5jcmVtZW50WChjeCk7XG5cdFx0XHRcdGVsc2UgdGhhdC5jYW52YXNYID0gY3g7XG5cdFx0XHR9XG5cdFx0XHRcblx0XHRcdGlmIChjeSkge1xuXHRcdFx0XHRpZiAoT2JqZWN0LmlzU3RyaW5nKGN5KSAmJiAoY3kuZmlyc3QoKSA9PT0gJysnIHx8IGN5LmZpcnN0KCkgPT09ICctJykpIGluY3JlbWVudFkoY3kpO1xuXHRcdFx0XHRlbHNlIHRoYXQuY2FudmFzWSA9IGN5O1xuXHRcdFx0fVxuXHRcdH07XG5cblx0XHR0aGlzLmdldENhbnZhc1Bvc2l0aW9uWCA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdHJldHVybiB0aGF0LmNhbnZhc1g7XG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0Q2FudmFzUG9zaXRpb25ZID0gZnVuY3Rpb24gICgpIHtcblx0XHRcdHJldHVybiB0aGF0LmNhbnZhc1k7XG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0TGVmdEhpdEJveEVkZ2UgPSBmdW5jdGlvbiAoekluZGV4KSB7XG5cdFx0XHR6SW5kZXggPSB6SW5kZXggfHwgMDtcblx0XHRcdHZhciBsaGJlID0gdGhpcy5nZXRDYW52YXNQb3NpdGlvblgoKTtcblx0XHRcdGlmIChnZXRIaXRCb3goekluZGV4KSkge1xuXHRcdFx0XHRsaGJlICs9IGdldEhpdEJveCh6SW5kZXgpWzBdO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGxoYmU7XG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0VG9wSGl0Qm94RWRnZSA9IGZ1bmN0aW9uICh6SW5kZXgpIHtcblx0XHRcdHpJbmRleCA9IHpJbmRleCB8fCAwO1xuXHRcdFx0dmFyIHRoYmUgPSB0aGlzLmdldENhbnZhc1Bvc2l0aW9uWSgpO1xuXHRcdFx0aWYgKGdldEhpdEJveCh6SW5kZXgpKSB7XG5cdFx0XHRcdHRoYmUgKz0gZ2V0SGl0Qm94KHpJbmRleClbMV07XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gdGhiZTtcblx0XHR9O1xuXG5cdFx0dGhpcy5nZXRSaWdodEhpdEJveEVkZ2UgPSBmdW5jdGlvbiAoekluZGV4KSB7XG5cdFx0XHR6SW5kZXggPSB6SW5kZXggfHwgMDtcblxuXHRcdFx0aWYgKGdldEhpdEJveCh6SW5kZXgpKSB7XG5cdFx0XHRcdHJldHVybiB0aGF0LmNhbnZhc1ggKyBnZXRIaXRCb3goekluZGV4KVsyXTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHRoYXQuY2FudmFzWCArIHRoYXQud2lkdGg7XG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0Qm90dG9tSGl0Qm94RWRnZSA9IGZ1bmN0aW9uICh6SW5kZXgpIHtcblx0XHRcdHpJbmRleCA9IHpJbmRleCB8fCAwO1xuXG5cdFx0XHRpZiAoZ2V0SGl0Qm94KHpJbmRleCkpIHtcblx0XHRcdFx0cmV0dXJuIHRoYXQuY2FudmFzWSArIGdldEhpdEJveCh6SW5kZXgpWzNdO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gdGhhdC5jYW52YXNZICsgdGhhdC5oZWlnaHQ7XG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0UG9zaXRpb25JbkZyb250T2YgPSBmdW5jdGlvbiAgKCkge1xuXHRcdFx0cmV0dXJuIFt0aGF0LmNhbnZhc1gsIHRoYXQuY2FudmFzWSArIHRoYXQuaGVpZ2h0XTtcblx0XHR9O1xuXG5cdFx0dGhpcy5zZXRTcGVlZCA9IGZ1bmN0aW9uIChzKSB7XG5cdFx0XHR0aGF0LnNwZWVkID0gcztcblx0XHRcdHRoYXQuc3BlZWRYID0gcztcblx0XHRcdHRoYXQuc3BlZWRZID0gcztcblx0XHR9O1xuXG5cdFx0dGhpcy5pbmNyZW1lbnRTcGVlZEJ5ID0gZnVuY3Rpb24gKHMpIHtcblx0XHRcdHRoYXQuc3BlZWQgKz0gcztcblx0XHR9O1xuXG5cdFx0dGhhdC5nZXRTcGVlZCA9IGZ1bmN0aW9uIGdldFNwZWVkICgpIHtcblx0XHRcdHJldHVybiB0aGF0LnNwZWVkO1xuXHRcdH07XG5cblx0XHR0aGF0LmdldFNwZWVkWCA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdHJldHVybiB0aGF0LnNwZWVkO1xuXHRcdH07XG5cblx0XHR0aGF0LmdldFNwZWVkWSA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdHJldHVybiB0aGF0LnNwZWVkO1xuXHRcdH07XG5cblx0XHR0aGlzLnNldEhlaWdodCA9IGZ1bmN0aW9uIChoKSB7XG5cdFx0XHR0aGF0LmhlaWdodCA9IGg7XG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0V2lkdGggPSBmdW5jdGlvbiAodykge1xuXHRcdFx0dGhhdC53aWR0aCA9IHc7XG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0TWF4SGVpZ2h0ID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0cmV0dXJuIHRoYXQubWF4SGVpZ2h0O1xuXHRcdH07XG5cblx0XHR0aGF0LmdldE1vdmluZ1Rvd2FyZE9wcG9zaXRlID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0aWYgKCF0aGF0LmlzTW92aW5nKSB7XG5cdFx0XHRcdHJldHVybiBbMCwgMF07XG5cdFx0XHR9XG5cblx0XHRcdHZhciBkeCA9ICh0aGF0Lm1vdmluZ1Rvd2FyZFswXSAtIHRoYXQubWFwUG9zaXRpb25bMF0pO1xuXHRcdFx0dmFyIGR5ID0gKHRoYXQubW92aW5nVG93YXJkWzFdIC0gdGhhdC5tYXBQb3NpdGlvblsxXSk7XG5cblx0XHRcdHZhciBvcHBvc2l0ZVggPSAoTWF0aC5hYnMoZHgpID4gNzUgPyAwIC0gZHggOiAwKTtcblx0XHRcdHZhciBvcHBvc2l0ZVkgPSAtZHk7XG5cblx0XHRcdHJldHVybiBbIG9wcG9zaXRlWCwgb3Bwb3NpdGVZIF07XG5cdFx0fTtcblxuXHRcdHRoaXMuY2hlY2tIaXR0YWJsZU9iamVjdHMgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRPYmplY3Qua2V5cyhoaXR0YWJsZU9iamVjdHMsIGZ1bmN0aW9uIChrLCBvYmplY3REYXRhKSB7XG5cdFx0XHRcdGlmIChvYmplY3REYXRhLm9iamVjdC5kZWxldGVkKSB7XG5cdFx0XHRcdFx0ZGVsZXRlIGhpdHRhYmxlT2JqZWN0c1trXTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRpZiAob2JqZWN0RGF0YS5vYmplY3QuaGl0cyh0aGF0KSkge1xuXHRcdFx0XHRcdFx0b2JqZWN0RGF0YS5jYWxsYmFja3MuZWFjaChmdW5jdGlvbiAoY2FsbGJhY2spIHtcblx0XHRcdFx0XHRcdFx0Y2FsbGJhY2sodGhhdCwgb2JqZWN0RGF0YS5vYmplY3QpO1xuXHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHR9O1xuXG5cdFx0dGhpcy5jeWNsZSA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdHRoYXQuY2hlY2tIaXR0YWJsZU9iamVjdHMoKTtcblxuXHRcdFx0aWYgKHRyYWNrZWRTcHJpdGVUb01vdmVUb3dhcmQpIHtcblx0XHRcdFx0dGhhdC5zZXRNYXBQb3NpdGlvblRhcmdldCh0cmFja2VkU3ByaXRlVG9Nb3ZlVG93YXJkLm1hcFBvc2l0aW9uWzBdLCB0cmFja2VkU3ByaXRlVG9Nb3ZlVG93YXJkLm1hcFBvc2l0aW9uWzFdLCB0cnVlKTtcblx0XHRcdH1cblxuXHRcdFx0bW92ZSgpO1xuXHRcdH07XG5cblx0XHR0aGlzLnNldE1hcFBvc2l0aW9uVGFyZ2V0ID0gZnVuY3Rpb24gKHgsIHksIG92ZXJyaWRlKSB7XG5cdFx0XHRpZiAob3ZlcnJpZGUpIHtcblx0XHRcdFx0dGhhdC5tb3ZpbmdXaXRoQ29udmljdGlvbiA9IGZhbHNlO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIXRoYXQubW92aW5nV2l0aENvbnZpY3Rpb24pIHtcblx0XHRcdFx0aWYgKHR5cGVvZiB4ID09PSAndW5kZWZpbmVkJykge1xuXHRcdFx0XHRcdHggPSB0aGF0Lm1vdmluZ1Rvd2FyZFswXTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICh0eXBlb2YgeSA9PT0gJ3VuZGVmaW5lZCcpIHtcblx0XHRcdFx0XHR5ID0gdGhhdC5tb3ZpbmdUb3dhcmRbMV07XG5cdFx0XHRcdH1cblxuXHRcdFx0XHR0aGF0Lm1vdmluZ1Rvd2FyZCA9IFsgeCwgeSBdO1xuXG5cdFx0XHRcdHRoYXQubW92aW5nV2l0aENvbnZpY3Rpb24gPSBmYWxzZTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gdGhhdC5yZXNldERpcmVjdGlvbigpO1xuXHRcdH07XG5cblx0XHR0aGlzLnNldERpcmVjdGlvbiA9IGZ1bmN0aW9uIChhbmdsZSkge1xuXHRcdFx0aWYgKGFuZ2xlID49IDM2MCkge1xuXHRcdFx0XHRhbmdsZSA9IDM2MCAtIGFuZ2xlO1xuXHRcdFx0fVxuXHRcdFx0dGhhdC5kaXJlY3Rpb24gPSBhbmdsZTtcblx0XHRcdHRoYXQubW92aW5nVG93YXJkID0gdW5kZWZpbmVkO1xuXHRcdH07XG5cblx0XHR0aGlzLnJlc2V0RGlyZWN0aW9uID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0dGhhdC5kaXJlY3Rpb24gPSB1bmRlZmluZWQ7XG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0TWFwUG9zaXRpb25UYXJnZXRXaXRoQ29udmljdGlvbiA9IGZ1bmN0aW9uIChjeCwgY3kpIHtcblx0XHRcdHRoYXQuc2V0TWFwUG9zaXRpb25UYXJnZXQoY3gsIGN5KTtcblx0XHRcdHRoYXQubW92aW5nV2l0aENvbnZpY3Rpb24gPSB0cnVlO1xuXHRcdFx0Ly8gdGhhdC5yZXNldERpcmVjdGlvbigpO1xuXHRcdH07XG5cblx0XHR0aGlzLmZvbGxvdyA9IGZ1bmN0aW9uIChzcHJpdGUpIHtcblx0XHRcdHRyYWNrZWRTcHJpdGVUb01vdmVUb3dhcmQgPSBzcHJpdGU7XG5cdFx0XHQvLyB0aGF0LnJlc2V0RGlyZWN0aW9uKCk7XG5cdFx0fTtcblxuXHRcdHRoaXMuc3RvcEZvbGxvd2luZyA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdHRyYWNrZWRTcHJpdGVUb01vdmVUb3dhcmQgPSBmYWxzZTtcblx0XHR9O1xuXG5cdFx0dGhpcy5vbkhpdHRpbmcgPSBmdW5jdGlvbiAob2JqZWN0VG9IaXQsIGNhbGxiYWNrKSB7XG5cdFx0XHRpZiAoaGl0dGFibGVPYmplY3RzW29iamVjdFRvSGl0LmlkXSkge1xuXHRcdFx0XHRyZXR1cm4gaGl0dGFibGVPYmplY3RzW29iamVjdFRvSGl0LmlkXS5jYWxsYmFja3MucHVzaChjYWxsYmFjayk7XG5cdFx0XHR9XG5cblx0XHRcdGhpdHRhYmxlT2JqZWN0c1tvYmplY3RUb0hpdC5pZF0gPSB7XG5cdFx0XHRcdG9iamVjdDogb2JqZWN0VG9IaXQsXG5cdFx0XHRcdGNhbGxiYWNrczogWyBjYWxsYmFjayBdXG5cdFx0XHR9O1xuXHRcdH07XG5cblx0XHR0aGlzLmRlbGV0ZU9uTmV4dEN5Y2xlID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0dGhhdC5kZWxldGVkID0gdHJ1ZTtcblx0XHR9O1xuXG5cdFx0dGhpcy5vY2N1cGllc1pJbmRleCA9IGZ1bmN0aW9uICh6KSB7XG5cdFx0XHRyZXR1cm4gekluZGV4ZXNPY2N1cGllZC5pbmRleE9mKHopID49IDA7XG5cdFx0fTtcblxuXHRcdHRoaXMuaGl0cyA9IGZ1bmN0aW9uIChvdGhlcikge1xuXHRcdFx0dmFyIHZlcnRpY2FsSW50ZXJzZWN0ID0gZmFsc2U7XG5cdFx0XHR2YXIgaG9yaXpvbnRhbEludGVyc2VjdCA9IGZhbHNlO1xuXG5cdFx0XHQvLyBUZXN0IHRoYXQgVEhJUyBoYXMgYSBib3R0b20gZWRnZSBpbnNpZGUgb2YgdGhlIG90aGVyIG9iamVjdFxuXHRcdFx0aWYgKG90aGVyLmdldFRvcEhpdEJveEVkZ2UodGhhdC5tYXBQb3NpdGlvblsyXSkgPD0gdGhhdC5nZXRCb3R0b21IaXRCb3hFZGdlKHRoYXQubWFwUG9zaXRpb25bMl0pICYmIG90aGVyLmdldEJvdHRvbUhpdEJveEVkZ2UodGhhdC5tYXBQb3NpdGlvblsyXSkgPj0gdGhhdC5nZXRCb3R0b21IaXRCb3hFZGdlKHRoYXQubWFwUG9zaXRpb25bMl0pKSB7XG5cdFx0XHRcdHZlcnRpY2FsSW50ZXJzZWN0ID0gdHJ1ZTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gVGVzdCB0aGF0IFRISVMgaGFzIGEgdG9wIGVkZ2UgaW5zaWRlIG9mIHRoZSBvdGhlciBvYmplY3Rcblx0XHRcdGlmIChvdGhlci5nZXRUb3BIaXRCb3hFZGdlKHRoYXQubWFwUG9zaXRpb25bMl0pIDw9IHRoYXQuZ2V0VG9wSGl0Qm94RWRnZSh0aGF0Lm1hcFBvc2l0aW9uWzJdKSAmJiBvdGhlci5nZXRCb3R0b21IaXRCb3hFZGdlKHRoYXQubWFwUG9zaXRpb25bMl0pID49IHRoYXQuZ2V0VG9wSGl0Qm94RWRnZSh0aGF0Lm1hcFBvc2l0aW9uWzJdKSkge1xuXHRcdFx0XHR2ZXJ0aWNhbEludGVyc2VjdCA9IHRydWU7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFRlc3QgdGhhdCBUSElTIGhhcyBhIHJpZ2h0IGVkZ2UgaW5zaWRlIG9mIHRoZSBvdGhlciBvYmplY3Rcblx0XHRcdGlmIChvdGhlci5nZXRMZWZ0SGl0Qm94RWRnZSh0aGF0Lm1hcFBvc2l0aW9uWzJdKSA8PSB0aGF0LmdldFJpZ2h0SGl0Qm94RWRnZSh0aGF0Lm1hcFBvc2l0aW9uWzJdKSAmJiBvdGhlci5nZXRSaWdodEhpdEJveEVkZ2UodGhhdC5tYXBQb3NpdGlvblsyXSkgPj0gdGhhdC5nZXRSaWdodEhpdEJveEVkZ2UodGhhdC5tYXBQb3NpdGlvblsyXSkpIHtcblx0XHRcdFx0aG9yaXpvbnRhbEludGVyc2VjdCA9IHRydWU7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFRlc3QgdGhhdCBUSElTIGhhcyBhIGxlZnQgZWRnZSBpbnNpZGUgb2YgdGhlIG90aGVyIG9iamVjdFxuXHRcdFx0aWYgKG90aGVyLmdldExlZnRIaXRCb3hFZGdlKHRoYXQubWFwUG9zaXRpb25bMl0pIDw9IHRoYXQuZ2V0TGVmdEhpdEJveEVkZ2UodGhhdC5tYXBQb3NpdGlvblsyXSkgJiYgb3RoZXIuZ2V0UmlnaHRIaXRCb3hFZGdlKHRoYXQubWFwUG9zaXRpb25bMl0pID49IHRoYXQuZ2V0TGVmdEhpdEJveEVkZ2UodGhhdC5tYXBQb3NpdGlvblsyXSkpIHtcblx0XHRcdFx0aG9yaXpvbnRhbEludGVyc2VjdCA9IHRydWU7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB2ZXJ0aWNhbEludGVyc2VjdCAmJiBob3Jpem9udGFsSW50ZXJzZWN0O1xuXHRcdH07XG5cblx0XHR0aGlzLmlzQWJvdmVPbkNhbnZhcyA9IGZ1bmN0aW9uIChjeSkge1xuXHRcdFx0cmV0dXJuICh0aGF0LmNhbnZhc1kgKyB0aGF0LmhlaWdodCkgPCBjeTtcblx0XHR9O1xuXG5cdFx0dGhpcy5pc0JlbG93T25DYW52YXMgPSBmdW5jdGlvbiAoY3kpIHtcblx0XHRcdHJldHVybiAodGhhdC5jYW52YXNZKSA+IGN5O1xuXHRcdH07XG5cblx0XHRyZXR1cm4gdGhhdDtcblx0fVxuXG5cdFNwcml0ZS5jcmVhdGVPYmplY3RzID0gZnVuY3Rpb24gY3JlYXRlT2JqZWN0cyhzcHJpdGVJbmZvQXJyYXksIG9wdHMpIHtcblx0XHRpZiAoIUFycmF5LmlzQXJyYXkoc3ByaXRlSW5mb0FycmF5KSkgc3ByaXRlSW5mb0FycmF5ID0gWyBzcHJpdGVJbmZvQXJyYXkgXTtcblx0XHRvcHRzID0gT2JqZWN0Lm1lcmdlKG9wdHMsIHtcblx0XHRcdHJhdGVNb2RpZmllcjogMCxcblx0XHRcdGRyb3BSYXRlOiAxLFxuXHRcdFx0cG9zaXRpb246IFswLCAwXVxuXHRcdH0sIGZhbHNlLCBmYWxzZSk7XG5cblx0XHRmdW5jdGlvbiBjcmVhdGVPbmUgKHNwcml0ZUluZm8pIHtcblx0XHRcdHZhciBwb3NpdGlvbiA9IG9wdHMucG9zaXRpb247XG5cdFx0XHRpZiAoTnVtYmVyLnJhbmRvbSgxMDAgKyBvcHRzLnJhdGVNb2RpZmllcikgPD0gc3ByaXRlSW5mby5kcm9wUmF0ZSkge1xuXHRcdFx0XHR2YXIgc3ByaXRlID0gbmV3IFNwcml0ZShzcHJpdGVJbmZvLnNwcml0ZSk7XG5cdFx0XHRcdHNwcml0ZS5zZXRTcGVlZCgwKTtcblxuXHRcdFx0XHRpZiAoT2JqZWN0LmlzRnVuY3Rpb24ocG9zaXRpb24pKSB7XG5cdFx0XHRcdFx0cG9zaXRpb24gPSBwb3NpdGlvbigpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0c3ByaXRlLnNldE1hcFBvc2l0aW9uKHBvc2l0aW9uWzBdLCBwb3NpdGlvblsxXSk7XG5cblx0XHRcdFx0aWYgKHNwcml0ZUluZm8uc3ByaXRlLmhpdEJlaGF2aW91ciAmJiBzcHJpdGVJbmZvLnNwcml0ZS5oaXRCZWhhdmlvdXIuc2tpZXIgJiYgb3B0cy5wbGF5ZXIpIHtcblx0XHRcdFx0XHRzcHJpdGUub25IaXR0aW5nKG9wdHMucGxheWVyLCBzcHJpdGVJbmZvLnNwcml0ZS5oaXRCZWhhdmlvdXIuc2tpZXIpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0cmV0dXJuIHNwcml0ZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR2YXIgb2JqZWN0cyA9IHNwcml0ZUluZm9BcnJheS5tYXAoY3JlYXRlT25lKS5yZW1vdmUodW5kZWZpbmVkKTtcblxuXHRcdHJldHVybiBvYmplY3RzO1xuXHR9O1xuXG5cdGdsb2JhbC5zcHJpdGUgPSBTcHJpdGU7XG59KSggdGhpcyApO1xuXG5cbmlmICh0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJykge1xuXHRtb2R1bGUuZXhwb3J0cyA9IHRoaXMuc3ByaXRlO1xufSIsIihmdW5jdGlvbiAoZ2xvYmFsKSB7XG5cdGZ1bmN0aW9uIFNwcml0ZUFycmF5KCkge1xuXHRcdHRoaXMucHVzaEhhbmRsZXJzID0gW107XG5cblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdFNwcml0ZUFycmF5LnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoQXJyYXkucHJvdG90eXBlKTtcblxuXHRTcHJpdGVBcnJheS5wcm90b3R5cGUub25QdXNoID0gZnVuY3Rpb24oZiwgcmV0cm9hY3RpdmUpIHtcblx0XHR0aGlzLnB1c2hIYW5kbGVycy5wdXNoKGYpO1xuXG5cdFx0aWYgKHJldHJvYWN0aXZlKSB7XG5cdFx0XHR0aGlzLmVhY2goZik7XG5cdFx0fVxuXHR9O1xuXG5cdFNwcml0ZUFycmF5LnByb3RvdHlwZS5wdXNoID0gZnVuY3Rpb24ob2JqKSB7XG5cdFx0QXJyYXkucHJvdG90eXBlLnB1c2guY2FsbCh0aGlzLCBvYmopO1xuXHRcdHRoaXMucHVzaEhhbmRsZXJzLmVhY2goZnVuY3Rpb24oaGFuZGxlcikge1xuXHRcdFx0aGFuZGxlcihvYmopO1xuXHRcdH0pO1xuXHR9O1xuXG5cdFNwcml0ZUFycmF5LnByb3RvdHlwZS5jdWxsID0gZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5lYWNoKGZ1bmN0aW9uIChvYmosIGkpIHtcblx0XHRcdGlmIChvYmouZGVsZXRlZCkge1xuXHRcdFx0XHRyZXR1cm4gKGRlbGV0ZSB0aGlzW2ldKTtcblx0XHRcdH1cblx0XHR9KTtcblx0fTtcblxuXHRnbG9iYWwuc3ByaXRlQXJyYXkgPSBTcHJpdGVBcnJheTtcbn0pKHRoaXMpO1xuXG5cbmlmICh0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJykge1xuXHRtb2R1bGUuZXhwb3J0cyA9IHRoaXMuc3ByaXRlQXJyYXk7XG59IiwiLy8gR2xvYmFsIGRlcGVuZGVuY2llcyB3aGljaCByZXR1cm4gbm8gbW9kdWxlc1xucmVxdWlyZSgnLi9saWIvY2FudmFzUmVuZGVyaW5nQ29udGV4dDJERXh0ZW5zaW9ucycpO1xucmVxdWlyZSgnLi9saWIvZXh0ZW5kZXJzJyk7XG5yZXF1aXJlKCcuL2xpYi9wbHVnaW5zJyk7XG5cbi8vIEV4dGVybmFsIGRlcGVuZGVuY2llc1xudmFyIEhhbW1lciA9IHJlcXVpcmUoJ2hhbW1lcmpzJyk7XG52YXIgTW91c2V0cmFwID0gcmVxdWlyZSgnYnItbW91c2V0cmFwJyk7XG5cbi8vIE1ldGhvZCBtb2R1bGVzXG52YXIgaXNNb2JpbGVEZXZpY2UgPSByZXF1aXJlKCcuL2xpYi9pc01vYmlsZURldmljZScpO1xuXG4vLyBHYW1lIE9iamVjdHNcbnZhciBTcHJpdGVBcnJheSA9IHJlcXVpcmUoJy4vbGliL3Nwcml0ZUFycmF5Jyk7XG52YXIgTW9uc3RlciA9IHJlcXVpcmUoJy4vbGliL21vbnN0ZXInKTtcbnZhciBTcHJpdGUgPSByZXF1aXJlKCcuL2xpYi9zcHJpdGUnKTtcbnZhciBTbm93Ym9hcmRlciA9IHJlcXVpcmUoJy4vbGliL3Nub3dib2FyZGVyJyk7XG52YXIgU2tpZXIgPSByZXF1aXJlKCcuL2xpYi9za2llcicpO1xudmFyIEluZm9Cb3ggPSByZXF1aXJlKCcuL2xpYi9pbmZvQm94Jyk7XG52YXIgR2FtZSA9IHJlcXVpcmUoJy4vbGliL2dhbWUnKTtcblxuLy8gTG9jYWwgdmFyaWFibGVzIGZvciBzdGFydGluZyB0aGUgZ2FtZVxudmFyIG1haW5DYW52YXMgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnc2tpZnJlZS1jYW52YXMnKTtcbnZhciBkQ29udGV4dCA9IG1haW5DYW52YXMuZ2V0Q29udGV4dCgnMmQnKTtcbnZhciBpbWFnZVNvdXJjZXMgPSBbICdzcHJpdGUtY2hhcmFjdGVycy5wbmcnLCAnc2tpZnJlZS1vYmplY3RzLnBuZycgXTtcbnZhciBnbG9iYWwgPSB0aGlzO1xudmFyIGluZm9Cb3hDb250cm9scyA9ICdVc2UgdGhlIG1vdXNlIG9yIFdBU0QgdG8gY29udHJvbCB0aGUgcGxheWVyJztcbmlmIChpc01vYmlsZURldmljZSgpKSBpbmZvQm94Q29udHJvbHMgPSAnVGFwIG9yIGRyYWcgb24gdGhlIHBpc3RlIHRvIGNvbnRyb2wgdGhlIHBsYXllcic7XG52YXIgc3ByaXRlcyA9IHJlcXVpcmUoJy4vc3ByaXRlSW5mbycpO1xuXG52YXIgcGl4ZWxzUGVyTWV0cmUgPSAxODtcbnZhciBkaXN0YW5jZVRyYXZlbGxlZEluTWV0cmVzID0gMDtcbnZhciBtb25zdGVyRGlzdGFuY2VUaHJlc2hvbGQgPSAyMDAwO1xudmFyIGxpdmVzTGVmdCA9IDU7XG52YXIgaGlnaFNjb3JlID0gMDtcbnZhciBsb3NlTGlmZU9uT2JzdGFjbGVIaXQgPSBmYWxzZTtcbnZhciBkcm9wUmF0ZXMgPSB7c21hbGxUcmVlOiA0LCB0YWxsVHJlZTogMiwganVtcDogMSwgdGhpY2tTbm93OiAxLCByb2NrOiAxfTtcbmlmIChsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnaGlnaFNjb3JlJykpIGhpZ2hTY29yZSA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKCdoaWdoU2NvcmUnKTtcblxuZnVuY3Rpb24gbG9hZEltYWdlcyAoc291cmNlcywgbmV4dCkge1xuXHR2YXIgbG9hZGVkID0gMDtcblx0dmFyIGltYWdlcyA9IHt9O1xuXG5cdGZ1bmN0aW9uIGZpbmlzaCAoKSB7XG5cdFx0bG9hZGVkICs9IDE7XG5cdFx0aWYgKGxvYWRlZCA9PT0gc291cmNlcy5sZW5ndGgpIHtcblx0XHRcdG5leHQoaW1hZ2VzKTtcblx0XHR9XG5cdH1cblxuXHRzb3VyY2VzLmVhY2goZnVuY3Rpb24gKHNyYykge1xuXHRcdHZhciBpbSA9IG5ldyBJbWFnZSgpO1xuXHRcdGltLm9ubG9hZCA9IGZpbmlzaDtcblx0XHRpbS5zcmMgPSBzcmM7XG5cdFx0ZENvbnRleHQuc3RvcmVMb2FkZWRJbWFnZShzcmMsIGltKTtcblx0fSk7XG59XG5cbmZ1bmN0aW9uIG1vbnN0ZXJIaXRzU2tpZXJCZWhhdmlvdXIobW9uc3Rlciwgc2tpZXIpIHtcblx0c2tpZXIuaXNFYXRlbkJ5KG1vbnN0ZXIsIGZ1bmN0aW9uICgpIHtcblx0XHRsaXZlc0xlZnQgLT0gMTtcblx0XHRtb25zdGVyLmlzRnVsbCA9IHRydWU7XG5cdFx0bW9uc3Rlci5pc0VhdGluZyA9IGZhbHNlO1xuXHRcdHNraWVyLmlzQmVpbmdFYXRlbiA9IGZhbHNlO1xuXHRcdG1vbnN0ZXIuc2V0U3BlZWQoc2tpZXIuZ2V0U3BlZWQoKSk7XG5cdFx0bW9uc3Rlci5zdG9wRm9sbG93aW5nKCk7XG5cdFx0dmFyIHJhbmRvbVBvc2l0aW9uQWJvdmUgPSBkQ29udGV4dC5nZXRSYW5kb21NYXBQb3NpdGlvbkFib3ZlVmlld3BvcnQoKTtcblx0XHRtb25zdGVyLnNldE1hcFBvc2l0aW9uVGFyZ2V0KHJhbmRvbVBvc2l0aW9uQWJvdmVbMF0sIHJhbmRvbVBvc2l0aW9uQWJvdmVbMV0pO1xuXHR9KTtcbn1cblxuZnVuY3Rpb24gc3RhcnROZXZlckVuZGluZ0dhbWUgKGltYWdlcykge1xuXHR2YXIgcGxheWVyO1xuXHR2YXIgc3RhcnRTaWduO1xuXHR2YXIgaW5mb0JveDtcblx0dmFyIGdhbWU7XG5cblx0ZnVuY3Rpb24gcmVzZXRHYW1lICgpIHtcblx0XHRkaXN0YW5jZVRyYXZlbGxlZEluTWV0cmVzID0gMDtcblx0XHRsaXZlc0xlZnQgPSA1O1xuXHRcdGhpZ2hTY29yZSA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKCdoaWdoU2NvcmUnKTtcblx0XHRnYW1lLnJlc2V0KCk7XG5cdFx0Z2FtZS5hZGRTdGF0aWNPYmplY3Qoc3RhcnRTaWduKTtcblx0fVxuXG5cdGZ1bmN0aW9uIGRldGVjdEVuZCAoKSB7XG5cdFx0aWYgKCFnYW1lLmlzUGF1c2VkKCkpIHtcblx0XHRcdGhpZ2hTY29yZSA9IGxvY2FsU3RvcmFnZS5zZXRJdGVtKCdoaWdoU2NvcmUnLCBkaXN0YW5jZVRyYXZlbGxlZEluTWV0cmVzKTtcblx0XHRcdGluZm9Cb3guc2V0TGluZXMoW1xuXHRcdFx0XHQnR2FtZSBvdmVyIScsXG5cdFx0XHRcdCdIaXQgc3BhY2UgdG8gcmVzdGFydCdcblx0XHRcdF0pO1xuXHRcdFx0Z2FtZS5wYXVzZSgpO1xuXHRcdFx0Z2FtZS5jeWNsZSgpO1xuXHRcdH1cblx0fVxuXG5cdGZ1bmN0aW9uIHJhbmRvbWx5U3Bhd25OUEMoc3Bhd25GdW5jdGlvbiwgZHJvcFJhdGUpIHtcblx0XHR2YXIgcmF0ZU1vZGlmaWVyID0gTWF0aC5tYXgoODAwIC0gbWFpbkNhbnZhcy53aWR0aCwgMCk7XG5cdFx0aWYgKE51bWJlci5yYW5kb20oMTAwMCArIHJhdGVNb2RpZmllcikgPD0gZHJvcFJhdGUpIHtcblx0XHRcdHNwYXduRnVuY3Rpb24oKTtcblx0XHR9XG5cdH1cblxuXHRmdW5jdGlvbiBzcGF3bk1vbnN0ZXIgKCkge1xuXHRcdHZhciBuZXdNb25zdGVyID0gbmV3IE1vbnN0ZXIoc3ByaXRlcy5tb25zdGVyKTtcblx0XHR2YXIgcmFuZG9tUG9zaXRpb24gPSBkQ29udGV4dC5nZXRSYW5kb21NYXBQb3NpdGlvbkFib3ZlVmlld3BvcnQoKTtcblx0XHRuZXdNb25zdGVyLnNldE1hcFBvc2l0aW9uKHJhbmRvbVBvc2l0aW9uWzBdLCByYW5kb21Qb3NpdGlvblsxXSk7XG5cdFx0bmV3TW9uc3Rlci5mb2xsb3cocGxheWVyKTtcblx0XHRuZXdNb25zdGVyLnNldFNwZWVkKHBsYXllci5nZXRTdGFuZGFyZFNwZWVkKCkpO1xuXHRcdG5ld01vbnN0ZXIub25IaXR0aW5nKHBsYXllciwgbW9uc3RlckhpdHNTa2llckJlaGF2aW91cik7XG5cblx0XHRnYW1lLmFkZE1vdmluZ09iamVjdChuZXdNb25zdGVyLCAnbW9uc3RlcicpO1xuXHR9XG5cblx0ZnVuY3Rpb24gc3Bhd25Cb2FyZGVyICgpIHtcblx0XHR2YXIgbmV3Qm9hcmRlciA9IG5ldyBTbm93Ym9hcmRlcihzcHJpdGVzLnNub3dib2FyZGVyKTtcblx0XHR2YXIgcmFuZG9tUG9zaXRpb25BYm92ZSA9IGRDb250ZXh0LmdldFJhbmRvbU1hcFBvc2l0aW9uQWJvdmVWaWV3cG9ydCgpO1xuXHRcdHZhciByYW5kb21Qb3NpdGlvbkJlbG93ID0gZENvbnRleHQuZ2V0UmFuZG9tTWFwUG9zaXRpb25CZWxvd1ZpZXdwb3J0KCk7XG5cdFx0bmV3Qm9hcmRlci5zZXRNYXBQb3NpdGlvbihyYW5kb21Qb3NpdGlvbkFib3ZlWzBdLCByYW5kb21Qb3NpdGlvbkFib3ZlWzFdKTtcblx0XHRuZXdCb2FyZGVyLnNldE1hcFBvc2l0aW9uVGFyZ2V0KHJhbmRvbVBvc2l0aW9uQmVsb3dbMF0sIHJhbmRvbVBvc2l0aW9uQmVsb3dbMV0pO1xuXHRcdG5ld0JvYXJkZXIub25IaXR0aW5nKHBsYXllciwgc3ByaXRlcy5zbm93Ym9hcmRlci5oaXRCZWhhdmlvdXIuc2tpZXIpO1xuXG5cdFx0Z2FtZS5hZGRNb3ZpbmdPYmplY3QobmV3Qm9hcmRlcik7XG5cdH1cblxuXHRwbGF5ZXIgPSBuZXcgU2tpZXIoc3ByaXRlcy5za2llcik7XG5cdHBsYXllci5zZXRNYXBQb3NpdGlvbigwLCAwKTtcblx0cGxheWVyLnNldE1hcFBvc2l0aW9uVGFyZ2V0KDAsIC0xMCk7XG5cdGlmICggbG9zZUxpZmVPbk9ic3RhY2xlSGl0ICkge1xuXHRcdHBsYXllci5zZXRIaXRPYnN0YWNsZUNiKGZ1bmN0aW9uKCkge1xuXHRcdFx0bGl2ZXNMZWZ0IC09IDE7XG5cdFx0fSk7XG5cdH1cblxuXHRnYW1lID0gbmV3IEdhbWUobWFpbkNhbnZhcywgcGxheWVyKTtcblxuXHRzdGFydFNpZ24gPSBuZXcgU3ByaXRlKHNwcml0ZXMuc2lnblN0YXJ0KTtcblx0Z2FtZS5hZGRTdGF0aWNPYmplY3Qoc3RhcnRTaWduKTtcblx0c3RhcnRTaWduLnNldE1hcFBvc2l0aW9uKC01MCwgMCk7XG5cdGRDb250ZXh0LmZvbGxvd1Nwcml0ZShwbGF5ZXIpO1xuXG5cdGluZm9Cb3ggPSBuZXcgSW5mb0JveCh7XG5cdFx0aW5pdGlhbExpbmVzIDogW1xuXHRcdFx0J1NraUZyZWUuanMnLFxuXHRcdFx0aW5mb0JveENvbnRyb2xzLFxuXHRcdFx0J1RyYXZlbGxlZCAwbScsXG5cdFx0XHQnSGlnaCBTY29yZTogJyArIGhpZ2hTY29yZSxcblx0XHRcdCdTa2llcnMgbGVmdDogJyArIGxpdmVzTGVmdCxcblx0XHRcdCdDcmVhdGVkIGJ5IERhbiBIb3VnaCAoQGJhc2ljYWxseWRhbiknXG5cdFx0XSxcblx0XHRwb3NpdGlvbjoge1xuXHRcdFx0dG9wOiAxNSxcblx0XHRcdHJpZ2h0OiAxMFxuXHRcdH1cblx0fSk7XG5cblx0Z2FtZS5iZWZvcmVDeWNsZShmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIG5ld09iamVjdHMgPSBbXTtcblx0XHRpZiAocGxheWVyLmlzTW92aW5nKSB7XG5cdFx0XHRuZXdPYmplY3RzID0gU3ByaXRlLmNyZWF0ZU9iamVjdHMoW1xuXHRcdFx0XHR7IHNwcml0ZTogc3ByaXRlcy5zbWFsbFRyZWUsIGRyb3BSYXRlOiBkcm9wUmF0ZXMuc21hbGxUcmVlIH0sXG5cdFx0XHRcdHsgc3ByaXRlOiBzcHJpdGVzLnRhbGxUcmVlLCBkcm9wUmF0ZTogZHJvcFJhdGVzLnRhbGxUcmVlIH0sXG5cdFx0XHRcdHsgc3ByaXRlOiBzcHJpdGVzLmp1bXAsIGRyb3BSYXRlOiBkcm9wUmF0ZXMuanVtcCB9LFxuXHRcdFx0XHR7IHNwcml0ZTogc3ByaXRlcy50aGlja1Nub3csIGRyb3BSYXRlOiBkcm9wUmF0ZXMudGhpY2tTbm93IH0sXG5cdFx0XHRcdHsgc3ByaXRlOiBzcHJpdGVzLnJvY2ssIGRyb3BSYXRlOiBkcm9wUmF0ZXMucm9jayB9LFxuXHRcdFx0XSwge1xuXHRcdFx0XHRyYXRlTW9kaWZpZXI6IE1hdGgubWF4KDgwMCAtIG1haW5DYW52YXMud2lkdGgsIDApLFxuXHRcdFx0XHRwb3NpdGlvbjogZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdHJldHVybiBkQ29udGV4dC5nZXRSYW5kb21NYXBQb3NpdGlvbkJlbG93Vmlld3BvcnQoKTtcblx0XHRcdFx0fSxcblx0XHRcdFx0cGxheWVyOiBwbGF5ZXJcblx0XHRcdH0pO1xuXHRcdH1cblx0XHRpZiAoIWdhbWUuaXNQYXVzZWQoKSkge1xuXHRcdFx0Z2FtZS5hZGRTdGF0aWNPYmplY3RzKG5ld09iamVjdHMpO1xuXG5cdFx0XHRyYW5kb21seVNwYXduTlBDKHNwYXduQm9hcmRlciwgMC4xKTtcblx0XHRcdGRpc3RhbmNlVHJhdmVsbGVkSW5NZXRyZXMgPSBwYXJzZUZsb2F0KHBsYXllci5nZXRQaXhlbHNUcmF2ZWxsZWREb3duTW91bnRhaW4oKSAvIHBpeGVsc1Blck1ldHJlKS50b0ZpeGVkKDEpO1xuXG5cdFx0XHRpZiAoZGlzdGFuY2VUcmF2ZWxsZWRJbk1ldHJlcyA+IG1vbnN0ZXJEaXN0YW5jZVRocmVzaG9sZCkge1xuXHRcdFx0XHRyYW5kb21seVNwYXduTlBDKHNwYXduTW9uc3RlciwgMC4wMDEpO1xuXHRcdFx0fVxuXG5cdFx0XHRpbmZvQm94LnNldExpbmVzKFtcblx0XHRcdFx0J1NraUZyZWUuanMnLFxuXHRcdFx0XHRpbmZvQm94Q29udHJvbHMsXG5cdFx0XHRcdCdUcmF2ZWxsZWQgJyArIGRpc3RhbmNlVHJhdmVsbGVkSW5NZXRyZXMgKyAnbScsXG5cdFx0XHRcdCdTa2llcnMgbGVmdDogJyArIGxpdmVzTGVmdCxcblx0XHRcdFx0J0hpZ2ggU2NvcmU6ICcgKyBoaWdoU2NvcmUsXG5cdFx0XHRcdCdDcmVhdGVkIGJ5IERhbiBIb3VnaCAoQGJhc2ljYWxseWRhbiknLFxuXHRcdFx0XHQnQ3VycmVudCBTcGVlZDogJyArIHBsYXllci5nZXRTcGVlZCgpLyosXG5cdFx0XHRcdCdTa2llciBNYXAgUG9zaXRpb246ICcgKyBwbGF5ZXIubWFwUG9zaXRpb25bMF0udG9GaXhlZCgxKSArICcsICcgKyBwbGF5ZXIubWFwUG9zaXRpb25bMV0udG9GaXhlZCgxKSxcblx0XHRcdFx0J01vdXNlIE1hcCBQb3NpdGlvbjogJyArIG1vdXNlTWFwUG9zaXRpb25bMF0udG9GaXhlZCgxKSArICcsICcgKyBtb3VzZU1hcFBvc2l0aW9uWzFdLnRvRml4ZWQoMSkqL1xuXHRcdFx0XSk7XG5cdFx0fVxuXHR9KTtcblxuXHRnYW1lLmFmdGVyQ3ljbGUoZnVuY3Rpb24oKSB7XG5cdFx0aWYgKGxpdmVzTGVmdCA9PT0gMCkge1xuXHRcdFx0ZGV0ZWN0RW5kKCk7XG5cdFx0fVxuXHR9KTtcblxuXHRnYW1lLmFkZFVJRWxlbWVudChpbmZvQm94KTtcblx0XG5cdCQobWFpbkNhbnZhcylcblx0Lm1vdXNlbW92ZShmdW5jdGlvbiAoZSkge1xuXHRcdGdhbWUuc2V0TW91c2VYKGUucGFnZVgpO1xuXHRcdGdhbWUuc2V0TW91c2VZKGUucGFnZVkpO1xuXHRcdHBsYXllci5yZXNldERpcmVjdGlvbigpO1xuXHRcdHBsYXllci5zdGFydE1vdmluZ0lmUG9zc2libGUoKTtcblx0fSlcblx0LmJpbmQoJ2NsaWNrJywgZnVuY3Rpb24gKGUpIHtcblx0XHRnYW1lLnNldE1vdXNlWChlLnBhZ2VYKTtcblx0XHRnYW1lLnNldE1vdXNlWShlLnBhZ2VZKTtcblx0XHRwbGF5ZXIucmVzZXREaXJlY3Rpb24oKTtcblx0XHRwbGF5ZXIuc3RhcnRNb3ZpbmdJZlBvc3NpYmxlKCk7XG5cdH0pXG5cdC5mb2N1cygpOyAvLyBTbyB3ZSBjYW4gbGlzdGVuIHRvIGV2ZW50cyBpbW1lZGlhdGVseVxuXG5cdE1vdXNldHJhcC5iaW5kKCdmJywgcGxheWVyLnNwZWVkQm9vc3QpO1xuXHRNb3VzZXRyYXAuYmluZCgndCcsIHBsYXllci5hdHRlbXB0VHJpY2spO1xuXHRNb3VzZXRyYXAuYmluZChbJ3cnLCAndXAnXSwgZnVuY3Rpb24gKCkge1xuXHRcdHBsYXllci5zdG9wKCk7XG5cdH0pO1xuXHRNb3VzZXRyYXAuYmluZChbJ2EnLCAnbGVmdCddLCBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHBsYXllci5kaXJlY3Rpb24gPT09IDI3MCkge1xuXHRcdFx0cGxheWVyLnN0ZXBXZXN0KCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHBsYXllci50dXJuV2VzdCgpO1xuXHRcdH1cblx0fSk7XG5cdE1vdXNldHJhcC5iaW5kKFsncycsICdkb3duJ10sIGZ1bmN0aW9uICgpIHtcblx0XHRwbGF5ZXIuc2V0RGlyZWN0aW9uKDE4MCk7XG5cdFx0cGxheWVyLnN0YXJ0TW92aW5nSWZQb3NzaWJsZSgpO1xuXHR9KTtcblx0TW91c2V0cmFwLmJpbmQoWydkJywgJ3JpZ2h0J10sIGZ1bmN0aW9uICgpIHtcblx0XHRpZiAocGxheWVyLmRpcmVjdGlvbiA9PT0gOTApIHtcblx0XHRcdHBsYXllci5zdGVwRWFzdCgpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRwbGF5ZXIudHVybkVhc3QoKTtcblx0XHR9XG5cdH0pO1xuXHRNb3VzZXRyYXAuYmluZCgnbScsIHNwYXduTW9uc3Rlcik7XG5cdE1vdXNldHJhcC5iaW5kKCdiJywgc3Bhd25Cb2FyZGVyKTtcblx0TW91c2V0cmFwLmJpbmQoJ3NwYWNlJywgcmVzZXRHYW1lKTtcblxuXHR2YXIgaGFtbWVydGltZSA9IEhhbW1lcihtYWluQ2FudmFzKS5vbigncHJlc3MnLCBmdW5jdGlvbiAoZSkge1xuXHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRnYW1lLnNldE1vdXNlWChlLmNlbnRlci54KTtcblx0XHRnYW1lLnNldE1vdXNlWShlLmNlbnRlci55KTtcblx0fSkub24oJ3RhcCcsIGZ1bmN0aW9uIChlKSB7XG5cdFx0Z2FtZS5zZXRNb3VzZVgoZS5jZW50ZXIueCk7XG5cdFx0Z2FtZS5zZXRNb3VzZVkoZS5jZW50ZXIueSk7XG5cdH0pLm9uKCdwYW4nLCBmdW5jdGlvbiAoZSkge1xuXHRcdGdhbWUuc2V0TW91c2VYKGUuY2VudGVyLngpO1xuXHRcdGdhbWUuc2V0TW91c2VZKGUuY2VudGVyLnkpO1xuXHRcdHBsYXllci5yZXNldERpcmVjdGlvbigpO1xuXHRcdHBsYXllci5zdGFydE1vdmluZ0lmUG9zc2libGUoKTtcblx0fSkub24oJ2RvdWJsZXRhcCcsIGZ1bmN0aW9uIChlKSB7XG5cdFx0cGxheWVyLnNwZWVkQm9vc3QoKTtcblx0fSk7XG5cblx0cGxheWVyLmlzTW92aW5nID0gZmFsc2U7XG5cdHBsYXllci5zZXREaXJlY3Rpb24oMjcwKTtcblxuXHRnYW1lLnN0YXJ0KCk7XG59XG5cbmZ1bmN0aW9uIHJlc2l6ZUNhbnZhcygpIHtcblx0bWFpbkNhbnZhcy53aWR0aCA9IHdpbmRvdy5pbm5lcldpZHRoO1xuXHRtYWluQ2FudmFzLmhlaWdodCA9IHdpbmRvdy5pbm5lckhlaWdodDtcbn1cblxud2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIHJlc2l6ZUNhbnZhcywgZmFsc2UpO1xuXG5yZXNpemVDYW52YXMoKTtcblxubG9hZEltYWdlcyhpbWFnZVNvdXJjZXMsIHN0YXJ0TmV2ZXJFbmRpbmdHYW1lKTtcblxudGhpcy5leHBvcnRzID0gd2luZG93O1xuIiwiKGZ1bmN0aW9uIChnbG9iYWwpIHtcblx0dmFyIHNwcml0ZXMgPSB7XG5cdFx0J3NraWVyJyA6IHtcblx0XHRcdCRpbWFnZUZpbGUgOiAnc3ByaXRlLWNoYXJhY3RlcnMucG5nJyxcblx0XHRcdHBhcnRzIDoge1xuXHRcdFx0XHRibGFuayA6IFsgMCwgMCwgMCwgMCBdLFxuXHRcdFx0XHRlYXN0IDogWyAwLCAwLCAyNCwgMzQgXSxcblx0XHRcdFx0ZXNFYXN0IDogWyAyNCwgMCwgMjQsIDM0IF0sXG5cdFx0XHRcdHNFYXN0IDogWyA0OSwgMCwgMTcsIDM0IF0sXG5cdFx0XHRcdHNvdXRoIDogWyA2NSwgMCwgMTcsIDM0IF0sXG5cdFx0XHRcdHNXZXN0IDogWyA0OSwgMzcsIDE3LCAzNCBdLFxuXHRcdFx0XHR3c1dlc3QgOiBbIDI0LCAzNywgMjQsIDM0IF0sXG5cdFx0XHRcdHdlc3QgOiBbIDAsIDM3LCAyNCwgMzQgXSxcblx0XHRcdFx0aGl0IDogWyAwLCA3OCwgMzEsIDMxIF0sXG5cdFx0XHRcdGp1bXBpbmcgOiBbIDg0LCAwLCAzMiwgMzQgXSxcblx0XHRcdFx0c29tZXJzYXVsdDEgOiBbIDExNiwgMCwgMzIsIDM0IF0sXG5cdFx0XHRcdHNvbWVyc2F1bHQyIDogWyAxNDgsIDAsIDMyLCAzNCBdXG5cdFx0XHR9LFxuXHRcdFx0aGl0Qm94ZXM6IHtcblx0XHRcdFx0MDogWyA3LCAyMCwgMjcsIDM0IF1cblx0XHRcdH0sXG5cdFx0XHRpZCA6ICdwbGF5ZXInLFxuXHRcdFx0aGl0QmVoYXZpb3VyOiB7fVxuXHRcdH0sXG5cdFx0J3NtYWxsVHJlZScgOiB7XG5cdFx0XHQkaW1hZ2VGaWxlIDogJ3NraWZyZWUtb2JqZWN0cy5wbmcnLFxuXHRcdFx0cGFydHMgOiB7XG5cdFx0XHRcdG1haW4gOiBbIDAsIDI4LCAzMCwgMzQgXVxuXHRcdFx0fSxcblx0XHRcdGhpdEJveGVzOiB7XG5cdFx0XHRcdDA6IFsgMCwgMTgsIDMwLCAzNCBdXG5cdFx0XHR9LFxuXHRcdFx0aGl0QmVoYXZpb3VyOiB7fVxuXHRcdH0sXG5cdFx0J3RhbGxUcmVlJyA6IHtcblx0XHRcdCRpbWFnZUZpbGUgOiAnc2tpZnJlZS1vYmplY3RzLnBuZycsXG5cdFx0XHRwYXJ0cyA6IHtcblx0XHRcdFx0bWFpbiA6IFsgOTUsIDY2LCAzMiwgNjQgXVxuXHRcdFx0fSxcblx0XHRcdHpJbmRleGVzT2NjdXBpZWQgOiBbMCwgMV0sXG5cdFx0XHRoaXRCb3hlczoge1xuXHRcdFx0XHQwOiBbMCwgNTQsIDMyLCA2NF0sXG5cdFx0XHRcdDE6IFswLCAxMCwgMzIsIDU0XVxuXHRcdFx0fSxcblx0XHRcdGhpdEJlaGF2aW91cjoge31cblx0XHR9LFxuXHRcdCd0aGlja1Nub3cnIDoge1xuXHRcdFx0JGltYWdlRmlsZSA6ICdza2lmcmVlLW9iamVjdHMucG5nJyxcblx0XHRcdHBhcnRzIDoge1xuXHRcdFx0XHRtYWluIDogWyAxNDMsIDUzLCA0MywgMTAgXVxuXHRcdFx0fSxcblx0XHRcdGhpdEJlaGF2aW91cjoge31cblx0XHR9LFxuXHRcdCdyb2NrJyA6IHtcblx0XHRcdCRpbWFnZUZpbGUgOiAnc2tpZnJlZS1vYmplY3RzLnBuZycsXG5cdFx0XHRwYXJ0cyA6IHtcblx0XHRcdFx0bWFpbiA6IFsgMzAsIDUyLCAyMywgMTEgXVxuXHRcdFx0fSxcblx0XHRcdGhpdEJlaGF2aW91cjoge31cblx0XHR9LFxuXHRcdCdtb25zdGVyJyA6IHtcblx0XHRcdCRpbWFnZUZpbGUgOiAnc3ByaXRlLWNoYXJhY3RlcnMucG5nJyxcblx0XHRcdHBhcnRzIDoge1xuXHRcdFx0XHRzRWFzdDEgOiBbIDY0LCAxMTIsIDI2LCA0MyBdLFxuXHRcdFx0XHRzRWFzdDIgOiBbIDkwLCAxMTIsIDMyLCA0MyBdLFxuXHRcdFx0XHRzV2VzdDEgOiBbIDY0LCAxNTgsIDI2LCA0MyBdLFxuXHRcdFx0XHRzV2VzdDIgOiBbIDkwLCAxNTgsIDMyLCA0MyBdLFxuXHRcdFx0XHRlYXRpbmcxIDogWyAxMjIsIDExMiwgMzQsIDQzIF0sXG5cdFx0XHRcdGVhdGluZzIgOiBbIDE1NiwgMTEyLCAzMSwgNDMgXSxcblx0XHRcdFx0ZWF0aW5nMyA6IFsgMTg3LCAxMTIsIDMxLCA0MyBdLFxuXHRcdFx0XHRlYXRpbmc0IDogWyAyMTksIDExMiwgMjUsIDQzIF0sXG5cdFx0XHRcdGVhdGluZzUgOiBbIDI0MywgMTEyLCAyNiwgNDMgXVxuXHRcdFx0fSxcblx0XHRcdGhpdEJlaGF2aW91cjoge31cblx0XHR9LFxuXHRcdCdqdW1wJyA6IHtcblx0XHRcdCRpbWFnZUZpbGUgOiAnc2tpZnJlZS1vYmplY3RzLnBuZycsXG5cdFx0XHRwYXJ0cyA6IHtcblx0XHRcdFx0bWFpbiA6IFsgMTA5LCA1NSwgMzIsIDggXVxuXHRcdFx0fSxcblx0XHRcdGhpdEJlaGF2aW91cjoge31cblx0XHR9LFxuXHRcdCdzaWduU3RhcnQnIDoge1xuXHRcdFx0JGltYWdlRmlsZSA6ICdza2lmcmVlLW9iamVjdHMucG5nJyxcblx0XHRcdHBhcnRzIDoge1xuXHRcdFx0XHRtYWluIDogWyAyNjAsIDEwMywgNDIsIDI3IF1cblx0XHRcdH0sXG5cdFx0XHRoaXRCZWhhdmlvdXI6IHt9XG5cdFx0fSxcblx0XHQnc25vd2JvYXJkZXInIDoge1xuXHRcdFx0JGltYWdlRmlsZSA6ICdzcHJpdGUtY2hhcmFjdGVycy5wbmcnLFxuXHRcdFx0cGFydHMgOiB7XG5cdFx0XHRcdHNFYXN0IDogWyA3MywgMjI5LCAyMCwgMjkgXSxcblx0XHRcdFx0c1dlc3QgOiBbIDk1LCAyMjgsIDI2LCAzMCBdXG5cdFx0XHR9LFxuXHRcdFx0aGl0QmVoYXZpb3VyOiB7fVxuXHRcdH0sXG5cdFx0J2VtcHR5Q2hhaXJMaWZ0Jzoge1xuXHRcdFx0JGltYWdlRmlsZSA6ICdza2lmcmVlLW9iamVjdHMucG5nJyxcblx0XHRcdHBhcnRzOiB7XG5cdFx0XHRcdG1haW4gOiBbIDkyLCAxMzYsIDI2LCAzMCBdXG5cdFx0XHR9LFxuXHRcdFx0ekluZGV4ZXNPY2N1cGllZCA6IFsxXSxcblx0XHR9XG5cdH07XG5cblx0ZnVuY3Rpb24gbW9uc3RlckhpdHNUcmVlQmVoYXZpb3VyKG1vbnN0ZXIpIHtcblx0XHRtb25zdGVyLmRlbGV0ZU9uTmV4dEN5Y2xlKCk7XG5cdH1cblxuXHRzcHJpdGVzLm1vbnN0ZXIuaGl0QmVoYXZpb3VyLnRyZWUgPSBtb25zdGVySGl0c1RyZWVCZWhhdmlvdXI7XG5cblx0ZnVuY3Rpb24gdHJlZUhpdHNNb25zdGVyQmVoYXZpb3VyKHRyZWUsIG1vbnN0ZXIpIHtcblx0XHRtb25zdGVyLmRlbGV0ZU9uTmV4dEN5Y2xlKCk7XG5cdH1cblxuXHRzcHJpdGVzLnNtYWxsVHJlZS5oaXRCZWhhdmlvdXIubW9uc3RlciA9IHRyZWVIaXRzTW9uc3RlckJlaGF2aW91cjtcblx0c3ByaXRlcy50YWxsVHJlZS5oaXRCZWhhdmlvdXIubW9uc3RlciA9IHRyZWVIaXRzTW9uc3RlckJlaGF2aW91cjtcblxuXHRmdW5jdGlvbiBza2llckhpdHNUcmVlQmVoYXZpb3VyKHNraWVyLCB0cmVlKSB7XG5cdFx0c2tpZXIuaGFzSGl0T2JzdGFjbGUodHJlZSk7XG5cdH1cblxuXHRmdW5jdGlvbiB0cmVlSGl0c1NraWVyQmVoYXZpb3VyKHRyZWUsIHNraWVyKSB7XG5cdFx0c2tpZXIuaGFzSGl0T2JzdGFjbGUodHJlZSk7XG5cdH1cblxuXHRzcHJpdGVzLnNtYWxsVHJlZS5oaXRCZWhhdmlvdXIuc2tpZXIgPSB0cmVlSGl0c1NraWVyQmVoYXZpb3VyO1xuXHRzcHJpdGVzLnRhbGxUcmVlLmhpdEJlaGF2aW91ci5za2llciA9IHRyZWVIaXRzU2tpZXJCZWhhdmlvdXI7XG5cblx0ZnVuY3Rpb24gcm9ja0hpdHNTa2llckJlaGF2aW91cihyb2NrLCBza2llcikge1xuXHRcdHNraWVyLmhhc0hpdE9ic3RhY2xlKHJvY2spO1xuXHR9XG5cblx0c3ByaXRlcy5yb2NrLmhpdEJlaGF2aW91ci5za2llciA9IHJvY2tIaXRzU2tpZXJCZWhhdmlvdXI7XG5cblx0ZnVuY3Rpb24gc2tpZXJIaXRzSnVtcEJlaGF2aW91cihza2llciwganVtcCkge1xuXHRcdHNraWVyLmhhc0hpdEp1bXAoanVtcCk7XG5cdH1cblxuXHRmdW5jdGlvbiBqdW1wSGl0c1NraWVyQmVoYXZpb3VyKGp1bXAsIHNraWVyKSB7XG5cdFx0c2tpZXIuaGFzSGl0SnVtcChqdW1wKTtcblx0fVxuXG5cdHNwcml0ZXMuanVtcC5oaXRCZWhhdmlvdXIuc2tpZXIgPSBqdW1wSGl0c1NraWVyQmVoYXZpb3VyO1xuXG4vLyBSZWFsbHkgbm90IGEgZmFuIG9mIHRoaXMgYmVoYXZpb3VyLlxuLypcdGZ1bmN0aW9uIHNraWVySGl0c1RoaWNrU25vd0JlaGF2aW91cihza2llciwgdGhpY2tTbm93KSB7XG5cdFx0Ly8gTmVlZCB0byBpbXBsZW1lbnQgdGhpcyBwcm9wZXJseVxuXHRcdHNraWVyLnNldFNwZWVkKDIpO1xuXHRcdHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG5cdFx0XHRza2llci5yZXNldFNwZWVkKCk7XG5cdFx0fSwgNzAwKTtcblx0fVxuXG5cdGZ1bmN0aW9uIHRoaWNrU25vd0hpdHNTa2llckJlaGF2aW91cih0aGlja1Nub3csIHNraWVyKSB7XG5cdFx0Ly8gTmVlZCB0byBpbXBsZW1lbnQgdGhpcyBwcm9wZXJseVxuXHRcdHNraWVyLnNldFNwZWVkKDIpO1xuXHRcdHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG5cdFx0XHRza2llci5yZXNldFNwZWVkKCk7XG5cdFx0fSwgMzAwKTtcblx0fSovXG5cblx0Ly8gc3ByaXRlcy50aGlja1Nub3cuaGl0QmVoYXZpb3VyLnNraWVyID0gdGhpY2tTbm93SGl0c1NraWVyQmVoYXZpb3VyO1xuXG5cdGZ1bmN0aW9uIHNub3dib2FyZGVySGl0c1NraWVyQmVoYXZpb3VyKHNub3dib2FyZGVyLCBza2llcikge1xuXHRcdHNraWVyLmhhc0hpdE9ic3RhY2xlKHNub3dib2FyZGVyKTtcblx0fVxuXG5cdHNwcml0ZXMuc25vd2JvYXJkZXIuaGl0QmVoYXZpb3VyLnNraWVyID0gc25vd2JvYXJkZXJIaXRzU2tpZXJCZWhhdmlvdXI7XG5cblx0Z2xvYmFsLnNwcml0ZUluZm8gPSBzcHJpdGVzO1xufSkoIHRoaXMgKTtcblxuXG5pZiAodHlwZW9mIG1vZHVsZSAhPT0gJ3VuZGVmaW5lZCcpIHtcblx0bW9kdWxlLmV4cG9ydHMgPSB0aGlzLnNwcml0ZUluZm87XG59IiwiLyoqXG4gKiBDb3B5cmlnaHQgMjAxMiBDcmFpZyBDYW1wYmVsbFxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICpcbiAqIE1vdXNldHJhcCBpcyBhIHNpbXBsZSBrZXlib2FyZCBzaG9ydGN1dCBsaWJyYXJ5IGZvciBKYXZhc2NyaXB0IHdpdGhcbiAqIG5vIGV4dGVybmFsIGRlcGVuZGVuY2llc1xuICpcbiAqIEB2ZXJzaW9uIDEuMS4zXG4gKiBAdXJsIGNyYWlnLmlzL2tpbGxpbmcvbWljZVxuICovXG4oZnVuY3Rpb24oKSB7XG5cbiAgICAvKipcbiAgICAgKiBtYXBwaW5nIG9mIHNwZWNpYWwga2V5Y29kZXMgdG8gdGhlaXIgY29ycmVzcG9uZGluZyBrZXlzXG4gICAgICpcbiAgICAgKiBldmVyeXRoaW5nIGluIHRoaXMgZGljdGlvbmFyeSBjYW5ub3QgdXNlIGtleXByZXNzIGV2ZW50c1xuICAgICAqIHNvIGl0IGhhcyB0byBiZSBoZXJlIHRvIG1hcCB0byB0aGUgY29ycmVjdCBrZXljb2RlcyBmb3JcbiAgICAgKiBrZXl1cC9rZXlkb3duIGV2ZW50c1xuICAgICAqXG4gICAgICogQHR5cGUge09iamVjdH1cbiAgICAgKi9cbiAgICB2YXIgX01BUCA9IHtcbiAgICAgICAgICAgIDg6ICdiYWNrc3BhY2UnLFxuICAgICAgICAgICAgOTogJ3RhYicsXG4gICAgICAgICAgICAxMzogJ2VudGVyJyxcbiAgICAgICAgICAgIDE2OiAnc2hpZnQnLFxuICAgICAgICAgICAgMTc6ICdjdHJsJyxcbiAgICAgICAgICAgIDE4OiAnYWx0JyxcbiAgICAgICAgICAgIDIwOiAnY2Fwc2xvY2snLFxuICAgICAgICAgICAgMjc6ICdlc2MnLFxuICAgICAgICAgICAgMzI6ICdzcGFjZScsXG4gICAgICAgICAgICAzMzogJ3BhZ2V1cCcsXG4gICAgICAgICAgICAzNDogJ3BhZ2Vkb3duJyxcbiAgICAgICAgICAgIDM1OiAnZW5kJyxcbiAgICAgICAgICAgIDM2OiAnaG9tZScsXG4gICAgICAgICAgICAzNzogJ2xlZnQnLFxuICAgICAgICAgICAgMzg6ICd1cCcsXG4gICAgICAgICAgICAzOTogJ3JpZ2h0JyxcbiAgICAgICAgICAgIDQwOiAnZG93bicsXG4gICAgICAgICAgICA0NTogJ2lucycsXG4gICAgICAgICAgICA0NjogJ2RlbCcsXG4gICAgICAgICAgICA5MTogJ21ldGEnLFxuICAgICAgICAgICAgOTM6ICdtZXRhJyxcbiAgICAgICAgICAgIDIyNDogJ21ldGEnXG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIG1hcHBpbmcgZm9yIHNwZWNpYWwgY2hhcmFjdGVycyBzbyB0aGV5IGNhbiBzdXBwb3J0XG4gICAgICAgICAqXG4gICAgICAgICAqIHRoaXMgZGljdGlvbmFyeSBpcyBvbmx5IHVzZWQgaW5jYXNlIHlvdSB3YW50IHRvIGJpbmQgYVxuICAgICAgICAgKiBrZXl1cCBvciBrZXlkb3duIGV2ZW50IHRvIG9uZSBvZiB0aGVzZSBrZXlzXG4gICAgICAgICAqXG4gICAgICAgICAqIEB0eXBlIHtPYmplY3R9XG4gICAgICAgICAqL1xuICAgICAgICBfS0VZQ09ERV9NQVAgPSB7XG4gICAgICAgICAgICAxMDY6ICcqJyxcbiAgICAgICAgICAgIDEwNzogJysnLFxuICAgICAgICAgICAgMTA5OiAnLScsXG4gICAgICAgICAgICAxMTA6ICcuJyxcbiAgICAgICAgICAgIDExMSA6ICcvJyxcbiAgICAgICAgICAgIDE4NjogJzsnLFxuICAgICAgICAgICAgMTg3OiAnPScsXG4gICAgICAgICAgICAxODg6ICcsJyxcbiAgICAgICAgICAgIDE4OTogJy0nLFxuICAgICAgICAgICAgMTkwOiAnLicsXG4gICAgICAgICAgICAxOTE6ICcvJyxcbiAgICAgICAgICAgIDE5MjogJ2AnLFxuICAgICAgICAgICAgMjE5OiAnWycsXG4gICAgICAgICAgICAyMjA6ICdcXFxcJyxcbiAgICAgICAgICAgIDIyMTogJ10nLFxuICAgICAgICAgICAgMjIyOiAnXFwnJ1xuICAgICAgICB9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiB0aGlzIGlzIGEgbWFwcGluZyBvZiBrZXlzIHRoYXQgcmVxdWlyZSBzaGlmdCBvbiBhIFVTIGtleXBhZFxuICAgICAgICAgKiBiYWNrIHRvIHRoZSBub24gc2hpZnQgZXF1aXZlbGVudHNcbiAgICAgICAgICpcbiAgICAgICAgICogdGhpcyBpcyBzbyB5b3UgY2FuIHVzZSBrZXl1cCBldmVudHMgd2l0aCB0aGVzZSBrZXlzXG4gICAgICAgICAqXG4gICAgICAgICAqIG5vdGUgdGhhdCB0aGlzIHdpbGwgb25seSB3b3JrIHJlbGlhYmx5IG9uIFVTIGtleWJvYXJkc1xuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgX1NISUZUX01BUCA9IHtcbiAgICAgICAgICAgICd+JzogJ2AnLFxuICAgICAgICAgICAgJyEnOiAnMScsXG4gICAgICAgICAgICAnQCc6ICcyJyxcbiAgICAgICAgICAgICcjJzogJzMnLFxuICAgICAgICAgICAgJyQnOiAnNCcsXG4gICAgICAgICAgICAnJSc6ICc1JyxcbiAgICAgICAgICAgICdeJzogJzYnLFxuICAgICAgICAgICAgJyYnOiAnNycsXG4gICAgICAgICAgICAnKic6ICc4JyxcbiAgICAgICAgICAgICcoJzogJzknLFxuICAgICAgICAgICAgJyknOiAnMCcsXG4gICAgICAgICAgICAnXyc6ICctJyxcbiAgICAgICAgICAgICcrJzogJz0nLFxuICAgICAgICAgICAgJzonOiAnOycsXG4gICAgICAgICAgICAnXFxcIic6ICdcXCcnLFxuICAgICAgICAgICAgJzwnOiAnLCcsXG4gICAgICAgICAgICAnPic6ICcuJyxcbiAgICAgICAgICAgICc/JzogJy8nLFxuICAgICAgICAgICAgJ3wnOiAnXFxcXCdcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogdGhpcyBpcyBhIGxpc3Qgb2Ygc3BlY2lhbCBzdHJpbmdzIHlvdSBjYW4gdXNlIHRvIG1hcFxuICAgICAgICAgKiB0byBtb2RpZmllciBrZXlzIHdoZW4geW91IHNwZWNpZnkgeW91ciBrZXlib2FyZCBzaG9ydGN1dHNcbiAgICAgICAgICpcbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIF9TUEVDSUFMX0FMSUFTRVMgPSB7XG4gICAgICAgICAgICAnb3B0aW9uJzogJ2FsdCcsXG4gICAgICAgICAgICAnY29tbWFuZCc6ICdtZXRhJyxcbiAgICAgICAgICAgICdyZXR1cm4nOiAnZW50ZXInLFxuICAgICAgICAgICAgJ2VzY2FwZSc6ICdlc2MnXG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIHZhcmlhYmxlIHRvIHN0b3JlIHRoZSBmbGlwcGVkIHZlcnNpb24gb2YgX01BUCBmcm9tIGFib3ZlXG4gICAgICAgICAqIG5lZWRlZCB0byBjaGVjayBpZiB3ZSBzaG91bGQgdXNlIGtleXByZXNzIG9yIG5vdCB3aGVuIG5vIGFjdGlvblxuICAgICAgICAgKiBpcyBzcGVjaWZpZWRcbiAgICAgICAgICpcbiAgICAgICAgICogQHR5cGUge09iamVjdHx1bmRlZmluZWR9XG4gICAgICAgICAqL1xuICAgICAgICBfUkVWRVJTRV9NQVAsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIGEgbGlzdCBvZiBhbGwgdGhlIGNhbGxiYWNrcyBzZXR1cCB2aWEgTW91c2V0cmFwLmJpbmQoKVxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgX2NhbGxiYWNrcyA9IHt9LFxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiBkaXJlY3QgbWFwIG9mIHN0cmluZyBjb21iaW5hdGlvbnMgdG8gY2FsbGJhY2tzIHVzZWQgZm9yIHRyaWdnZXIoKVxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7T2JqZWN0fVxuICAgICAgICAgKi9cbiAgICAgICAgX2RpcmVjdF9tYXAgPSB7fSxcblxuICAgICAgICAvKipcbiAgICAgICAgICoga2VlcHMgdHJhY2sgb2Ygd2hhdCBsZXZlbCBlYWNoIHNlcXVlbmNlIGlzIGF0IHNpbmNlIG11bHRpcGxlXG4gICAgICAgICAqIHNlcXVlbmNlcyBjYW4gc3RhcnQgb3V0IHdpdGggdGhlIHNhbWUgc2VxdWVuY2VcbiAgICAgICAgICpcbiAgICAgICAgICogQHR5cGUge09iamVjdH1cbiAgICAgICAgICovXG4gICAgICAgIF9zZXF1ZW5jZV9sZXZlbHMgPSB7fSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogdmFyaWFibGUgdG8gc3RvcmUgdGhlIHNldFRpbWVvdXQgY2FsbFxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7bnVsbHxudW1iZXJ9XG4gICAgICAgICAqL1xuICAgICAgICBfcmVzZXRfdGltZXIsXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIHRlbXBvcmFyeSBzdGF0ZSB3aGVyZSB3ZSB3aWxsIGlnbm9yZSB0aGUgbmV4dCBrZXl1cFxuICAgICAgICAgKlxuICAgICAgICAgKiBAdHlwZSB7Ym9vbGVhbnxzdHJpbmd9XG4gICAgICAgICAqL1xuICAgICAgICBfaWdub3JlX25leHRfa2V5dXAgPSBmYWxzZSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogYXJlIHdlIGN1cnJlbnRseSBpbnNpZGUgb2YgYSBzZXF1ZW5jZT9cbiAgICAgICAgICogdHlwZSBvZiBhY3Rpb24gKFwia2V5dXBcIiBvciBcImtleWRvd25cIiBvciBcImtleXByZXNzXCIpIG9yIGZhbHNlXG4gICAgICAgICAqXG4gICAgICAgICAqIEB0eXBlIHtib29sZWFufHN0cmluZ31cbiAgICAgICAgICovXG4gICAgICAgIF9pbnNpZGVfc2VxdWVuY2UgPSBmYWxzZTtcblxuICAgIC8qKlxuICAgICAqIGxvb3AgdGhyb3VnaCB0aGUgZiBrZXlzLCBmMSB0byBmMTkgYW5kIGFkZCB0aGVtIHRvIHRoZSBtYXBcbiAgICAgKiBwcm9ncmFtYXRpY2FsbHlcbiAgICAgKi9cbiAgICBmb3IgKHZhciBpID0gMTsgaSA8IDIwOyArK2kpIHtcbiAgICAgICAgX01BUFsxMTEgKyBpXSA9ICdmJyArIGk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogbG9vcCB0aHJvdWdoIHRvIG1hcCBudW1iZXJzIG9uIHRoZSBudW1lcmljIGtleXBhZFxuICAgICAqL1xuICAgIGZvciAoaSA9IDA7IGkgPD0gOTsgKytpKSB7XG4gICAgICAgIF9NQVBbaSArIDk2XSA9IGk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogY3Jvc3MgYnJvd3NlciBhZGQgZXZlbnQgbWV0aG9kXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0VsZW1lbnR8SFRNTERvY3VtZW50fSBvYmplY3RcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gdHlwZVxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrXG4gICAgICogQHJldHVybnMgdm9pZFxuICAgICAqL1xuICAgIGZ1bmN0aW9uIF9hZGRFdmVudChvYmplY3QsIHR5cGUsIGNhbGxiYWNrKSB7XG4gICAgICAgIGlmIChvYmplY3QuYWRkRXZlbnRMaXN0ZW5lcikge1xuICAgICAgICAgICAgb2JqZWN0LmFkZEV2ZW50TGlzdGVuZXIodHlwZSwgY2FsbGJhY2ssIGZhbHNlKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIG9iamVjdC5hdHRhY2hFdmVudCgnb24nICsgdHlwZSwgY2FsbGJhY2spO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIHRha2VzIHRoZSBldmVudCBhbmQgcmV0dXJucyB0aGUga2V5IGNoYXJhY3RlclxuICAgICAqXG4gICAgICogQHBhcmFtIHtFdmVudH0gZVxuICAgICAqIEByZXR1cm4ge3N0cmluZ31cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBfY2hhcmFjdGVyRnJvbUV2ZW50KGUpIHtcblxuICAgICAgICAvLyBmb3Iga2V5cHJlc3MgZXZlbnRzIHdlIHNob3VsZCByZXR1cm4gdGhlIGNoYXJhY3RlciBhcyBpc1xuICAgICAgICBpZiAoZS50eXBlID09ICdrZXlwcmVzcycpIHtcbiAgICAgICAgICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlKGUud2hpY2gpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZm9yIG5vbiBrZXlwcmVzcyBldmVudHMgdGhlIHNwZWNpYWwgbWFwcyBhcmUgbmVlZGVkXG4gICAgICAgIGlmIChfTUFQW2Uud2hpY2hdKSB7XG4gICAgICAgICAgICByZXR1cm4gX01BUFtlLndoaWNoXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChfS0VZQ09ERV9NQVBbZS53aGljaF0pIHtcbiAgICAgICAgICAgIHJldHVybiBfS0VZQ09ERV9NQVBbZS53aGljaF07XG4gICAgICAgIH1cblxuICAgICAgICAvLyBpZiBpdCBpcyBub3QgaW4gdGhlIHNwZWNpYWwgbWFwXG4gICAgICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlKGUud2hpY2gpLnRvTG93ZXJDYXNlKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogY2hlY2tzIGlmIHR3byBhcnJheXMgYXJlIGVxdWFsXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBtb2RpZmllcnMxXG4gICAgICogQHBhcmFtIHtBcnJheX0gbW9kaWZpZXJzMlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIF9tb2RpZmllcnNNYXRjaChtb2RpZmllcnMxLCBtb2RpZmllcnMyKSB7XG4gICAgICAgIHJldHVybiBtb2RpZmllcnMxLnNvcnQoKS5qb2luKCcsJykgPT09IG1vZGlmaWVyczIuc29ydCgpLmpvaW4oJywnKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiByZXNldHMgYWxsIHNlcXVlbmNlIGNvdW50ZXJzIGV4Y2VwdCBmb3IgdGhlIG9uZXMgcGFzc2VkIGluXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gZG9fbm90X3Jlc2V0XG4gICAgICogQHJldHVybnMgdm9pZFxuICAgICAqL1xuICAgIGZ1bmN0aW9uIF9yZXNldFNlcXVlbmNlcyhkb19ub3RfcmVzZXQpIHtcbiAgICAgICAgZG9fbm90X3Jlc2V0ID0gZG9fbm90X3Jlc2V0IHx8IHt9O1xuXG4gICAgICAgIHZhciBhY3RpdmVfc2VxdWVuY2VzID0gZmFsc2UsXG4gICAgICAgICAgICBrZXk7XG5cbiAgICAgICAgZm9yIChrZXkgaW4gX3NlcXVlbmNlX2xldmVscykge1xuICAgICAgICAgICAgaWYgKGRvX25vdF9yZXNldFtrZXldKSB7XG4gICAgICAgICAgICAgICAgYWN0aXZlX3NlcXVlbmNlcyA9IHRydWU7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBfc2VxdWVuY2VfbGV2ZWxzW2tleV0gPSAwO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFhY3RpdmVfc2VxdWVuY2VzKSB7XG4gICAgICAgICAgICBfaW5zaWRlX3NlcXVlbmNlID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBmaW5kcyBhbGwgY2FsbGJhY2tzIHRoYXQgbWF0Y2ggYmFzZWQgb24gdGhlIGtleWNvZGUsIG1vZGlmaWVycyxcbiAgICAgKiBhbmQgYWN0aW9uXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gY2hhcmFjdGVyXG4gICAgICogQHBhcmFtIHtBcnJheX0gbW9kaWZpZXJzXG4gICAgICogQHBhcmFtIHtFdmVudHxPYmplY3R9IGVcbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW49fSByZW1vdmUgLSBzaG91bGQgd2UgcmVtb3ZlIGFueSBtYXRjaGVzXG4gICAgICogQHBhcmFtIHtzdHJpbmc9fSBjb21iaW5hdGlvblxuICAgICAqIEByZXR1cm5zIHtBcnJheX1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBfZ2V0TWF0Y2hlcyhjaGFyYWN0ZXIsIG1vZGlmaWVycywgZSwgcmVtb3ZlLCBjb21iaW5hdGlvbikge1xuICAgICAgICB2YXIgaSxcbiAgICAgICAgICAgIGNhbGxiYWNrLFxuICAgICAgICAgICAgbWF0Y2hlcyA9IFtdLFxuICAgICAgICAgICAgYWN0aW9uID0gZS50eXBlO1xuXG4gICAgICAgIC8vIGlmIHRoZXJlIGFyZSBubyBldmVudHMgcmVsYXRlZCB0byB0aGlzIGtleWNvZGVcbiAgICAgICAgaWYgKCFfY2FsbGJhY2tzW2NoYXJhY3Rlcl0pIHtcbiAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGlmIGEgbW9kaWZpZXIga2V5IGlzIGNvbWluZyB1cCBvbiBpdHMgb3duIHdlIHNob3VsZCBhbGxvdyBpdFxuICAgICAgICBpZiAoYWN0aW9uID09ICdrZXl1cCcgJiYgX2lzTW9kaWZpZXIoY2hhcmFjdGVyKSkge1xuICAgICAgICAgICAgbW9kaWZpZXJzID0gW2NoYXJhY3Rlcl07XG4gICAgICAgIH1cblxuICAgICAgICAvLyBsb29wIHRocm91Z2ggYWxsIGNhbGxiYWNrcyBmb3IgdGhlIGtleSB0aGF0IHdhcyBwcmVzc2VkXG4gICAgICAgIC8vIGFuZCBzZWUgaWYgYW55IG9mIHRoZW0gbWF0Y2hcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IF9jYWxsYmFja3NbY2hhcmFjdGVyXS5sZW5ndGg7ICsraSkge1xuICAgICAgICAgICAgY2FsbGJhY2sgPSBfY2FsbGJhY2tzW2NoYXJhY3Rlcl1baV07XG5cbiAgICAgICAgICAgIC8vIGlmIHRoaXMgaXMgYSBzZXF1ZW5jZSBidXQgaXQgaXMgbm90IGF0IHRoZSByaWdodCBsZXZlbFxuICAgICAgICAgICAgLy8gdGhlbiBtb3ZlIG9udG8gdGhlIG5leHQgbWF0Y2hcbiAgICAgICAgICAgIGlmIChjYWxsYmFjay5zZXEgJiYgX3NlcXVlbmNlX2xldmVsc1tjYWxsYmFjay5zZXFdICE9IGNhbGxiYWNrLmxldmVsKSB7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIGlmIHRoZSBhY3Rpb24gd2UgYXJlIGxvb2tpbmcgZm9yIGRvZXNuJ3QgbWF0Y2ggdGhlIGFjdGlvbiB3ZSBnb3RcbiAgICAgICAgICAgIC8vIHRoZW4gd2Ugc2hvdWxkIGtlZXAgZ29pbmdcbiAgICAgICAgICAgIGlmIChhY3Rpb24gIT0gY2FsbGJhY2suYWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIGlmIHRoaXMgaXMgYSBrZXlwcmVzcyBldmVudCBhbmQgdGhlIG1ldGEga2V5IGFuZCBjb250cm9sIGtleVxuICAgICAgICAgICAgLy8gYXJlIG5vdCBwcmVzc2VkIHRoYXQgbWVhbnMgdGhhdCB3ZSBuZWVkIHRvIG9ubHkgbG9vayBhdCB0aGVcbiAgICAgICAgICAgIC8vIGNoYXJhY3Rlciwgb3RoZXJ3aXNlIGNoZWNrIHRoZSBtb2RpZmllcnMgYXMgd2VsbFxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIGNocm9tZSB3aWxsIG5vdCBmaXJlIGEga2V5cHJlc3MgaWYgbWV0YSBvciBjb250cm9sIGlzIGRvd25cbiAgICAgICAgICAgIC8vIHNhZmFyaSB3aWxsIGZpcmUgYSBrZXlwcmVzcyBpZiBtZXRhIG9yIG1ldGErc2hpZnQgaXMgZG93blxuICAgICAgICAgICAgLy8gZmlyZWZveCB3aWxsIGZpcmUgYSBrZXlwcmVzcyBpZiBtZXRhIG9yIGNvbnRyb2wgaXMgZG93blxuICAgICAgICAgICAgaWYgKChhY3Rpb24gPT0gJ2tleXByZXNzJyAmJiAhZS5tZXRhS2V5ICYmICFlLmN0cmxLZXkpIHx8IF9tb2RpZmllcnNNYXRjaChtb2RpZmllcnMsIGNhbGxiYWNrLm1vZGlmaWVycykpIHtcblxuICAgICAgICAgICAgICAgIC8vIHJlbW92ZSBpcyB1c2VkIHNvIGlmIHlvdSBjaGFuZ2UgeW91ciBtaW5kIGFuZCBjYWxsIGJpbmQgYVxuICAgICAgICAgICAgICAgIC8vIHNlY29uZCB0aW1lIHdpdGggYSBuZXcgZnVuY3Rpb24gdGhlIGZpcnN0IG9uZSBpcyBvdmVyd3JpdHRlblxuICAgICAgICAgICAgICAgIGlmIChyZW1vdmUgJiYgY2FsbGJhY2suY29tYm8gPT0gY29tYmluYXRpb24pIHtcbiAgICAgICAgICAgICAgICAgICAgX2NhbGxiYWNrc1tjaGFyYWN0ZXJdLnNwbGljZShpLCAxKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBtYXRjaGVzLnB1c2goY2FsbGJhY2spO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG1hdGNoZXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogdGFrZXMgYSBrZXkgZXZlbnQgYW5kIGZpZ3VyZXMgb3V0IHdoYXQgdGhlIG1vZGlmaWVycyBhcmVcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7RXZlbnR9IGVcbiAgICAgKiBAcmV0dXJucyB7QXJyYXl9XG4gICAgICovXG4gICAgZnVuY3Rpb24gX2V2ZW50TW9kaWZpZXJzKGUpIHtcbiAgICAgICAgdmFyIG1vZGlmaWVycyA9IFtdO1xuXG4gICAgICAgIGlmIChlLnNoaWZ0S2V5KSB7XG4gICAgICAgICAgICBtb2RpZmllcnMucHVzaCgnc2hpZnQnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChlLmFsdEtleSkge1xuICAgICAgICAgICAgbW9kaWZpZXJzLnB1c2goJ2FsdCcpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGUuY3RybEtleSkge1xuICAgICAgICAgICAgbW9kaWZpZXJzLnB1c2goJ2N0cmwnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChlLm1ldGFLZXkpIHtcbiAgICAgICAgICAgIG1vZGlmaWVycy5wdXNoKCdtZXRhJyk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbW9kaWZpZXJzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIGFjdHVhbGx5IGNhbGxzIHRoZSBjYWxsYmFjayBmdW5jdGlvblxuICAgICAqXG4gICAgICogaWYgeW91ciBjYWxsYmFjayBmdW5jdGlvbiByZXR1cm5zIGZhbHNlIHRoaXMgd2lsbCB1c2UgdGhlIGpxdWVyeVxuICAgICAqIGNvbnZlbnRpb24gLSBwcmV2ZW50IGRlZmF1bHQgYW5kIHN0b3AgcHJvcG9nYXRpb24gb24gdGhlIGV2ZW50XG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICAgICAqIEBwYXJhbSB7RXZlbnR9IGVcbiAgICAgKiBAcmV0dXJucyB2b2lkXG4gICAgICovXG4gICAgZnVuY3Rpb24gX2ZpcmVDYWxsYmFjayhjYWxsYmFjaywgZSkge1xuICAgICAgICBpZiAoY2FsbGJhY2soZSkgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICBpZiAoZS5wcmV2ZW50RGVmYXVsdCkge1xuICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGUuc3RvcFByb3BhZ2F0aW9uKSB7XG4gICAgICAgICAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZS5yZXR1cm5WYWx1ZSA9IGZhbHNlO1xuICAgICAgICAgICAgZS5jYW5jZWxCdWJibGUgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogaGFuZGxlcyBhIGNoYXJhY3RlciBrZXkgZXZlbnRcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBjaGFyYWN0ZXJcbiAgICAgKiBAcGFyYW0ge0V2ZW50fSBlXG4gICAgICogQHJldHVybnMgdm9pZFxuICAgICAqL1xuICAgIGZ1bmN0aW9uIF9oYW5kbGVDaGFyYWN0ZXIoY2hhcmFjdGVyLCBlKSB7XG5cbiAgICAgICAgLy8gaWYgdGhpcyBldmVudCBzaG91bGQgbm90IGhhcHBlbiBzdG9wIGhlcmVcbiAgICAgICAgaWYgKE1vdXNldHJhcC5zdG9wQ2FsbGJhY2soZSwgZS50YXJnZXQgfHwgZS5zcmNFbGVtZW50KSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGNhbGxiYWNrcyA9IF9nZXRNYXRjaGVzKGNoYXJhY3RlciwgX2V2ZW50TW9kaWZpZXJzKGUpLCBlKSxcbiAgICAgICAgICAgIGksXG4gICAgICAgICAgICBkb19ub3RfcmVzZXQgPSB7fSxcbiAgICAgICAgICAgIHByb2Nlc3NlZF9zZXF1ZW5jZV9jYWxsYmFjayA9IGZhbHNlO1xuXG4gICAgICAgIC8vIGxvb3AgdGhyb3VnaCBtYXRjaGluZyBjYWxsYmFja3MgZm9yIHRoaXMga2V5IGV2ZW50XG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBjYWxsYmFja3MubGVuZ3RoOyArK2kpIHtcblxuICAgICAgICAgICAgLy8gZmlyZSBmb3IgYWxsIHNlcXVlbmNlIGNhbGxiYWNrc1xuICAgICAgICAgICAgLy8gdGhpcyBpcyBiZWNhdXNlIGlmIGZvciBleGFtcGxlIHlvdSBoYXZlIG11bHRpcGxlIHNlcXVlbmNlc1xuICAgICAgICAgICAgLy8gYm91bmQgc3VjaCBhcyBcImcgaVwiIGFuZCBcImcgdFwiIHRoZXkgYm90aCBuZWVkIHRvIGZpcmUgdGhlXG4gICAgICAgICAgICAvLyBjYWxsYmFjayBmb3IgbWF0Y2hpbmcgZyBjYXVzZSBvdGhlcndpc2UgeW91IGNhbiBvbmx5IGV2ZXJcbiAgICAgICAgICAgIC8vIG1hdGNoIHRoZSBmaXJzdCBvbmVcbiAgICAgICAgICAgIGlmIChjYWxsYmFja3NbaV0uc2VxKSB7XG4gICAgICAgICAgICAgICAgcHJvY2Vzc2VkX3NlcXVlbmNlX2NhbGxiYWNrID0gdHJ1ZTtcblxuICAgICAgICAgICAgICAgIC8vIGtlZXAgYSBsaXN0IG9mIHdoaWNoIHNlcXVlbmNlcyB3ZXJlIG1hdGNoZXMgZm9yIGxhdGVyXG4gICAgICAgICAgICAgICAgZG9fbm90X3Jlc2V0W2NhbGxiYWNrc1tpXS5zZXFdID0gMTtcbiAgICAgICAgICAgICAgICBfZmlyZUNhbGxiYWNrKGNhbGxiYWNrc1tpXS5jYWxsYmFjaywgZSk7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIGlmIHRoZXJlIHdlcmUgbm8gc2VxdWVuY2UgbWF0Y2hlcyBidXQgd2UgYXJlIHN0aWxsIGhlcmVcbiAgICAgICAgICAgIC8vIHRoYXQgbWVhbnMgdGhpcyBpcyBhIHJlZ3VsYXIgbWF0Y2ggc28gd2Ugc2hvdWxkIGZpcmUgdGhhdFxuICAgICAgICAgICAgaWYgKCFwcm9jZXNzZWRfc2VxdWVuY2VfY2FsbGJhY2sgJiYgIV9pbnNpZGVfc2VxdWVuY2UpIHtcbiAgICAgICAgICAgICAgICBfZmlyZUNhbGxiYWNrKGNhbGxiYWNrc1tpXS5jYWxsYmFjaywgZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBpZiB5b3UgYXJlIGluc2lkZSBvZiBhIHNlcXVlbmNlIGFuZCB0aGUga2V5IHlvdSBhcmUgcHJlc3NpbmdcbiAgICAgICAgLy8gaXMgbm90IGEgbW9kaWZpZXIga2V5IHRoZW4gd2Ugc2hvdWxkIHJlc2V0IGFsbCBzZXF1ZW5jZXNcbiAgICAgICAgLy8gdGhhdCB3ZXJlIG5vdCBtYXRjaGVkIGJ5IHRoaXMga2V5IGV2ZW50XG4gICAgICAgIGlmIChlLnR5cGUgPT0gX2luc2lkZV9zZXF1ZW5jZSAmJiAhX2lzTW9kaWZpZXIoY2hhcmFjdGVyKSkge1xuICAgICAgICAgICAgX3Jlc2V0U2VxdWVuY2VzKGRvX25vdF9yZXNldCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBoYW5kbGVzIGEga2V5ZG93biBldmVudFxuICAgICAqXG4gICAgICogQHBhcmFtIHtFdmVudH0gZVxuICAgICAqIEByZXR1cm5zIHZvaWRcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBfaGFuZGxlS2V5KGUpIHtcblxuICAgICAgICAvLyBub3JtYWxpemUgZS53aGljaCBmb3Iga2V5IGV2ZW50c1xuICAgICAgICAvLyBAc2VlIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvNDI4NTYyNy9qYXZhc2NyaXB0LWtleWNvZGUtdnMtY2hhcmNvZGUtdXR0ZXItY29uZnVzaW9uXG4gICAgICAgIGUud2hpY2ggPSB0eXBlb2YgZS53aGljaCA9PSBcIm51bWJlclwiID8gZS53aGljaCA6IGUua2V5Q29kZTtcblxuICAgICAgICB2YXIgY2hhcmFjdGVyID0gX2NoYXJhY3RlckZyb21FdmVudChlKTtcblxuICAgICAgICAvLyBubyBjaGFyYWN0ZXIgZm91bmQgdGhlbiBzdG9wXG4gICAgICAgIGlmICghY2hhcmFjdGVyKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZS50eXBlID09ICdrZXl1cCcgJiYgX2lnbm9yZV9uZXh0X2tleXVwID09IGNoYXJhY3Rlcikge1xuICAgICAgICAgICAgX2lnbm9yZV9uZXh0X2tleXVwID0gZmFsc2U7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBfaGFuZGxlQ2hhcmFjdGVyKGNoYXJhY3RlciwgZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogZGV0ZXJtaW5lcyBpZiB0aGUga2V5Y29kZSBzcGVjaWZpZWQgaXMgYSBtb2RpZmllciBrZXkgb3Igbm90XG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5XG4gICAgICogQHJldHVybnMge2Jvb2xlYW59XG4gICAgICovXG4gICAgZnVuY3Rpb24gX2lzTW9kaWZpZXIoa2V5KSB7XG4gICAgICAgIHJldHVybiBrZXkgPT0gJ3NoaWZ0JyB8fCBrZXkgPT0gJ2N0cmwnIHx8IGtleSA9PSAnYWx0JyB8fCBrZXkgPT0gJ21ldGEnO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIGNhbGxlZCB0byBzZXQgYSAxIHNlY29uZCB0aW1lb3V0IG9uIHRoZSBzcGVjaWZpZWQgc2VxdWVuY2VcbiAgICAgKlxuICAgICAqIHRoaXMgaXMgc28gYWZ0ZXIgZWFjaCBrZXkgcHJlc3MgaW4gdGhlIHNlcXVlbmNlIHlvdSBoYXZlIDEgc2Vjb25kXG4gICAgICogdG8gcHJlc3MgdGhlIG5leHQga2V5IGJlZm9yZSB5b3UgaGF2ZSB0byBzdGFydCBvdmVyXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB2b2lkXG4gICAgICovXG4gICAgZnVuY3Rpb24gX3Jlc2V0U2VxdWVuY2VUaW1lcigpIHtcbiAgICAgICAgY2xlYXJUaW1lb3V0KF9yZXNldF90aW1lcik7XG4gICAgICAgIF9yZXNldF90aW1lciA9IHNldFRpbWVvdXQoX3Jlc2V0U2VxdWVuY2VzLCAxMDAwKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiByZXZlcnNlcyB0aGUgbWFwIGxvb2t1cCBzbyB0aGF0IHdlIGNhbiBsb29rIGZvciBzcGVjaWZpYyBrZXlzXG4gICAgICogdG8gc2VlIHdoYXQgY2FuIGFuZCBjYW4ndCB1c2Uga2V5cHJlc3NcbiAgICAgKlxuICAgICAqIEByZXR1cm4ge09iamVjdH1cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBfZ2V0UmV2ZXJzZU1hcCgpIHtcbiAgICAgICAgaWYgKCFfUkVWRVJTRV9NQVApIHtcbiAgICAgICAgICAgIF9SRVZFUlNFX01BUCA9IHt9O1xuICAgICAgICAgICAgZm9yICh2YXIga2V5IGluIF9NQVApIHtcblxuICAgICAgICAgICAgICAgIC8vIHB1bGwgb3V0IHRoZSBudW1lcmljIGtleXBhZCBmcm9tIGhlcmUgY2F1c2Uga2V5cHJlc3Mgc2hvdWxkXG4gICAgICAgICAgICAgICAgLy8gYmUgYWJsZSB0byBkZXRlY3QgdGhlIGtleXMgZnJvbSB0aGUgY2hhcmFjdGVyXG4gICAgICAgICAgICAgICAgaWYgKGtleSA+IDk1ICYmIGtleSA8IDExMikge1xuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoX01BUC5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICAgICAgICAgICAgICAgIF9SRVZFUlNFX01BUFtfTUFQW2tleV1dID0ga2V5O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gX1JFVkVSU0VfTUFQO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIHBpY2tzIHRoZSBiZXN0IGFjdGlvbiBiYXNlZCBvbiB0aGUga2V5IGNvbWJpbmF0aW9uXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5IC0gY2hhcmFjdGVyIGZvciBrZXlcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBtb2RpZmllcnNcbiAgICAgKiBAcGFyYW0ge3N0cmluZz19IGFjdGlvbiBwYXNzZWQgaW5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBfcGlja0Jlc3RBY3Rpb24oa2V5LCBtb2RpZmllcnMsIGFjdGlvbikge1xuXG4gICAgICAgIC8vIGlmIG5vIGFjdGlvbiB3YXMgcGlja2VkIGluIHdlIHNob3VsZCB0cnkgdG8gcGljayB0aGUgb25lXG4gICAgICAgIC8vIHRoYXQgd2UgdGhpbmsgd291bGQgd29yayBiZXN0IGZvciB0aGlzIGtleVxuICAgICAgICBpZiAoIWFjdGlvbikge1xuICAgICAgICAgICAgYWN0aW9uID0gX2dldFJldmVyc2VNYXAoKVtrZXldID8gJ2tleWRvd24nIDogJ2tleXByZXNzJztcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIG1vZGlmaWVyIGtleXMgZG9uJ3Qgd29yayBhcyBleHBlY3RlZCB3aXRoIGtleXByZXNzLFxuICAgICAgICAvLyBzd2l0Y2ggdG8ga2V5ZG93blxuICAgICAgICBpZiAoYWN0aW9uID09ICdrZXlwcmVzcycgJiYgbW9kaWZpZXJzLmxlbmd0aCkge1xuICAgICAgICAgICAgYWN0aW9uID0gJ2tleWRvd24nO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGFjdGlvbjtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBiaW5kcyBhIGtleSBzZXF1ZW5jZSB0byBhbiBldmVudFxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGNvbWJvIC0gY29tYm8gc3BlY2lmaWVkIGluIGJpbmQgY2FsbFxuICAgICAqIEBwYXJhbSB7QXJyYXl9IGtleXNcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICAgICAqIEBwYXJhbSB7c3RyaW5nPX0gYWN0aW9uXG4gICAgICogQHJldHVybnMgdm9pZFxuICAgICAqL1xuICAgIGZ1bmN0aW9uIF9iaW5kU2VxdWVuY2UoY29tYm8sIGtleXMsIGNhbGxiYWNrLCBhY3Rpb24pIHtcblxuICAgICAgICAvLyBzdGFydCBvZmYgYnkgYWRkaW5nIGEgc2VxdWVuY2UgbGV2ZWwgcmVjb3JkIGZvciB0aGlzIGNvbWJpbmF0aW9uXG4gICAgICAgIC8vIGFuZCBzZXR0aW5nIHRoZSBsZXZlbCB0byAwXG4gICAgICAgIF9zZXF1ZW5jZV9sZXZlbHNbY29tYm9dID0gMDtcblxuICAgICAgICAvLyBpZiB0aGVyZSBpcyBubyBhY3Rpb24gcGljayB0aGUgYmVzdCBvbmUgZm9yIHRoZSBmaXJzdCBrZXlcbiAgICAgICAgLy8gaW4gdGhlIHNlcXVlbmNlXG4gICAgICAgIGlmICghYWN0aW9uKSB7XG4gICAgICAgICAgICBhY3Rpb24gPSBfcGlja0Jlc3RBY3Rpb24oa2V5c1swXSwgW10pO1xuICAgICAgICB9XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIGNhbGxiYWNrIHRvIGluY3JlYXNlIHRoZSBzZXF1ZW5jZSBsZXZlbCBmb3IgdGhpcyBzZXF1ZW5jZSBhbmQgcmVzZXRcbiAgICAgICAgICogYWxsIG90aGVyIHNlcXVlbmNlcyB0aGF0IHdlcmUgYWN0aXZlXG4gICAgICAgICAqXG4gICAgICAgICAqIEBwYXJhbSB7RXZlbnR9IGVcbiAgICAgICAgICogQHJldHVybnMgdm9pZFxuICAgICAgICAgKi9cbiAgICAgICAgdmFyIF9pbmNyZWFzZVNlcXVlbmNlID0gZnVuY3Rpb24oZSkge1xuICAgICAgICAgICAgICAgIF9pbnNpZGVfc2VxdWVuY2UgPSBhY3Rpb247XG4gICAgICAgICAgICAgICAgKytfc2VxdWVuY2VfbGV2ZWxzW2NvbWJvXTtcbiAgICAgICAgICAgICAgICBfcmVzZXRTZXF1ZW5jZVRpbWVyKCk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAqIHdyYXBzIHRoZSBzcGVjaWZpZWQgY2FsbGJhY2sgaW5zaWRlIG9mIGFub3RoZXIgZnVuY3Rpb24gaW4gb3JkZXJcbiAgICAgICAgICAgICAqIHRvIHJlc2V0IGFsbCBzZXF1ZW5jZSBjb3VudGVycyBhcyBzb29uIGFzIHRoaXMgc2VxdWVuY2UgaXMgZG9uZVxuICAgICAgICAgICAgICpcbiAgICAgICAgICAgICAqIEBwYXJhbSB7RXZlbnR9IGVcbiAgICAgICAgICAgICAqIEByZXR1cm5zIHZvaWRcbiAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgX2NhbGxiYWNrQW5kUmVzZXQgPSBmdW5jdGlvbihlKSB7XG4gICAgICAgICAgICAgICAgX2ZpcmVDYWxsYmFjayhjYWxsYmFjaywgZSk7XG5cbiAgICAgICAgICAgICAgICAvLyB3ZSBzaG91bGQgaWdub3JlIHRoZSBuZXh0IGtleSB1cCBpZiB0aGUgYWN0aW9uIGlzIGtleSBkb3duXG4gICAgICAgICAgICAgICAgLy8gb3Iga2V5cHJlc3MuICB0aGlzIGlzIHNvIGlmIHlvdSBmaW5pc2ggYSBzZXF1ZW5jZSBhbmRcbiAgICAgICAgICAgICAgICAvLyByZWxlYXNlIHRoZSBrZXkgdGhlIGZpbmFsIGtleSB3aWxsIG5vdCB0cmlnZ2VyIGEga2V5dXBcbiAgICAgICAgICAgICAgICBpZiAoYWN0aW9uICE9PSAna2V5dXAnKSB7XG4gICAgICAgICAgICAgICAgICAgIF9pZ25vcmVfbmV4dF9rZXl1cCA9IF9jaGFyYWN0ZXJGcm9tRXZlbnQoZSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gd2VpcmQgcmFjZSBjb25kaXRpb24gaWYgYSBzZXF1ZW5jZSBlbmRzIHdpdGggdGhlIGtleVxuICAgICAgICAgICAgICAgIC8vIGFub3RoZXIgc2VxdWVuY2UgYmVnaW5zIHdpdGhcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KF9yZXNldFNlcXVlbmNlcywgMTApO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGk7XG5cbiAgICAgICAgLy8gbG9vcCB0aHJvdWdoIGtleXMgb25lIGF0IGEgdGltZSBhbmQgYmluZCB0aGUgYXBwcm9wcmlhdGUgY2FsbGJhY2tcbiAgICAgICAgLy8gZnVuY3Rpb24uICBmb3IgYW55IGtleSBsZWFkaW5nIHVwIHRvIHRoZSBmaW5hbCBvbmUgaXQgc2hvdWxkXG4gICAgICAgIC8vIGluY3JlYXNlIHRoZSBzZXF1ZW5jZS4gYWZ0ZXIgdGhlIGZpbmFsLCBpdCBzaG91bGQgcmVzZXQgYWxsIHNlcXVlbmNlc1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwga2V5cy5sZW5ndGg7ICsraSkge1xuICAgICAgICAgICAgX2JpbmRTaW5nbGUoa2V5c1tpXSwgaSA8IGtleXMubGVuZ3RoIC0gMSA/IF9pbmNyZWFzZVNlcXVlbmNlIDogX2NhbGxiYWNrQW5kUmVzZXQsIGFjdGlvbiwgY29tYm8sIGkpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogYmluZHMgYSBzaW5nbGUga2V5Ym9hcmQgY29tYmluYXRpb25cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBjb21iaW5hdGlvblxuICAgICAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrXG4gICAgICogQHBhcmFtIHtzdHJpbmc9fSBhY3Rpb25cbiAgICAgKiBAcGFyYW0ge3N0cmluZz19IHNlcXVlbmNlX25hbWUgLSBuYW1lIG9mIHNlcXVlbmNlIGlmIHBhcnQgb2Ygc2VxdWVuY2VcbiAgICAgKiBAcGFyYW0ge251bWJlcj19IGxldmVsIC0gd2hhdCBwYXJ0IG9mIHRoZSBzZXF1ZW5jZSB0aGUgY29tbWFuZCBpc1xuICAgICAqIEByZXR1cm5zIHZvaWRcbiAgICAgKi9cbiAgICBmdW5jdGlvbiBfYmluZFNpbmdsZShjb21iaW5hdGlvbiwgY2FsbGJhY2ssIGFjdGlvbiwgc2VxdWVuY2VfbmFtZSwgbGV2ZWwpIHtcblxuICAgICAgICAvLyBtYWtlIHN1cmUgbXVsdGlwbGUgc3BhY2VzIGluIGEgcm93IGJlY29tZSBhIHNpbmdsZSBzcGFjZVxuICAgICAgICBjb21iaW5hdGlvbiA9IGNvbWJpbmF0aW9uLnJlcGxhY2UoL1xccysvZywgJyAnKTtcblxuICAgICAgICB2YXIgc2VxdWVuY2UgPSBjb21iaW5hdGlvbi5zcGxpdCgnICcpLFxuICAgICAgICAgICAgaSxcbiAgICAgICAgICAgIGtleSxcbiAgICAgICAgICAgIGtleXMsXG4gICAgICAgICAgICBtb2RpZmllcnMgPSBbXTtcblxuICAgICAgICAvLyBpZiB0aGlzIHBhdHRlcm4gaXMgYSBzZXF1ZW5jZSBvZiBrZXlzIHRoZW4gcnVuIHRocm91Z2ggdGhpcyBtZXRob2RcbiAgICAgICAgLy8gdG8gcmVwcm9jZXNzIGVhY2ggcGF0dGVybiBvbmUga2V5IGF0IGEgdGltZVxuICAgICAgICBpZiAoc2VxdWVuY2UubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgX2JpbmRTZXF1ZW5jZShjb21iaW5hdGlvbiwgc2VxdWVuY2UsIGNhbGxiYWNrLCBhY3Rpb24pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gdGFrZSB0aGUga2V5cyBmcm9tIHRoaXMgcGF0dGVybiBhbmQgZmlndXJlIG91dCB3aGF0IHRoZSBhY3R1YWxcbiAgICAgICAgLy8gcGF0dGVybiBpcyBhbGwgYWJvdXRcbiAgICAgICAga2V5cyA9IGNvbWJpbmF0aW9uID09PSAnKycgPyBbJysnXSA6IGNvbWJpbmF0aW9uLnNwbGl0KCcrJyk7XG5cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGtleXMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgICAgIGtleSA9IGtleXNbaV07XG5cbiAgICAgICAgICAgIC8vIG5vcm1hbGl6ZSBrZXkgbmFtZXNcbiAgICAgICAgICAgIGlmIChfU1BFQ0lBTF9BTElBU0VTW2tleV0pIHtcbiAgICAgICAgICAgICAgICBrZXkgPSBfU1BFQ0lBTF9BTElBU0VTW2tleV07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIGlmIHRoaXMgaXMgbm90IGEga2V5cHJlc3MgZXZlbnQgdGhlbiB3ZSBzaG91bGRcbiAgICAgICAgICAgIC8vIGJlIHNtYXJ0IGFib3V0IHVzaW5nIHNoaWZ0IGtleXNcbiAgICAgICAgICAgIC8vIHRoaXMgd2lsbCBvbmx5IHdvcmsgZm9yIFVTIGtleWJvYXJkcyBob3dldmVyXG4gICAgICAgICAgICBpZiAoYWN0aW9uICYmIGFjdGlvbiAhPSAna2V5cHJlc3MnICYmIF9TSElGVF9NQVBba2V5XSkge1xuICAgICAgICAgICAgICAgIGtleSA9IF9TSElGVF9NQVBba2V5XTtcbiAgICAgICAgICAgICAgICBtb2RpZmllcnMucHVzaCgnc2hpZnQnKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gaWYgdGhpcyBrZXkgaXMgYSBtb2RpZmllciB0aGVuIGFkZCBpdCB0byB0aGUgbGlzdCBvZiBtb2RpZmllcnNcbiAgICAgICAgICAgIGlmIChfaXNNb2RpZmllcihrZXkpKSB7XG4gICAgICAgICAgICAgICAgbW9kaWZpZXJzLnB1c2goa2V5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGRlcGVuZGluZyBvbiB3aGF0IHRoZSBrZXkgY29tYmluYXRpb24gaXNcbiAgICAgICAgLy8gd2Ugd2lsbCB0cnkgdG8gcGljayB0aGUgYmVzdCBldmVudCBmb3IgaXRcbiAgICAgICAgYWN0aW9uID0gX3BpY2tCZXN0QWN0aW9uKGtleSwgbW9kaWZpZXJzLCBhY3Rpb24pO1xuXG4gICAgICAgIC8vIG1ha2Ugc3VyZSB0byBpbml0aWFsaXplIGFycmF5IGlmIHRoaXMgaXMgdGhlIGZpcnN0IHRpbWVcbiAgICAgICAgLy8gYSBjYWxsYmFjayBpcyBhZGRlZCBmb3IgdGhpcyBrZXlcbiAgICAgICAgaWYgKCFfY2FsbGJhY2tzW2tleV0pIHtcbiAgICAgICAgICAgIF9jYWxsYmFja3Nba2V5XSA9IFtdO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gcmVtb3ZlIGFuIGV4aXN0aW5nIG1hdGNoIGlmIHRoZXJlIGlzIG9uZVxuICAgICAgICBfZ2V0TWF0Y2hlcyhrZXksIG1vZGlmaWVycywge3R5cGU6IGFjdGlvbn0sICFzZXF1ZW5jZV9uYW1lLCBjb21iaW5hdGlvbik7XG5cbiAgICAgICAgLy8gYWRkIHRoaXMgY2FsbCBiYWNrIHRvIHRoZSBhcnJheVxuICAgICAgICAvLyBpZiBpdCBpcyBhIHNlcXVlbmNlIHB1dCBpdCBhdCB0aGUgYmVnaW5uaW5nXG4gICAgICAgIC8vIGlmIG5vdCBwdXQgaXQgYXQgdGhlIGVuZFxuICAgICAgICAvL1xuICAgICAgICAvLyB0aGlzIGlzIGltcG9ydGFudCBiZWNhdXNlIHRoZSB3YXkgdGhlc2UgYXJlIHByb2Nlc3NlZCBleHBlY3RzXG4gICAgICAgIC8vIHRoZSBzZXF1ZW5jZSBvbmVzIHRvIGNvbWUgZmlyc3RcbiAgICAgICAgX2NhbGxiYWNrc1trZXldW3NlcXVlbmNlX25hbWUgPyAndW5zaGlmdCcgOiAncHVzaCddKHtcbiAgICAgICAgICAgIGNhbGxiYWNrOiBjYWxsYmFjayxcbiAgICAgICAgICAgIG1vZGlmaWVyczogbW9kaWZpZXJzLFxuICAgICAgICAgICAgYWN0aW9uOiBhY3Rpb24sXG4gICAgICAgICAgICBzZXE6IHNlcXVlbmNlX25hbWUsXG4gICAgICAgICAgICBsZXZlbDogbGV2ZWwsXG4gICAgICAgICAgICBjb21ibzogY29tYmluYXRpb25cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogYmluZHMgbXVsdGlwbGUgY29tYmluYXRpb25zIHRvIHRoZSBzYW1lIGNhbGxiYWNrXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0FycmF5fSBjb21iaW5hdGlvbnNcbiAgICAgKiBAcGFyYW0ge0Z1bmN0aW9ufSBjYWxsYmFja1xuICAgICAqIEBwYXJhbSB7c3RyaW5nfHVuZGVmaW5lZH0gYWN0aW9uXG4gICAgICogQHJldHVybnMgdm9pZFxuICAgICAqL1xuICAgIGZ1bmN0aW9uIF9iaW5kTXVsdGlwbGUoY29tYmluYXRpb25zLCBjYWxsYmFjaywgYWN0aW9uKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY29tYmluYXRpb25zLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICBfYmluZFNpbmdsZShjb21iaW5hdGlvbnNbaV0sIGNhbGxiYWNrLCBhY3Rpb24pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gc3RhcnQhXG4gICAgX2FkZEV2ZW50KGRvY3VtZW50LCAna2V5cHJlc3MnLCBfaGFuZGxlS2V5KTtcbiAgICBfYWRkRXZlbnQoZG9jdW1lbnQsICdrZXlkb3duJywgX2hhbmRsZUtleSk7XG4gICAgX2FkZEV2ZW50KGRvY3VtZW50LCAna2V5dXAnLCBfaGFuZGxlS2V5KTtcblxuICAgIHZhciBNb3VzZXRyYXAgPSB7XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIGJpbmRzIGFuIGV2ZW50IHRvIG1vdXNldHJhcFxuICAgICAgICAgKlxuICAgICAgICAgKiBjYW4gYmUgYSBzaW5nbGUga2V5LCBhIGNvbWJpbmF0aW9uIG9mIGtleXMgc2VwYXJhdGVkIHdpdGggKyxcbiAgICAgICAgICogYW4gYXJyYXkgb2Yga2V5cywgb3IgYSBzZXF1ZW5jZSBvZiBrZXlzIHNlcGFyYXRlZCBieSBzcGFjZXNcbiAgICAgICAgICpcbiAgICAgICAgICogYmUgc3VyZSB0byBsaXN0IHRoZSBtb2RpZmllciBrZXlzIGZpcnN0IHRvIG1ha2Ugc3VyZSB0aGF0IHRoZVxuICAgICAgICAgKiBjb3JyZWN0IGtleSBlbmRzIHVwIGdldHRpbmcgYm91bmQgKHRoZSBsYXN0IGtleSBpbiB0aGUgcGF0dGVybilcbiAgICAgICAgICpcbiAgICAgICAgICogQHBhcmFtIHtzdHJpbmd8QXJyYXl9IGtleXNcbiAgICAgICAgICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcbiAgICAgICAgICogQHBhcmFtIHtzdHJpbmc9fSBhY3Rpb24gLSAna2V5cHJlc3MnLCAna2V5ZG93bicsIG9yICdrZXl1cCdcbiAgICAgICAgICogQHJldHVybnMgdm9pZFxuICAgICAgICAgKi9cbiAgICAgICAgYmluZDogZnVuY3Rpb24oa2V5cywgY2FsbGJhY2ssIGFjdGlvbikge1xuICAgICAgICAgICAgX2JpbmRNdWx0aXBsZShrZXlzIGluc3RhbmNlb2YgQXJyYXkgPyBrZXlzIDogW2tleXNdLCBjYWxsYmFjaywgYWN0aW9uKTtcbiAgICAgICAgICAgIF9kaXJlY3RfbWFwW2tleXMgKyAnOicgKyBhY3Rpb25dID0gY2FsbGJhY2s7XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogdW5iaW5kcyBhbiBldmVudCB0byBtb3VzZXRyYXBcbiAgICAgICAgICpcbiAgICAgICAgICogdGhlIHVuYmluZGluZyBzZXRzIHRoZSBjYWxsYmFjayBmdW5jdGlvbiBvZiB0aGUgc3BlY2lmaWVkIGtleSBjb21ib1xuICAgICAgICAgKiB0byBhbiBlbXB0eSBmdW5jdGlvbiBhbmQgZGVsZXRlcyB0aGUgY29ycmVzcG9uZGluZyBrZXkgaW4gdGhlXG4gICAgICAgICAqIF9kaXJlY3RfbWFwIGRpY3QuXG4gICAgICAgICAqXG4gICAgICAgICAqIHRoZSBrZXljb21ibythY3Rpb24gaGFzIHRvIGJlIGV4YWN0bHkgdGhlIHNhbWUgYXNcbiAgICAgICAgICogaXQgd2FzIGRlZmluZWQgaW4gdGhlIGJpbmQgbWV0aG9kXG4gICAgICAgICAqXG4gICAgICAgICAqIFRPRE86IGFjdHVhbGx5IHJlbW92ZSB0aGlzIGZyb20gdGhlIF9jYWxsYmFja3MgZGljdGlvbmFyeSBpbnN0ZWFkXG4gICAgICAgICAqIG9mIGJpbmRpbmcgYW4gZW1wdHkgZnVuY3Rpb25cbiAgICAgICAgICpcbiAgICAgICAgICogQHBhcmFtIHtzdHJpbmd8QXJyYXl9IGtleXNcbiAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGFjdGlvblxuICAgICAgICAgKiBAcmV0dXJucyB2b2lkXG4gICAgICAgICAqL1xuICAgICAgICB1bmJpbmQ6IGZ1bmN0aW9uKGtleXMsIGFjdGlvbikge1xuICAgICAgICAgICAgaWYgKF9kaXJlY3RfbWFwW2tleXMgKyAnOicgKyBhY3Rpb25dKSB7XG4gICAgICAgICAgICAgICAgZGVsZXRlIF9kaXJlY3RfbWFwW2tleXMgKyAnOicgKyBhY3Rpb25dO1xuICAgICAgICAgICAgICAgIHRoaXMuYmluZChrZXlzLCBmdW5jdGlvbigpIHt9LCBhY3Rpb24pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIHRyaWdnZXJzIGFuIGV2ZW50IHRoYXQgaGFzIGFscmVhZHkgYmVlbiBib3VuZFxuICAgICAgICAgKlxuICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5c1xuICAgICAgICAgKiBAcGFyYW0ge3N0cmluZz19IGFjdGlvblxuICAgICAgICAgKiBAcmV0dXJucyB2b2lkXG4gICAgICAgICAqL1xuICAgICAgICB0cmlnZ2VyOiBmdW5jdGlvbihrZXlzLCBhY3Rpb24pIHtcbiAgICAgICAgICAgIF9kaXJlY3RfbWFwW2tleXMgKyAnOicgKyBhY3Rpb25dKCk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogcmVzZXRzIHRoZSBsaWJyYXJ5IGJhY2sgdG8gaXRzIGluaXRpYWwgc3RhdGUuICB0aGlzIGlzIHVzZWZ1bFxuICAgICAgICAgKiBpZiB5b3Ugd2FudCB0byBjbGVhciBvdXQgdGhlIGN1cnJlbnQga2V5Ym9hcmQgc2hvcnRjdXRzIGFuZCBiaW5kXG4gICAgICAgICAqIG5ldyBvbmVzIC0gZm9yIGV4YW1wbGUgaWYgeW91IHN3aXRjaCB0byBhbm90aGVyIHBhZ2VcbiAgICAgICAgICpcbiAgICAgICAgICogQHJldHVybnMgdm9pZFxuICAgICAgICAgKi9cbiAgICAgICAgcmVzZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgX2NhbGxiYWNrcyA9IHt9O1xuICAgICAgICAgICAgX2RpcmVjdF9tYXAgPSB7fTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICB9LFxuXG4gICAgICAgLyoqXG4gICAgICAgICogc2hvdWxkIHdlIHN0b3AgdGhpcyBldmVudCBiZWZvcmUgZmlyaW5nIG9mZiBjYWxsYmFja3NcbiAgICAgICAgKlxuICAgICAgICAqIEBwYXJhbSB7RXZlbnR9IGVcbiAgICAgICAgKiBAcGFyYW0ge0VsZW1lbnR9IGVsZW1lbnRcbiAgICAgICAgKiBAcmV0dXJuIHtib29sZWFufVxuICAgICAgICAqL1xuICAgICAgICBzdG9wQ2FsbGJhY2s6IGZ1bmN0aW9uKGUsIGVsZW1lbnQpIHtcblxuICAgICAgICAgICAgLy8gaWYgdGhlIGVsZW1lbnQgaGFzIHRoZSBjbGFzcyBcIm1vdXNldHJhcFwiIHRoZW4gbm8gbmVlZCB0byBzdG9wXG4gICAgICAgICAgICBpZiAoKCcgJyArIGVsZW1lbnQuY2xhc3NOYW1lICsgJyAnKS5pbmRleE9mKCcgbW91c2V0cmFwICcpID4gLTEpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIHN0b3AgZm9yIGlucHV0LCBzZWxlY3QsIGFuZCB0ZXh0YXJlYVxuICAgICAgICAgICAgcmV0dXJuIGVsZW1lbnQudGFnTmFtZSA9PSAnSU5QVVQnIHx8IGVsZW1lbnQudGFnTmFtZSA9PSAnU0VMRUNUJyB8fCBlbGVtZW50LnRhZ05hbWUgPT0gJ1RFWFRBUkVBJyB8fCAoZWxlbWVudC5jb250ZW50RWRpdGFibGUgJiYgZWxlbWVudC5jb250ZW50RWRpdGFibGUgPT0gJ3RydWUnKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvLyBleHBvc2UgbW91c2V0cmFwIHRvIHRoZSBnbG9iYWwgb2JqZWN0XG4gICAgd2luZG93Lk1vdXNldHJhcCA9IE1vdXNldHJhcDtcblxuICAgIC8vIGV4cG9zZSBtb3VzZXRyYXAgYXMgYW4gQU1EIG1vZHVsZVxuICAgIGlmICh0eXBlb2YgZGVmaW5lID09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCkge1xuICAgICAgICBkZWZpbmUoJ21vdXNldHJhcCcsIGZ1bmN0aW9uKCkgeyByZXR1cm4gTW91c2V0cmFwOyB9KTtcbiAgICB9XG4gICAgLy8gYnJvd3NlcmlmeSBzdXBwb3J0XG4gICAgaWYodHlwZW9mIG1vZHVsZSA9PT0gJ29iamVjdCcgJiYgbW9kdWxlLmV4cG9ydHMpIHtcbiAgICAgICAgbW9kdWxlLmV4cG9ydHMgPSBNb3VzZXRyYXA7XG4gICAgfVxufSkgKCk7XG4iLCIoZnVuY3Rpb24gKGdsb2JhbCl7XG4oZnVuY3Rpb24oKSB7XG4gICAgdmFyIHJvb3QgPSB0aGlzO1xuICAgIHZhciBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKCdldmVudHMnKS5FdmVudEVtaXR0ZXI7XG5cdHZhciBfID0gcmVxdWlyZSgndW5kZXJzY29yZScpO1xuXHR2YXIgaW50ZXJ2YWxQYXJzZXIgPSAvKFswLTlcXC5dKykobXN8c3xtfGgpPy87XG5cdHZhciByb290ID0gZ2xvYmFsIHx8IHdpbmRvdztcblxuXHQvLyBMaWwgYml0IG9mIHVzZWZ1bCBwb2x5ZmlsbC4uLlxuXHRpZiAodHlwZW9mKEZ1bmN0aW9uLnByb3RvdHlwZS5pbmhlcml0cykgPT09ICd1bmRlZmluZWQnKSB7XG5cdFx0RnVuY3Rpb24ucHJvdG90eXBlLmluaGVyaXRzID0gZnVuY3Rpb24ocGFyZW50KSB7XG5cdFx0XHR0aGlzLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUocGFyZW50LnByb3RvdHlwZSk7XG5cdFx0fTtcblx0fVxuXG5cdGlmICh0eXBlb2YoQXJyYXkucHJvdG90eXBlLnJlbW92ZU9uZSkgPT09ICd1bmRlZmluZWQnKSB7XG5cdFx0QXJyYXkucHJvdG90eXBlLnJlbW92ZU9uZSA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHdoYXQsIGEgPSBhcmd1bWVudHMsIEwgPSBhLmxlbmd0aCwgYXg7XG5cdFx0XHR3aGlsZSAoTCAmJiB0aGlzLmxlbmd0aCkge1xuXHRcdFx0XHR3aGF0ID0gYVstLUxdO1xuXHRcdFx0XHR3aGlsZSAoKGF4ID0gdGhpcy5pbmRleE9mKHdoYXQpKSAhPT0gLTEpIHtcblx0XHRcdFx0XHRyZXR1cm4gdGhpcy5zcGxpY2UoYXgsIDEpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fTtcblx0fVxuXG5cdGZ1bmN0aW9uIGdyZWF0ZXN0Q29tbW9uRmFjdG9yKGludGVydmFscykge1xuXHRcdHZhciBzdW1PZk1vZHVsaSA9IDE7XG5cdFx0dmFyIGludGVydmFsID0gXy5taW4oaW50ZXJ2YWxzKTtcblx0XHR3aGlsZSAoc3VtT2ZNb2R1bGkgIT09IDApIHtcblx0XHRcdHN1bU9mTW9kdWxpID0gXy5yZWR1Y2UoaW50ZXJ2YWxzLCBmdW5jdGlvbihtZW1vLCBpKXsgcmV0dXJuIG1lbW8gKyAoaSAlIGludGVydmFsKTsgfSwgMCk7XG5cdFx0XHRpZiAoc3VtT2ZNb2R1bGkgIT09IDApIHtcblx0XHRcdFx0aW50ZXJ2YWwgLT0gMTA7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiBpbnRlcnZhbDtcblx0fVxuXG5cdGZ1bmN0aW9uIHBhcnNlRXZlbnQoZSkge1xuXHRcdHZhciBpbnRlcnZhbEdyb3VwcyA9IGludGVydmFsUGFyc2VyLmV4ZWMoZSk7XG5cdFx0aWYgKCFpbnRlcnZhbEdyb3Vwcykge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdJIGRvblxcJ3QgdW5kZXJzdGFuZCB0aGF0IHBhcnRpY3VsYXIgaW50ZXJ2YWwnKTtcblx0XHR9XG5cdFx0dmFyIGludGVydmFsQW1vdW50ID0gK2ludGVydmFsR3JvdXBzWzFdO1xuXHRcdHZhciBpbnRlcnZhbFR5cGUgPSBpbnRlcnZhbEdyb3Vwc1syXSB8fCAnbXMnO1xuXHRcdGlmIChpbnRlcnZhbFR5cGUgPT09ICdzJykge1xuXHRcdFx0aW50ZXJ2YWxBbW91bnQgPSBpbnRlcnZhbEFtb3VudCAqIDEwMDA7XG5cdFx0fSBlbHNlIGlmIChpbnRlcnZhbFR5cGUgPT09ICdtJykge1xuXHRcdFx0aW50ZXJ2YWxBbW91bnQgPSBpbnRlcnZhbEFtb3VudCAqIDEwMDAgKiA2MDtcblx0XHR9IGVsc2UgaWYgKGludGVydmFsVHlwZSA9PT0gJ2gnKSB7XG5cdFx0XHRpbnRlcnZhbEFtb3VudCA9IGludGVydmFsQW1vdW50ICogMTAwMCAqIDYwICogNjA7XG5cdFx0fSBlbHNlIGlmICghIWludGVydmFsVHlwZSAmJiBpbnRlcnZhbFR5cGUgIT09ICdtcycpIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcignWW91IGNhbiBvbmx5IHNwZWNpZnkgaW50ZXJ2YWxzIG9mIG1zLCBzLCBtLCBvciBoJyk7XG5cdFx0fVxuXHRcdGlmIChpbnRlcnZhbEFtb3VudCA8IDEwIHx8IGludGVydmFsQW1vdW50ICUgMTAgIT09IDApIHtcblx0XHRcdC8vIFdlIG9ubHkgZGVhbCBpbiAxMCdzIG9mIG1pbGxpc2Vjb25kcyBmb3Igc2ltcGxpY2l0eVxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdZb3UgY2FuIG9ubHkgc3BlY2lmeSAxMHMgb2YgbWlsbGlzZWNvbmRzLCB0cnVzdCBtZSBvbiB0aGlzIG9uZScpO1xuXHRcdH1cblx0XHRyZXR1cm4ge1xuXHRcdFx0YW1vdW50OmludGVydmFsQW1vdW50LFxuXHRcdFx0dHlwZTppbnRlcnZhbFR5cGVcblx0XHR9O1xuXHR9XG5cblx0ZnVuY3Rpb24gRXZlbnRlZExvb3AoKSB7XG5cdFx0dGhpcy5pbnRlcnZhbElkID0gdW5kZWZpbmVkO1xuXHRcdHRoaXMuaW50ZXJ2YWxMZW5ndGggPSB1bmRlZmluZWQ7XG5cdFx0dGhpcy5pbnRlcnZhbHNUb0VtaXQgPSB7fTtcblx0XHR0aGlzLmN1cnJlbnRUaWNrID0gMTtcblx0XHR0aGlzLm1heFRpY2tzID0gMDtcblx0XHR0aGlzLmxpc3RlbmluZ0ZvckZvY3VzID0gZmFsc2U7XG5cblx0XHQvLyBQcml2YXRlIG1ldGhvZFxuXHRcdHZhciBkZXRlcm1pbmVJbnRlcnZhbExlbmd0aCA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdHZhciBwb3RlbnRpYWxJbnRlcnZhbExlbmd0aCA9IGdyZWF0ZXN0Q29tbW9uRmFjdG9yKF8ua2V5cyh0aGlzLmludGVydmFsc1RvRW1pdCkpO1xuXHRcdFx0dmFyIGNoYW5nZWQgPSBmYWxzZTtcblxuXHRcdFx0aWYgKHRoaXMuaW50ZXJ2YWxMZW5ndGgpIHtcblx0XHRcdFx0aWYgKHBvdGVudGlhbEludGVydmFsTGVuZ3RoICE9PSB0aGlzLmludGVydmFsTGVuZ3RoKSB7XG5cdFx0XHRcdFx0Ly8gTG9va3MgbGlrZSB3ZSBuZWVkIGEgbmV3IGludGVydmFsXG5cdFx0XHRcdFx0dGhpcy5pbnRlcnZhbExlbmd0aCA9IHBvdGVudGlhbEludGVydmFsTGVuZ3RoO1xuXHRcdFx0XHRcdGNoYW5nZWQgPSB0cnVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzLmludGVydmFsTGVuZ3RoID0gcG90ZW50aWFsSW50ZXJ2YWxMZW5ndGg7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMubWF4VGlja3MgPSBfLm1heChfLm1hcChfLmtleXModGhpcy5pbnRlcnZhbHNUb0VtaXQpLCBmdW5jdGlvbihhKSB7IHJldHVybiArYTsgfSkpIC8gdGhpcy5pbnRlcnZhbExlbmd0aDtcblx0XHRcdHJldHVybiBjaGFuZ2VkO1xuXHRcdH0uYmluZCh0aGlzKTtcblxuXHRcdHRoaXMub24oJ25ld0xpc3RlbmVyJywgZnVuY3Rpb24gKGUpIHtcblx0XHRcdGlmIChlID09PSAncmVtb3ZlTGlzdGVuZXInIHx8IGUgPT09ICduZXdMaXN0ZW5lcicpIHJldHVybjsgLy8gV2UgZG9uJ3QgY2FyZSBhYm91dCB0aGF0IG9uZVxuXHRcdFx0dmFyIGludGVydmFsSW5mbyA9IHBhcnNlRXZlbnQoZSk7XG5cdFx0XHR2YXIgaW50ZXJ2YWxBbW91bnQgPSBpbnRlcnZhbEluZm8uYW1vdW50O1xuXG5cdFx0XHR0aGlzLmludGVydmFsc1RvRW1pdFsraW50ZXJ2YWxBbW91bnRdID0gXy51bmlvbih0aGlzLmludGVydmFsc1RvRW1pdFsraW50ZXJ2YWxBbW91bnRdIHx8IFtdLCBbZV0pO1xuXHRcdFx0XG5cdFx0XHRpZiAoZGV0ZXJtaW5lSW50ZXJ2YWxMZW5ndGgoKSAmJiB0aGlzLmlzU3RhcnRlZCgpKSB7XG5cdFx0XHRcdHRoaXMuc3RvcCgpLnN0YXJ0KCk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cblx0XHR0aGlzLm9uKCdyZW1vdmVMaXN0ZW5lcicsIGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRpZiAoRXZlbnRFbWl0dGVyLmxpc3RlbmVyQ291bnQodGhpcywgZSkgPiAwKSByZXR1cm47XG5cdFx0XHR2YXIgaW50ZXJ2YWxJbmZvID0gcGFyc2VFdmVudChlKTtcblx0XHRcdHZhciBpbnRlcnZhbEFtb3VudCA9IGludGVydmFsSW5mby5hbW91bnQ7XG5cblx0XHRcdHZhciByZW1vdmVkRXZlbnQgPSB0aGlzLmludGVydmFsc1RvRW1pdFsraW50ZXJ2YWxBbW91bnRdLnJlbW92ZU9uZShlKTtcblx0XHRcdGlmICh0aGlzLmludGVydmFsc1RvRW1pdFsraW50ZXJ2YWxBbW91bnRdLmxlbmd0aCA9PT0gMCkge1xuXHRcdFx0XHRkZWxldGUgdGhpcy5pbnRlcnZhbHNUb0VtaXRbK2ludGVydmFsQW1vdW50XTtcblx0XHRcdH1cblx0XHRcdGNvbnNvbGUubG9nKCdEZXRlcm1pbmluZyBpbnRlcnZhbCBsZW5ndGggYWZ0ZXIgcmVtb3ZhbCBvZicsIHJlbW92ZWRFdmVudCk7XG5cdFx0XHRkZXRlcm1pbmVJbnRlcnZhbExlbmd0aCgpO1xuXG5cdFx0XHRpZiAoZGV0ZXJtaW5lSW50ZXJ2YWxMZW5ndGgoKSAmJiB0aGlzLmlzU3RhcnRlZCgpKSB7XG5cdFx0XHRcdHRoaXMuc3RvcCgpLnN0YXJ0KCk7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH1cblxuXHRFdmVudGVkTG9vcC5pbmhlcml0cyhFdmVudEVtaXR0ZXIpO1xuXG5cdC8vIFB1YmxpYyBtZXRob2RzXG5cdEV2ZW50ZWRMb29wLnByb3RvdHlwZS50aWNrID0gZnVuY3Rpb24gKCkge1xuXHRcdHZhciBtaWxsaXNlY29uZHMgPSB0aGlzLmN1cnJlbnRUaWNrICogdGhpcy5pbnRlcnZhbExlbmd0aDtcblx0XHRfLmVhY2godGhpcy5pbnRlcnZhbHNUb0VtaXQsIGZ1bmN0aW9uIChldmVudHMsIGtleSkge1xuXHRcdFx0aWYgKG1pbGxpc2Vjb25kcyAlIGtleSA9PT0gMCkge1xuXHRcdFx0XHRfLmVhY2goZXZlbnRzLCBmdW5jdGlvbihlKSB7IHRoaXMuZW1pdChlLCBlLCBrZXkpOyB9LmJpbmQodGhpcykpO1xuXHRcdFx0fVxuXHRcdH0uYmluZCh0aGlzKSk7XG5cdFx0dGhpcy5jdXJyZW50VGljayArPSAxO1xuXHRcdGlmICh0aGlzLmN1cnJlbnRUaWNrID4gdGhpcy5tYXhUaWNrcykge1xuXHRcdFx0dGhpcy5jdXJyZW50VGljayA9IDE7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzO1xuXHR9O1xuXG5cdEV2ZW50ZWRMb29wLnByb3RvdHlwZS5zdGFydCA9IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAoIXRoaXMuaW50ZXJ2YWxMZW5ndGgpIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcignWW91IGhhdmVuXFwndCBzcGVjaWZpZWQgYW55IGludGVydmFsIGNhbGxiYWNrcy4gVXNlIEV2ZW50ZWRMb29wLm9uKFxcJzUwMG1zXFwnLCBmdW5jdGlvbiAoKSB7IC4uLiB9KSB0byBkbyBzbywgYW5kIHRoZW4geW91IGNhbiBzdGFydCcpO1xuXHRcdH1cblx0XHRpZiAodGhpcy5pbnRlcnZhbElkKSB7XG5cdFx0XHRyZXR1cm4gY29uc29sZS5sb2coJ05vIG5lZWQgdG8gc3RhcnQgdGhlIGxvb3AgYWdhaW4sIGl0XFwncyBhbHJlYWR5IHN0YXJ0ZWQuJyk7XG5cdFx0fVxuXG5cdFx0dGhpcy5pbnRlcnZhbElkID0gc2V0SW50ZXJ2YWwodGhpcy50aWNrLmJpbmQodGhpcyksIHRoaXMuaW50ZXJ2YWxMZW5ndGgpO1xuXG5cdFx0aWYgKHJvb3QgJiYgIXRoaXMubGlzdGVuaW5nRm9yRm9jdXMgJiYgcm9vdC5hZGRFdmVudExpc3RlbmVyKSB7XG5cdFx0XHRyb290LmFkZEV2ZW50TGlzdGVuZXIoJ2ZvY3VzJywgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHRoaXMuc3RhcnQoKTtcblx0XHRcdH0uYmluZCh0aGlzKSk7XG5cblx0XHRcdHJvb3QuYWRkRXZlbnRMaXN0ZW5lcignYmx1cicsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGlzLnN0b3AoKTtcblx0XHRcdH0uYmluZCh0aGlzKSk7XG5cblx0XHRcdHRoaXMubGlzdGVuaW5nRm9yRm9jdXMgPSB0cnVlO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcztcblx0fTtcblxuXHRFdmVudGVkTG9vcC5wcm90b3R5cGUuc3RvcCA9IGZ1bmN0aW9uICgpIHtcblx0XHRjbGVhckludGVydmFsKHRoaXMuaW50ZXJ2YWxJZCk7XG5cdFx0dGhpcy5pbnRlcnZhbElkID0gdW5kZWZpbmVkO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9O1xuXG5cdEV2ZW50ZWRMb29wLnByb3RvdHlwZS5pc1N0YXJ0ZWQgPSBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuICEhdGhpcy5pbnRlcnZhbElkO1xuXHR9O1xuXG5cdEV2ZW50ZWRMb29wLnByb3RvdHlwZS5ldmVyeSA9IEV2ZW50ZWRMb29wLnByb3RvdHlwZS5vbjtcblxuICAgIC8vIEV4cG9ydCB0aGUgRXZlbnRlZExvb3Agb2JqZWN0IGZvciAqKk5vZGUuanMqKiBvciBvdGhlclxuICAgIC8vIGNvbW1vbmpzIHN5c3RlbXMuIE90aGVyd2lzZSwgYWRkIGl0IGFzIGEgZ2xvYmFsIG9iamVjdCB0byB0aGUgcm9vdFxuICAgIGlmICh0eXBlb2YgZXhwb3J0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBtb2R1bGUgIT09ICd1bmRlZmluZWQnICYmIG1vZHVsZS5leHBvcnRzKSB7XG4gICAgICAgICAgICBleHBvcnRzID0gbW9kdWxlLmV4cG9ydHMgPSBFdmVudGVkTG9vcDtcbiAgICAgICAgfVxuICAgICAgICBleHBvcnRzLkV2ZW50ZWRMb29wID0gRXZlbnRlZExvb3A7XG4gICAgfVxuICAgIGlmICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICB3aW5kb3cuRXZlbnRlZExvb3AgPSBFdmVudGVkTG9vcDtcbiAgICB9XG59KS5jYWxsKHRoaXMpO1xufSkuY2FsbCh0aGlzLHR5cGVvZiBnbG9iYWwgIT09IFwidW5kZWZpbmVkXCIgPyBnbG9iYWwgOiB0eXBlb2Ygc2VsZiAhPT0gXCJ1bmRlZmluZWRcIiA/IHNlbGYgOiB0eXBlb2Ygd2luZG93ICE9PSBcInVuZGVmaW5lZFwiID8gd2luZG93IDoge30pIiwiLy8gICAgIFVuZGVyc2NvcmUuanMgMS42LjBcbi8vICAgICBodHRwOi8vdW5kZXJzY29yZWpzLm9yZ1xuLy8gICAgIChjKSAyMDA5LTIwMTQgSmVyZW15IEFzaGtlbmFzLCBEb2N1bWVudENsb3VkIGFuZCBJbnZlc3RpZ2F0aXZlIFJlcG9ydGVycyAmIEVkaXRvcnNcbi8vICAgICBVbmRlcnNjb3JlIG1heSBiZSBmcmVlbHkgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuXG4oZnVuY3Rpb24oKSB7XG5cbiAgLy8gQmFzZWxpbmUgc2V0dXBcbiAgLy8gLS0tLS0tLS0tLS0tLS1cblxuICAvLyBFc3RhYmxpc2ggdGhlIHJvb3Qgb2JqZWN0LCBgd2luZG93YCBpbiB0aGUgYnJvd3Nlciwgb3IgYGV4cG9ydHNgIG9uIHRoZSBzZXJ2ZXIuXG4gIHZhciByb290ID0gdGhpcztcblxuICAvLyBTYXZlIHRoZSBwcmV2aW91cyB2YWx1ZSBvZiB0aGUgYF9gIHZhcmlhYmxlLlxuICB2YXIgcHJldmlvdXNVbmRlcnNjb3JlID0gcm9vdC5fO1xuXG4gIC8vIEVzdGFibGlzaCB0aGUgb2JqZWN0IHRoYXQgZ2V0cyByZXR1cm5lZCB0byBicmVhayBvdXQgb2YgYSBsb29wIGl0ZXJhdGlvbi5cbiAgdmFyIGJyZWFrZXIgPSB7fTtcblxuICAvLyBTYXZlIGJ5dGVzIGluIHRoZSBtaW5pZmllZCAoYnV0IG5vdCBnemlwcGVkKSB2ZXJzaW9uOlxuICB2YXIgQXJyYXlQcm90byA9IEFycmF5LnByb3RvdHlwZSwgT2JqUHJvdG8gPSBPYmplY3QucHJvdG90eXBlLCBGdW5jUHJvdG8gPSBGdW5jdGlvbi5wcm90b3R5cGU7XG5cbiAgLy8gQ3JlYXRlIHF1aWNrIHJlZmVyZW5jZSB2YXJpYWJsZXMgZm9yIHNwZWVkIGFjY2VzcyB0byBjb3JlIHByb3RvdHlwZXMuXG4gIHZhclxuICAgIHB1c2ggICAgICAgICAgICAgPSBBcnJheVByb3RvLnB1c2gsXG4gICAgc2xpY2UgICAgICAgICAgICA9IEFycmF5UHJvdG8uc2xpY2UsXG4gICAgY29uY2F0ICAgICAgICAgICA9IEFycmF5UHJvdG8uY29uY2F0LFxuICAgIHRvU3RyaW5nICAgICAgICAgPSBPYmpQcm90by50b1N0cmluZyxcbiAgICBoYXNPd25Qcm9wZXJ0eSAgID0gT2JqUHJvdG8uaGFzT3duUHJvcGVydHk7XG5cbiAgLy8gQWxsICoqRUNNQVNjcmlwdCA1KiogbmF0aXZlIGZ1bmN0aW9uIGltcGxlbWVudGF0aW9ucyB0aGF0IHdlIGhvcGUgdG8gdXNlXG4gIC8vIGFyZSBkZWNsYXJlZCBoZXJlLlxuICB2YXJcbiAgICBuYXRpdmVGb3JFYWNoICAgICAgPSBBcnJheVByb3RvLmZvckVhY2gsXG4gICAgbmF0aXZlTWFwICAgICAgICAgID0gQXJyYXlQcm90by5tYXAsXG4gICAgbmF0aXZlUmVkdWNlICAgICAgID0gQXJyYXlQcm90by5yZWR1Y2UsXG4gICAgbmF0aXZlUmVkdWNlUmlnaHQgID0gQXJyYXlQcm90by5yZWR1Y2VSaWdodCxcbiAgICBuYXRpdmVGaWx0ZXIgICAgICAgPSBBcnJheVByb3RvLmZpbHRlcixcbiAgICBuYXRpdmVFdmVyeSAgICAgICAgPSBBcnJheVByb3RvLmV2ZXJ5LFxuICAgIG5hdGl2ZVNvbWUgICAgICAgICA9IEFycmF5UHJvdG8uc29tZSxcbiAgICBuYXRpdmVJbmRleE9mICAgICAgPSBBcnJheVByb3RvLmluZGV4T2YsXG4gICAgbmF0aXZlTGFzdEluZGV4T2YgID0gQXJyYXlQcm90by5sYXN0SW5kZXhPZixcbiAgICBuYXRpdmVJc0FycmF5ICAgICAgPSBBcnJheS5pc0FycmF5LFxuICAgIG5hdGl2ZUtleXMgICAgICAgICA9IE9iamVjdC5rZXlzLFxuICAgIG5hdGl2ZUJpbmQgICAgICAgICA9IEZ1bmNQcm90by5iaW5kO1xuXG4gIC8vIENyZWF0ZSBhIHNhZmUgcmVmZXJlbmNlIHRvIHRoZSBVbmRlcnNjb3JlIG9iamVjdCBmb3IgdXNlIGJlbG93LlxuICB2YXIgXyA9IGZ1bmN0aW9uKG9iaikge1xuICAgIGlmIChvYmogaW5zdGFuY2VvZiBfKSByZXR1cm4gb2JqO1xuICAgIGlmICghKHRoaXMgaW5zdGFuY2VvZiBfKSkgcmV0dXJuIG5ldyBfKG9iaik7XG4gICAgdGhpcy5fd3JhcHBlZCA9IG9iajtcbiAgfTtcblxuICAvLyBFeHBvcnQgdGhlIFVuZGVyc2NvcmUgb2JqZWN0IGZvciAqKk5vZGUuanMqKiwgd2l0aFxuICAvLyBiYWNrd2FyZHMtY29tcGF0aWJpbGl0eSBmb3IgdGhlIG9sZCBgcmVxdWlyZSgpYCBBUEkuIElmIHdlJ3JlIGluXG4gIC8vIHRoZSBicm93c2VyLCBhZGQgYF9gIGFzIGEgZ2xvYmFsIG9iamVjdCB2aWEgYSBzdHJpbmcgaWRlbnRpZmllcixcbiAgLy8gZm9yIENsb3N1cmUgQ29tcGlsZXIgXCJhZHZhbmNlZFwiIG1vZGUuXG4gIGlmICh0eXBlb2YgZXhwb3J0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBpZiAodHlwZW9mIG1vZHVsZSAhPT0gJ3VuZGVmaW5lZCcgJiYgbW9kdWxlLmV4cG9ydHMpIHtcbiAgICAgIGV4cG9ydHMgPSBtb2R1bGUuZXhwb3J0cyA9IF87XG4gICAgfVxuICAgIGV4cG9ydHMuXyA9IF87XG4gIH0gZWxzZSB7XG4gICAgcm9vdC5fID0gXztcbiAgfVxuXG4gIC8vIEN1cnJlbnQgdmVyc2lvbi5cbiAgXy5WRVJTSU9OID0gJzEuNi4wJztcblxuICAvLyBDb2xsZWN0aW9uIEZ1bmN0aW9uc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8vIFRoZSBjb3JuZXJzdG9uZSwgYW4gYGVhY2hgIGltcGxlbWVudGF0aW9uLCBha2EgYGZvckVhY2hgLlxuICAvLyBIYW5kbGVzIG9iamVjdHMgd2l0aCB0aGUgYnVpbHQtaW4gYGZvckVhY2hgLCBhcnJheXMsIGFuZCByYXcgb2JqZWN0cy5cbiAgLy8gRGVsZWdhdGVzIHRvICoqRUNNQVNjcmlwdCA1KioncyBuYXRpdmUgYGZvckVhY2hgIGlmIGF2YWlsYWJsZS5cbiAgdmFyIGVhY2ggPSBfLmVhY2ggPSBfLmZvckVhY2ggPSBmdW5jdGlvbihvYmosIGl0ZXJhdG9yLCBjb250ZXh0KSB7XG4gICAgaWYgKG9iaiA9PSBudWxsKSByZXR1cm4gb2JqO1xuICAgIGlmIChuYXRpdmVGb3JFYWNoICYmIG9iai5mb3JFYWNoID09PSBuYXRpdmVGb3JFYWNoKSB7XG4gICAgICBvYmouZm9yRWFjaChpdGVyYXRvciwgY29udGV4dCk7XG4gICAgfSBlbHNlIGlmIChvYmoubGVuZ3RoID09PSArb2JqLmxlbmd0aCkge1xuICAgICAgZm9yICh2YXIgaSA9IDAsIGxlbmd0aCA9IG9iai5sZW5ndGg7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAoaXRlcmF0b3IuY2FsbChjb250ZXh0LCBvYmpbaV0sIGksIG9iaikgPT09IGJyZWFrZXIpIHJldHVybjtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIGtleXMgPSBfLmtleXMob2JqKTtcbiAgICAgIGZvciAodmFyIGkgPSAwLCBsZW5ndGggPSBrZXlzLmxlbmd0aDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChpdGVyYXRvci5jYWxsKGNvbnRleHQsIG9ialtrZXlzW2ldXSwga2V5c1tpXSwgb2JqKSA9PT0gYnJlYWtlcikgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gb2JqO1xuICB9O1xuXG4gIC8vIFJldHVybiB0aGUgcmVzdWx0cyBvZiBhcHBseWluZyB0aGUgaXRlcmF0b3IgdG8gZWFjaCBlbGVtZW50LlxuICAvLyBEZWxlZ2F0ZXMgdG8gKipFQ01BU2NyaXB0IDUqKidzIG5hdGl2ZSBgbWFwYCBpZiBhdmFpbGFibGUuXG4gIF8ubWFwID0gXy5jb2xsZWN0ID0gZnVuY3Rpb24ob2JqLCBpdGVyYXRvciwgY29udGV4dCkge1xuICAgIHZhciByZXN1bHRzID0gW107XG4gICAgaWYgKG9iaiA9PSBudWxsKSByZXR1cm4gcmVzdWx0cztcbiAgICBpZiAobmF0aXZlTWFwICYmIG9iai5tYXAgPT09IG5hdGl2ZU1hcCkgcmV0dXJuIG9iai5tYXAoaXRlcmF0b3IsIGNvbnRleHQpO1xuICAgIGVhY2gob2JqLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGxpc3QpIHtcbiAgICAgIHJlc3VsdHMucHVzaChpdGVyYXRvci5jYWxsKGNvbnRleHQsIHZhbHVlLCBpbmRleCwgbGlzdCkpO1xuICAgIH0pO1xuICAgIHJldHVybiByZXN1bHRzO1xuICB9O1xuXG4gIHZhciByZWR1Y2VFcnJvciA9ICdSZWR1Y2Ugb2YgZW1wdHkgYXJyYXkgd2l0aCBubyBpbml0aWFsIHZhbHVlJztcblxuICAvLyAqKlJlZHVjZSoqIGJ1aWxkcyB1cCBhIHNpbmdsZSByZXN1bHQgZnJvbSBhIGxpc3Qgb2YgdmFsdWVzLCBha2EgYGluamVjdGAsXG4gIC8vIG9yIGBmb2xkbGAuIERlbGVnYXRlcyB0byAqKkVDTUFTY3JpcHQgNSoqJ3MgbmF0aXZlIGByZWR1Y2VgIGlmIGF2YWlsYWJsZS5cbiAgXy5yZWR1Y2UgPSBfLmZvbGRsID0gXy5pbmplY3QgPSBmdW5jdGlvbihvYmosIGl0ZXJhdG9yLCBtZW1vLCBjb250ZXh0KSB7XG4gICAgdmFyIGluaXRpYWwgPSBhcmd1bWVudHMubGVuZ3RoID4gMjtcbiAgICBpZiAob2JqID09IG51bGwpIG9iaiA9IFtdO1xuICAgIGlmIChuYXRpdmVSZWR1Y2UgJiYgb2JqLnJlZHVjZSA9PT0gbmF0aXZlUmVkdWNlKSB7XG4gICAgICBpZiAoY29udGV4dCkgaXRlcmF0b3IgPSBfLmJpbmQoaXRlcmF0b3IsIGNvbnRleHQpO1xuICAgICAgcmV0dXJuIGluaXRpYWwgPyBvYmoucmVkdWNlKGl0ZXJhdG9yLCBtZW1vKSA6IG9iai5yZWR1Y2UoaXRlcmF0b3IpO1xuICAgIH1cbiAgICBlYWNoKG9iaiwgZnVuY3Rpb24odmFsdWUsIGluZGV4LCBsaXN0KSB7XG4gICAgICBpZiAoIWluaXRpYWwpIHtcbiAgICAgICAgbWVtbyA9IHZhbHVlO1xuICAgICAgICBpbml0aWFsID0gdHJ1ZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG1lbW8gPSBpdGVyYXRvci5jYWxsKGNvbnRleHQsIG1lbW8sIHZhbHVlLCBpbmRleCwgbGlzdCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgaWYgKCFpbml0aWFsKSB0aHJvdyBuZXcgVHlwZUVycm9yKHJlZHVjZUVycm9yKTtcbiAgICByZXR1cm4gbWVtbztcbiAgfTtcblxuICAvLyBUaGUgcmlnaHQtYXNzb2NpYXRpdmUgdmVyc2lvbiBvZiByZWR1Y2UsIGFsc28ga25vd24gYXMgYGZvbGRyYC5cbiAgLy8gRGVsZWdhdGVzIHRvICoqRUNNQVNjcmlwdCA1KioncyBuYXRpdmUgYHJlZHVjZVJpZ2h0YCBpZiBhdmFpbGFibGUuXG4gIF8ucmVkdWNlUmlnaHQgPSBfLmZvbGRyID0gZnVuY3Rpb24ob2JqLCBpdGVyYXRvciwgbWVtbywgY29udGV4dCkge1xuICAgIHZhciBpbml0aWFsID0gYXJndW1lbnRzLmxlbmd0aCA+IDI7XG4gICAgaWYgKG9iaiA9PSBudWxsKSBvYmogPSBbXTtcbiAgICBpZiAobmF0aXZlUmVkdWNlUmlnaHQgJiYgb2JqLnJlZHVjZVJpZ2h0ID09PSBuYXRpdmVSZWR1Y2VSaWdodCkge1xuICAgICAgaWYgKGNvbnRleHQpIGl0ZXJhdG9yID0gXy5iaW5kKGl0ZXJhdG9yLCBjb250ZXh0KTtcbiAgICAgIHJldHVybiBpbml0aWFsID8gb2JqLnJlZHVjZVJpZ2h0KGl0ZXJhdG9yLCBtZW1vKSA6IG9iai5yZWR1Y2VSaWdodChpdGVyYXRvcik7XG4gICAgfVxuICAgIHZhciBsZW5ndGggPSBvYmoubGVuZ3RoO1xuICAgIGlmIChsZW5ndGggIT09ICtsZW5ndGgpIHtcbiAgICAgIHZhciBrZXlzID0gXy5rZXlzKG9iaik7XG4gICAgICBsZW5ndGggPSBrZXlzLmxlbmd0aDtcbiAgICB9XG4gICAgZWFjaChvYmosIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgbGlzdCkge1xuICAgICAgaW5kZXggPSBrZXlzID8ga2V5c1stLWxlbmd0aF0gOiAtLWxlbmd0aDtcbiAgICAgIGlmICghaW5pdGlhbCkge1xuICAgICAgICBtZW1vID0gb2JqW2luZGV4XTtcbiAgICAgICAgaW5pdGlhbCA9IHRydWU7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBtZW1vID0gaXRlcmF0b3IuY2FsbChjb250ZXh0LCBtZW1vLCBvYmpbaW5kZXhdLCBpbmRleCwgbGlzdCk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgaWYgKCFpbml0aWFsKSB0aHJvdyBuZXcgVHlwZUVycm9yKHJlZHVjZUVycm9yKTtcbiAgICByZXR1cm4gbWVtbztcbiAgfTtcblxuICAvLyBSZXR1cm4gdGhlIGZpcnN0IHZhbHVlIHdoaWNoIHBhc3NlcyBhIHRydXRoIHRlc3QuIEFsaWFzZWQgYXMgYGRldGVjdGAuXG4gIF8uZmluZCA9IF8uZGV0ZWN0ID0gZnVuY3Rpb24ob2JqLCBwcmVkaWNhdGUsIGNvbnRleHQpIHtcbiAgICB2YXIgcmVzdWx0O1xuICAgIGFueShvYmosIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgbGlzdCkge1xuICAgICAgaWYgKHByZWRpY2F0ZS5jYWxsKGNvbnRleHQsIHZhbHVlLCBpbmRleCwgbGlzdCkpIHtcbiAgICAgICAgcmVzdWx0ID0gdmFsdWU7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG5cbiAgLy8gUmV0dXJuIGFsbCB0aGUgZWxlbWVudHMgdGhhdCBwYXNzIGEgdHJ1dGggdGVzdC5cbiAgLy8gRGVsZWdhdGVzIHRvICoqRUNNQVNjcmlwdCA1KioncyBuYXRpdmUgYGZpbHRlcmAgaWYgYXZhaWxhYmxlLlxuICAvLyBBbGlhc2VkIGFzIGBzZWxlY3RgLlxuICBfLmZpbHRlciA9IF8uc2VsZWN0ID0gZnVuY3Rpb24ob2JqLCBwcmVkaWNhdGUsIGNvbnRleHQpIHtcbiAgICB2YXIgcmVzdWx0cyA9IFtdO1xuICAgIGlmIChvYmogPT0gbnVsbCkgcmV0dXJuIHJlc3VsdHM7XG4gICAgaWYgKG5hdGl2ZUZpbHRlciAmJiBvYmouZmlsdGVyID09PSBuYXRpdmVGaWx0ZXIpIHJldHVybiBvYmouZmlsdGVyKHByZWRpY2F0ZSwgY29udGV4dCk7XG4gICAgZWFjaChvYmosIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgbGlzdCkge1xuICAgICAgaWYgKHByZWRpY2F0ZS5jYWxsKGNvbnRleHQsIHZhbHVlLCBpbmRleCwgbGlzdCkpIHJlc3VsdHMucHVzaCh2YWx1ZSk7XG4gICAgfSk7XG4gICAgcmV0dXJuIHJlc3VsdHM7XG4gIH07XG5cbiAgLy8gUmV0dXJuIGFsbCB0aGUgZWxlbWVudHMgZm9yIHdoaWNoIGEgdHJ1dGggdGVzdCBmYWlscy5cbiAgXy5yZWplY3QgPSBmdW5jdGlvbihvYmosIHByZWRpY2F0ZSwgY29udGV4dCkge1xuICAgIHJldHVybiBfLmZpbHRlcihvYmosIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgbGlzdCkge1xuICAgICAgcmV0dXJuICFwcmVkaWNhdGUuY2FsbChjb250ZXh0LCB2YWx1ZSwgaW5kZXgsIGxpc3QpO1xuICAgIH0sIGNvbnRleHQpO1xuICB9O1xuXG4gIC8vIERldGVybWluZSB3aGV0aGVyIGFsbCBvZiB0aGUgZWxlbWVudHMgbWF0Y2ggYSB0cnV0aCB0ZXN0LlxuICAvLyBEZWxlZ2F0ZXMgdG8gKipFQ01BU2NyaXB0IDUqKidzIG5hdGl2ZSBgZXZlcnlgIGlmIGF2YWlsYWJsZS5cbiAgLy8gQWxpYXNlZCBhcyBgYWxsYC5cbiAgXy5ldmVyeSA9IF8uYWxsID0gZnVuY3Rpb24ob2JqLCBwcmVkaWNhdGUsIGNvbnRleHQpIHtcbiAgICBwcmVkaWNhdGUgfHwgKHByZWRpY2F0ZSA9IF8uaWRlbnRpdHkpO1xuICAgIHZhciByZXN1bHQgPSB0cnVlO1xuICAgIGlmIChvYmogPT0gbnVsbCkgcmV0dXJuIHJlc3VsdDtcbiAgICBpZiAobmF0aXZlRXZlcnkgJiYgb2JqLmV2ZXJ5ID09PSBuYXRpdmVFdmVyeSkgcmV0dXJuIG9iai5ldmVyeShwcmVkaWNhdGUsIGNvbnRleHQpO1xuICAgIGVhY2gob2JqLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGxpc3QpIHtcbiAgICAgIGlmICghKHJlc3VsdCA9IHJlc3VsdCAmJiBwcmVkaWNhdGUuY2FsbChjb250ZXh0LCB2YWx1ZSwgaW5kZXgsIGxpc3QpKSkgcmV0dXJuIGJyZWFrZXI7XG4gICAgfSk7XG4gICAgcmV0dXJuICEhcmVzdWx0O1xuICB9O1xuXG4gIC8vIERldGVybWluZSBpZiBhdCBsZWFzdCBvbmUgZWxlbWVudCBpbiB0aGUgb2JqZWN0IG1hdGNoZXMgYSB0cnV0aCB0ZXN0LlxuICAvLyBEZWxlZ2F0ZXMgdG8gKipFQ01BU2NyaXB0IDUqKidzIG5hdGl2ZSBgc29tZWAgaWYgYXZhaWxhYmxlLlxuICAvLyBBbGlhc2VkIGFzIGBhbnlgLlxuICB2YXIgYW55ID0gXy5zb21lID0gXy5hbnkgPSBmdW5jdGlvbihvYmosIHByZWRpY2F0ZSwgY29udGV4dCkge1xuICAgIHByZWRpY2F0ZSB8fCAocHJlZGljYXRlID0gXy5pZGVudGl0eSk7XG4gICAgdmFyIHJlc3VsdCA9IGZhbHNlO1xuICAgIGlmIChvYmogPT0gbnVsbCkgcmV0dXJuIHJlc3VsdDtcbiAgICBpZiAobmF0aXZlU29tZSAmJiBvYmouc29tZSA9PT0gbmF0aXZlU29tZSkgcmV0dXJuIG9iai5zb21lKHByZWRpY2F0ZSwgY29udGV4dCk7XG4gICAgZWFjaChvYmosIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCwgbGlzdCkge1xuICAgICAgaWYgKHJlc3VsdCB8fCAocmVzdWx0ID0gcHJlZGljYXRlLmNhbGwoY29udGV4dCwgdmFsdWUsIGluZGV4LCBsaXN0KSkpIHJldHVybiBicmVha2VyO1xuICAgIH0pO1xuICAgIHJldHVybiAhIXJlc3VsdDtcbiAgfTtcblxuICAvLyBEZXRlcm1pbmUgaWYgdGhlIGFycmF5IG9yIG9iamVjdCBjb250YWlucyBhIGdpdmVuIHZhbHVlICh1c2luZyBgPT09YCkuXG4gIC8vIEFsaWFzZWQgYXMgYGluY2x1ZGVgLlxuICBfLmNvbnRhaW5zID0gXy5pbmNsdWRlID0gZnVuY3Rpb24ob2JqLCB0YXJnZXQpIHtcbiAgICBpZiAob2JqID09IG51bGwpIHJldHVybiBmYWxzZTtcbiAgICBpZiAobmF0aXZlSW5kZXhPZiAmJiBvYmouaW5kZXhPZiA9PT0gbmF0aXZlSW5kZXhPZikgcmV0dXJuIG9iai5pbmRleE9mKHRhcmdldCkgIT0gLTE7XG4gICAgcmV0dXJuIGFueShvYmosIGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICByZXR1cm4gdmFsdWUgPT09IHRhcmdldDtcbiAgICB9KTtcbiAgfTtcblxuICAvLyBJbnZva2UgYSBtZXRob2QgKHdpdGggYXJndW1lbnRzKSBvbiBldmVyeSBpdGVtIGluIGEgY29sbGVjdGlvbi5cbiAgXy5pbnZva2UgPSBmdW5jdGlvbihvYmosIG1ldGhvZCkge1xuICAgIHZhciBhcmdzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpO1xuICAgIHZhciBpc0Z1bmMgPSBfLmlzRnVuY3Rpb24obWV0aG9kKTtcbiAgICByZXR1cm4gXy5tYXAob2JqLCBmdW5jdGlvbih2YWx1ZSkge1xuICAgICAgcmV0dXJuIChpc0Z1bmMgPyBtZXRob2QgOiB2YWx1ZVttZXRob2RdKS5hcHBseSh2YWx1ZSwgYXJncyk7XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gQ29udmVuaWVuY2UgdmVyc2lvbiBvZiBhIGNvbW1vbiB1c2UgY2FzZSBvZiBgbWFwYDogZmV0Y2hpbmcgYSBwcm9wZXJ0eS5cbiAgXy5wbHVjayA9IGZ1bmN0aW9uKG9iaiwga2V5KSB7XG4gICAgcmV0dXJuIF8ubWFwKG9iaiwgXy5wcm9wZXJ0eShrZXkpKTtcbiAgfTtcblxuICAvLyBDb252ZW5pZW5jZSB2ZXJzaW9uIG9mIGEgY29tbW9uIHVzZSBjYXNlIG9mIGBmaWx0ZXJgOiBzZWxlY3Rpbmcgb25seSBvYmplY3RzXG4gIC8vIGNvbnRhaW5pbmcgc3BlY2lmaWMgYGtleTp2YWx1ZWAgcGFpcnMuXG4gIF8ud2hlcmUgPSBmdW5jdGlvbihvYmosIGF0dHJzKSB7XG4gICAgcmV0dXJuIF8uZmlsdGVyKG9iaiwgXy5tYXRjaGVzKGF0dHJzKSk7XG4gIH07XG5cbiAgLy8gQ29udmVuaWVuY2UgdmVyc2lvbiBvZiBhIGNvbW1vbiB1c2UgY2FzZSBvZiBgZmluZGA6IGdldHRpbmcgdGhlIGZpcnN0IG9iamVjdFxuICAvLyBjb250YWluaW5nIHNwZWNpZmljIGBrZXk6dmFsdWVgIHBhaXJzLlxuICBfLmZpbmRXaGVyZSA9IGZ1bmN0aW9uKG9iaiwgYXR0cnMpIHtcbiAgICByZXR1cm4gXy5maW5kKG9iaiwgXy5tYXRjaGVzKGF0dHJzKSk7XG4gIH07XG5cbiAgLy8gUmV0dXJuIHRoZSBtYXhpbXVtIGVsZW1lbnQgb3IgKGVsZW1lbnQtYmFzZWQgY29tcHV0YXRpb24pLlxuICAvLyBDYW4ndCBvcHRpbWl6ZSBhcnJheXMgb2YgaW50ZWdlcnMgbG9uZ2VyIHRoYW4gNjUsNTM1IGVsZW1lbnRzLlxuICAvLyBTZWUgW1dlYktpdCBCdWcgODA3OTddKGh0dHBzOi8vYnVncy53ZWJraXQub3JnL3Nob3dfYnVnLmNnaT9pZD04MDc5NylcbiAgXy5tYXggPSBmdW5jdGlvbihvYmosIGl0ZXJhdG9yLCBjb250ZXh0KSB7XG4gICAgaWYgKCFpdGVyYXRvciAmJiBfLmlzQXJyYXkob2JqKSAmJiBvYmpbMF0gPT09ICtvYmpbMF0gJiYgb2JqLmxlbmd0aCA8IDY1NTM1KSB7XG4gICAgICByZXR1cm4gTWF0aC5tYXguYXBwbHkoTWF0aCwgb2JqKTtcbiAgICB9XG4gICAgdmFyIHJlc3VsdCA9IC1JbmZpbml0eSwgbGFzdENvbXB1dGVkID0gLUluZmluaXR5O1xuICAgIGVhY2gob2JqLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGxpc3QpIHtcbiAgICAgIHZhciBjb21wdXRlZCA9IGl0ZXJhdG9yID8gaXRlcmF0b3IuY2FsbChjb250ZXh0LCB2YWx1ZSwgaW5kZXgsIGxpc3QpIDogdmFsdWU7XG4gICAgICBpZiAoY29tcHV0ZWQgPiBsYXN0Q29tcHV0ZWQpIHtcbiAgICAgICAgcmVzdWx0ID0gdmFsdWU7XG4gICAgICAgIGxhc3RDb21wdXRlZCA9IGNvbXB1dGVkO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG5cbiAgLy8gUmV0dXJuIHRoZSBtaW5pbXVtIGVsZW1lbnQgKG9yIGVsZW1lbnQtYmFzZWQgY29tcHV0YXRpb24pLlxuICBfLm1pbiA9IGZ1bmN0aW9uKG9iaiwgaXRlcmF0b3IsIGNvbnRleHQpIHtcbiAgICBpZiAoIWl0ZXJhdG9yICYmIF8uaXNBcnJheShvYmopICYmIG9ialswXSA9PT0gK29ialswXSAmJiBvYmoubGVuZ3RoIDwgNjU1MzUpIHtcbiAgICAgIHJldHVybiBNYXRoLm1pbi5hcHBseShNYXRoLCBvYmopO1xuICAgIH1cbiAgICB2YXIgcmVzdWx0ID0gSW5maW5pdHksIGxhc3RDb21wdXRlZCA9IEluZmluaXR5O1xuICAgIGVhY2gob2JqLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGxpc3QpIHtcbiAgICAgIHZhciBjb21wdXRlZCA9IGl0ZXJhdG9yID8gaXRlcmF0b3IuY2FsbChjb250ZXh0LCB2YWx1ZSwgaW5kZXgsIGxpc3QpIDogdmFsdWU7XG4gICAgICBpZiAoY29tcHV0ZWQgPCBsYXN0Q29tcHV0ZWQpIHtcbiAgICAgICAgcmVzdWx0ID0gdmFsdWU7XG4gICAgICAgIGxhc3RDb21wdXRlZCA9IGNvbXB1dGVkO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG5cbiAgLy8gU2h1ZmZsZSBhbiBhcnJheSwgdXNpbmcgdGhlIG1vZGVybiB2ZXJzaW9uIG9mIHRoZVxuICAvLyBbRmlzaGVyLVlhdGVzIHNodWZmbGVdKGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRmlzaGVy4oCTWWF0ZXNfc2h1ZmZsZSkuXG4gIF8uc2h1ZmZsZSA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHZhciByYW5kO1xuICAgIHZhciBpbmRleCA9IDA7XG4gICAgdmFyIHNodWZmbGVkID0gW107XG4gICAgZWFjaChvYmosIGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgICByYW5kID0gXy5yYW5kb20oaW5kZXgrKyk7XG4gICAgICBzaHVmZmxlZFtpbmRleCAtIDFdID0gc2h1ZmZsZWRbcmFuZF07XG4gICAgICBzaHVmZmxlZFtyYW5kXSA9IHZhbHVlO1xuICAgIH0pO1xuICAgIHJldHVybiBzaHVmZmxlZDtcbiAgfTtcblxuICAvLyBTYW1wbGUgKipuKiogcmFuZG9tIHZhbHVlcyBmcm9tIGEgY29sbGVjdGlvbi5cbiAgLy8gSWYgKipuKiogaXMgbm90IHNwZWNpZmllZCwgcmV0dXJucyBhIHNpbmdsZSByYW5kb20gZWxlbWVudC5cbiAgLy8gVGhlIGludGVybmFsIGBndWFyZGAgYXJndW1lbnQgYWxsb3dzIGl0IHRvIHdvcmsgd2l0aCBgbWFwYC5cbiAgXy5zYW1wbGUgPSBmdW5jdGlvbihvYmosIG4sIGd1YXJkKSB7XG4gICAgaWYgKG4gPT0gbnVsbCB8fCBndWFyZCkge1xuICAgICAgaWYgKG9iai5sZW5ndGggIT09ICtvYmoubGVuZ3RoKSBvYmogPSBfLnZhbHVlcyhvYmopO1xuICAgICAgcmV0dXJuIG9ialtfLnJhbmRvbShvYmoubGVuZ3RoIC0gMSldO1xuICAgIH1cbiAgICByZXR1cm4gXy5zaHVmZmxlKG9iaikuc2xpY2UoMCwgTWF0aC5tYXgoMCwgbikpO1xuICB9O1xuXG4gIC8vIEFuIGludGVybmFsIGZ1bmN0aW9uIHRvIGdlbmVyYXRlIGxvb2t1cCBpdGVyYXRvcnMuXG4gIHZhciBsb29rdXBJdGVyYXRvciA9IGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgaWYgKHZhbHVlID09IG51bGwpIHJldHVybiBfLmlkZW50aXR5O1xuICAgIGlmIChfLmlzRnVuY3Rpb24odmFsdWUpKSByZXR1cm4gdmFsdWU7XG4gICAgcmV0dXJuIF8ucHJvcGVydHkodmFsdWUpO1xuICB9O1xuXG4gIC8vIFNvcnQgdGhlIG9iamVjdCdzIHZhbHVlcyBieSBhIGNyaXRlcmlvbiBwcm9kdWNlZCBieSBhbiBpdGVyYXRvci5cbiAgXy5zb3J0QnkgPSBmdW5jdGlvbihvYmosIGl0ZXJhdG9yLCBjb250ZXh0KSB7XG4gICAgaXRlcmF0b3IgPSBsb29rdXBJdGVyYXRvcihpdGVyYXRvcik7XG4gICAgcmV0dXJuIF8ucGx1Y2soXy5tYXAob2JqLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgsIGxpc3QpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHZhbHVlOiB2YWx1ZSxcbiAgICAgICAgaW5kZXg6IGluZGV4LFxuICAgICAgICBjcml0ZXJpYTogaXRlcmF0b3IuY2FsbChjb250ZXh0LCB2YWx1ZSwgaW5kZXgsIGxpc3QpXG4gICAgICB9O1xuICAgIH0pLnNvcnQoZnVuY3Rpb24obGVmdCwgcmlnaHQpIHtcbiAgICAgIHZhciBhID0gbGVmdC5jcml0ZXJpYTtcbiAgICAgIHZhciBiID0gcmlnaHQuY3JpdGVyaWE7XG4gICAgICBpZiAoYSAhPT0gYikge1xuICAgICAgICBpZiAoYSA+IGIgfHwgYSA9PT0gdm9pZCAwKSByZXR1cm4gMTtcbiAgICAgICAgaWYgKGEgPCBiIHx8IGIgPT09IHZvaWQgMCkgcmV0dXJuIC0xO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGxlZnQuaW5kZXggLSByaWdodC5pbmRleDtcbiAgICB9KSwgJ3ZhbHVlJyk7XG4gIH07XG5cbiAgLy8gQW4gaW50ZXJuYWwgZnVuY3Rpb24gdXNlZCBmb3IgYWdncmVnYXRlIFwiZ3JvdXAgYnlcIiBvcGVyYXRpb25zLlxuICB2YXIgZ3JvdXAgPSBmdW5jdGlvbihiZWhhdmlvcikge1xuICAgIHJldHVybiBmdW5jdGlvbihvYmosIGl0ZXJhdG9yLCBjb250ZXh0KSB7XG4gICAgICB2YXIgcmVzdWx0ID0ge307XG4gICAgICBpdGVyYXRvciA9IGxvb2t1cEl0ZXJhdG9yKGl0ZXJhdG9yKTtcbiAgICAgIGVhY2gob2JqLCBmdW5jdGlvbih2YWx1ZSwgaW5kZXgpIHtcbiAgICAgICAgdmFyIGtleSA9IGl0ZXJhdG9yLmNhbGwoY29udGV4dCwgdmFsdWUsIGluZGV4LCBvYmopO1xuICAgICAgICBiZWhhdmlvcihyZXN1bHQsIGtleSwgdmFsdWUpO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH07XG4gIH07XG5cbiAgLy8gR3JvdXBzIHRoZSBvYmplY3QncyB2YWx1ZXMgYnkgYSBjcml0ZXJpb24uIFBhc3MgZWl0aGVyIGEgc3RyaW5nIGF0dHJpYnV0ZVxuICAvLyB0byBncm91cCBieSwgb3IgYSBmdW5jdGlvbiB0aGF0IHJldHVybnMgdGhlIGNyaXRlcmlvbi5cbiAgXy5ncm91cEJ5ID0gZ3JvdXAoZnVuY3Rpb24ocmVzdWx0LCBrZXksIHZhbHVlKSB7XG4gICAgXy5oYXMocmVzdWx0LCBrZXkpID8gcmVzdWx0W2tleV0ucHVzaCh2YWx1ZSkgOiByZXN1bHRba2V5XSA9IFt2YWx1ZV07XG4gIH0pO1xuXG4gIC8vIEluZGV4ZXMgdGhlIG9iamVjdCdzIHZhbHVlcyBieSBhIGNyaXRlcmlvbiwgc2ltaWxhciB0byBgZ3JvdXBCeWAsIGJ1dCBmb3JcbiAgLy8gd2hlbiB5b3Uga25vdyB0aGF0IHlvdXIgaW5kZXggdmFsdWVzIHdpbGwgYmUgdW5pcXVlLlxuICBfLmluZGV4QnkgPSBncm91cChmdW5jdGlvbihyZXN1bHQsIGtleSwgdmFsdWUpIHtcbiAgICByZXN1bHRba2V5XSA9IHZhbHVlO1xuICB9KTtcblxuICAvLyBDb3VudHMgaW5zdGFuY2VzIG9mIGFuIG9iamVjdCB0aGF0IGdyb3VwIGJ5IGEgY2VydGFpbiBjcml0ZXJpb24uIFBhc3NcbiAgLy8gZWl0aGVyIGEgc3RyaW5nIGF0dHJpYnV0ZSB0byBjb3VudCBieSwgb3IgYSBmdW5jdGlvbiB0aGF0IHJldHVybnMgdGhlXG4gIC8vIGNyaXRlcmlvbi5cbiAgXy5jb3VudEJ5ID0gZ3JvdXAoZnVuY3Rpb24ocmVzdWx0LCBrZXkpIHtcbiAgICBfLmhhcyhyZXN1bHQsIGtleSkgPyByZXN1bHRba2V5XSsrIDogcmVzdWx0W2tleV0gPSAxO1xuICB9KTtcblxuICAvLyBVc2UgYSBjb21wYXJhdG9yIGZ1bmN0aW9uIHRvIGZpZ3VyZSBvdXQgdGhlIHNtYWxsZXN0IGluZGV4IGF0IHdoaWNoXG4gIC8vIGFuIG9iamVjdCBzaG91bGQgYmUgaW5zZXJ0ZWQgc28gYXMgdG8gbWFpbnRhaW4gb3JkZXIuIFVzZXMgYmluYXJ5IHNlYXJjaC5cbiAgXy5zb3J0ZWRJbmRleCA9IGZ1bmN0aW9uKGFycmF5LCBvYmosIGl0ZXJhdG9yLCBjb250ZXh0KSB7XG4gICAgaXRlcmF0b3IgPSBsb29rdXBJdGVyYXRvcihpdGVyYXRvcik7XG4gICAgdmFyIHZhbHVlID0gaXRlcmF0b3IuY2FsbChjb250ZXh0LCBvYmopO1xuICAgIHZhciBsb3cgPSAwLCBoaWdoID0gYXJyYXkubGVuZ3RoO1xuICAgIHdoaWxlIChsb3cgPCBoaWdoKSB7XG4gICAgICB2YXIgbWlkID0gKGxvdyArIGhpZ2gpID4+PiAxO1xuICAgICAgaXRlcmF0b3IuY2FsbChjb250ZXh0LCBhcnJheVttaWRdKSA8IHZhbHVlID8gbG93ID0gbWlkICsgMSA6IGhpZ2ggPSBtaWQ7XG4gICAgfVxuICAgIHJldHVybiBsb3c7XG4gIH07XG5cbiAgLy8gU2FmZWx5IGNyZWF0ZSBhIHJlYWwsIGxpdmUgYXJyYXkgZnJvbSBhbnl0aGluZyBpdGVyYWJsZS5cbiAgXy50b0FycmF5ID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgaWYgKCFvYmopIHJldHVybiBbXTtcbiAgICBpZiAoXy5pc0FycmF5KG9iaikpIHJldHVybiBzbGljZS5jYWxsKG9iaik7XG4gICAgaWYgKG9iai5sZW5ndGggPT09ICtvYmoubGVuZ3RoKSByZXR1cm4gXy5tYXAob2JqLCBfLmlkZW50aXR5KTtcbiAgICByZXR1cm4gXy52YWx1ZXMob2JqKTtcbiAgfTtcblxuICAvLyBSZXR1cm4gdGhlIG51bWJlciBvZiBlbGVtZW50cyBpbiBhbiBvYmplY3QuXG4gIF8uc2l6ZSA9IGZ1bmN0aW9uKG9iaikge1xuICAgIGlmIChvYmogPT0gbnVsbCkgcmV0dXJuIDA7XG4gICAgcmV0dXJuIChvYmoubGVuZ3RoID09PSArb2JqLmxlbmd0aCkgPyBvYmoubGVuZ3RoIDogXy5rZXlzKG9iaikubGVuZ3RoO1xuICB9O1xuXG4gIC8vIEFycmF5IEZ1bmN0aW9uc1xuICAvLyAtLS0tLS0tLS0tLS0tLS1cblxuICAvLyBHZXQgdGhlIGZpcnN0IGVsZW1lbnQgb2YgYW4gYXJyYXkuIFBhc3NpbmcgKipuKiogd2lsbCByZXR1cm4gdGhlIGZpcnN0IE5cbiAgLy8gdmFsdWVzIGluIHRoZSBhcnJheS4gQWxpYXNlZCBhcyBgaGVhZGAgYW5kIGB0YWtlYC4gVGhlICoqZ3VhcmQqKiBjaGVja1xuICAvLyBhbGxvd3MgaXQgdG8gd29yayB3aXRoIGBfLm1hcGAuXG4gIF8uZmlyc3QgPSBfLmhlYWQgPSBfLnRha2UgPSBmdW5jdGlvbihhcnJheSwgbiwgZ3VhcmQpIHtcbiAgICBpZiAoYXJyYXkgPT0gbnVsbCkgcmV0dXJuIHZvaWQgMDtcbiAgICBpZiAoKG4gPT0gbnVsbCkgfHwgZ3VhcmQpIHJldHVybiBhcnJheVswXTtcbiAgICBpZiAobiA8IDApIHJldHVybiBbXTtcbiAgICByZXR1cm4gc2xpY2UuY2FsbChhcnJheSwgMCwgbik7XG4gIH07XG5cbiAgLy8gUmV0dXJucyBldmVyeXRoaW5nIGJ1dCB0aGUgbGFzdCBlbnRyeSBvZiB0aGUgYXJyYXkuIEVzcGVjaWFsbHkgdXNlZnVsIG9uXG4gIC8vIHRoZSBhcmd1bWVudHMgb2JqZWN0LiBQYXNzaW5nICoqbioqIHdpbGwgcmV0dXJuIGFsbCB0aGUgdmFsdWVzIGluXG4gIC8vIHRoZSBhcnJheSwgZXhjbHVkaW5nIHRoZSBsYXN0IE4uIFRoZSAqKmd1YXJkKiogY2hlY2sgYWxsb3dzIGl0IHRvIHdvcmsgd2l0aFxuICAvLyBgXy5tYXBgLlxuICBfLmluaXRpYWwgPSBmdW5jdGlvbihhcnJheSwgbiwgZ3VhcmQpIHtcbiAgICByZXR1cm4gc2xpY2UuY2FsbChhcnJheSwgMCwgYXJyYXkubGVuZ3RoIC0gKChuID09IG51bGwpIHx8IGd1YXJkID8gMSA6IG4pKTtcbiAgfTtcblxuICAvLyBHZXQgdGhlIGxhc3QgZWxlbWVudCBvZiBhbiBhcnJheS4gUGFzc2luZyAqKm4qKiB3aWxsIHJldHVybiB0aGUgbGFzdCBOXG4gIC8vIHZhbHVlcyBpbiB0aGUgYXJyYXkuIFRoZSAqKmd1YXJkKiogY2hlY2sgYWxsb3dzIGl0IHRvIHdvcmsgd2l0aCBgXy5tYXBgLlxuICBfLmxhc3QgPSBmdW5jdGlvbihhcnJheSwgbiwgZ3VhcmQpIHtcbiAgICBpZiAoYXJyYXkgPT0gbnVsbCkgcmV0dXJuIHZvaWQgMDtcbiAgICBpZiAoKG4gPT0gbnVsbCkgfHwgZ3VhcmQpIHJldHVybiBhcnJheVthcnJheS5sZW5ndGggLSAxXTtcbiAgICByZXR1cm4gc2xpY2UuY2FsbChhcnJheSwgTWF0aC5tYXgoYXJyYXkubGVuZ3RoIC0gbiwgMCkpO1xuICB9O1xuXG4gIC8vIFJldHVybnMgZXZlcnl0aGluZyBidXQgdGhlIGZpcnN0IGVudHJ5IG9mIHRoZSBhcnJheS4gQWxpYXNlZCBhcyBgdGFpbGAgYW5kIGBkcm9wYC5cbiAgLy8gRXNwZWNpYWxseSB1c2VmdWwgb24gdGhlIGFyZ3VtZW50cyBvYmplY3QuIFBhc3NpbmcgYW4gKipuKiogd2lsbCByZXR1cm5cbiAgLy8gdGhlIHJlc3QgTiB2YWx1ZXMgaW4gdGhlIGFycmF5LiBUaGUgKipndWFyZCoqXG4gIC8vIGNoZWNrIGFsbG93cyBpdCB0byB3b3JrIHdpdGggYF8ubWFwYC5cbiAgXy5yZXN0ID0gXy50YWlsID0gXy5kcm9wID0gZnVuY3Rpb24oYXJyYXksIG4sIGd1YXJkKSB7XG4gICAgcmV0dXJuIHNsaWNlLmNhbGwoYXJyYXksIChuID09IG51bGwpIHx8IGd1YXJkID8gMSA6IG4pO1xuICB9O1xuXG4gIC8vIFRyaW0gb3V0IGFsbCBmYWxzeSB2YWx1ZXMgZnJvbSBhbiBhcnJheS5cbiAgXy5jb21wYWN0ID0gZnVuY3Rpb24oYXJyYXkpIHtcbiAgICByZXR1cm4gXy5maWx0ZXIoYXJyYXksIF8uaWRlbnRpdHkpO1xuICB9O1xuXG4gIC8vIEludGVybmFsIGltcGxlbWVudGF0aW9uIG9mIGEgcmVjdXJzaXZlIGBmbGF0dGVuYCBmdW5jdGlvbi5cbiAgdmFyIGZsYXR0ZW4gPSBmdW5jdGlvbihpbnB1dCwgc2hhbGxvdywgb3V0cHV0KSB7XG4gICAgaWYgKHNoYWxsb3cgJiYgXy5ldmVyeShpbnB1dCwgXy5pc0FycmF5KSkge1xuICAgICAgcmV0dXJuIGNvbmNhdC5hcHBseShvdXRwdXQsIGlucHV0KTtcbiAgICB9XG4gICAgZWFjaChpbnB1dCwgZnVuY3Rpb24odmFsdWUpIHtcbiAgICAgIGlmIChfLmlzQXJyYXkodmFsdWUpIHx8IF8uaXNBcmd1bWVudHModmFsdWUpKSB7XG4gICAgICAgIHNoYWxsb3cgPyBwdXNoLmFwcGx5KG91dHB1dCwgdmFsdWUpIDogZmxhdHRlbih2YWx1ZSwgc2hhbGxvdywgb3V0cHV0KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG91dHB1dC5wdXNoKHZhbHVlKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gb3V0cHV0O1xuICB9O1xuXG4gIC8vIEZsYXR0ZW4gb3V0IGFuIGFycmF5LCBlaXRoZXIgcmVjdXJzaXZlbHkgKGJ5IGRlZmF1bHQpLCBvciBqdXN0IG9uZSBsZXZlbC5cbiAgXy5mbGF0dGVuID0gZnVuY3Rpb24oYXJyYXksIHNoYWxsb3cpIHtcbiAgICByZXR1cm4gZmxhdHRlbihhcnJheSwgc2hhbGxvdywgW10pO1xuICB9O1xuXG4gIC8vIFJldHVybiBhIHZlcnNpb24gb2YgdGhlIGFycmF5IHRoYXQgZG9lcyBub3QgY29udGFpbiB0aGUgc3BlY2lmaWVkIHZhbHVlKHMpLlxuICBfLndpdGhvdXQgPSBmdW5jdGlvbihhcnJheSkge1xuICAgIHJldHVybiBfLmRpZmZlcmVuY2UoYXJyYXksIHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSk7XG4gIH07XG5cbiAgLy8gU3BsaXQgYW4gYXJyYXkgaW50byB0d28gYXJyYXlzOiBvbmUgd2hvc2UgZWxlbWVudHMgYWxsIHNhdGlzZnkgdGhlIGdpdmVuXG4gIC8vIHByZWRpY2F0ZSwgYW5kIG9uZSB3aG9zZSBlbGVtZW50cyBhbGwgZG8gbm90IHNhdGlzZnkgdGhlIHByZWRpY2F0ZS5cbiAgXy5wYXJ0aXRpb24gPSBmdW5jdGlvbihhcnJheSwgcHJlZGljYXRlKSB7XG4gICAgdmFyIHBhc3MgPSBbXSwgZmFpbCA9IFtdO1xuICAgIGVhY2goYXJyYXksIGZ1bmN0aW9uKGVsZW0pIHtcbiAgICAgIChwcmVkaWNhdGUoZWxlbSkgPyBwYXNzIDogZmFpbCkucHVzaChlbGVtKTtcbiAgICB9KTtcbiAgICByZXR1cm4gW3Bhc3MsIGZhaWxdO1xuICB9O1xuXG4gIC8vIFByb2R1Y2UgYSBkdXBsaWNhdGUtZnJlZSB2ZXJzaW9uIG9mIHRoZSBhcnJheS4gSWYgdGhlIGFycmF5IGhhcyBhbHJlYWR5XG4gIC8vIGJlZW4gc29ydGVkLCB5b3UgaGF2ZSB0aGUgb3B0aW9uIG9mIHVzaW5nIGEgZmFzdGVyIGFsZ29yaXRobS5cbiAgLy8gQWxpYXNlZCBhcyBgdW5pcXVlYC5cbiAgXy51bmlxID0gXy51bmlxdWUgPSBmdW5jdGlvbihhcnJheSwgaXNTb3J0ZWQsIGl0ZXJhdG9yLCBjb250ZXh0KSB7XG4gICAgaWYgKF8uaXNGdW5jdGlvbihpc1NvcnRlZCkpIHtcbiAgICAgIGNvbnRleHQgPSBpdGVyYXRvcjtcbiAgICAgIGl0ZXJhdG9yID0gaXNTb3J0ZWQ7XG4gICAgICBpc1NvcnRlZCA9IGZhbHNlO1xuICAgIH1cbiAgICB2YXIgaW5pdGlhbCA9IGl0ZXJhdG9yID8gXy5tYXAoYXJyYXksIGl0ZXJhdG9yLCBjb250ZXh0KSA6IGFycmF5O1xuICAgIHZhciByZXN1bHRzID0gW107XG4gICAgdmFyIHNlZW4gPSBbXTtcbiAgICBlYWNoKGluaXRpYWwsIGZ1bmN0aW9uKHZhbHVlLCBpbmRleCkge1xuICAgICAgaWYgKGlzU29ydGVkID8gKCFpbmRleCB8fCBzZWVuW3NlZW4ubGVuZ3RoIC0gMV0gIT09IHZhbHVlKSA6ICFfLmNvbnRhaW5zKHNlZW4sIHZhbHVlKSkge1xuICAgICAgICBzZWVuLnB1c2godmFsdWUpO1xuICAgICAgICByZXN1bHRzLnB1c2goYXJyYXlbaW5kZXhdKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gcmVzdWx0cztcbiAgfTtcblxuICAvLyBQcm9kdWNlIGFuIGFycmF5IHRoYXQgY29udGFpbnMgdGhlIHVuaW9uOiBlYWNoIGRpc3RpbmN0IGVsZW1lbnQgZnJvbSBhbGwgb2ZcbiAgLy8gdGhlIHBhc3NlZC1pbiBhcnJheXMuXG4gIF8udW5pb24gPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gXy51bmlxKF8uZmxhdHRlbihhcmd1bWVudHMsIHRydWUpKTtcbiAgfTtcblxuICAvLyBQcm9kdWNlIGFuIGFycmF5IHRoYXQgY29udGFpbnMgZXZlcnkgaXRlbSBzaGFyZWQgYmV0d2VlbiBhbGwgdGhlXG4gIC8vIHBhc3NlZC1pbiBhcnJheXMuXG4gIF8uaW50ZXJzZWN0aW9uID0gZnVuY3Rpb24oYXJyYXkpIHtcbiAgICB2YXIgcmVzdCA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICByZXR1cm4gXy5maWx0ZXIoXy51bmlxKGFycmF5KSwgZnVuY3Rpb24oaXRlbSkge1xuICAgICAgcmV0dXJuIF8uZXZlcnkocmVzdCwgZnVuY3Rpb24ob3RoZXIpIHtcbiAgICAgICAgcmV0dXJuIF8uY29udGFpbnMob3RoZXIsIGl0ZW0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gVGFrZSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIG9uZSBhcnJheSBhbmQgYSBudW1iZXIgb2Ygb3RoZXIgYXJyYXlzLlxuICAvLyBPbmx5IHRoZSBlbGVtZW50cyBwcmVzZW50IGluIGp1c3QgdGhlIGZpcnN0IGFycmF5IHdpbGwgcmVtYWluLlxuICBfLmRpZmZlcmVuY2UgPSBmdW5jdGlvbihhcnJheSkge1xuICAgIHZhciByZXN0ID0gY29uY2F0LmFwcGx5KEFycmF5UHJvdG8sIHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSk7XG4gICAgcmV0dXJuIF8uZmlsdGVyKGFycmF5LCBmdW5jdGlvbih2YWx1ZSl7IHJldHVybiAhXy5jb250YWlucyhyZXN0LCB2YWx1ZSk7IH0pO1xuICB9O1xuXG4gIC8vIFppcCB0b2dldGhlciBtdWx0aXBsZSBsaXN0cyBpbnRvIGEgc2luZ2xlIGFycmF5IC0tIGVsZW1lbnRzIHRoYXQgc2hhcmVcbiAgLy8gYW4gaW5kZXggZ28gdG9nZXRoZXIuXG4gIF8uemlwID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGxlbmd0aCA9IF8ubWF4KF8ucGx1Y2soYXJndW1lbnRzLCAnbGVuZ3RoJykuY29uY2F0KDApKTtcbiAgICB2YXIgcmVzdWx0cyA9IG5ldyBBcnJheShsZW5ndGgpO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIHJlc3VsdHNbaV0gPSBfLnBsdWNrKGFyZ3VtZW50cywgJycgKyBpKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdHM7XG4gIH07XG5cbiAgLy8gQ29udmVydHMgbGlzdHMgaW50byBvYmplY3RzLiBQYXNzIGVpdGhlciBhIHNpbmdsZSBhcnJheSBvZiBgW2tleSwgdmFsdWVdYFxuICAvLyBwYWlycywgb3IgdHdvIHBhcmFsbGVsIGFycmF5cyBvZiB0aGUgc2FtZSBsZW5ndGggLS0gb25lIG9mIGtleXMsIGFuZCBvbmUgb2ZcbiAgLy8gdGhlIGNvcnJlc3BvbmRpbmcgdmFsdWVzLlxuICBfLm9iamVjdCA9IGZ1bmN0aW9uKGxpc3QsIHZhbHVlcykge1xuICAgIGlmIChsaXN0ID09IG51bGwpIHJldHVybiB7fTtcbiAgICB2YXIgcmVzdWx0ID0ge307XG4gICAgZm9yICh2YXIgaSA9IDAsIGxlbmd0aCA9IGxpc3QubGVuZ3RoOyBpIDwgbGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmICh2YWx1ZXMpIHtcbiAgICAgICAgcmVzdWx0W2xpc3RbaV1dID0gdmFsdWVzW2ldO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVzdWx0W2xpc3RbaV1bMF1dID0gbGlzdFtpXVsxXTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfTtcblxuICAvLyBJZiB0aGUgYnJvd3NlciBkb2Vzbid0IHN1cHBseSB1cyB3aXRoIGluZGV4T2YgKEknbSBsb29raW5nIGF0IHlvdSwgKipNU0lFKiopLFxuICAvLyB3ZSBuZWVkIHRoaXMgZnVuY3Rpb24uIFJldHVybiB0aGUgcG9zaXRpb24gb2YgdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2YgYW5cbiAgLy8gaXRlbSBpbiBhbiBhcnJheSwgb3IgLTEgaWYgdGhlIGl0ZW0gaXMgbm90IGluY2x1ZGVkIGluIHRoZSBhcnJheS5cbiAgLy8gRGVsZWdhdGVzIHRvICoqRUNNQVNjcmlwdCA1KioncyBuYXRpdmUgYGluZGV4T2ZgIGlmIGF2YWlsYWJsZS5cbiAgLy8gSWYgdGhlIGFycmF5IGlzIGxhcmdlIGFuZCBhbHJlYWR5IGluIHNvcnQgb3JkZXIsIHBhc3MgYHRydWVgXG4gIC8vIGZvciAqKmlzU29ydGVkKiogdG8gdXNlIGJpbmFyeSBzZWFyY2guXG4gIF8uaW5kZXhPZiA9IGZ1bmN0aW9uKGFycmF5LCBpdGVtLCBpc1NvcnRlZCkge1xuICAgIGlmIChhcnJheSA9PSBudWxsKSByZXR1cm4gLTE7XG4gICAgdmFyIGkgPSAwLCBsZW5ndGggPSBhcnJheS5sZW5ndGg7XG4gICAgaWYgKGlzU29ydGVkKSB7XG4gICAgICBpZiAodHlwZW9mIGlzU29ydGVkID09ICdudW1iZXInKSB7XG4gICAgICAgIGkgPSAoaXNTb3J0ZWQgPCAwID8gTWF0aC5tYXgoMCwgbGVuZ3RoICsgaXNTb3J0ZWQpIDogaXNTb3J0ZWQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaSA9IF8uc29ydGVkSW5kZXgoYXJyYXksIGl0ZW0pO1xuICAgICAgICByZXR1cm4gYXJyYXlbaV0gPT09IGl0ZW0gPyBpIDogLTE7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChuYXRpdmVJbmRleE9mICYmIGFycmF5LmluZGV4T2YgPT09IG5hdGl2ZUluZGV4T2YpIHJldHVybiBhcnJheS5pbmRleE9mKGl0ZW0sIGlzU29ydGVkKTtcbiAgICBmb3IgKDsgaSA8IGxlbmd0aDsgaSsrKSBpZiAoYXJyYXlbaV0gPT09IGl0ZW0pIHJldHVybiBpO1xuICAgIHJldHVybiAtMTtcbiAgfTtcblxuICAvLyBEZWxlZ2F0ZXMgdG8gKipFQ01BU2NyaXB0IDUqKidzIG5hdGl2ZSBgbGFzdEluZGV4T2ZgIGlmIGF2YWlsYWJsZS5cbiAgXy5sYXN0SW5kZXhPZiA9IGZ1bmN0aW9uKGFycmF5LCBpdGVtLCBmcm9tKSB7XG4gICAgaWYgKGFycmF5ID09IG51bGwpIHJldHVybiAtMTtcbiAgICB2YXIgaGFzSW5kZXggPSBmcm9tICE9IG51bGw7XG4gICAgaWYgKG5hdGl2ZUxhc3RJbmRleE9mICYmIGFycmF5Lmxhc3RJbmRleE9mID09PSBuYXRpdmVMYXN0SW5kZXhPZikge1xuICAgICAgcmV0dXJuIGhhc0luZGV4ID8gYXJyYXkubGFzdEluZGV4T2YoaXRlbSwgZnJvbSkgOiBhcnJheS5sYXN0SW5kZXhPZihpdGVtKTtcbiAgICB9XG4gICAgdmFyIGkgPSAoaGFzSW5kZXggPyBmcm9tIDogYXJyYXkubGVuZ3RoKTtcbiAgICB3aGlsZSAoaS0tKSBpZiAoYXJyYXlbaV0gPT09IGl0ZW0pIHJldHVybiBpO1xuICAgIHJldHVybiAtMTtcbiAgfTtcblxuICAvLyBHZW5lcmF0ZSBhbiBpbnRlZ2VyIEFycmF5IGNvbnRhaW5pbmcgYW4gYXJpdGhtZXRpYyBwcm9ncmVzc2lvbi4gQSBwb3J0IG9mXG4gIC8vIHRoZSBuYXRpdmUgUHl0aG9uIGByYW5nZSgpYCBmdW5jdGlvbi4gU2VlXG4gIC8vIFt0aGUgUHl0aG9uIGRvY3VtZW50YXRpb25dKGh0dHA6Ly9kb2NzLnB5dGhvbi5vcmcvbGlicmFyeS9mdW5jdGlvbnMuaHRtbCNyYW5nZSkuXG4gIF8ucmFuZ2UgPSBmdW5jdGlvbihzdGFydCwgc3RvcCwgc3RlcCkge1xuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoIDw9IDEpIHtcbiAgICAgIHN0b3AgPSBzdGFydCB8fCAwO1xuICAgICAgc3RhcnQgPSAwO1xuICAgIH1cbiAgICBzdGVwID0gYXJndW1lbnRzWzJdIHx8IDE7XG5cbiAgICB2YXIgbGVuZ3RoID0gTWF0aC5tYXgoTWF0aC5jZWlsKChzdG9wIC0gc3RhcnQpIC8gc3RlcCksIDApO1xuICAgIHZhciBpZHggPSAwO1xuICAgIHZhciByYW5nZSA9IG5ldyBBcnJheShsZW5ndGgpO1xuXG4gICAgd2hpbGUoaWR4IDwgbGVuZ3RoKSB7XG4gICAgICByYW5nZVtpZHgrK10gPSBzdGFydDtcbiAgICAgIHN0YXJ0ICs9IHN0ZXA7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJhbmdlO1xuICB9O1xuXG4gIC8vIEZ1bmN0aW9uIChhaGVtKSBGdW5jdGlvbnNcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgLy8gUmV1c2FibGUgY29uc3RydWN0b3IgZnVuY3Rpb24gZm9yIHByb3RvdHlwZSBzZXR0aW5nLlxuICB2YXIgY3RvciA9IGZ1bmN0aW9uKCl7fTtcblxuICAvLyBDcmVhdGUgYSBmdW5jdGlvbiBib3VuZCB0byBhIGdpdmVuIG9iamVjdCAoYXNzaWduaW5nIGB0aGlzYCwgYW5kIGFyZ3VtZW50cyxcbiAgLy8gb3B0aW9uYWxseSkuIERlbGVnYXRlcyB0byAqKkVDTUFTY3JpcHQgNSoqJ3MgbmF0aXZlIGBGdW5jdGlvbi5iaW5kYCBpZlxuICAvLyBhdmFpbGFibGUuXG4gIF8uYmluZCA9IGZ1bmN0aW9uKGZ1bmMsIGNvbnRleHQpIHtcbiAgICB2YXIgYXJncywgYm91bmQ7XG4gICAgaWYgKG5hdGl2ZUJpbmQgJiYgZnVuYy5iaW5kID09PSBuYXRpdmVCaW5kKSByZXR1cm4gbmF0aXZlQmluZC5hcHBseShmdW5jLCBzbGljZS5jYWxsKGFyZ3VtZW50cywgMSkpO1xuICAgIGlmICghXy5pc0Z1bmN0aW9uKGZ1bmMpKSB0aHJvdyBuZXcgVHlwZUVycm9yO1xuICAgIGFyZ3MgPSBzbGljZS5jYWxsKGFyZ3VtZW50cywgMik7XG4gICAgcmV0dXJuIGJvdW5kID0gZnVuY3Rpb24oKSB7XG4gICAgICBpZiAoISh0aGlzIGluc3RhbmNlb2YgYm91bmQpKSByZXR1cm4gZnVuYy5hcHBseShjb250ZXh0LCBhcmdzLmNvbmNhdChzbGljZS5jYWxsKGFyZ3VtZW50cykpKTtcbiAgICAgIGN0b3IucHJvdG90eXBlID0gZnVuYy5wcm90b3R5cGU7XG4gICAgICB2YXIgc2VsZiA9IG5ldyBjdG9yO1xuICAgICAgY3Rvci5wcm90b3R5cGUgPSBudWxsO1xuICAgICAgdmFyIHJlc3VsdCA9IGZ1bmMuYXBwbHkoc2VsZiwgYXJncy5jb25jYXQoc2xpY2UuY2FsbChhcmd1bWVudHMpKSk7XG4gICAgICBpZiAoT2JqZWN0KHJlc3VsdCkgPT09IHJlc3VsdCkgcmV0dXJuIHJlc3VsdDtcbiAgICAgIHJldHVybiBzZWxmO1xuICAgIH07XG4gIH07XG5cbiAgLy8gUGFydGlhbGx5IGFwcGx5IGEgZnVuY3Rpb24gYnkgY3JlYXRpbmcgYSB2ZXJzaW9uIHRoYXQgaGFzIGhhZCBzb21lIG9mIGl0c1xuICAvLyBhcmd1bWVudHMgcHJlLWZpbGxlZCwgd2l0aG91dCBjaGFuZ2luZyBpdHMgZHluYW1pYyBgdGhpc2AgY29udGV4dC4gXyBhY3RzXG4gIC8vIGFzIGEgcGxhY2Vob2xkZXIsIGFsbG93aW5nIGFueSBjb21iaW5hdGlvbiBvZiBhcmd1bWVudHMgdG8gYmUgcHJlLWZpbGxlZC5cbiAgXy5wYXJ0aWFsID0gZnVuY3Rpb24oZnVuYykge1xuICAgIHZhciBib3VuZEFyZ3MgPSBzbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIHBvc2l0aW9uID0gMDtcbiAgICAgIHZhciBhcmdzID0gYm91bmRBcmdzLnNsaWNlKCk7XG4gICAgICBmb3IgKHZhciBpID0gMCwgbGVuZ3RoID0gYXJncy5sZW5ndGg7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAoYXJnc1tpXSA9PT0gXykgYXJnc1tpXSA9IGFyZ3VtZW50c1twb3NpdGlvbisrXTtcbiAgICAgIH1cbiAgICAgIHdoaWxlIChwb3NpdGlvbiA8IGFyZ3VtZW50cy5sZW5ndGgpIGFyZ3MucHVzaChhcmd1bWVudHNbcG9zaXRpb24rK10pO1xuICAgICAgcmV0dXJuIGZ1bmMuYXBwbHkodGhpcywgYXJncyk7XG4gICAgfTtcbiAgfTtcblxuICAvLyBCaW5kIGEgbnVtYmVyIG9mIGFuIG9iamVjdCdzIG1ldGhvZHMgdG8gdGhhdCBvYmplY3QuIFJlbWFpbmluZyBhcmd1bWVudHNcbiAgLy8gYXJlIHRoZSBtZXRob2QgbmFtZXMgdG8gYmUgYm91bmQuIFVzZWZ1bCBmb3IgZW5zdXJpbmcgdGhhdCBhbGwgY2FsbGJhY2tzXG4gIC8vIGRlZmluZWQgb24gYW4gb2JqZWN0IGJlbG9uZyB0byBpdC5cbiAgXy5iaW5kQWxsID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgdmFyIGZ1bmNzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIGlmIChmdW5jcy5sZW5ndGggPT09IDApIHRocm93IG5ldyBFcnJvcignYmluZEFsbCBtdXN0IGJlIHBhc3NlZCBmdW5jdGlvbiBuYW1lcycpO1xuICAgIGVhY2goZnVuY3MsIGZ1bmN0aW9uKGYpIHsgb2JqW2ZdID0gXy5iaW5kKG9ialtmXSwgb2JqKTsgfSk7XG4gICAgcmV0dXJuIG9iajtcbiAgfTtcblxuICAvLyBNZW1vaXplIGFuIGV4cGVuc2l2ZSBmdW5jdGlvbiBieSBzdG9yaW5nIGl0cyByZXN1bHRzLlxuICBfLm1lbW9pemUgPSBmdW5jdGlvbihmdW5jLCBoYXNoZXIpIHtcbiAgICB2YXIgbWVtbyA9IHt9O1xuICAgIGhhc2hlciB8fCAoaGFzaGVyID0gXy5pZGVudGl0eSk7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIGtleSA9IGhhc2hlci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgcmV0dXJuIF8uaGFzKG1lbW8sIGtleSkgPyBtZW1vW2tleV0gOiAobWVtb1trZXldID0gZnVuYy5hcHBseSh0aGlzLCBhcmd1bWVudHMpKTtcbiAgICB9O1xuICB9O1xuXG4gIC8vIERlbGF5cyBhIGZ1bmN0aW9uIGZvciB0aGUgZ2l2ZW4gbnVtYmVyIG9mIG1pbGxpc2Vjb25kcywgYW5kIHRoZW4gY2FsbHNcbiAgLy8gaXQgd2l0aCB0aGUgYXJndW1lbnRzIHN1cHBsaWVkLlxuICBfLmRlbGF5ID0gZnVuY3Rpb24oZnVuYywgd2FpdCkge1xuICAgIHZhciBhcmdzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpO1xuICAgIHJldHVybiBzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7IHJldHVybiBmdW5jLmFwcGx5KG51bGwsIGFyZ3MpOyB9LCB3YWl0KTtcbiAgfTtcblxuICAvLyBEZWZlcnMgYSBmdW5jdGlvbiwgc2NoZWR1bGluZyBpdCB0byBydW4gYWZ0ZXIgdGhlIGN1cnJlbnQgY2FsbCBzdGFjayBoYXNcbiAgLy8gY2xlYXJlZC5cbiAgXy5kZWZlciA9IGZ1bmN0aW9uKGZ1bmMpIHtcbiAgICByZXR1cm4gXy5kZWxheS5hcHBseShfLCBbZnVuYywgMV0uY29uY2F0KHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSkpO1xuICB9O1xuXG4gIC8vIFJldHVybnMgYSBmdW5jdGlvbiwgdGhhdCwgd2hlbiBpbnZva2VkLCB3aWxsIG9ubHkgYmUgdHJpZ2dlcmVkIGF0IG1vc3Qgb25jZVxuICAvLyBkdXJpbmcgYSBnaXZlbiB3aW5kb3cgb2YgdGltZS4gTm9ybWFsbHksIHRoZSB0aHJvdHRsZWQgZnVuY3Rpb24gd2lsbCBydW5cbiAgLy8gYXMgbXVjaCBhcyBpdCBjYW4sIHdpdGhvdXQgZXZlciBnb2luZyBtb3JlIHRoYW4gb25jZSBwZXIgYHdhaXRgIGR1cmF0aW9uO1xuICAvLyBidXQgaWYgeW91J2QgbGlrZSB0byBkaXNhYmxlIHRoZSBleGVjdXRpb24gb24gdGhlIGxlYWRpbmcgZWRnZSwgcGFzc1xuICAvLyBge2xlYWRpbmc6IGZhbHNlfWAuIFRvIGRpc2FibGUgZXhlY3V0aW9uIG9uIHRoZSB0cmFpbGluZyBlZGdlLCBkaXR0by5cbiAgXy50aHJvdHRsZSA9IGZ1bmN0aW9uKGZ1bmMsIHdhaXQsIG9wdGlvbnMpIHtcbiAgICB2YXIgY29udGV4dCwgYXJncywgcmVzdWx0O1xuICAgIHZhciB0aW1lb3V0ID0gbnVsbDtcbiAgICB2YXIgcHJldmlvdXMgPSAwO1xuICAgIG9wdGlvbnMgfHwgKG9wdGlvbnMgPSB7fSk7XG4gICAgdmFyIGxhdGVyID0gZnVuY3Rpb24oKSB7XG4gICAgICBwcmV2aW91cyA9IG9wdGlvbnMubGVhZGluZyA9PT0gZmFsc2UgPyAwIDogXy5ub3coKTtcbiAgICAgIHRpbWVvdXQgPSBudWxsO1xuICAgICAgcmVzdWx0ID0gZnVuYy5hcHBseShjb250ZXh0LCBhcmdzKTtcbiAgICAgIGNvbnRleHQgPSBhcmdzID0gbnVsbDtcbiAgICB9O1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgIHZhciBub3cgPSBfLm5vdygpO1xuICAgICAgaWYgKCFwcmV2aW91cyAmJiBvcHRpb25zLmxlYWRpbmcgPT09IGZhbHNlKSBwcmV2aW91cyA9IG5vdztcbiAgICAgIHZhciByZW1haW5pbmcgPSB3YWl0IC0gKG5vdyAtIHByZXZpb3VzKTtcbiAgICAgIGNvbnRleHQgPSB0aGlzO1xuICAgICAgYXJncyA9IGFyZ3VtZW50cztcbiAgICAgIGlmIChyZW1haW5pbmcgPD0gMCkge1xuICAgICAgICBjbGVhclRpbWVvdXQodGltZW91dCk7XG4gICAgICAgIHRpbWVvdXQgPSBudWxsO1xuICAgICAgICBwcmV2aW91cyA9IG5vdztcbiAgICAgICAgcmVzdWx0ID0gZnVuYy5hcHBseShjb250ZXh0LCBhcmdzKTtcbiAgICAgICAgY29udGV4dCA9IGFyZ3MgPSBudWxsO1xuICAgICAgfSBlbHNlIGlmICghdGltZW91dCAmJiBvcHRpb25zLnRyYWlsaW5nICE9PSBmYWxzZSkge1xuICAgICAgICB0aW1lb3V0ID0gc2V0VGltZW91dChsYXRlciwgcmVtYWluaW5nKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfTtcbiAgfTtcblxuICAvLyBSZXR1cm5zIGEgZnVuY3Rpb24sIHRoYXQsIGFzIGxvbmcgYXMgaXQgY29udGludWVzIHRvIGJlIGludm9rZWQsIHdpbGwgbm90XG4gIC8vIGJlIHRyaWdnZXJlZC4gVGhlIGZ1bmN0aW9uIHdpbGwgYmUgY2FsbGVkIGFmdGVyIGl0IHN0b3BzIGJlaW5nIGNhbGxlZCBmb3JcbiAgLy8gTiBtaWxsaXNlY29uZHMuIElmIGBpbW1lZGlhdGVgIGlzIHBhc3NlZCwgdHJpZ2dlciB0aGUgZnVuY3Rpb24gb24gdGhlXG4gIC8vIGxlYWRpbmcgZWRnZSwgaW5zdGVhZCBvZiB0aGUgdHJhaWxpbmcuXG4gIF8uZGVib3VuY2UgPSBmdW5jdGlvbihmdW5jLCB3YWl0LCBpbW1lZGlhdGUpIHtcbiAgICB2YXIgdGltZW91dCwgYXJncywgY29udGV4dCwgdGltZXN0YW1wLCByZXN1bHQ7XG5cbiAgICB2YXIgbGF0ZXIgPSBmdW5jdGlvbigpIHtcbiAgICAgIHZhciBsYXN0ID0gXy5ub3coKSAtIHRpbWVzdGFtcDtcbiAgICAgIGlmIChsYXN0IDwgd2FpdCkge1xuICAgICAgICB0aW1lb3V0ID0gc2V0VGltZW91dChsYXRlciwgd2FpdCAtIGxhc3QpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGltZW91dCA9IG51bGw7XG4gICAgICAgIGlmICghaW1tZWRpYXRlKSB7XG4gICAgICAgICAgcmVzdWx0ID0gZnVuYy5hcHBseShjb250ZXh0LCBhcmdzKTtcbiAgICAgICAgICBjb250ZXh0ID0gYXJncyA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgY29udGV4dCA9IHRoaXM7XG4gICAgICBhcmdzID0gYXJndW1lbnRzO1xuICAgICAgdGltZXN0YW1wID0gXy5ub3coKTtcbiAgICAgIHZhciBjYWxsTm93ID0gaW1tZWRpYXRlICYmICF0aW1lb3V0O1xuICAgICAgaWYgKCF0aW1lb3V0KSB7XG4gICAgICAgIHRpbWVvdXQgPSBzZXRUaW1lb3V0KGxhdGVyLCB3YWl0KTtcbiAgICAgIH1cbiAgICAgIGlmIChjYWxsTm93KSB7XG4gICAgICAgIHJlc3VsdCA9IGZ1bmMuYXBwbHkoY29udGV4dCwgYXJncyk7XG4gICAgICAgIGNvbnRleHQgPSBhcmdzID0gbnVsbDtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xuICB9O1xuXG4gIC8vIFJldHVybnMgYSBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgZXhlY3V0ZWQgYXQgbW9zdCBvbmUgdGltZSwgbm8gbWF0dGVyIGhvd1xuICAvLyBvZnRlbiB5b3UgY2FsbCBpdC4gVXNlZnVsIGZvciBsYXp5IGluaXRpYWxpemF0aW9uLlxuICBfLm9uY2UgPSBmdW5jdGlvbihmdW5jKSB7XG4gICAgdmFyIHJhbiA9IGZhbHNlLCBtZW1vO1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgIGlmIChyYW4pIHJldHVybiBtZW1vO1xuICAgICAgcmFuID0gdHJ1ZTtcbiAgICAgIG1lbW8gPSBmdW5jLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICBmdW5jID0gbnVsbDtcbiAgICAgIHJldHVybiBtZW1vO1xuICAgIH07XG4gIH07XG5cbiAgLy8gUmV0dXJucyB0aGUgZmlyc3QgZnVuY3Rpb24gcGFzc2VkIGFzIGFuIGFyZ3VtZW50IHRvIHRoZSBzZWNvbmQsXG4gIC8vIGFsbG93aW5nIHlvdSB0byBhZGp1c3QgYXJndW1lbnRzLCBydW4gY29kZSBiZWZvcmUgYW5kIGFmdGVyLCBhbmRcbiAgLy8gY29uZGl0aW9uYWxseSBleGVjdXRlIHRoZSBvcmlnaW5hbCBmdW5jdGlvbi5cbiAgXy53cmFwID0gZnVuY3Rpb24oZnVuYywgd3JhcHBlcikge1xuICAgIHJldHVybiBfLnBhcnRpYWwod3JhcHBlciwgZnVuYyk7XG4gIH07XG5cbiAgLy8gUmV0dXJucyBhIGZ1bmN0aW9uIHRoYXQgaXMgdGhlIGNvbXBvc2l0aW9uIG9mIGEgbGlzdCBvZiBmdW5jdGlvbnMsIGVhY2hcbiAgLy8gY29uc3VtaW5nIHRoZSByZXR1cm4gdmFsdWUgb2YgdGhlIGZ1bmN0aW9uIHRoYXQgZm9sbG93cy5cbiAgXy5jb21wb3NlID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGZ1bmNzID0gYXJndW1lbnRzO1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgIHZhciBhcmdzID0gYXJndW1lbnRzO1xuICAgICAgZm9yICh2YXIgaSA9IGZ1bmNzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICAgIGFyZ3MgPSBbZnVuY3NbaV0uYXBwbHkodGhpcywgYXJncyldO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGFyZ3NbMF07XG4gICAgfTtcbiAgfTtcblxuICAvLyBSZXR1cm5zIGEgZnVuY3Rpb24gdGhhdCB3aWxsIG9ubHkgYmUgZXhlY3V0ZWQgYWZ0ZXIgYmVpbmcgY2FsbGVkIE4gdGltZXMuXG4gIF8uYWZ0ZXIgPSBmdW5jdGlvbih0aW1lcywgZnVuYykge1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgIGlmICgtLXRpbWVzIDwgMSkge1xuICAgICAgICByZXR1cm4gZnVuYy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgfVxuICAgIH07XG4gIH07XG5cbiAgLy8gT2JqZWN0IEZ1bmN0aW9uc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tXG5cbiAgLy8gUmV0cmlldmUgdGhlIG5hbWVzIG9mIGFuIG9iamVjdCdzIHByb3BlcnRpZXMuXG4gIC8vIERlbGVnYXRlcyB0byAqKkVDTUFTY3JpcHQgNSoqJ3MgbmF0aXZlIGBPYmplY3Qua2V5c2BcbiAgXy5rZXlzID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgaWYgKCFfLmlzT2JqZWN0KG9iaikpIHJldHVybiBbXTtcbiAgICBpZiAobmF0aXZlS2V5cykgcmV0dXJuIG5hdGl2ZUtleXMob2JqKTtcbiAgICB2YXIga2V5cyA9IFtdO1xuICAgIGZvciAodmFyIGtleSBpbiBvYmopIGlmIChfLmhhcyhvYmosIGtleSkpIGtleXMucHVzaChrZXkpO1xuICAgIHJldHVybiBrZXlzO1xuICB9O1xuXG4gIC8vIFJldHJpZXZlIHRoZSB2YWx1ZXMgb2YgYW4gb2JqZWN0J3MgcHJvcGVydGllcy5cbiAgXy52YWx1ZXMgPSBmdW5jdGlvbihvYmopIHtcbiAgICB2YXIga2V5cyA9IF8ua2V5cyhvYmopO1xuICAgIHZhciBsZW5ndGggPSBrZXlzLmxlbmd0aDtcbiAgICB2YXIgdmFsdWVzID0gbmV3IEFycmF5KGxlbmd0aCk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgdmFsdWVzW2ldID0gb2JqW2tleXNbaV1dO1xuICAgIH1cbiAgICByZXR1cm4gdmFsdWVzO1xuICB9O1xuXG4gIC8vIENvbnZlcnQgYW4gb2JqZWN0IGludG8gYSBsaXN0IG9mIGBba2V5LCB2YWx1ZV1gIHBhaXJzLlxuICBfLnBhaXJzID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgdmFyIGtleXMgPSBfLmtleXMob2JqKTtcbiAgICB2YXIgbGVuZ3RoID0ga2V5cy5sZW5ndGg7XG4gICAgdmFyIHBhaXJzID0gbmV3IEFycmF5KGxlbmd0aCk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgcGFpcnNbaV0gPSBba2V5c1tpXSwgb2JqW2tleXNbaV1dXTtcbiAgICB9XG4gICAgcmV0dXJuIHBhaXJzO1xuICB9O1xuXG4gIC8vIEludmVydCB0aGUga2V5cyBhbmQgdmFsdWVzIG9mIGFuIG9iamVjdC4gVGhlIHZhbHVlcyBtdXN0IGJlIHNlcmlhbGl6YWJsZS5cbiAgXy5pbnZlcnQgPSBmdW5jdGlvbihvYmopIHtcbiAgICB2YXIgcmVzdWx0ID0ge307XG4gICAgdmFyIGtleXMgPSBfLmtleXMob2JqKTtcbiAgICBmb3IgKHZhciBpID0gMCwgbGVuZ3RoID0ga2V5cy5sZW5ndGg7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgcmVzdWx0W29ialtrZXlzW2ldXV0gPSBrZXlzW2ldO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9O1xuXG4gIC8vIFJldHVybiBhIHNvcnRlZCBsaXN0IG9mIHRoZSBmdW5jdGlvbiBuYW1lcyBhdmFpbGFibGUgb24gdGhlIG9iamVjdC5cbiAgLy8gQWxpYXNlZCBhcyBgbWV0aG9kc2BcbiAgXy5mdW5jdGlvbnMgPSBfLm1ldGhvZHMgPSBmdW5jdGlvbihvYmopIHtcbiAgICB2YXIgbmFtZXMgPSBbXTtcbiAgICBmb3IgKHZhciBrZXkgaW4gb2JqKSB7XG4gICAgICBpZiAoXy5pc0Z1bmN0aW9uKG9ialtrZXldKSkgbmFtZXMucHVzaChrZXkpO1xuICAgIH1cbiAgICByZXR1cm4gbmFtZXMuc29ydCgpO1xuICB9O1xuXG4gIC8vIEV4dGVuZCBhIGdpdmVuIG9iamVjdCB3aXRoIGFsbCB0aGUgcHJvcGVydGllcyBpbiBwYXNzZWQtaW4gb2JqZWN0KHMpLlxuICBfLmV4dGVuZCA9IGZ1bmN0aW9uKG9iaikge1xuICAgIGVhY2goc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpLCBmdW5jdGlvbihzb3VyY2UpIHtcbiAgICAgIGlmIChzb3VyY2UpIHtcbiAgICAgICAgZm9yICh2YXIgcHJvcCBpbiBzb3VyY2UpIHtcbiAgICAgICAgICBvYmpbcHJvcF0gPSBzb3VyY2VbcHJvcF07XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gb2JqO1xuICB9O1xuXG4gIC8vIFJldHVybiBhIGNvcHkgb2YgdGhlIG9iamVjdCBvbmx5IGNvbnRhaW5pbmcgdGhlIHdoaXRlbGlzdGVkIHByb3BlcnRpZXMuXG4gIF8ucGljayA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHZhciBjb3B5ID0ge307XG4gICAgdmFyIGtleXMgPSBjb25jYXQuYXBwbHkoQXJyYXlQcm90bywgc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpKTtcbiAgICBlYWNoKGtleXMsIGZ1bmN0aW9uKGtleSkge1xuICAgICAgaWYgKGtleSBpbiBvYmopIGNvcHlba2V5XSA9IG9ialtrZXldO1xuICAgIH0pO1xuICAgIHJldHVybiBjb3B5O1xuICB9O1xuXG4gICAvLyBSZXR1cm4gYSBjb3B5IG9mIHRoZSBvYmplY3Qgd2l0aG91dCB0aGUgYmxhY2tsaXN0ZWQgcHJvcGVydGllcy5cbiAgXy5vbWl0ID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgdmFyIGNvcHkgPSB7fTtcbiAgICB2YXIga2V5cyA9IGNvbmNhdC5hcHBseShBcnJheVByb3RvLCBzbGljZS5jYWxsKGFyZ3VtZW50cywgMSkpO1xuICAgIGZvciAodmFyIGtleSBpbiBvYmopIHtcbiAgICAgIGlmICghXy5jb250YWlucyhrZXlzLCBrZXkpKSBjb3B5W2tleV0gPSBvYmpba2V5XTtcbiAgICB9XG4gICAgcmV0dXJuIGNvcHk7XG4gIH07XG5cbiAgLy8gRmlsbCBpbiBhIGdpdmVuIG9iamVjdCB3aXRoIGRlZmF1bHQgcHJvcGVydGllcy5cbiAgXy5kZWZhdWx0cyA9IGZ1bmN0aW9uKG9iaikge1xuICAgIGVhY2goc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpLCBmdW5jdGlvbihzb3VyY2UpIHtcbiAgICAgIGlmIChzb3VyY2UpIHtcbiAgICAgICAgZm9yICh2YXIgcHJvcCBpbiBzb3VyY2UpIHtcbiAgICAgICAgICBpZiAob2JqW3Byb3BdID09PSB2b2lkIDApIG9ialtwcm9wXSA9IHNvdXJjZVtwcm9wXTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBvYmo7XG4gIH07XG5cbiAgLy8gQ3JlYXRlIGEgKHNoYWxsb3ctY2xvbmVkKSBkdXBsaWNhdGUgb2YgYW4gb2JqZWN0LlxuICBfLmNsb25lID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgaWYgKCFfLmlzT2JqZWN0KG9iaikpIHJldHVybiBvYmo7XG4gICAgcmV0dXJuIF8uaXNBcnJheShvYmopID8gb2JqLnNsaWNlKCkgOiBfLmV4dGVuZCh7fSwgb2JqKTtcbiAgfTtcblxuICAvLyBJbnZva2VzIGludGVyY2VwdG9yIHdpdGggdGhlIG9iaiwgYW5kIHRoZW4gcmV0dXJucyBvYmouXG4gIC8vIFRoZSBwcmltYXJ5IHB1cnBvc2Ugb2YgdGhpcyBtZXRob2QgaXMgdG8gXCJ0YXAgaW50b1wiIGEgbWV0aG9kIGNoYWluLCBpblxuICAvLyBvcmRlciB0byBwZXJmb3JtIG9wZXJhdGlvbnMgb24gaW50ZXJtZWRpYXRlIHJlc3VsdHMgd2l0aGluIHRoZSBjaGFpbi5cbiAgXy50YXAgPSBmdW5jdGlvbihvYmosIGludGVyY2VwdG9yKSB7XG4gICAgaW50ZXJjZXB0b3Iob2JqKTtcbiAgICByZXR1cm4gb2JqO1xuICB9O1xuXG4gIC8vIEludGVybmFsIHJlY3Vyc2l2ZSBjb21wYXJpc29uIGZ1bmN0aW9uIGZvciBgaXNFcXVhbGAuXG4gIHZhciBlcSA9IGZ1bmN0aW9uKGEsIGIsIGFTdGFjaywgYlN0YWNrKSB7XG4gICAgLy8gSWRlbnRpY2FsIG9iamVjdHMgYXJlIGVxdWFsLiBgMCA9PT0gLTBgLCBidXQgdGhleSBhcmVuJ3QgaWRlbnRpY2FsLlxuICAgIC8vIFNlZSB0aGUgW0hhcm1vbnkgYGVnYWxgIHByb3Bvc2FsXShodHRwOi8vd2lraS5lY21hc2NyaXB0Lm9yZy9kb2t1LnBocD9pZD1oYXJtb255OmVnYWwpLlxuICAgIGlmIChhID09PSBiKSByZXR1cm4gYSAhPT0gMCB8fCAxIC8gYSA9PSAxIC8gYjtcbiAgICAvLyBBIHN0cmljdCBjb21wYXJpc29uIGlzIG5lY2Vzc2FyeSBiZWNhdXNlIGBudWxsID09IHVuZGVmaW5lZGAuXG4gICAgaWYgKGEgPT0gbnVsbCB8fCBiID09IG51bGwpIHJldHVybiBhID09PSBiO1xuICAgIC8vIFVud3JhcCBhbnkgd3JhcHBlZCBvYmplY3RzLlxuICAgIGlmIChhIGluc3RhbmNlb2YgXykgYSA9IGEuX3dyYXBwZWQ7XG4gICAgaWYgKGIgaW5zdGFuY2VvZiBfKSBiID0gYi5fd3JhcHBlZDtcbiAgICAvLyBDb21wYXJlIGBbW0NsYXNzXV1gIG5hbWVzLlxuICAgIHZhciBjbGFzc05hbWUgPSB0b1N0cmluZy5jYWxsKGEpO1xuICAgIGlmIChjbGFzc05hbWUgIT0gdG9TdHJpbmcuY2FsbChiKSkgcmV0dXJuIGZhbHNlO1xuICAgIHN3aXRjaCAoY2xhc3NOYW1lKSB7XG4gICAgICAvLyBTdHJpbmdzLCBudW1iZXJzLCBkYXRlcywgYW5kIGJvb2xlYW5zIGFyZSBjb21wYXJlZCBieSB2YWx1ZS5cbiAgICAgIGNhc2UgJ1tvYmplY3QgU3RyaW5nXSc6XG4gICAgICAgIC8vIFByaW1pdGl2ZXMgYW5kIHRoZWlyIGNvcnJlc3BvbmRpbmcgb2JqZWN0IHdyYXBwZXJzIGFyZSBlcXVpdmFsZW50OyB0aHVzLCBgXCI1XCJgIGlzXG4gICAgICAgIC8vIGVxdWl2YWxlbnQgdG8gYG5ldyBTdHJpbmcoXCI1XCIpYC5cbiAgICAgICAgcmV0dXJuIGEgPT0gU3RyaW5nKGIpO1xuICAgICAgY2FzZSAnW29iamVjdCBOdW1iZXJdJzpcbiAgICAgICAgLy8gYE5hTmBzIGFyZSBlcXVpdmFsZW50LCBidXQgbm9uLXJlZmxleGl2ZS4gQW4gYGVnYWxgIGNvbXBhcmlzb24gaXMgcGVyZm9ybWVkIGZvclxuICAgICAgICAvLyBvdGhlciBudW1lcmljIHZhbHVlcy5cbiAgICAgICAgcmV0dXJuIGEgIT0gK2EgPyBiICE9ICtiIDogKGEgPT0gMCA/IDEgLyBhID09IDEgLyBiIDogYSA9PSArYik7XG4gICAgICBjYXNlICdbb2JqZWN0IERhdGVdJzpcbiAgICAgIGNhc2UgJ1tvYmplY3QgQm9vbGVhbl0nOlxuICAgICAgICAvLyBDb2VyY2UgZGF0ZXMgYW5kIGJvb2xlYW5zIHRvIG51bWVyaWMgcHJpbWl0aXZlIHZhbHVlcy4gRGF0ZXMgYXJlIGNvbXBhcmVkIGJ5IHRoZWlyXG4gICAgICAgIC8vIG1pbGxpc2Vjb25kIHJlcHJlc2VudGF0aW9ucy4gTm90ZSB0aGF0IGludmFsaWQgZGF0ZXMgd2l0aCBtaWxsaXNlY29uZCByZXByZXNlbnRhdGlvbnNcbiAgICAgICAgLy8gb2YgYE5hTmAgYXJlIG5vdCBlcXVpdmFsZW50LlxuICAgICAgICByZXR1cm4gK2EgPT0gK2I7XG4gICAgICAvLyBSZWdFeHBzIGFyZSBjb21wYXJlZCBieSB0aGVpciBzb3VyY2UgcGF0dGVybnMgYW5kIGZsYWdzLlxuICAgICAgY2FzZSAnW29iamVjdCBSZWdFeHBdJzpcbiAgICAgICAgcmV0dXJuIGEuc291cmNlID09IGIuc291cmNlICYmXG4gICAgICAgICAgICAgICBhLmdsb2JhbCA9PSBiLmdsb2JhbCAmJlxuICAgICAgICAgICAgICAgYS5tdWx0aWxpbmUgPT0gYi5tdWx0aWxpbmUgJiZcbiAgICAgICAgICAgICAgIGEuaWdub3JlQ2FzZSA9PSBiLmlnbm9yZUNhc2U7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgYSAhPSAnb2JqZWN0JyB8fCB0eXBlb2YgYiAhPSAnb2JqZWN0JykgcmV0dXJuIGZhbHNlO1xuICAgIC8vIEFzc3VtZSBlcXVhbGl0eSBmb3IgY3ljbGljIHN0cnVjdHVyZXMuIFRoZSBhbGdvcml0aG0gZm9yIGRldGVjdGluZyBjeWNsaWNcbiAgICAvLyBzdHJ1Y3R1cmVzIGlzIGFkYXB0ZWQgZnJvbSBFUyA1LjEgc2VjdGlvbiAxNS4xMi4zLCBhYnN0cmFjdCBvcGVyYXRpb24gYEpPYC5cbiAgICB2YXIgbGVuZ3RoID0gYVN0YWNrLmxlbmd0aDtcbiAgICB3aGlsZSAobGVuZ3RoLS0pIHtcbiAgICAgIC8vIExpbmVhciBzZWFyY2guIFBlcmZvcm1hbmNlIGlzIGludmVyc2VseSBwcm9wb3J0aW9uYWwgdG8gdGhlIG51bWJlciBvZlxuICAgICAgLy8gdW5pcXVlIG5lc3RlZCBzdHJ1Y3R1cmVzLlxuICAgICAgaWYgKGFTdGFja1tsZW5ndGhdID09IGEpIHJldHVybiBiU3RhY2tbbGVuZ3RoXSA9PSBiO1xuICAgIH1cbiAgICAvLyBPYmplY3RzIHdpdGggZGlmZmVyZW50IGNvbnN0cnVjdG9ycyBhcmUgbm90IGVxdWl2YWxlbnQsIGJ1dCBgT2JqZWN0YHNcbiAgICAvLyBmcm9tIGRpZmZlcmVudCBmcmFtZXMgYXJlLlxuICAgIHZhciBhQ3RvciA9IGEuY29uc3RydWN0b3IsIGJDdG9yID0gYi5jb25zdHJ1Y3RvcjtcbiAgICBpZiAoYUN0b3IgIT09IGJDdG9yICYmICEoXy5pc0Z1bmN0aW9uKGFDdG9yKSAmJiAoYUN0b3IgaW5zdGFuY2VvZiBhQ3RvcikgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXy5pc0Z1bmN0aW9uKGJDdG9yKSAmJiAoYkN0b3IgaW5zdGFuY2VvZiBiQ3RvcikpXG4gICAgICAgICAgICAgICAgICAgICAgICAmJiAoJ2NvbnN0cnVjdG9yJyBpbiBhICYmICdjb25zdHJ1Y3RvcicgaW4gYikpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgLy8gQWRkIHRoZSBmaXJzdCBvYmplY3QgdG8gdGhlIHN0YWNrIG9mIHRyYXZlcnNlZCBvYmplY3RzLlxuICAgIGFTdGFjay5wdXNoKGEpO1xuICAgIGJTdGFjay5wdXNoKGIpO1xuICAgIHZhciBzaXplID0gMCwgcmVzdWx0ID0gdHJ1ZTtcbiAgICAvLyBSZWN1cnNpdmVseSBjb21wYXJlIG9iamVjdHMgYW5kIGFycmF5cy5cbiAgICBpZiAoY2xhc3NOYW1lID09ICdbb2JqZWN0IEFycmF5XScpIHtcbiAgICAgIC8vIENvbXBhcmUgYXJyYXkgbGVuZ3RocyB0byBkZXRlcm1pbmUgaWYgYSBkZWVwIGNvbXBhcmlzb24gaXMgbmVjZXNzYXJ5LlxuICAgICAgc2l6ZSA9IGEubGVuZ3RoO1xuICAgICAgcmVzdWx0ID0gc2l6ZSA9PSBiLmxlbmd0aDtcbiAgICAgIGlmIChyZXN1bHQpIHtcbiAgICAgICAgLy8gRGVlcCBjb21wYXJlIHRoZSBjb250ZW50cywgaWdub3Jpbmcgbm9uLW51bWVyaWMgcHJvcGVydGllcy5cbiAgICAgICAgd2hpbGUgKHNpemUtLSkge1xuICAgICAgICAgIGlmICghKHJlc3VsdCA9IGVxKGFbc2l6ZV0sIGJbc2l6ZV0sIGFTdGFjaywgYlN0YWNrKSkpIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIERlZXAgY29tcGFyZSBvYmplY3RzLlxuICAgICAgZm9yICh2YXIga2V5IGluIGEpIHtcbiAgICAgICAgaWYgKF8uaGFzKGEsIGtleSkpIHtcbiAgICAgICAgICAvLyBDb3VudCB0aGUgZXhwZWN0ZWQgbnVtYmVyIG9mIHByb3BlcnRpZXMuXG4gICAgICAgICAgc2l6ZSsrO1xuICAgICAgICAgIC8vIERlZXAgY29tcGFyZSBlYWNoIG1lbWJlci5cbiAgICAgICAgICBpZiAoIShyZXN1bHQgPSBfLmhhcyhiLCBrZXkpICYmIGVxKGFba2V5XSwgYltrZXldLCBhU3RhY2ssIGJTdGFjaykpKSBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gRW5zdXJlIHRoYXQgYm90aCBvYmplY3RzIGNvbnRhaW4gdGhlIHNhbWUgbnVtYmVyIG9mIHByb3BlcnRpZXMuXG4gICAgICBpZiAocmVzdWx0KSB7XG4gICAgICAgIGZvciAoa2V5IGluIGIpIHtcbiAgICAgICAgICBpZiAoXy5oYXMoYiwga2V5KSAmJiAhKHNpemUtLSkpIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIHJlc3VsdCA9ICFzaXplO1xuICAgICAgfVxuICAgIH1cbiAgICAvLyBSZW1vdmUgdGhlIGZpcnN0IG9iamVjdCBmcm9tIHRoZSBzdGFjayBvZiB0cmF2ZXJzZWQgb2JqZWN0cy5cbiAgICBhU3RhY2sucG9wKCk7XG4gICAgYlN0YWNrLnBvcCgpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH07XG5cbiAgLy8gUGVyZm9ybSBhIGRlZXAgY29tcGFyaXNvbiB0byBjaGVjayBpZiB0d28gb2JqZWN0cyBhcmUgZXF1YWwuXG4gIF8uaXNFcXVhbCA9IGZ1bmN0aW9uKGEsIGIpIHtcbiAgICByZXR1cm4gZXEoYSwgYiwgW10sIFtdKTtcbiAgfTtcblxuICAvLyBJcyBhIGdpdmVuIGFycmF5LCBzdHJpbmcsIG9yIG9iamVjdCBlbXB0eT9cbiAgLy8gQW4gXCJlbXB0eVwiIG9iamVjdCBoYXMgbm8gZW51bWVyYWJsZSBvd24tcHJvcGVydGllcy5cbiAgXy5pc0VtcHR5ID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgaWYgKG9iaiA9PSBudWxsKSByZXR1cm4gdHJ1ZTtcbiAgICBpZiAoXy5pc0FycmF5KG9iaikgfHwgXy5pc1N0cmluZyhvYmopKSByZXR1cm4gb2JqLmxlbmd0aCA9PT0gMDtcbiAgICBmb3IgKHZhciBrZXkgaW4gb2JqKSBpZiAoXy5oYXMob2JqLCBrZXkpKSByZXR1cm4gZmFsc2U7XG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG5cbiAgLy8gSXMgYSBnaXZlbiB2YWx1ZSBhIERPTSBlbGVtZW50P1xuICBfLmlzRWxlbWVudCA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiAhIShvYmogJiYgb2JqLm5vZGVUeXBlID09PSAxKTtcbiAgfTtcblxuICAvLyBJcyBhIGdpdmVuIHZhbHVlIGFuIGFycmF5P1xuICAvLyBEZWxlZ2F0ZXMgdG8gRUNNQTUncyBuYXRpdmUgQXJyYXkuaXNBcnJheVxuICBfLmlzQXJyYXkgPSBuYXRpdmVJc0FycmF5IHx8IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiB0b1N0cmluZy5jYWxsKG9iaikgPT0gJ1tvYmplY3QgQXJyYXldJztcbiAgfTtcblxuICAvLyBJcyBhIGdpdmVuIHZhcmlhYmxlIGFuIG9iamVjdD9cbiAgXy5pc09iamVjdCA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiBvYmogPT09IE9iamVjdChvYmopO1xuICB9O1xuXG4gIC8vIEFkZCBzb21lIGlzVHlwZSBtZXRob2RzOiBpc0FyZ3VtZW50cywgaXNGdW5jdGlvbiwgaXNTdHJpbmcsIGlzTnVtYmVyLCBpc0RhdGUsIGlzUmVnRXhwLlxuICBlYWNoKFsnQXJndW1lbnRzJywgJ0Z1bmN0aW9uJywgJ1N0cmluZycsICdOdW1iZXInLCAnRGF0ZScsICdSZWdFeHAnXSwgZnVuY3Rpb24obmFtZSkge1xuICAgIF9bJ2lzJyArIG5hbWVdID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgICByZXR1cm4gdG9TdHJpbmcuY2FsbChvYmopID09ICdbb2JqZWN0ICcgKyBuYW1lICsgJ10nO1xuICAgIH07XG4gIH0pO1xuXG4gIC8vIERlZmluZSBhIGZhbGxiYWNrIHZlcnNpb24gb2YgdGhlIG1ldGhvZCBpbiBicm93c2VycyAoYWhlbSwgSUUpLCB3aGVyZVxuICAvLyB0aGVyZSBpc24ndCBhbnkgaW5zcGVjdGFibGUgXCJBcmd1bWVudHNcIiB0eXBlLlxuICBpZiAoIV8uaXNBcmd1bWVudHMoYXJndW1lbnRzKSkge1xuICAgIF8uaXNBcmd1bWVudHMgPSBmdW5jdGlvbihvYmopIHtcbiAgICAgIHJldHVybiAhIShvYmogJiYgXy5oYXMob2JqLCAnY2FsbGVlJykpO1xuICAgIH07XG4gIH1cblxuICAvLyBPcHRpbWl6ZSBgaXNGdW5jdGlvbmAgaWYgYXBwcm9wcmlhdGUuXG4gIGlmICh0eXBlb2YgKC8uLykgIT09ICdmdW5jdGlvbicpIHtcbiAgICBfLmlzRnVuY3Rpb24gPSBmdW5jdGlvbihvYmopIHtcbiAgICAgIHJldHVybiB0eXBlb2Ygb2JqID09PSAnZnVuY3Rpb24nO1xuICAgIH07XG4gIH1cblxuICAvLyBJcyBhIGdpdmVuIG9iamVjdCBhIGZpbml0ZSBudW1iZXI/XG4gIF8uaXNGaW5pdGUgPSBmdW5jdGlvbihvYmopIHtcbiAgICByZXR1cm4gaXNGaW5pdGUob2JqKSAmJiAhaXNOYU4ocGFyc2VGbG9hdChvYmopKTtcbiAgfTtcblxuICAvLyBJcyB0aGUgZ2l2ZW4gdmFsdWUgYE5hTmA/IChOYU4gaXMgdGhlIG9ubHkgbnVtYmVyIHdoaWNoIGRvZXMgbm90IGVxdWFsIGl0c2VsZikuXG4gIF8uaXNOYU4gPSBmdW5jdGlvbihvYmopIHtcbiAgICByZXR1cm4gXy5pc051bWJlcihvYmopICYmIG9iaiAhPSArb2JqO1xuICB9O1xuXG4gIC8vIElzIGEgZ2l2ZW4gdmFsdWUgYSBib29sZWFuP1xuICBfLmlzQm9vbGVhbiA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiBvYmogPT09IHRydWUgfHwgb2JqID09PSBmYWxzZSB8fCB0b1N0cmluZy5jYWxsKG9iaikgPT0gJ1tvYmplY3QgQm9vbGVhbl0nO1xuICB9O1xuXG4gIC8vIElzIGEgZ2l2ZW4gdmFsdWUgZXF1YWwgdG8gbnVsbD9cbiAgXy5pc051bGwgPSBmdW5jdGlvbihvYmopIHtcbiAgICByZXR1cm4gb2JqID09PSBudWxsO1xuICB9O1xuXG4gIC8vIElzIGEgZ2l2ZW4gdmFyaWFibGUgdW5kZWZpbmVkP1xuICBfLmlzVW5kZWZpbmVkID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgcmV0dXJuIG9iaiA9PT0gdm9pZCAwO1xuICB9O1xuXG4gIC8vIFNob3J0Y3V0IGZ1bmN0aW9uIGZvciBjaGVja2luZyBpZiBhbiBvYmplY3QgaGFzIGEgZ2l2ZW4gcHJvcGVydHkgZGlyZWN0bHlcbiAgLy8gb24gaXRzZWxmIChpbiBvdGhlciB3b3Jkcywgbm90IG9uIGEgcHJvdG90eXBlKS5cbiAgXy5oYXMgPSBmdW5jdGlvbihvYmosIGtleSkge1xuICAgIHJldHVybiBoYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwga2V5KTtcbiAgfTtcblxuICAvLyBVdGlsaXR5IEZ1bmN0aW9uc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8vIFJ1biBVbmRlcnNjb3JlLmpzIGluICpub0NvbmZsaWN0KiBtb2RlLCByZXR1cm5pbmcgdGhlIGBfYCB2YXJpYWJsZSB0byBpdHNcbiAgLy8gcHJldmlvdXMgb3duZXIuIFJldHVybnMgYSByZWZlcmVuY2UgdG8gdGhlIFVuZGVyc2NvcmUgb2JqZWN0LlxuICBfLm5vQ29uZmxpY3QgPSBmdW5jdGlvbigpIHtcbiAgICByb290Ll8gPSBwcmV2aW91c1VuZGVyc2NvcmU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH07XG5cbiAgLy8gS2VlcCB0aGUgaWRlbnRpdHkgZnVuY3Rpb24gYXJvdW5kIGZvciBkZWZhdWx0IGl0ZXJhdG9ycy5cbiAgXy5pZGVudGl0eSA9IGZ1bmN0aW9uKHZhbHVlKSB7XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9O1xuXG4gIF8uY29uc3RhbnQgPSBmdW5jdGlvbih2YWx1ZSkge1xuICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICByZXR1cm4gdmFsdWU7XG4gICAgfTtcbiAgfTtcblxuICBfLnByb3BlcnR5ID0gZnVuY3Rpb24oa2V5KSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKG9iaikge1xuICAgICAgcmV0dXJuIG9ialtrZXldO1xuICAgIH07XG4gIH07XG5cbiAgLy8gUmV0dXJucyBhIHByZWRpY2F0ZSBmb3IgY2hlY2tpbmcgd2hldGhlciBhbiBvYmplY3QgaGFzIGEgZ2l2ZW4gc2V0IG9mIGBrZXk6dmFsdWVgIHBhaXJzLlxuICBfLm1hdGNoZXMgPSBmdW5jdGlvbihhdHRycykge1xuICAgIHJldHVybiBmdW5jdGlvbihvYmopIHtcbiAgICAgIGlmIChvYmogPT09IGF0dHJzKSByZXR1cm4gdHJ1ZTsgLy9hdm9pZCBjb21wYXJpbmcgYW4gb2JqZWN0IHRvIGl0c2VsZi5cbiAgICAgIGZvciAodmFyIGtleSBpbiBhdHRycykge1xuICAgICAgICBpZiAoYXR0cnNba2V5XSAhPT0gb2JqW2tleV0pXG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICB9O1xuXG4gIC8vIFJ1biBhIGZ1bmN0aW9uICoqbioqIHRpbWVzLlxuICBfLnRpbWVzID0gZnVuY3Rpb24obiwgaXRlcmF0b3IsIGNvbnRleHQpIHtcbiAgICB2YXIgYWNjdW0gPSBBcnJheShNYXRoLm1heCgwLCBuKSk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBuOyBpKyspIGFjY3VtW2ldID0gaXRlcmF0b3IuY2FsbChjb250ZXh0LCBpKTtcbiAgICByZXR1cm4gYWNjdW07XG4gIH07XG5cbiAgLy8gUmV0dXJuIGEgcmFuZG9tIGludGVnZXIgYmV0d2VlbiBtaW4gYW5kIG1heCAoaW5jbHVzaXZlKS5cbiAgXy5yYW5kb20gPSBmdW5jdGlvbihtaW4sIG1heCkge1xuICAgIGlmIChtYXggPT0gbnVsbCkge1xuICAgICAgbWF4ID0gbWluO1xuICAgICAgbWluID0gMDtcbiAgICB9XG4gICAgcmV0dXJuIG1pbiArIE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIChtYXggLSBtaW4gKyAxKSk7XG4gIH07XG5cbiAgLy8gQSAocG9zc2libHkgZmFzdGVyKSB3YXkgdG8gZ2V0IHRoZSBjdXJyZW50IHRpbWVzdGFtcCBhcyBhbiBpbnRlZ2VyLlxuICBfLm5vdyA9IERhdGUubm93IHx8IGZ1bmN0aW9uKCkgeyByZXR1cm4gbmV3IERhdGUoKS5nZXRUaW1lKCk7IH07XG5cbiAgLy8gTGlzdCBvZiBIVE1MIGVudGl0aWVzIGZvciBlc2NhcGluZy5cbiAgdmFyIGVudGl0eU1hcCA9IHtcbiAgICBlc2NhcGU6IHtcbiAgICAgICcmJzogJyZhbXA7JyxcbiAgICAgICc8JzogJyZsdDsnLFxuICAgICAgJz4nOiAnJmd0OycsXG4gICAgICAnXCInOiAnJnF1b3Q7JyxcbiAgICAgIFwiJ1wiOiAnJiN4Mjc7J1xuICAgIH1cbiAgfTtcbiAgZW50aXR5TWFwLnVuZXNjYXBlID0gXy5pbnZlcnQoZW50aXR5TWFwLmVzY2FwZSk7XG5cbiAgLy8gUmVnZXhlcyBjb250YWluaW5nIHRoZSBrZXlzIGFuZCB2YWx1ZXMgbGlzdGVkIGltbWVkaWF0ZWx5IGFib3ZlLlxuICB2YXIgZW50aXR5UmVnZXhlcyA9IHtcbiAgICBlc2NhcGU6ICAgbmV3IFJlZ0V4cCgnWycgKyBfLmtleXMoZW50aXR5TWFwLmVzY2FwZSkuam9pbignJykgKyAnXScsICdnJyksXG4gICAgdW5lc2NhcGU6IG5ldyBSZWdFeHAoJygnICsgXy5rZXlzKGVudGl0eU1hcC51bmVzY2FwZSkuam9pbignfCcpICsgJyknLCAnZycpXG4gIH07XG5cbiAgLy8gRnVuY3Rpb25zIGZvciBlc2NhcGluZyBhbmQgdW5lc2NhcGluZyBzdHJpbmdzIHRvL2Zyb20gSFRNTCBpbnRlcnBvbGF0aW9uLlxuICBfLmVhY2goWydlc2NhcGUnLCAndW5lc2NhcGUnXSwgZnVuY3Rpb24obWV0aG9kKSB7XG4gICAgX1ttZXRob2RdID0gZnVuY3Rpb24oc3RyaW5nKSB7XG4gICAgICBpZiAoc3RyaW5nID09IG51bGwpIHJldHVybiAnJztcbiAgICAgIHJldHVybiAoJycgKyBzdHJpbmcpLnJlcGxhY2UoZW50aXR5UmVnZXhlc1ttZXRob2RdLCBmdW5jdGlvbihtYXRjaCkge1xuICAgICAgICByZXR1cm4gZW50aXR5TWFwW21ldGhvZF1bbWF0Y2hdO1xuICAgICAgfSk7XG4gICAgfTtcbiAgfSk7XG5cbiAgLy8gSWYgdGhlIHZhbHVlIG9mIHRoZSBuYW1lZCBgcHJvcGVydHlgIGlzIGEgZnVuY3Rpb24gdGhlbiBpbnZva2UgaXQgd2l0aCB0aGVcbiAgLy8gYG9iamVjdGAgYXMgY29udGV4dDsgb3RoZXJ3aXNlLCByZXR1cm4gaXQuXG4gIF8ucmVzdWx0ID0gZnVuY3Rpb24ob2JqZWN0LCBwcm9wZXJ0eSkge1xuICAgIGlmIChvYmplY3QgPT0gbnVsbCkgcmV0dXJuIHZvaWQgMDtcbiAgICB2YXIgdmFsdWUgPSBvYmplY3RbcHJvcGVydHldO1xuICAgIHJldHVybiBfLmlzRnVuY3Rpb24odmFsdWUpID8gdmFsdWUuY2FsbChvYmplY3QpIDogdmFsdWU7XG4gIH07XG5cbiAgLy8gQWRkIHlvdXIgb3duIGN1c3RvbSBmdW5jdGlvbnMgdG8gdGhlIFVuZGVyc2NvcmUgb2JqZWN0LlxuICBfLm1peGluID0gZnVuY3Rpb24ob2JqKSB7XG4gICAgZWFjaChfLmZ1bmN0aW9ucyhvYmopLCBmdW5jdGlvbihuYW1lKSB7XG4gICAgICB2YXIgZnVuYyA9IF9bbmFtZV0gPSBvYmpbbmFtZV07XG4gICAgICBfLnByb3RvdHlwZVtuYW1lXSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgYXJncyA9IFt0aGlzLl93cmFwcGVkXTtcbiAgICAgICAgcHVzaC5hcHBseShhcmdzLCBhcmd1bWVudHMpO1xuICAgICAgICByZXR1cm4gcmVzdWx0LmNhbGwodGhpcywgZnVuYy5hcHBseShfLCBhcmdzKSk7XG4gICAgICB9O1xuICAgIH0pO1xuICB9O1xuXG4gIC8vIEdlbmVyYXRlIGEgdW5pcXVlIGludGVnZXIgaWQgKHVuaXF1ZSB3aXRoaW4gdGhlIGVudGlyZSBjbGllbnQgc2Vzc2lvbikuXG4gIC8vIFVzZWZ1bCBmb3IgdGVtcG9yYXJ5IERPTSBpZHMuXG4gIHZhciBpZENvdW50ZXIgPSAwO1xuICBfLnVuaXF1ZUlkID0gZnVuY3Rpb24ocHJlZml4KSB7XG4gICAgdmFyIGlkID0gKytpZENvdW50ZXIgKyAnJztcbiAgICByZXR1cm4gcHJlZml4ID8gcHJlZml4ICsgaWQgOiBpZDtcbiAgfTtcblxuICAvLyBCeSBkZWZhdWx0LCBVbmRlcnNjb3JlIHVzZXMgRVJCLXN0eWxlIHRlbXBsYXRlIGRlbGltaXRlcnMsIGNoYW5nZSB0aGVcbiAgLy8gZm9sbG93aW5nIHRlbXBsYXRlIHNldHRpbmdzIHRvIHVzZSBhbHRlcm5hdGl2ZSBkZWxpbWl0ZXJzLlxuICBfLnRlbXBsYXRlU2V0dGluZ3MgPSB7XG4gICAgZXZhbHVhdGUgICAgOiAvPCUoW1xcc1xcU10rPyklPi9nLFxuICAgIGludGVycG9sYXRlIDogLzwlPShbXFxzXFxTXSs/KSU+L2csXG4gICAgZXNjYXBlICAgICAgOiAvPCUtKFtcXHNcXFNdKz8pJT4vZ1xuICB9O1xuXG4gIC8vIFdoZW4gY3VzdG9taXppbmcgYHRlbXBsYXRlU2V0dGluZ3NgLCBpZiB5b3UgZG9uJ3Qgd2FudCB0byBkZWZpbmUgYW5cbiAgLy8gaW50ZXJwb2xhdGlvbiwgZXZhbHVhdGlvbiBvciBlc2NhcGluZyByZWdleCwgd2UgbmVlZCBvbmUgdGhhdCBpc1xuICAvLyBndWFyYW50ZWVkIG5vdCB0byBtYXRjaC5cbiAgdmFyIG5vTWF0Y2ggPSAvKC4pXi87XG5cbiAgLy8gQ2VydGFpbiBjaGFyYWN0ZXJzIG5lZWQgdG8gYmUgZXNjYXBlZCBzbyB0aGF0IHRoZXkgY2FuIGJlIHB1dCBpbnRvIGFcbiAgLy8gc3RyaW5nIGxpdGVyYWwuXG4gIHZhciBlc2NhcGVzID0ge1xuICAgIFwiJ1wiOiAgICAgIFwiJ1wiLFxuICAgICdcXFxcJzogICAgICdcXFxcJyxcbiAgICAnXFxyJzogICAgICdyJyxcbiAgICAnXFxuJzogICAgICduJyxcbiAgICAnXFx0JzogICAgICd0JyxcbiAgICAnXFx1MjAyOCc6ICd1MjAyOCcsXG4gICAgJ1xcdTIwMjknOiAndTIwMjknXG4gIH07XG5cbiAgdmFyIGVzY2FwZXIgPSAvXFxcXHwnfFxccnxcXG58XFx0fFxcdTIwMjh8XFx1MjAyOS9nO1xuXG4gIC8vIEphdmFTY3JpcHQgbWljcm8tdGVtcGxhdGluZywgc2ltaWxhciB0byBKb2huIFJlc2lnJ3MgaW1wbGVtZW50YXRpb24uXG4gIC8vIFVuZGVyc2NvcmUgdGVtcGxhdGluZyBoYW5kbGVzIGFyYml0cmFyeSBkZWxpbWl0ZXJzLCBwcmVzZXJ2ZXMgd2hpdGVzcGFjZSxcbiAgLy8gYW5kIGNvcnJlY3RseSBlc2NhcGVzIHF1b3RlcyB3aXRoaW4gaW50ZXJwb2xhdGVkIGNvZGUuXG4gIF8udGVtcGxhdGUgPSBmdW5jdGlvbih0ZXh0LCBkYXRhLCBzZXR0aW5ncykge1xuICAgIHZhciByZW5kZXI7XG4gICAgc2V0dGluZ3MgPSBfLmRlZmF1bHRzKHt9LCBzZXR0aW5ncywgXy50ZW1wbGF0ZVNldHRpbmdzKTtcblxuICAgIC8vIENvbWJpbmUgZGVsaW1pdGVycyBpbnRvIG9uZSByZWd1bGFyIGV4cHJlc3Npb24gdmlhIGFsdGVybmF0aW9uLlxuICAgIHZhciBtYXRjaGVyID0gbmV3IFJlZ0V4cChbXG4gICAgICAoc2V0dGluZ3MuZXNjYXBlIHx8IG5vTWF0Y2gpLnNvdXJjZSxcbiAgICAgIChzZXR0aW5ncy5pbnRlcnBvbGF0ZSB8fCBub01hdGNoKS5zb3VyY2UsXG4gICAgICAoc2V0dGluZ3MuZXZhbHVhdGUgfHwgbm9NYXRjaCkuc291cmNlXG4gICAgXS5qb2luKCd8JykgKyAnfCQnLCAnZycpO1xuXG4gICAgLy8gQ29tcGlsZSB0aGUgdGVtcGxhdGUgc291cmNlLCBlc2NhcGluZyBzdHJpbmcgbGl0ZXJhbHMgYXBwcm9wcmlhdGVseS5cbiAgICB2YXIgaW5kZXggPSAwO1xuICAgIHZhciBzb3VyY2UgPSBcIl9fcCs9J1wiO1xuICAgIHRleHQucmVwbGFjZShtYXRjaGVyLCBmdW5jdGlvbihtYXRjaCwgZXNjYXBlLCBpbnRlcnBvbGF0ZSwgZXZhbHVhdGUsIG9mZnNldCkge1xuICAgICAgc291cmNlICs9IHRleHQuc2xpY2UoaW5kZXgsIG9mZnNldClcbiAgICAgICAgLnJlcGxhY2UoZXNjYXBlciwgZnVuY3Rpb24obWF0Y2gpIHsgcmV0dXJuICdcXFxcJyArIGVzY2FwZXNbbWF0Y2hdOyB9KTtcblxuICAgICAgaWYgKGVzY2FwZSkge1xuICAgICAgICBzb3VyY2UgKz0gXCInK1xcbigoX190PShcIiArIGVzY2FwZSArIFwiKSk9PW51bGw/Jyc6Xy5lc2NhcGUoX190KSkrXFxuJ1wiO1xuICAgICAgfVxuICAgICAgaWYgKGludGVycG9sYXRlKSB7XG4gICAgICAgIHNvdXJjZSArPSBcIicrXFxuKChfX3Q9KFwiICsgaW50ZXJwb2xhdGUgKyBcIikpPT1udWxsPycnOl9fdCkrXFxuJ1wiO1xuICAgICAgfVxuICAgICAgaWYgKGV2YWx1YXRlKSB7XG4gICAgICAgIHNvdXJjZSArPSBcIic7XFxuXCIgKyBldmFsdWF0ZSArIFwiXFxuX19wKz0nXCI7XG4gICAgICB9XG4gICAgICBpbmRleCA9IG9mZnNldCArIG1hdGNoLmxlbmd0aDtcbiAgICAgIHJldHVybiBtYXRjaDtcbiAgICB9KTtcbiAgICBzb3VyY2UgKz0gXCInO1xcblwiO1xuXG4gICAgLy8gSWYgYSB2YXJpYWJsZSBpcyBub3Qgc3BlY2lmaWVkLCBwbGFjZSBkYXRhIHZhbHVlcyBpbiBsb2NhbCBzY29wZS5cbiAgICBpZiAoIXNldHRpbmdzLnZhcmlhYmxlKSBzb3VyY2UgPSAnd2l0aChvYmp8fHt9KXtcXG4nICsgc291cmNlICsgJ31cXG4nO1xuXG4gICAgc291cmNlID0gXCJ2YXIgX190LF9fcD0nJyxfX2o9QXJyYXkucHJvdG90eXBlLmpvaW4sXCIgK1xuICAgICAgXCJwcmludD1mdW5jdGlvbigpe19fcCs9X19qLmNhbGwoYXJndW1lbnRzLCcnKTt9O1xcblwiICtcbiAgICAgIHNvdXJjZSArIFwicmV0dXJuIF9fcDtcXG5cIjtcblxuICAgIHRyeSB7XG4gICAgICByZW5kZXIgPSBuZXcgRnVuY3Rpb24oc2V0dGluZ3MudmFyaWFibGUgfHwgJ29iaicsICdfJywgc291cmNlKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBlLnNvdXJjZSA9IHNvdXJjZTtcbiAgICAgIHRocm93IGU7XG4gICAgfVxuXG4gICAgaWYgKGRhdGEpIHJldHVybiByZW5kZXIoZGF0YSwgXyk7XG4gICAgdmFyIHRlbXBsYXRlID0gZnVuY3Rpb24oZGF0YSkge1xuICAgICAgcmV0dXJuIHJlbmRlci5jYWxsKHRoaXMsIGRhdGEsIF8pO1xuICAgIH07XG5cbiAgICAvLyBQcm92aWRlIHRoZSBjb21waWxlZCBmdW5jdGlvbiBzb3VyY2UgYXMgYSBjb252ZW5pZW5jZSBmb3IgcHJlY29tcGlsYXRpb24uXG4gICAgdGVtcGxhdGUuc291cmNlID0gJ2Z1bmN0aW9uKCcgKyAoc2V0dGluZ3MudmFyaWFibGUgfHwgJ29iaicpICsgJyl7XFxuJyArIHNvdXJjZSArICd9JztcblxuICAgIHJldHVybiB0ZW1wbGF0ZTtcbiAgfTtcblxuICAvLyBBZGQgYSBcImNoYWluXCIgZnVuY3Rpb24sIHdoaWNoIHdpbGwgZGVsZWdhdGUgdG8gdGhlIHdyYXBwZXIuXG4gIF8uY2hhaW4gPSBmdW5jdGlvbihvYmopIHtcbiAgICByZXR1cm4gXyhvYmopLmNoYWluKCk7XG4gIH07XG5cbiAgLy8gT09QXG4gIC8vIC0tLS0tLS0tLS0tLS0tLVxuICAvLyBJZiBVbmRlcnNjb3JlIGlzIGNhbGxlZCBhcyBhIGZ1bmN0aW9uLCBpdCByZXR1cm5zIGEgd3JhcHBlZCBvYmplY3QgdGhhdFxuICAvLyBjYW4gYmUgdXNlZCBPTy1zdHlsZS4gVGhpcyB3cmFwcGVyIGhvbGRzIGFsdGVyZWQgdmVyc2lvbnMgb2YgYWxsIHRoZVxuICAvLyB1bmRlcnNjb3JlIGZ1bmN0aW9ucy4gV3JhcHBlZCBvYmplY3RzIG1heSBiZSBjaGFpbmVkLlxuXG4gIC8vIEhlbHBlciBmdW5jdGlvbiB0byBjb250aW51ZSBjaGFpbmluZyBpbnRlcm1lZGlhdGUgcmVzdWx0cy5cbiAgdmFyIHJlc3VsdCA9IGZ1bmN0aW9uKG9iaikge1xuICAgIHJldHVybiB0aGlzLl9jaGFpbiA/IF8ob2JqKS5jaGFpbigpIDogb2JqO1xuICB9O1xuXG4gIC8vIEFkZCBhbGwgb2YgdGhlIFVuZGVyc2NvcmUgZnVuY3Rpb25zIHRvIHRoZSB3cmFwcGVyIG9iamVjdC5cbiAgXy5taXhpbihfKTtcblxuICAvLyBBZGQgYWxsIG11dGF0b3IgQXJyYXkgZnVuY3Rpb25zIHRvIHRoZSB3cmFwcGVyLlxuICBlYWNoKFsncG9wJywgJ3B1c2gnLCAncmV2ZXJzZScsICdzaGlmdCcsICdzb3J0JywgJ3NwbGljZScsICd1bnNoaWZ0J10sIGZ1bmN0aW9uKG5hbWUpIHtcbiAgICB2YXIgbWV0aG9kID0gQXJyYXlQcm90b1tuYW1lXTtcbiAgICBfLnByb3RvdHlwZVtuYW1lXSA9IGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIG9iaiA9IHRoaXMuX3dyYXBwZWQ7XG4gICAgICBtZXRob2QuYXBwbHkob2JqLCBhcmd1bWVudHMpO1xuICAgICAgaWYgKChuYW1lID09ICdzaGlmdCcgfHwgbmFtZSA9PSAnc3BsaWNlJykgJiYgb2JqLmxlbmd0aCA9PT0gMCkgZGVsZXRlIG9ialswXTtcbiAgICAgIHJldHVybiByZXN1bHQuY2FsbCh0aGlzLCBvYmopO1xuICAgIH07XG4gIH0pO1xuXG4gIC8vIEFkZCBhbGwgYWNjZXNzb3IgQXJyYXkgZnVuY3Rpb25zIHRvIHRoZSB3cmFwcGVyLlxuICBlYWNoKFsnY29uY2F0JywgJ2pvaW4nLCAnc2xpY2UnXSwgZnVuY3Rpb24obmFtZSkge1xuICAgIHZhciBtZXRob2QgPSBBcnJheVByb3RvW25hbWVdO1xuICAgIF8ucHJvdG90eXBlW25hbWVdID0gZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gcmVzdWx0LmNhbGwodGhpcywgbWV0aG9kLmFwcGx5KHRoaXMuX3dyYXBwZWQsIGFyZ3VtZW50cykpO1xuICAgIH07XG4gIH0pO1xuXG4gIF8uZXh0ZW5kKF8ucHJvdG90eXBlLCB7XG5cbiAgICAvLyBTdGFydCBjaGFpbmluZyBhIHdyYXBwZWQgVW5kZXJzY29yZSBvYmplY3QuXG4gICAgY2hhaW46IGZ1bmN0aW9uKCkge1xuICAgICAgdGhpcy5fY2hhaW4gPSB0cnVlO1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIC8vIEV4dHJhY3RzIHRoZSByZXN1bHQgZnJvbSBhIHdyYXBwZWQgYW5kIGNoYWluZWQgb2JqZWN0LlxuICAgIHZhbHVlOiBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiB0aGlzLl93cmFwcGVkO1xuICAgIH1cblxuICB9KTtcblxuICAvLyBBTUQgcmVnaXN0cmF0aW9uIGhhcHBlbnMgYXQgdGhlIGVuZCBmb3IgY29tcGF0aWJpbGl0eSB3aXRoIEFNRCBsb2FkZXJzXG4gIC8vIHRoYXQgbWF5IG5vdCBlbmZvcmNlIG5leHQtdHVybiBzZW1hbnRpY3Mgb24gbW9kdWxlcy4gRXZlbiB0aG91Z2ggZ2VuZXJhbFxuICAvLyBwcmFjdGljZSBmb3IgQU1EIHJlZ2lzdHJhdGlvbiBpcyB0byBiZSBhbm9ueW1vdXMsIHVuZGVyc2NvcmUgcmVnaXN0ZXJzXG4gIC8vIGFzIGEgbmFtZWQgbW9kdWxlIGJlY2F1c2UsIGxpa2UgalF1ZXJ5LCBpdCBpcyBhIGJhc2UgbGlicmFyeSB0aGF0IGlzXG4gIC8vIHBvcHVsYXIgZW5vdWdoIHRvIGJlIGJ1bmRsZWQgaW4gYSB0aGlyZCBwYXJ0eSBsaWIsIGJ1dCBub3QgYmUgcGFydCBvZlxuICAvLyBhbiBBTUQgbG9hZCByZXF1ZXN0LiBUaG9zZSBjYXNlcyBjb3VsZCBnZW5lcmF0ZSBhbiBlcnJvciB3aGVuIGFuXG4gIC8vIGFub255bW91cyBkZWZpbmUoKSBpcyBjYWxsZWQgb3V0c2lkZSBvZiBhIGxvYWRlciByZXF1ZXN0LlxuICBpZiAodHlwZW9mIGRlZmluZSA9PT0gJ2Z1bmN0aW9uJyAmJiBkZWZpbmUuYW1kKSB7XG4gICAgZGVmaW5lKCd1bmRlcnNjb3JlJywgW10sIGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIF87XG4gICAgfSk7XG4gIH1cbn0pLmNhbGwodGhpcyk7XG4iLCIvKiEgSGFtbWVyLkpTIC0gdjEuMC43ZGV2IC0gMjAxNC0wMi0xOFxuICogaHR0cDovL2VpZ2h0bWVkaWEuZ2l0aHViLmNvbS9oYW1tZXIuanNcbiAqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTQgSm9yaWsgVGFuZ2VsZGVyIDxqLnRhbmdlbGRlckBnbWFpbC5jb20+O1xuICogTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlICovXG5cbihmdW5jdGlvbih3aW5kb3csIHVuZGVmaW5lZCkge1xuICAndXNlIHN0cmljdCc7XG5cbi8qKlxuICogSGFtbWVyXG4gKiB1c2UgdGhpcyB0byBjcmVhdGUgaW5zdGFuY2VzXG4gKiBAcGFyYW0gICB7SFRNTEVsZW1lbnR9ICAgZWxlbWVudFxuICogQHBhcmFtICAge09iamVjdH0gICAgICAgIG9wdGlvbnNcbiAqIEByZXR1cm5zIHtIYW1tZXIuSW5zdGFuY2V9XG4gKiBAY29uc3RydWN0b3JcbiAqL1xudmFyIEhhbW1lciA9IGZ1bmN0aW9uKGVsZW1lbnQsIG9wdGlvbnMpIHtcbiAgcmV0dXJuIG5ldyBIYW1tZXIuSW5zdGFuY2UoZWxlbWVudCwgb3B0aW9ucyB8fCB7fSk7XG59O1xuXG4vLyBkZWZhdWx0IHNldHRpbmdzXG5IYW1tZXIuZGVmYXVsdHMgPSB7XG4gIC8vIGFkZCBzdHlsZXMgYW5kIGF0dHJpYnV0ZXMgdG8gdGhlIGVsZW1lbnQgdG8gcHJldmVudCB0aGUgYnJvd3NlciBmcm9tIGRvaW5nXG4gIC8vIGl0cyBuYXRpdmUgYmVoYXZpb3IuIHRoaXMgZG9lc250IHByZXZlbnQgdGhlIHNjcm9sbGluZywgYnV0IGNhbmNlbHNcbiAgLy8gdGhlIGNvbnRleHRtZW51LCB0YXAgaGlnaGxpZ2h0aW5nIGV0Y1xuICAvLyBzZXQgdG8gZmFsc2UgdG8gZGlzYWJsZSB0aGlzXG4gIHN0b3BfYnJvd3Nlcl9iZWhhdmlvcjoge1xuICAgIC8vIHRoaXMgYWxzbyB0cmlnZ2VycyBvbnNlbGVjdHN0YXJ0PWZhbHNlIGZvciBJRVxuICAgIHVzZXJTZWxlY3QgICAgICAgOiAnbm9uZScsXG4gICAgLy8gdGhpcyBtYWtlcyB0aGUgZWxlbWVudCBibG9ja2luZyBpbiBJRTEwID4sIHlvdSBjb3VsZCBleHBlcmltZW50IHdpdGggdGhlIHZhbHVlXG4gICAgLy8gc2VlIGZvciBtb3JlIG9wdGlvbnMgdGhpcyBpc3N1ZTsgaHR0cHM6Ly9naXRodWIuY29tL0VpZ2h0TWVkaWEvaGFtbWVyLmpzL2lzc3Vlcy8yNDFcbiAgICB0b3VjaEFjdGlvbiAgICAgIDogJ25vbmUnLFxuICAgIHRvdWNoQ2FsbG91dCAgICAgOiAnbm9uZScsXG4gICAgY29udGVudFpvb21pbmcgICA6ICdub25lJyxcbiAgICB1c2VyRHJhZyAgICAgICAgIDogJ25vbmUnLFxuICAgIHRhcEhpZ2hsaWdodENvbG9yOiAncmdiYSgwLDAsMCwwKSdcbiAgfVxuXG4gIC8vXG4gIC8vIG1vcmUgc2V0dGluZ3MgYXJlIGRlZmluZWQgcGVyIGdlc3R1cmUgYXQgZ2VzdHVyZXMuanNcbiAgLy9cbn07XG5cbi8vIGRldGVjdCB0b3VjaGV2ZW50c1xuSGFtbWVyLkhBU19QT0lOVEVSRVZFTlRTID0gd2luZG93Lm5hdmlnYXRvci5wb2ludGVyRW5hYmxlZCB8fCB3aW5kb3cubmF2aWdhdG9yLm1zUG9pbnRlckVuYWJsZWQ7XG5IYW1tZXIuSEFTX1RPVUNIRVZFTlRTID0gKCdvbnRvdWNoc3RhcnQnIGluIHdpbmRvdyk7XG5cbi8vIGRvbnQgdXNlIG1vdXNlZXZlbnRzIG9uIG1vYmlsZSBkZXZpY2VzXG5IYW1tZXIuTU9CSUxFX1JFR0VYID0gL21vYmlsZXx0YWJsZXR8aXAoYWR8aG9uZXxvZCl8YW5kcm9pZHxzaWxrL2k7XG5IYW1tZXIuTk9fTU9VU0VFVkVOVFMgPSBIYW1tZXIuSEFTX1RPVUNIRVZFTlRTICYmIHdpbmRvdy5uYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKEhhbW1lci5NT0JJTEVfUkVHRVgpO1xuXG4vLyBldmVudHR5cGVzIHBlciB0b3VjaGV2ZW50IChzdGFydCwgbW92ZSwgZW5kKVxuLy8gYXJlIGZpbGxlZCBieSBIYW1tZXIuZXZlbnQuZGV0ZXJtaW5lRXZlbnRUeXBlcyBvbiBzZXR1cFxuSGFtbWVyLkVWRU5UX1RZUEVTID0ge307XG5cbi8vIGRpcmVjdGlvbiBkZWZpbmVzXG5IYW1tZXIuRElSRUNUSU9OX0RPV04gPSAnZG93bic7XG5IYW1tZXIuRElSRUNUSU9OX0xFRlQgPSAnbGVmdCc7XG5IYW1tZXIuRElSRUNUSU9OX1VQID0gJ3VwJztcbkhhbW1lci5ESVJFQ1RJT05fUklHSFQgPSAncmlnaHQnO1xuXG4vLyBwb2ludGVyIHR5cGVcbkhhbW1lci5QT0lOVEVSX01PVVNFID0gJ21vdXNlJztcbkhhbW1lci5QT0lOVEVSX1RPVUNIID0gJ3RvdWNoJztcbkhhbW1lci5QT0lOVEVSX1BFTiA9ICdwZW4nO1xuXG4vLyBpbnRlcnZhbCBpbiB3aGljaCBIYW1tZXIgcmVjYWxjdWxhdGVzIGN1cnJlbnQgdmVsb2NpdHkgaW4gbXNcbkhhbW1lci5VUERBVEVfVkVMT0NJVFlfSU5URVJWQUwgPSAyMDtcblxuLy8gdG91Y2ggZXZlbnQgZGVmaW5lc1xuSGFtbWVyLkVWRU5UX1NUQVJUID0gJ3N0YXJ0JztcbkhhbW1lci5FVkVOVF9NT1ZFID0gJ21vdmUnO1xuSGFtbWVyLkVWRU5UX0VORCA9ICdlbmQnO1xuXG4vLyBoYW1tZXIgZG9jdW1lbnQgd2hlcmUgdGhlIGJhc2UgZXZlbnRzIGFyZSBhZGRlZCBhdFxuSGFtbWVyLkRPQ1VNRU5UID0gd2luZG93LmRvY3VtZW50O1xuXG4vLyBwbHVnaW5zIGFuZCBnZXN0dXJlcyBuYW1lc3BhY2VzXG5IYW1tZXIucGx1Z2lucyA9IEhhbW1lci5wbHVnaW5zIHx8IHt9O1xuSGFtbWVyLmdlc3R1cmVzID0gSGFtbWVyLmdlc3R1cmVzIHx8IHt9O1xuXG5cbi8vIGlmIHRoZSB3aW5kb3cgZXZlbnRzIGFyZSBzZXQuLi5cbkhhbW1lci5SRUFEWSA9IGZhbHNlO1xuXG4vKipcbiAqIHNldHVwIGV2ZW50cyB0byBkZXRlY3QgZ2VzdHVyZXMgb24gdGhlIGRvY3VtZW50XG4gKi9cbmZ1bmN0aW9uIHNldHVwKCkge1xuICBpZihIYW1tZXIuUkVBRFkpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBmaW5kIHdoYXQgZXZlbnR0eXBlcyB3ZSBhZGQgbGlzdGVuZXJzIHRvXG4gIEhhbW1lci5ldmVudC5kZXRlcm1pbmVFdmVudFR5cGVzKCk7XG5cbiAgLy8gUmVnaXN0ZXIgYWxsIGdlc3R1cmVzIGluc2lkZSBIYW1tZXIuZ2VzdHVyZXNcbiAgSGFtbWVyLnV0aWxzLmVhY2goSGFtbWVyLmdlc3R1cmVzLCBmdW5jdGlvbihnZXN0dXJlKXtcbiAgICBIYW1tZXIuZGV0ZWN0aW9uLnJlZ2lzdGVyKGdlc3R1cmUpO1xuICB9KTtcblxuICAvLyBBZGQgdG91Y2ggZXZlbnRzIG9uIHRoZSBkb2N1bWVudFxuICBIYW1tZXIuZXZlbnQub25Ub3VjaChIYW1tZXIuRE9DVU1FTlQsIEhhbW1lci5FVkVOVF9NT1ZFLCBIYW1tZXIuZGV0ZWN0aW9uLmRldGVjdCk7XG4gIEhhbW1lci5ldmVudC5vblRvdWNoKEhhbW1lci5ET0NVTUVOVCwgSGFtbWVyLkVWRU5UX0VORCwgSGFtbWVyLmRldGVjdGlvbi5kZXRlY3QpO1xuXG4gIC8vIEhhbW1lciBpcyByZWFkeS4uLiFcbiAgSGFtbWVyLlJFQURZID0gdHJ1ZTtcbn1cblxuSGFtbWVyLnV0aWxzID0ge1xuICAvKipcbiAgICogZXh0ZW5kIG1ldGhvZCxcbiAgICogYWxzbyB1c2VkIGZvciBjbG9uaW5nIHdoZW4gZGVzdCBpcyBhbiBlbXB0eSBvYmplY3RcbiAgICogQHBhcmFtICAge09iamVjdH0gICAgZGVzdFxuICAgKiBAcGFyYW0gICB7T2JqZWN0fSAgICBzcmNcbiAgICogQHBhcm0gIHtCb29sZWFufSAgbWVyZ2UgICAgZG8gYSBtZXJnZVxuICAgKiBAcmV0dXJucyB7T2JqZWN0fSAgICBkZXN0XG4gICAqL1xuICBleHRlbmQ6IGZ1bmN0aW9uIGV4dGVuZChkZXN0LCBzcmMsIG1lcmdlKSB7XG4gICAgZm9yKHZhciBrZXkgaW4gc3JjKSB7XG4gICAgICBpZihkZXN0W2tleV0gIT09IHVuZGVmaW5lZCAmJiBtZXJnZSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGRlc3Rba2V5XSA9IHNyY1trZXldO1xuICAgIH1cbiAgICByZXR1cm4gZGVzdDtcbiAgfSxcblxuXG4gIC8qKlxuICAgKiBmb3IgZWFjaFxuICAgKiBAcGFyYW0gb2JqXG4gICAqIEBwYXJhbSBpdGVyYXRvclxuICAgKi9cbiAgZWFjaDogZnVuY3Rpb24ob2JqLCBpdGVyYXRvciwgY29udGV4dCkge1xuICAgIHZhciBpLCBsZW5ndGg7XG4gICAgLy8gbmF0aXZlIGZvckVhY2ggb24gYXJyYXlzXG4gICAgaWYgKCdmb3JFYWNoJyBpbiBvYmopIHtcbiAgICAgIG9iai5mb3JFYWNoKGl0ZXJhdG9yLCBjb250ZXh0KTtcbiAgICB9XG4gICAgLy8gYXJyYXlzXG4gICAgZWxzZSBpZihvYmoubGVuZ3RoICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGZvciAoaSA9IDAsIGxlbmd0aCA9IG9iai5sZW5ndGg7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAoaXRlcmF0b3IuY2FsbChjb250ZXh0LCBvYmpbaV0sIGksIG9iaikgPT09IGZhbHNlKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIC8vIG9iamVjdHNcbiAgICBlbHNlIHtcbiAgICAgIGZvciAoaSBpbiBvYmopIHtcbiAgICAgICAgaWYgKG9iai5oYXNPd25Qcm9wZXJ0eShpKSAmJiBpdGVyYXRvci5jYWxsKGNvbnRleHQsIG9ialtpXSwgaSwgb2JqKSA9PT0gZmFsc2UpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0sXG5cbiAgLyoqXG4gICAqIGZpbmQgaWYgYSBub2RlIGlzIGluIHRoZSBnaXZlbiBwYXJlbnRcbiAgICogdXNlZCBmb3IgZXZlbnQgZGVsZWdhdGlvbiB0cmlja3NcbiAgICogQHBhcmFtICAge0hUTUxFbGVtZW50fSAgIG5vZGVcbiAgICogQHBhcmFtICAge0hUTUxFbGVtZW50fSAgIHBhcmVudFxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gICAgICAgaGFzX3BhcmVudFxuICAgKi9cbiAgaGFzUGFyZW50OiBmdW5jdGlvbihub2RlLCBwYXJlbnQpIHtcbiAgICB3aGlsZShub2RlKSB7XG4gICAgICBpZihub2RlID09IHBhcmVudCkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIG5vZGUgPSBub2RlLnBhcmVudE5vZGU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfSxcblxuXG4gIC8qKlxuICAgKiBnZXQgdGhlIGNlbnRlciBvZiBhbGwgdGhlIHRvdWNoZXNcbiAgICogQHBhcmFtICAge0FycmF5fSAgICAgdG91Y2hlc1xuICAgKiBAcmV0dXJucyB7T2JqZWN0fSAgICBjZW50ZXJcbiAgICovXG4gIGdldENlbnRlcjogZnVuY3Rpb24gZ2V0Q2VudGVyKHRvdWNoZXMpIHtcbiAgICB2YXIgdmFsdWVzWCA9IFtdLCB2YWx1ZXNZID0gW107XG5cbiAgICBIYW1tZXIudXRpbHMuZWFjaCh0b3VjaGVzLCBmdW5jdGlvbih0b3VjaCkge1xuICAgICAgLy8gSSBwcmVmZXIgY2xpZW50WCBiZWNhdXNlIGl0IGlnbm9yZSB0aGUgc2Nyb2xsaW5nIHBvc2l0aW9uXG4gICAgICB2YWx1ZXNYLnB1c2godHlwZW9mIHRvdWNoLmNsaWVudFggIT09ICd1bmRlZmluZWQnID8gdG91Y2guY2xpZW50WCA6IHRvdWNoLnBhZ2VYICk7XG4gICAgICB2YWx1ZXNZLnB1c2godHlwZW9mIHRvdWNoLmNsaWVudFkgIT09ICd1bmRlZmluZWQnID8gdG91Y2guY2xpZW50WSA6IHRvdWNoLnBhZ2VZICk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgcGFnZVg6ICgoTWF0aC5taW4uYXBwbHkoTWF0aCwgdmFsdWVzWCkgKyBNYXRoLm1heC5hcHBseShNYXRoLCB2YWx1ZXNYKSkgLyAyKSxcbiAgICAgIHBhZ2VZOiAoKE1hdGgubWluLmFwcGx5KE1hdGgsIHZhbHVlc1kpICsgTWF0aC5tYXguYXBwbHkoTWF0aCwgdmFsdWVzWSkpIC8gMilcbiAgICB9O1xuICB9LFxuXG5cbiAgLyoqXG4gICAqIGNhbGN1bGF0ZSB0aGUgdmVsb2NpdHkgYmV0d2VlbiB0d28gcG9pbnRzXG4gICAqIEBwYXJhbSAgIHtOdW1iZXJ9ICAgIGRlbHRhX3RpbWVcbiAgICogQHBhcmFtICAge051bWJlcn0gICAgZGVsdGFfeFxuICAgKiBAcGFyYW0gICB7TnVtYmVyfSAgICBkZWx0YV95XG4gICAqIEByZXR1cm5zIHtPYmplY3R9ICAgIHZlbG9jaXR5XG4gICAqL1xuICBnZXRWZWxvY2l0eTogZnVuY3Rpb24gZ2V0VmVsb2NpdHkoZGVsdGFfdGltZSwgZGVsdGFfeCwgZGVsdGFfeSkge1xuICAgIHJldHVybiB7XG4gICAgICB4OiBNYXRoLmFicyhkZWx0YV94IC8gZGVsdGFfdGltZSkgfHwgMCxcbiAgICAgIHk6IE1hdGguYWJzKGRlbHRhX3kgLyBkZWx0YV90aW1lKSB8fCAwXG4gICAgfTtcbiAgfSxcblxuXG4gIC8qKlxuICAgKiBjYWxjdWxhdGUgdGhlIGFuZ2xlIGJldHdlZW4gdHdvIGNvb3JkaW5hdGVzXG4gICAqIEBwYXJhbSAgIHtUb3VjaH0gICAgIHRvdWNoMVxuICAgKiBAcGFyYW0gICB7VG91Y2h9ICAgICB0b3VjaDJcbiAgICogQHJldHVybnMge051bWJlcn0gICAgYW5nbGVcbiAgICovXG4gIGdldEFuZ2xlOiBmdW5jdGlvbiBnZXRBbmdsZSh0b3VjaDEsIHRvdWNoMikge1xuICAgIHZhciB5ID0gdG91Y2gyLnBhZ2VZIC0gdG91Y2gxLnBhZ2VZLFxuICAgICAgeCA9IHRvdWNoMi5wYWdlWCAtIHRvdWNoMS5wYWdlWDtcbiAgICByZXR1cm4gTWF0aC5hdGFuMih5LCB4KSAqIDE4MCAvIE1hdGguUEk7XG4gIH0sXG5cblxuICAvKipcbiAgICogYW5nbGUgdG8gZGlyZWN0aW9uIGRlZmluZVxuICAgKiBAcGFyYW0gICB7VG91Y2h9ICAgICB0b3VjaDFcbiAgICogQHBhcmFtICAge1RvdWNofSAgICAgdG91Y2gyXG4gICAqIEByZXR1cm5zIHtTdHJpbmd9ICAgIGRpcmVjdGlvbiBjb25zdGFudCwgbGlrZSBIYW1tZXIuRElSRUNUSU9OX0xFRlRcbiAgICovXG4gIGdldERpcmVjdGlvbjogZnVuY3Rpb24gZ2V0RGlyZWN0aW9uKHRvdWNoMSwgdG91Y2gyKSB7XG4gICAgdmFyIHggPSBNYXRoLmFicyh0b3VjaDEucGFnZVggLSB0b3VjaDIucGFnZVgpLFxuICAgICAgeSA9IE1hdGguYWJzKHRvdWNoMS5wYWdlWSAtIHRvdWNoMi5wYWdlWSk7XG5cbiAgICBpZih4ID49IHkpIHtcbiAgICAgIHJldHVybiB0b3VjaDEucGFnZVggLSB0b3VjaDIucGFnZVggPiAwID8gSGFtbWVyLkRJUkVDVElPTl9MRUZUIDogSGFtbWVyLkRJUkVDVElPTl9SSUdIVDtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICByZXR1cm4gdG91Y2gxLnBhZ2VZIC0gdG91Y2gyLnBhZ2VZID4gMCA/IEhhbW1lci5ESVJFQ1RJT05fVVAgOiBIYW1tZXIuRElSRUNUSU9OX0RPV047XG4gICAgfVxuICB9LFxuXG5cbiAgLyoqXG4gICAqIGNhbGN1bGF0ZSB0aGUgZGlzdGFuY2UgYmV0d2VlbiB0d28gdG91Y2hlc1xuICAgKiBAcGFyYW0gICB7VG91Y2h9ICAgICB0b3VjaDFcbiAgICogQHBhcmFtICAge1RvdWNofSAgICAgdG91Y2gyXG4gICAqIEByZXR1cm5zIHtOdW1iZXJ9ICAgIGRpc3RhbmNlXG4gICAqL1xuICBnZXREaXN0YW5jZTogZnVuY3Rpb24gZ2V0RGlzdGFuY2UodG91Y2gxLCB0b3VjaDIpIHtcbiAgICB2YXIgeCA9IHRvdWNoMi5wYWdlWCAtIHRvdWNoMS5wYWdlWCxcbiAgICAgIHkgPSB0b3VjaDIucGFnZVkgLSB0b3VjaDEucGFnZVk7XG4gICAgcmV0dXJuIE1hdGguc3FydCgoeCAqIHgpICsgKHkgKiB5KSk7XG4gIH0sXG5cblxuICAvKipcbiAgICogY2FsY3VsYXRlIHRoZSBzY2FsZSBmYWN0b3IgYmV0d2VlbiB0d28gdG91Y2hMaXN0cyAoZmluZ2VycylcbiAgICogbm8gc2NhbGUgaXMgMSwgYW5kIGdvZXMgZG93biB0byAwIHdoZW4gcGluY2hlZCB0b2dldGhlciwgYW5kIGJpZ2dlciB3aGVuIHBpbmNoZWQgb3V0XG4gICAqIEBwYXJhbSAgIHtBcnJheX0gICAgIHN0YXJ0XG4gICAqIEBwYXJhbSAgIHtBcnJheX0gICAgIGVuZFxuICAgKiBAcmV0dXJucyB7TnVtYmVyfSAgICBzY2FsZVxuICAgKi9cbiAgZ2V0U2NhbGU6IGZ1bmN0aW9uIGdldFNjYWxlKHN0YXJ0LCBlbmQpIHtcbiAgICAvLyBuZWVkIHR3byBmaW5nZXJzLi4uXG4gICAgaWYoc3RhcnQubGVuZ3RoID49IDIgJiYgZW5kLmxlbmd0aCA+PSAyKSB7XG4gICAgICByZXR1cm4gdGhpcy5nZXREaXN0YW5jZShlbmRbMF0sIGVuZFsxXSkgL1xuICAgICAgICB0aGlzLmdldERpc3RhbmNlKHN0YXJ0WzBdLCBzdGFydFsxXSk7XG4gICAgfVxuICAgIHJldHVybiAxO1xuICB9LFxuXG5cbiAgLyoqXG4gICAqIGNhbGN1bGF0ZSB0aGUgcm90YXRpb24gZGVncmVlcyBiZXR3ZWVuIHR3byB0b3VjaExpc3RzIChmaW5nZXJzKVxuICAgKiBAcGFyYW0gICB7QXJyYXl9ICAgICBzdGFydFxuICAgKiBAcGFyYW0gICB7QXJyYXl9ICAgICBlbmRcbiAgICogQHJldHVybnMge051bWJlcn0gICAgcm90YXRpb25cbiAgICovXG4gIGdldFJvdGF0aW9uOiBmdW5jdGlvbiBnZXRSb3RhdGlvbihzdGFydCwgZW5kKSB7XG4gICAgLy8gbmVlZCB0d28gZmluZ2Vyc1xuICAgIGlmKHN0YXJ0Lmxlbmd0aCA+PSAyICYmIGVuZC5sZW5ndGggPj0gMikge1xuICAgICAgcmV0dXJuIHRoaXMuZ2V0QW5nbGUoZW5kWzFdLCBlbmRbMF0pIC1cbiAgICAgICAgdGhpcy5nZXRBbmdsZShzdGFydFsxXSwgc3RhcnRbMF0pO1xuICAgIH1cbiAgICByZXR1cm4gMDtcbiAgfSxcblxuXG4gIC8qKlxuICAgKiBib29sZWFuIGlmIHRoZSBkaXJlY3Rpb24gaXMgdmVydGljYWxcbiAgICogQHBhcmFtICAgIHtTdHJpbmd9ICAgIGRpcmVjdGlvblxuICAgKiBAcmV0dXJucyAge0Jvb2xlYW59ICAgaXNfdmVydGljYWxcbiAgICovXG4gIGlzVmVydGljYWw6IGZ1bmN0aW9uIGlzVmVydGljYWwoZGlyZWN0aW9uKSB7XG4gICAgcmV0dXJuIChkaXJlY3Rpb24gPT0gSGFtbWVyLkRJUkVDVElPTl9VUCB8fCBkaXJlY3Rpb24gPT0gSGFtbWVyLkRJUkVDVElPTl9ET1dOKTtcbiAgfSxcblxuXG4gIC8qKlxuICAgKiBzdG9wIGJyb3dzZXIgZGVmYXVsdCBiZWhhdmlvciB3aXRoIGNzcyBwcm9wc1xuICAgKiBAcGFyYW0gICB7SHRtbEVsZW1lbnR9ICAgZWxlbWVudFxuICAgKiBAcGFyYW0gICB7T2JqZWN0fSAgICAgICAgY3NzX3Byb3BzXG4gICAqL1xuICBzdG9wRGVmYXVsdEJyb3dzZXJCZWhhdmlvcjogZnVuY3Rpb24gc3RvcERlZmF1bHRCcm93c2VyQmVoYXZpb3IoZWxlbWVudCwgY3NzX3Byb3BzKSB7XG4gICAgaWYoIWNzc19wcm9wcyB8fCAhZWxlbWVudCB8fCAhZWxlbWVudC5zdHlsZSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIHdpdGggY3NzIHByb3BlcnRpZXMgZm9yIG1vZGVybiBicm93c2Vyc1xuICAgIEhhbW1lci51dGlscy5lYWNoKFsnd2Via2l0JywgJ2todG1sJywgJ21veicsICdNb3onLCAnbXMnLCAnbycsICcnXSwgZnVuY3Rpb24odmVuZG9yKSB7XG4gICAgICBIYW1tZXIudXRpbHMuZWFjaChjc3NfcHJvcHMsIGZ1bmN0aW9uKHZhbHVlLCBwcm9wKSB7XG4gICAgICAgICAgLy8gdmVuZGVyIHByZWZpeCBhdCB0aGUgcHJvcGVydHlcbiAgICAgICAgICBpZih2ZW5kb3IpIHtcbiAgICAgICAgICAgIHByb3AgPSB2ZW5kb3IgKyBwcm9wLnN1YnN0cmluZygwLCAxKS50b1VwcGVyQ2FzZSgpICsgcHJvcC5zdWJzdHJpbmcoMSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIHNldCB0aGUgc3R5bGVcbiAgICAgICAgICBpZihwcm9wIGluIGVsZW1lbnQuc3R5bGUpIHtcbiAgICAgICAgICAgIGVsZW1lbnQuc3R5bGVbcHJvcF0gPSB2YWx1ZTtcbiAgICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIC8vIGFsc28gdGhlIGRpc2FibGUgb25zZWxlY3RzdGFydFxuICAgIGlmKGNzc19wcm9wcy51c2VyU2VsZWN0ID09ICdub25lJykge1xuICAgICAgZWxlbWVudC5vbnNlbGVjdHN0YXJ0ID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gYW5kIGRpc2FibGUgb25kcmFnc3RhcnRcbiAgICBpZihjc3NfcHJvcHMudXNlckRyYWcgPT0gJ25vbmUnKSB7XG4gICAgICBlbGVtZW50Lm9uZHJhZ3N0YXJ0ID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH07XG4gICAgfVxuICB9LFxuXG5cbiAgLyoqXG4gICAqIHJldmVydHMgYWxsIGNoYW5nZXMgbWFkZSBieSAnc3RvcERlZmF1bHRCcm93c2VyQmVoYXZpb3InXG4gICAqIEBwYXJhbSAgIHtIdG1sRWxlbWVudH0gICBlbGVtZW50XG4gICAqIEBwYXJhbSAgIHtPYmplY3R9ICAgICAgICBjc3NfcHJvcHNcbiAgICovXG4gIHN0YXJ0RGVmYXVsdEJyb3dzZXJCZWhhdmlvcjogZnVuY3Rpb24gc3RhcnREZWZhdWx0QnJvd3NlckJlaGF2aW9yKGVsZW1lbnQsIGNzc19wcm9wcykge1xuICAgIGlmKCFjc3NfcHJvcHMgfHwgIWVsZW1lbnQgfHwgIWVsZW1lbnQuc3R5bGUpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyB3aXRoIGNzcyBwcm9wZXJ0aWVzIGZvciBtb2Rlcm4gYnJvd3NlcnNcbiAgICBIYW1tZXIudXRpbHMuZWFjaChbJ3dlYmtpdCcsICdraHRtbCcsICdtb3onLCAnTW96JywgJ21zJywgJ28nLCAnJ10sIGZ1bmN0aW9uKHZlbmRvcikge1xuICAgICAgSGFtbWVyLnV0aWxzLmVhY2goY3NzX3Byb3BzLCBmdW5jdGlvbih2YWx1ZSwgcHJvcCkge1xuICAgICAgICAgIC8vIHZlbmRlciBwcmVmaXggYXQgdGhlIHByb3BlcnR5XG4gICAgICAgICAgaWYodmVuZG9yKSB7XG4gICAgICAgICAgICBwcm9wID0gdmVuZG9yICsgcHJvcC5zdWJzdHJpbmcoMCwgMSkudG9VcHBlckNhc2UoKSArIHByb3Auc3Vic3RyaW5nKDEpO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyByZXNldCB0aGUgc3R5bGVcbiAgICAgICAgICBpZihwcm9wIGluIGVsZW1lbnQuc3R5bGUpIHtcbiAgICAgICAgICAgIGVsZW1lbnQuc3R5bGVbcHJvcF0gPSAnJztcbiAgICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIC8vIGFsc28gdGhlIGVuYWJsZSBvbnNlbGVjdHN0YXJ0XG4gICAgaWYoY3NzX3Byb3BzLnVzZXJTZWxlY3QgPT0gJ25vbmUnKSB7XG4gICAgICBlbGVtZW50Lm9uc2VsZWN0c3RhcnQgPSBudWxsO1xuICAgIH1cblxuICAgIC8vIGFuZCBlbmFibGUgb25kcmFnc3RhcnRcbiAgICBpZihjc3NfcHJvcHMudXNlckRyYWcgPT0gJ25vbmUnKSB7XG4gICAgICBlbGVtZW50Lm9uZHJhZ3N0YXJ0ID0gbnVsbDtcbiAgICB9XG4gIH1cbn07XG5cblxuLyoqXG4gKiBjcmVhdGUgbmV3IGhhbW1lciBpbnN0YW5jZVxuICogYWxsIG1ldGhvZHMgc2hvdWxkIHJldHVybiB0aGUgaW5zdGFuY2UgaXRzZWxmLCBzbyBpdCBpcyBjaGFpbmFibGUuXG4gKiBAcGFyYW0gICB7SFRNTEVsZW1lbnR9ICAgICAgIGVsZW1lbnRcbiAqIEBwYXJhbSAgIHtPYmplY3R9ICAgICAgICAgICAgW29wdGlvbnM9e31dXG4gKiBAcmV0dXJucyB7SGFtbWVyLkluc3RhbmNlfVxuICogQGNvbnN0cnVjdG9yXG4gKi9cbkhhbW1lci5JbnN0YW5jZSA9IGZ1bmN0aW9uKGVsZW1lbnQsIG9wdGlvbnMpIHtcbiAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gIC8vIHNldHVwIEhhbW1lckpTIHdpbmRvdyBldmVudHMgYW5kIHJlZ2lzdGVyIGFsbCBnZXN0dXJlc1xuICAvLyB0aGlzIGFsc28gc2V0cyB1cCB0aGUgZGVmYXVsdCBvcHRpb25zXG4gIHNldHVwKCk7XG5cbiAgdGhpcy5lbGVtZW50ID0gZWxlbWVudDtcblxuICAvLyBzdGFydC9zdG9wIGRldGVjdGlvbiBvcHRpb25cbiAgdGhpcy5lbmFibGVkID0gdHJ1ZTtcblxuICAvLyBtZXJnZSBvcHRpb25zXG4gIHRoaXMub3B0aW9ucyA9IEhhbW1lci51dGlscy5leHRlbmQoXG4gICAgSGFtbWVyLnV0aWxzLmV4dGVuZCh7fSwgSGFtbWVyLmRlZmF1bHRzKSxcbiAgICBvcHRpb25zIHx8IHt9KTtcblxuICAvLyBhZGQgc29tZSBjc3MgdG8gdGhlIGVsZW1lbnQgdG8gcHJldmVudCB0aGUgYnJvd3NlciBmcm9tIGRvaW5nIGl0cyBuYXRpdmUgYmVoYXZvaXJcbiAgaWYodGhpcy5vcHRpb25zLnN0b3BfYnJvd3Nlcl9iZWhhdmlvcikge1xuICAgIEhhbW1lci51dGlscy5zdG9wRGVmYXVsdEJyb3dzZXJCZWhhdmlvcih0aGlzLmVsZW1lbnQsIHRoaXMub3B0aW9ucy5zdG9wX2Jyb3dzZXJfYmVoYXZpb3IpO1xuICB9XG5cbiAgLy8gc3RhcnQgZGV0ZWN0aW9uIG9uIHRvdWNoc3RhcnRcbiAgdGhpcy5fZXZlbnRTdGFydEhhbmRsZXIgPSBIYW1tZXIuZXZlbnQub25Ub3VjaChlbGVtZW50LCBIYW1tZXIuRVZFTlRfU1RBUlQsIGZ1bmN0aW9uKGV2KSB7XG4gICAgaWYoc2VsZi5lbmFibGVkKSB7XG4gICAgICBIYW1tZXIuZGV0ZWN0aW9uLnN0YXJ0RGV0ZWN0KHNlbGYsIGV2KTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIGtlZXAgYSBsaXN0IG9mIHVzZXIgZXZlbnQgaGFuZGxlcnMgd2hpY2ggbmVlZHMgdG8gYmUgcmVtb3ZlZCB3aGVuIGNhbGxpbmcgJ2Rpc3Bvc2UnXG4gIHRoaXMuX2V2ZW50SGFuZGxlciA9IFtdO1xuXG4gIC8vIHJldHVybiBpbnN0YW5jZVxuICByZXR1cm4gdGhpcztcbn07XG5cblxuSGFtbWVyLkluc3RhbmNlLnByb3RvdHlwZSA9IHtcbiAgLyoqXG4gICAqIGJpbmQgZXZlbnRzIHRvIHRoZSBpbnN0YW5jZVxuICAgKiBAcGFyYW0gICB7U3RyaW5nfSAgICAgIGdlc3R1cmVcbiAgICogQHBhcmFtICAge0Z1bmN0aW9ufSAgICBoYW5kbGVyXG4gICAqIEByZXR1cm5zIHtIYW1tZXIuSW5zdGFuY2V9XG4gICAqL1xuICBvbjogZnVuY3Rpb24gb25FdmVudChnZXN0dXJlLCBoYW5kbGVyKSB7XG4gICAgdmFyIGdlc3R1cmVzID0gZ2VzdHVyZS5zcGxpdCgnICcpO1xuICAgIEhhbW1lci51dGlscy5lYWNoKGdlc3R1cmVzLCBmdW5jdGlvbihnZXN0dXJlKSB7XG4gICAgICB0aGlzLmVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihnZXN0dXJlLCBoYW5kbGVyLCBmYWxzZSk7XG4gICAgICB0aGlzLl9ldmVudEhhbmRsZXIucHVzaCh7IGdlc3R1cmU6IGdlc3R1cmUsIGhhbmRsZXI6IGhhbmRsZXIgfSk7XG4gICAgfSwgdGhpcyk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH0sXG5cblxuICAvKipcbiAgICogdW5iaW5kIGV2ZW50cyB0byB0aGUgaW5zdGFuY2VcbiAgICogQHBhcmFtICAge1N0cmluZ30gICAgICBnZXN0dXJlXG4gICAqIEBwYXJhbSAgIHtGdW5jdGlvbn0gICAgaGFuZGxlclxuICAgKiBAcmV0dXJucyB7SGFtbWVyLkluc3RhbmNlfVxuICAgKi9cbiAgb2ZmOiBmdW5jdGlvbiBvZmZFdmVudChnZXN0dXJlLCBoYW5kbGVyKSB7XG4gICAgdmFyIGdlc3R1cmVzID0gZ2VzdHVyZS5zcGxpdCgnICcpO1xuICAgIEhhbW1lci51dGlscy5lYWNoKGdlc3R1cmVzLCBmdW5jdGlvbihnZXN0dXJlKSB7XG4gICAgICB0aGlzLmVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lcihnZXN0dXJlLCBoYW5kbGVyLCBmYWxzZSk7XG5cbiAgICAgIC8vIHJlbW92ZSB0aGUgZXZlbnQgaGFuZGxlciBmcm9tIHRoZSBpbnRlcm5hbCBsaXN0XG4gICAgICB2YXIgaW5kZXggPSAtMTtcbiAgICAgIEhhbW1lci51dGlscy5lYWNoKHRoaXMuX2V2ZW50SGFuZGxlciwgZnVuY3Rpb24oZXZlbnRIYW5kbGVyLCBpKSB7XG4gICAgICAgIGlmIChpbmRleCA9PT0gLTEgJiYgZXZlbnRIYW5kbGVyLmdlc3R1cmUgPT09IGdlc3R1cmUgJiYgZXZlbnRIYW5kbGVyLmhhbmRsZXIgPT09IGhhbmRsZXIpIHtcbiAgICAgICAgICBpbmRleCA9IGk7XG4gICAgICAgIH1cbiAgICAgIH0sIHRoaXMpO1xuXG4gICAgICBpZiAoaW5kZXggPiAtMSkge1xuICAgICAgICB0aGlzLl9ldmVudEhhbmRsZXIuc3BsaWNlKGluZGV4LCAxKTtcbiAgICAgIH1cbiAgICB9LCB0aGlzKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfSxcblxuXG4gIC8qKlxuICAgKiB0cmlnZ2VyIGdlc3R1cmUgZXZlbnRcbiAgICogQHBhcmFtICAge1N0cmluZ30gICAgICBnZXN0dXJlXG4gICAqIEBwYXJhbSAgIHtPYmplY3R9ICAgICAgW2V2ZW50RGF0YV1cbiAgICogQHJldHVybnMge0hhbW1lci5JbnN0YW5jZX1cbiAgICovXG4gIHRyaWdnZXI6IGZ1bmN0aW9uIHRyaWdnZXJFdmVudChnZXN0dXJlLCBldmVudERhdGEpIHtcbiAgICAvLyBvcHRpb25hbFxuICAgIGlmKCFldmVudERhdGEpIHtcbiAgICAgIGV2ZW50RGF0YSA9IHt9O1xuICAgIH1cblxuICAgIC8vIGNyZWF0ZSBET00gZXZlbnRcbiAgICB2YXIgZXZlbnQgPSBIYW1tZXIuRE9DVU1FTlQuY3JlYXRlRXZlbnQoJ0V2ZW50Jyk7XG4gICAgZXZlbnQuaW5pdEV2ZW50KGdlc3R1cmUsIHRydWUsIHRydWUpO1xuICAgIGV2ZW50Lmdlc3R1cmUgPSBldmVudERhdGE7XG5cbiAgICAvLyB0cmlnZ2VyIG9uIHRoZSB0YXJnZXQgaWYgaXQgaXMgaW4gdGhlIGluc3RhbmNlIGVsZW1lbnQsXG4gICAgLy8gdGhpcyBpcyBmb3IgZXZlbnQgZGVsZWdhdGlvbiB0cmlja3NcbiAgICB2YXIgZWxlbWVudCA9IHRoaXMuZWxlbWVudDtcbiAgICBpZihIYW1tZXIudXRpbHMuaGFzUGFyZW50KGV2ZW50RGF0YS50YXJnZXQsIGVsZW1lbnQpKSB7XG4gICAgICBlbGVtZW50ID0gZXZlbnREYXRhLnRhcmdldDtcbiAgICB9XG5cbiAgICBlbGVtZW50LmRpc3BhdGNoRXZlbnQoZXZlbnQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9LFxuXG5cbiAgLyoqXG4gICAqIGVuYWJsZSBvZiBkaXNhYmxlIGhhbW1lci5qcyBkZXRlY3Rpb25cbiAgICogQHBhcmFtICAge0Jvb2xlYW59ICAgc3RhdGVcbiAgICogQHJldHVybnMge0hhbW1lci5JbnN0YW5jZX1cbiAgICovXG4gIGVuYWJsZTogZnVuY3Rpb24gZW5hYmxlKHN0YXRlKSB7XG4gICAgdGhpcy5lbmFibGVkID0gc3RhdGU7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH0sXG5cblxuICAvKipcbiAgICogZGlzcG9zZSB0aGlzIGhhbW1lciBpbnN0YW5jZVxuICAgKiBAcmV0dXJucyB7SGFtbWVyLkluc3RhbmNlfVxuICAgKi9cbiAgZGlzcG9zZTogZnVuY3Rpb24gZGlzcG9zZSgpIHtcblxuICAgIC8vIHVuZG8gYWxsIGNoYW5nZXMgbWFkZSBieSBzdG9wX2Jyb3dzZXJfYmVoYXZpb3JcbiAgICBpZih0aGlzLm9wdGlvbnMuc3RvcF9icm93c2VyX2JlaGF2aW9yKSB7XG4gICAgICBIYW1tZXIudXRpbHMuc3RhcnREZWZhdWx0QnJvd3NlckJlaGF2aW9yKHRoaXMuZWxlbWVudCwgdGhpcy5vcHRpb25zLnN0b3BfYnJvd3Nlcl9iZWhhdmlvcik7XG4gICAgfVxuXG4gICAgLy8gdW5iaW5kIGFsbCBjdXN0b20gZXZlbnQgaGFuZGxlcnNcbiAgICBIYW1tZXIudXRpbHMuZWFjaCh0aGlzLl9ldmVudEhhbmRsZXIsIGZ1bmN0aW9uKGV2ZW50SGFuZGxlcikge1xuICAgICAgdGhpcy5lbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoZXZlbnRIYW5kbGVyLmdlc3R1cmUsIGV2ZW50SGFuZGxlci5oYW5kbGVyLCBmYWxzZSk7XG4gICAgfSwgdGhpcyk7XG4gICAgdGhpcy5fZXZlbnRIYW5kbGVyLmxlbmd0aCA9IDA7XG5cbiAgICAvLyB1bmJpbmQgdGhlIHN0YXJ0IGV2ZW50IGxpc3RlbmVyXG4gICAgSGFtbWVyLmV2ZW50LnVuYmluZERvbSh0aGlzLmVsZW1lbnQsIEhhbW1lci5FVkVOVF9UWVBFU1tIYW1tZXIuRVZFTlRfU1RBUlRdLCB0aGlzLl9ldmVudFN0YXJ0SGFuZGxlcik7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn07XG5cblxuLyoqXG4gKiB0aGlzIGhvbGRzIHRoZSBsYXN0IG1vdmUgZXZlbnQsXG4gKiB1c2VkIHRvIGZpeCBlbXB0eSB0b3VjaGVuZCBpc3N1ZVxuICogc2VlIHRoZSBvblRvdWNoIGV2ZW50IGZvciBhbiBleHBsYW5hdGlvblxuICogQHR5cGUge09iamVjdH1cbiAqL1xudmFyIGxhc3RfbW92ZV9ldmVudCA9IG51bGw7XG5cblxuLyoqXG4gKiB3aGVuIHRoZSBtb3VzZSBpcyBob2xkIGRvd24sIHRoaXMgaXMgdHJ1ZVxuICogQHR5cGUge0Jvb2xlYW59XG4gKi9cbnZhciBlbmFibGVfZGV0ZWN0ID0gZmFsc2U7XG5cblxuLyoqXG4gKiB3aGVuIHRvdWNoIGV2ZW50cyBoYXZlIGJlZW4gZmlyZWQsIHRoaXMgaXMgdHJ1ZVxuICogQHR5cGUge0Jvb2xlYW59XG4gKi9cbnZhciB0b3VjaF90cmlnZ2VyZWQgPSBmYWxzZTtcblxuXG5IYW1tZXIuZXZlbnQgPSB7XG4gIC8qKlxuICAgKiBzaW1wbGUgYWRkRXZlbnRMaXN0ZW5lclxuICAgKiBAcGFyYW0gICB7SFRNTEVsZW1lbnR9ICAgZWxlbWVudFxuICAgKiBAcGFyYW0gICB7U3RyaW5nfSAgICAgICAgdHlwZVxuICAgKiBAcGFyYW0gICB7RnVuY3Rpb259ICAgICAgaGFuZGxlclxuICAgKi9cbiAgYmluZERvbTogZnVuY3Rpb24oZWxlbWVudCwgdHlwZSwgaGFuZGxlcikge1xuICAgIHZhciB0eXBlcyA9IHR5cGUuc3BsaXQoJyAnKTtcbiAgICBIYW1tZXIudXRpbHMuZWFjaCh0eXBlcywgZnVuY3Rpb24odHlwZSl7XG4gICAgICBlbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIodHlwZSwgaGFuZGxlciwgZmFsc2UpO1xuICAgIH0pO1xuICB9LFxuXG5cbiAgLyoqXG4gICAqIHNpbXBsZSByZW1vdmVFdmVudExpc3RlbmVyXG4gICAqIEBwYXJhbSAgIHtIVE1MRWxlbWVudH0gICBlbGVtZW50XG4gICAqIEBwYXJhbSAgIHtTdHJpbmd9ICAgICAgICB0eXBlXG4gICAqIEBwYXJhbSAgIHtGdW5jdGlvbn0gICAgICBoYW5kbGVyXG4gICAqL1xuICB1bmJpbmREb206IGZ1bmN0aW9uKGVsZW1lbnQsIHR5cGUsIGhhbmRsZXIpIHtcbiAgICB2YXIgdHlwZXMgPSB0eXBlLnNwbGl0KCcgJyk7XG4gICAgSGFtbWVyLnV0aWxzLmVhY2godHlwZXMsIGZ1bmN0aW9uKHR5cGUpe1xuICAgICAgZWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKHR5cGUsIGhhbmRsZXIsIGZhbHNlKTtcbiAgICB9KTtcbiAgfSxcblxuXG4gIC8qKlxuICAgKiB0b3VjaCBldmVudHMgd2l0aCBtb3VzZSBmYWxsYmFja1xuICAgKiBAcGFyYW0gICB7SFRNTEVsZW1lbnR9ICAgZWxlbWVudFxuICAgKiBAcGFyYW0gICB7U3RyaW5nfSAgICAgICAgZXZlbnRUeXBlICAgICAgICBsaWtlIEhhbW1lci5FVkVOVF9NT1ZFXG4gICAqIEBwYXJhbSAgIHtGdW5jdGlvbn0gICAgICBoYW5kbGVyXG4gICAqL1xuICBvblRvdWNoOiBmdW5jdGlvbiBvblRvdWNoKGVsZW1lbnQsIGV2ZW50VHlwZSwgaGFuZGxlcikge1xuICAgIHZhciBzZWxmID0gdGhpcztcblxuICAgIHZhciBmbiA9IGZ1bmN0aW9uIGJpbmREb21PblRvdWNoKGV2KSB7XG4gICAgICB2YXIgc291cmNlRXZlbnRUeXBlID0gZXYudHlwZS50b0xvd2VyQ2FzZSgpO1xuXG4gICAgICAvLyBvbm1vdXNldXAsIGJ1dCB3aGVuIHRvdWNoZW5kIGhhcyBiZWVuIGZpcmVkIHdlIGRvIG5vdGhpbmcuXG4gICAgICAvLyB0aGlzIGlzIGZvciB0b3VjaGRldmljZXMgd2hpY2ggYWxzbyBmaXJlIGEgbW91c2V1cCBvbiB0b3VjaGVuZFxuICAgICAgaWYoc291cmNlRXZlbnRUeXBlLm1hdGNoKC9tb3VzZS8pICYmIHRvdWNoX3RyaWdnZXJlZCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIC8vIG1vdXNlYnV0dG9uIG11c3QgYmUgZG93biBvciBhIHRvdWNoIGV2ZW50XG4gICAgICBlbHNlIGlmKHNvdXJjZUV2ZW50VHlwZS5tYXRjaCgvdG91Y2gvKSB8fCAgIC8vIHRvdWNoIGV2ZW50cyBhcmUgYWx3YXlzIG9uIHNjcmVlblxuICAgICAgICBzb3VyY2VFdmVudFR5cGUubWF0Y2goL3BvaW50ZXJkb3duLykgfHwgLy8gcG9pbnRlcmV2ZW50cyB0b3VjaFxuICAgICAgICAoc291cmNlRXZlbnRUeXBlLm1hdGNoKC9tb3VzZS8pICYmIGV2LndoaWNoID09PSAxKSAgIC8vIG1vdXNlIGlzIHByZXNzZWRcbiAgICAgICAgKSB7XG4gICAgICAgIGVuYWJsZV9kZXRlY3QgPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICAvLyBtb3VzZSBpc24ndCBwcmVzc2VkXG4gICAgICBlbHNlIGlmKHNvdXJjZUV2ZW50VHlwZS5tYXRjaCgvbW91c2UvKSAmJiAhZXYud2hpY2gpIHtcbiAgICAgICAgZW5hYmxlX2RldGVjdCA9IGZhbHNlO1xuICAgICAgfVxuXG5cbiAgICAgIC8vIHdlIGFyZSBpbiBhIHRvdWNoIGV2ZW50LCBzZXQgdGhlIHRvdWNoIHRyaWdnZXJlZCBib29sIHRvIHRydWUsXG4gICAgICAvLyB0aGlzIGZvciB0aGUgY29uZmxpY3RzIHRoYXQgbWF5IG9jY3VyIG9uIGlvcyBhbmQgYW5kcm9pZFxuICAgICAgaWYoc291cmNlRXZlbnRUeXBlLm1hdGNoKC90b3VjaHxwb2ludGVyLykpIHtcbiAgICAgICAgdG91Y2hfdHJpZ2dlcmVkID0gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgLy8gY291bnQgdGhlIHRvdGFsIHRvdWNoZXMgb24gdGhlIHNjcmVlblxuICAgICAgdmFyIGNvdW50X3RvdWNoZXMgPSAwO1xuXG4gICAgICAvLyB3aGVuIHRvdWNoIGhhcyBiZWVuIHRyaWdnZXJlZCBpbiB0aGlzIGRldGVjdGlvbiBzZXNzaW9uXG4gICAgICAvLyBhbmQgd2UgYXJlIG5vdyBoYW5kbGluZyBhIG1vdXNlIGV2ZW50LCB3ZSBzdG9wIHRoYXQgdG8gcHJldmVudCBjb25mbGljdHNcbiAgICAgIGlmKGVuYWJsZV9kZXRlY3QpIHtcbiAgICAgICAgLy8gdXBkYXRlIHBvaW50ZXJldmVudFxuICAgICAgICBpZihIYW1tZXIuSEFTX1BPSU5URVJFVkVOVFMgJiYgZXZlbnRUeXBlICE9IEhhbW1lci5FVkVOVF9FTkQpIHtcbiAgICAgICAgICBjb3VudF90b3VjaGVzID0gSGFtbWVyLlBvaW50ZXJFdmVudC51cGRhdGVQb2ludGVyKGV2ZW50VHlwZSwgZXYpO1xuICAgICAgICB9XG4gICAgICAgIC8vIHRvdWNoXG4gICAgICAgIGVsc2UgaWYoc291cmNlRXZlbnRUeXBlLm1hdGNoKC90b3VjaC8pKSB7XG4gICAgICAgICAgY291bnRfdG91Y2hlcyA9IGV2LnRvdWNoZXMubGVuZ3RoO1xuICAgICAgICB9XG4gICAgICAgIC8vIG1vdXNlXG4gICAgICAgIGVsc2UgaWYoIXRvdWNoX3RyaWdnZXJlZCkge1xuICAgICAgICAgIGNvdW50X3RvdWNoZXMgPSBzb3VyY2VFdmVudFR5cGUubWF0Y2goL3VwLykgPyAwIDogMTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGlmIHdlIGFyZSBpbiBhIGVuZCBldmVudCwgYnV0IHdoZW4gd2UgcmVtb3ZlIG9uZSB0b3VjaCBhbmRcbiAgICAgICAgLy8gd2Ugc3RpbGwgaGF2ZSBlbm91Z2gsIHNldCBldmVudFR5cGUgdG8gbW92ZVxuICAgICAgICBpZihjb3VudF90b3VjaGVzID4gMCAmJiBldmVudFR5cGUgPT0gSGFtbWVyLkVWRU5UX0VORCkge1xuICAgICAgICAgIGV2ZW50VHlwZSA9IEhhbW1lci5FVkVOVF9NT1ZFO1xuICAgICAgICB9XG4gICAgICAgIC8vIG5vIHRvdWNoZXMsIGZvcmNlIHRoZSBlbmQgZXZlbnRcbiAgICAgICAgZWxzZSBpZighY291bnRfdG91Y2hlcykge1xuICAgICAgICAgIGV2ZW50VHlwZSA9IEhhbW1lci5FVkVOVF9FTkQ7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBzdG9yZSB0aGUgbGFzdCBtb3ZlIGV2ZW50XG4gICAgICAgIGlmKGNvdW50X3RvdWNoZXMgfHwgbGFzdF9tb3ZlX2V2ZW50ID09PSBudWxsKSB7XG4gICAgICAgICAgbGFzdF9tb3ZlX2V2ZW50ID0gZXY7XG4gICAgICAgIH1cblxuICAgICAgICAvLyB0cmlnZ2VyIHRoZSBoYW5kbGVyXG4gICAgICAgIGhhbmRsZXIuY2FsbChIYW1tZXIuZGV0ZWN0aW9uLCBzZWxmLmNvbGxlY3RFdmVudERhdGEoZWxlbWVudCwgZXZlbnRUeXBlLCBzZWxmLmdldFRvdWNoTGlzdChsYXN0X21vdmVfZXZlbnQsIGV2ZW50VHlwZSksIGV2KSk7XG5cbiAgICAgICAgLy8gcmVtb3ZlIHBvaW50ZXJldmVudCBmcm9tIGxpc3RcbiAgICAgICAgaWYoSGFtbWVyLkhBU19QT0lOVEVSRVZFTlRTICYmIGV2ZW50VHlwZSA9PSBIYW1tZXIuRVZFTlRfRU5EKSB7XG4gICAgICAgICAgY291bnRfdG91Y2hlcyA9IEhhbW1lci5Qb2ludGVyRXZlbnQudXBkYXRlUG9pbnRlcihldmVudFR5cGUsIGV2KTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBvbiB0aGUgZW5kIHdlIHJlc2V0IGV2ZXJ5dGhpbmdcbiAgICAgIGlmKCFjb3VudF90b3VjaGVzKSB7XG4gICAgICAgIGxhc3RfbW92ZV9ldmVudCA9IG51bGw7XG4gICAgICAgIGVuYWJsZV9kZXRlY3QgPSBmYWxzZTtcbiAgICAgICAgdG91Y2hfdHJpZ2dlcmVkID0gZmFsc2U7XG4gICAgICAgIEhhbW1lci5Qb2ludGVyRXZlbnQucmVzZXQoKTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5iaW5kRG9tKGVsZW1lbnQsIEhhbW1lci5FVkVOVF9UWVBFU1tldmVudFR5cGVdLCBmbik7XG5cbiAgICAvLyByZXR1cm4gdGhlIGJvdW5kIGZ1bmN0aW9uIHRvIGJlIGFibGUgdG8gdW5iaW5kIGl0IGxhdGVyXG4gICAgcmV0dXJuIGZuO1xuICAgIH0sXG5cblxuICAvKipcbiAgICogd2UgaGF2ZSBkaWZmZXJlbnQgZXZlbnRzIGZvciBlYWNoIGRldmljZS9icm93c2VyXG4gICAqIGRldGVybWluZSB3aGF0IHdlIG5lZWQgYW5kIHNldCB0aGVtIGluIHRoZSBIYW1tZXIuRVZFTlRfVFlQRVMgY29uc3RhbnRcbiAgICovXG4gIGRldGVybWluZUV2ZW50VHlwZXM6IGZ1bmN0aW9uIGRldGVybWluZUV2ZW50VHlwZXMoKSB7XG4gICAgLy8gZGV0ZXJtaW5lIHRoZSBldmVudHR5cGUgd2Ugd2FudCB0byBzZXRcbiAgICB2YXIgdHlwZXM7XG5cbiAgICAvLyBwb2ludGVyRXZlbnRzIG1hZ2ljXG4gICAgaWYoSGFtbWVyLkhBU19QT0lOVEVSRVZFTlRTKSB7XG4gICAgICB0eXBlcyA9IEhhbW1lci5Qb2ludGVyRXZlbnQuZ2V0RXZlbnRzKCk7XG4gICAgfVxuICAgIC8vIG9uIEFuZHJvaWQsIGlPUywgYmxhY2tiZXJyeSwgd2luZG93cyBtb2JpbGUgd2UgZG9udCB3YW50IGFueSBtb3VzZWV2ZW50c1xuICAgIGVsc2UgaWYoSGFtbWVyLk5PX01PVVNFRVZFTlRTKSB7XG4gICAgICB0eXBlcyA9IFtcbiAgICAgICAgJ3RvdWNoc3RhcnQnLFxuICAgICAgICAndG91Y2htb3ZlJyxcbiAgICAgICAgJ3RvdWNoZW5kIHRvdWNoY2FuY2VsJ107XG4gICAgfVxuICAgIC8vIGZvciBub24gcG9pbnRlciBldmVudHMgYnJvd3NlcnMgYW5kIG1peGVkIGJyb3dzZXJzLFxuICAgIC8vIGxpa2UgY2hyb21lIG9uIHdpbmRvd3M4IHRvdWNoIGxhcHRvcFxuICAgIGVsc2Uge1xuICAgICAgdHlwZXMgPSBbXG4gICAgICAgICd0b3VjaHN0YXJ0IG1vdXNlZG93bicsXG4gICAgICAgICd0b3VjaG1vdmUgbW91c2Vtb3ZlJyxcbiAgICAgICAgJ3RvdWNoZW5kIHRvdWNoY2FuY2VsIG1vdXNldXAnXTtcbiAgICB9XG5cbiAgICBIYW1tZXIuRVZFTlRfVFlQRVNbSGFtbWVyLkVWRU5UX1NUQVJUXSA9IHR5cGVzWzBdO1xuICAgIEhhbW1lci5FVkVOVF9UWVBFU1tIYW1tZXIuRVZFTlRfTU9WRV0gPSB0eXBlc1sxXTtcbiAgICBIYW1tZXIuRVZFTlRfVFlQRVNbSGFtbWVyLkVWRU5UX0VORF0gPSB0eXBlc1syXTtcbiAgfSxcblxuXG4gIC8qKlxuICAgKiBjcmVhdGUgdG91Y2hsaXN0IGRlcGVuZGluZyBvbiB0aGUgZXZlbnRcbiAgICogQHBhcmFtICAge09iamVjdH0gICAgZXZcbiAgICogQHBhcmFtICAge1N0cmluZ30gICAgZXZlbnRUeXBlICAgdXNlZCBieSB0aGUgZmFrZW11bHRpdG91Y2ggcGx1Z2luXG4gICAqL1xuICBnZXRUb3VjaExpc3Q6IGZ1bmN0aW9uIGdldFRvdWNoTGlzdChldi8qLCBldmVudFR5cGUqLykge1xuICAgIC8vIGdldCB0aGUgZmFrZSBwb2ludGVyRXZlbnQgdG91Y2hsaXN0XG4gICAgaWYoSGFtbWVyLkhBU19QT0lOVEVSRVZFTlRTKSB7XG4gICAgICByZXR1cm4gSGFtbWVyLlBvaW50ZXJFdmVudC5nZXRUb3VjaExpc3QoKTtcbiAgICB9XG4gICAgLy8gZ2V0IHRoZSB0b3VjaGxpc3RcbiAgICBlbHNlIGlmKGV2LnRvdWNoZXMpIHtcbiAgICAgIHJldHVybiBldi50b3VjaGVzO1xuICAgIH1cbiAgICAvLyBtYWtlIGZha2UgdG91Y2hsaXN0IGZyb20gbW91c2UgcG9zaXRpb25cbiAgICBlbHNlIHtcbiAgICAgIGV2LmlkZW50aWZpZXIgPSAxO1xuICAgICAgcmV0dXJuIFtldl07XG4gICAgfVxuICB9LFxuXG5cbiAgLyoqXG4gICAqIGNvbGxlY3QgZXZlbnQgZGF0YSBmb3IgSGFtbWVyIGpzXG4gICAqIEBwYXJhbSAgIHtIVE1MRWxlbWVudH0gICBlbGVtZW50XG4gICAqIEBwYXJhbSAgIHtTdHJpbmd9ICAgICAgICBldmVudFR5cGUgICAgICAgIGxpa2UgSGFtbWVyLkVWRU5UX01PVkVcbiAgICogQHBhcmFtICAge09iamVjdH0gICAgICAgIGV2ZW50RGF0YVxuICAgKi9cbiAgY29sbGVjdEV2ZW50RGF0YTogZnVuY3Rpb24gY29sbGVjdEV2ZW50RGF0YShlbGVtZW50LCBldmVudFR5cGUsIHRvdWNoZXMsIGV2KSB7XG4gICAgLy8gZmluZCBvdXQgcG9pbnRlclR5cGVcbiAgICB2YXIgcG9pbnRlclR5cGUgPSBIYW1tZXIuUE9JTlRFUl9UT1VDSDtcbiAgICBpZihldi50eXBlLm1hdGNoKC9tb3VzZS8pIHx8IEhhbW1lci5Qb2ludGVyRXZlbnQubWF0Y2hUeXBlKEhhbW1lci5QT0lOVEVSX01PVVNFLCBldikpIHtcbiAgICAgIHBvaW50ZXJUeXBlID0gSGFtbWVyLlBPSU5URVJfTU9VU0U7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGNlbnRlciAgICAgOiBIYW1tZXIudXRpbHMuZ2V0Q2VudGVyKHRvdWNoZXMpLFxuICAgICAgdGltZVN0YW1wICA6IG5ldyBEYXRlKCkuZ2V0VGltZSgpLFxuICAgICAgdGFyZ2V0ICAgICA6IGV2LnRhcmdldCxcbiAgICAgIHRvdWNoZXMgICAgOiB0b3VjaGVzLFxuICAgICAgZXZlbnRUeXBlICA6IGV2ZW50VHlwZSxcbiAgICAgIHBvaW50ZXJUeXBlOiBwb2ludGVyVHlwZSxcbiAgICAgIHNyY0V2ZW50ICAgOiBldixcblxuICAgICAgLyoqXG4gICAgICAgKiBwcmV2ZW50IHRoZSBicm93c2VyIGRlZmF1bHQgYWN0aW9uc1xuICAgICAgICogbW9zdGx5IHVzZWQgdG8gZGlzYWJsZSBzY3JvbGxpbmcgb2YgdGhlIGJyb3dzZXJcbiAgICAgICAqL1xuICAgICAgcHJldmVudERlZmF1bHQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICBpZih0aGlzLnNyY0V2ZW50LnByZXZlbnRNYW5pcHVsYXRpb24pIHtcbiAgICAgICAgICB0aGlzLnNyY0V2ZW50LnByZXZlbnRNYW5pcHVsYXRpb24oKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmKHRoaXMuc3JjRXZlbnQucHJldmVudERlZmF1bHQpIHtcbiAgICAgICAgICB0aGlzLnNyY0V2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIH1cbiAgICAgIH0sXG5cbiAgICAgIC8qKlxuICAgICAgICogc3RvcCBidWJibGluZyB0aGUgZXZlbnQgdXAgdG8gaXRzIHBhcmVudHNcbiAgICAgICAqL1xuICAgICAgc3RvcFByb3BhZ2F0aW9uOiBmdW5jdGlvbigpIHtcbiAgICAgICAgdGhpcy5zcmNFdmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgIH0sXG5cbiAgICAgIC8qKlxuICAgICAgICogaW1tZWRpYXRlbHkgc3RvcCBnZXN0dXJlIGRldGVjdGlvblxuICAgICAgICogbWlnaHQgYmUgdXNlZnVsIGFmdGVyIGEgc3dpcGUgd2FzIGRldGVjdGVkXG4gICAgICAgKiBAcmV0dXJuIHsqfVxuICAgICAgICovXG4gICAgICBzdG9wRGV0ZWN0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIEhhbW1lci5kZXRlY3Rpb24uc3RvcERldGVjdCgpO1xuICAgICAgfVxuICAgIH07XG4gIH1cbn07XG5cbkhhbW1lci5Qb2ludGVyRXZlbnQgPSB7XG4gIC8qKlxuICAgKiBob2xkcyBhbGwgcG9pbnRlcnNcbiAgICogQHR5cGUge09iamVjdH1cbiAgICovXG4gIHBvaW50ZXJzOiB7fSxcblxuICAvKipcbiAgICogZ2V0IGEgbGlzdCBvZiBwb2ludGVyc1xuICAgKiBAcmV0dXJucyB7QXJyYXl9ICAgICB0b3VjaGxpc3RcbiAgICovXG4gIGdldFRvdWNoTGlzdDogZnVuY3Rpb24oKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciB0b3VjaGxpc3QgPSBbXTtcblxuICAgIC8vIHdlIGNhbiB1c2UgZm9yRWFjaCBzaW5jZSBwb2ludGVyRXZlbnRzIG9ubHkgaXMgaW4gSUUxMFxuICAgIEhhbW1lci51dGlscy5lYWNoKHNlbGYucG9pbnRlcnMsIGZ1bmN0aW9uKHBvaW50ZXIpe1xuICAgICAgdG91Y2hsaXN0LnB1c2gocG9pbnRlcik7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gdG91Y2hsaXN0O1xuICB9LFxuXG4gIC8qKlxuICAgKiB1cGRhdGUgdGhlIHBvc2l0aW9uIG9mIGEgcG9pbnRlclxuICAgKiBAcGFyYW0gICB7U3RyaW5nfSAgIHR5cGUgICAgICAgICAgICAgSGFtbWVyLkVWRU5UX0VORFxuICAgKiBAcGFyYW0gICB7T2JqZWN0fSAgIHBvaW50ZXJFdmVudFxuICAgKi9cbiAgdXBkYXRlUG9pbnRlcjogZnVuY3Rpb24odHlwZSwgcG9pbnRlckV2ZW50KSB7XG4gICAgaWYodHlwZSA9PSBIYW1tZXIuRVZFTlRfRU5EKSB7XG4gICAgICBkZWxldGUgdGhpcy5wb2ludGVyc1twb2ludGVyRXZlbnQucG9pbnRlcklkXTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICBwb2ludGVyRXZlbnQuaWRlbnRpZmllciA9IHBvaW50ZXJFdmVudC5wb2ludGVySWQ7XG4gICAgICB0aGlzLnBvaW50ZXJzW3BvaW50ZXJFdmVudC5wb2ludGVySWRdID0gcG9pbnRlckV2ZW50O1xuICAgIH1cblxuICAgIHJldHVybiBPYmplY3Qua2V5cyh0aGlzLnBvaW50ZXJzKS5sZW5ndGg7XG4gIH0sXG5cbiAgLyoqXG4gICAqIGNoZWNrIGlmIGV2IG1hdGNoZXMgcG9pbnRlcnR5cGVcbiAgICogQHBhcmFtICAge1N0cmluZ30gICAgICAgIHBvaW50ZXJUeXBlICAgICBIYW1tZXIuUE9JTlRFUl9NT1VTRVxuICAgKiBAcGFyYW0gICB7UG9pbnRlckV2ZW50fSAgZXZcbiAgICovXG4gIG1hdGNoVHlwZTogZnVuY3Rpb24ocG9pbnRlclR5cGUsIGV2KSB7XG4gICAgaWYoIWV2LnBvaW50ZXJUeXBlKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgdmFyIHB0ID0gZXYucG9pbnRlclR5cGUsXG4gICAgICB0eXBlcyA9IHt9O1xuICAgIHR5cGVzW0hhbW1lci5QT0lOVEVSX01PVVNFXSA9IChwdCA9PT0gZXYuTVNQT0lOVEVSX1RZUEVfTU9VU0UgfHwgcHQgPT09IEhhbW1lci5QT0lOVEVSX01PVVNFKTtcbiAgICB0eXBlc1tIYW1tZXIuUE9JTlRFUl9UT1VDSF0gPSAocHQgPT09IGV2Lk1TUE9JTlRFUl9UWVBFX1RPVUNIIHx8IHB0ID09PSBIYW1tZXIuUE9JTlRFUl9UT1VDSCk7XG4gICAgdHlwZXNbSGFtbWVyLlBPSU5URVJfUEVOXSA9IChwdCA9PT0gZXYuTVNQT0lOVEVSX1RZUEVfUEVOIHx8IHB0ID09PSBIYW1tZXIuUE9JTlRFUl9QRU4pO1xuICAgIHJldHVybiB0eXBlc1twb2ludGVyVHlwZV07XG4gIH0sXG5cblxuICAvKipcbiAgICogZ2V0IGV2ZW50c1xuICAgKi9cbiAgZ2V0RXZlbnRzOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gW1xuICAgICAgJ3BvaW50ZXJkb3duIE1TUG9pbnRlckRvd24nLFxuICAgICAgJ3BvaW50ZXJtb3ZlIE1TUG9pbnRlck1vdmUnLFxuICAgICAgJ3BvaW50ZXJ1cCBwb2ludGVyY2FuY2VsIE1TUG9pbnRlclVwIE1TUG9pbnRlckNhbmNlbCdcbiAgICBdO1xuICB9LFxuXG4gIC8qKlxuICAgKiByZXNldCB0aGUgbGlzdFxuICAgKi9cbiAgcmVzZXQ6IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMucG9pbnRlcnMgPSB7fTtcbiAgfVxufTtcblxuXG5IYW1tZXIuZGV0ZWN0aW9uID0ge1xuICAvLyBjb250YWlucyBhbGwgcmVnaXN0cmVkIEhhbW1lci5nZXN0dXJlcyBpbiB0aGUgY29ycmVjdCBvcmRlclxuICBnZXN0dXJlczogW10sXG5cbiAgLy8gZGF0YSBvZiB0aGUgY3VycmVudCBIYW1tZXIuZ2VzdHVyZSBkZXRlY3Rpb24gc2Vzc2lvblxuICBjdXJyZW50IDogbnVsbCxcblxuICAvLyB0aGUgcHJldmlvdXMgSGFtbWVyLmdlc3R1cmUgc2Vzc2lvbiBkYXRhXG4gIC8vIGlzIGEgZnVsbCBjbG9uZSBvZiB0aGUgcHJldmlvdXMgZ2VzdHVyZS5jdXJyZW50IG9iamVjdFxuICBwcmV2aW91czogbnVsbCxcblxuICAvLyB3aGVuIHRoaXMgYmVjb21lcyB0cnVlLCBubyBnZXN0dXJlcyBhcmUgZmlyZWRcbiAgc3RvcHBlZCA6IGZhbHNlLFxuXG5cbiAgLyoqXG4gICAqIHN0YXJ0IEhhbW1lci5nZXN0dXJlIGRldGVjdGlvblxuICAgKiBAcGFyYW0gICB7SGFtbWVyLkluc3RhbmNlfSAgIGluc3RcbiAgICogQHBhcmFtICAge09iamVjdH0gICAgICAgICAgICBldmVudERhdGFcbiAgICovXG4gIHN0YXJ0RGV0ZWN0OiBmdW5jdGlvbiBzdGFydERldGVjdChpbnN0LCBldmVudERhdGEpIHtcbiAgICAvLyBhbHJlYWR5IGJ1c3kgd2l0aCBhIEhhbW1lci5nZXN0dXJlIGRldGVjdGlvbiBvbiBhbiBlbGVtZW50XG4gICAgaWYodGhpcy5jdXJyZW50KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5zdG9wcGVkID0gZmFsc2U7XG5cbiAgICB0aGlzLmN1cnJlbnQgPSB7XG4gICAgICBpbnN0ICAgICAgOiBpbnN0LCAvLyByZWZlcmVuY2UgdG8gSGFtbWVySW5zdGFuY2Ugd2UncmUgd29ya2luZyBmb3JcbiAgICAgIHN0YXJ0RXZlbnQ6IEhhbW1lci51dGlscy5leHRlbmQoe30sIGV2ZW50RGF0YSksIC8vIHN0YXJ0IGV2ZW50RGF0YSBmb3IgZGlzdGFuY2VzLCB0aW1pbmcgZXRjXG4gICAgICBsYXN0RXZlbnQgOiBmYWxzZSwgLy8gbGFzdCBldmVudERhdGFcbiAgICAgIGxhc3RWRXZlbnQ6IGZhbHNlLCAvLyBsYXN0IGV2ZW50RGF0YSBmb3IgdmVsb2NpdHkuXG4gICAgICB2ZWxvY2l0eSAgOiBmYWxzZSwgLy8gY3VycmVudCB2ZWxvY2l0eVxuICAgICAgbmFtZSAgICAgIDogJycgLy8gY3VycmVudCBnZXN0dXJlIHdlJ3JlIGluL2RldGVjdGVkLCBjYW4gYmUgJ3RhcCcsICdob2xkJyBldGNcbiAgICB9O1xuXG4gICAgdGhpcy5kZXRlY3QoZXZlbnREYXRhKTtcbiAgfSxcblxuXG4gIC8qKlxuICAgKiBIYW1tZXIuZ2VzdHVyZSBkZXRlY3Rpb25cbiAgICogQHBhcmFtICAge09iamVjdH0gICAgZXZlbnREYXRhXG4gICAqL1xuICBkZXRlY3Q6IGZ1bmN0aW9uIGRldGVjdChldmVudERhdGEpIHtcbiAgICBpZighdGhpcy5jdXJyZW50IHx8IHRoaXMuc3RvcHBlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIGV4dGVuZCBldmVudCBkYXRhIHdpdGggY2FsY3VsYXRpb25zIGFib3V0IHNjYWxlLCBkaXN0YW5jZSBldGNcbiAgICBldmVudERhdGEgPSB0aGlzLmV4dGVuZEV2ZW50RGF0YShldmVudERhdGEpO1xuXG4gICAgLy8gaW5zdGFuY2Ugb3B0aW9uc1xuICAgIHZhciBpbnN0X29wdGlvbnMgPSB0aGlzLmN1cnJlbnQuaW5zdC5vcHRpb25zO1xuXG4gICAgLy8gY2FsbCBIYW1tZXIuZ2VzdHVyZSBoYW5kbGVyc1xuICAgIEhhbW1lci51dGlscy5lYWNoKHRoaXMuZ2VzdHVyZXMsIGZ1bmN0aW9uKGdlc3R1cmUpIHtcbiAgICAgIC8vIG9ubHkgd2hlbiB0aGUgaW5zdGFuY2Ugb3B0aW9ucyBoYXZlIGVuYWJsZWQgdGhpcyBnZXN0dXJlXG4gICAgICBpZighdGhpcy5zdG9wcGVkICYmIGluc3Rfb3B0aW9uc1tnZXN0dXJlLm5hbWVdICE9PSBmYWxzZSkge1xuICAgICAgICAvLyBpZiBhIGhhbmRsZXIgcmV0dXJucyBmYWxzZSwgd2Ugc3RvcCB3aXRoIHRoZSBkZXRlY3Rpb25cbiAgICAgICAgaWYoZ2VzdHVyZS5oYW5kbGVyLmNhbGwoZ2VzdHVyZSwgZXZlbnREYXRhLCB0aGlzLmN1cnJlbnQuaW5zdCkgPT09IGZhbHNlKSB7XG4gICAgICAgICAgdGhpcy5zdG9wRGV0ZWN0KCk7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSwgdGhpcyk7XG5cbiAgICAvLyBzdG9yZSBhcyBwcmV2aW91cyBldmVudCBldmVudFxuICAgIGlmKHRoaXMuY3VycmVudCkge1xuICAgICAgdGhpcy5jdXJyZW50Lmxhc3RFdmVudCA9IGV2ZW50RGF0YTtcbiAgICB9XG5cbiAgICAvLyBlbmRldmVudCwgYnV0IG5vdCB0aGUgbGFzdCB0b3VjaCwgc28gZG9udCBzdG9wXG4gICAgaWYoZXZlbnREYXRhLmV2ZW50VHlwZSA9PSBIYW1tZXIuRVZFTlRfRU5EICYmICFldmVudERhdGEudG91Y2hlcy5sZW5ndGggLSAxKSB7XG4gICAgICB0aGlzLnN0b3BEZXRlY3QoKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZXZlbnREYXRhO1xuICB9LFxuXG5cbiAgLyoqXG4gICAqIGNsZWFyIHRoZSBIYW1tZXIuZ2VzdHVyZSB2YXJzXG4gICAqIHRoaXMgaXMgY2FsbGVkIG9uIGVuZERldGVjdCwgYnV0IGNhbiBhbHNvIGJlIHVzZWQgd2hlbiBhIGZpbmFsIEhhbW1lci5nZXN0dXJlIGhhcyBiZWVuIGRldGVjdGVkXG4gICAqIHRvIHN0b3Agb3RoZXIgSGFtbWVyLmdlc3R1cmVzIGZyb20gYmVpbmcgZmlyZWRcbiAgICovXG4gIHN0b3BEZXRlY3Q6IGZ1bmN0aW9uIHN0b3BEZXRlY3QoKSB7XG4gICAgLy8gY2xvbmUgY3VycmVudCBkYXRhIHRvIHRoZSBzdG9yZSBhcyB0aGUgcHJldmlvdXMgZ2VzdHVyZVxuICAgIC8vIHVzZWQgZm9yIHRoZSBkb3VibGUgdGFwIGdlc3R1cmUsIHNpbmNlIHRoaXMgaXMgYW4gb3RoZXIgZ2VzdHVyZSBkZXRlY3Qgc2Vzc2lvblxuICAgIHRoaXMucHJldmlvdXMgPSBIYW1tZXIudXRpbHMuZXh0ZW5kKHt9LCB0aGlzLmN1cnJlbnQpO1xuXG4gICAgLy8gcmVzZXQgdGhlIGN1cnJlbnRcbiAgICB0aGlzLmN1cnJlbnQgPSBudWxsO1xuXG4gICAgLy8gc3RvcHBlZCFcbiAgICB0aGlzLnN0b3BwZWQgPSB0cnVlO1xuICB9LFxuXG5cbiAgLyoqXG4gICAqIGV4dGVuZCBldmVudERhdGEgZm9yIEhhbW1lci5nZXN0dXJlc1xuICAgKiBAcGFyYW0gICB7T2JqZWN0fSAgIGV2XG4gICAqIEByZXR1cm5zIHtPYmplY3R9ICAgZXZcbiAgICovXG4gIGV4dGVuZEV2ZW50RGF0YTogZnVuY3Rpb24gZXh0ZW5kRXZlbnREYXRhKGV2KSB7XG4gICAgdmFyIHN0YXJ0RXYgPSB0aGlzLmN1cnJlbnQuc3RhcnRFdmVudCxcbiAgICAgICAgbGFzdFZFdiA9IHRoaXMuY3VycmVudC5sYXN0VkV2ZW50O1xuXG4gICAgLy8gaWYgdGhlIHRvdWNoZXMgY2hhbmdlLCBzZXQgdGhlIG5ldyB0b3VjaGVzIG92ZXIgdGhlIHN0YXJ0RXZlbnQgdG91Y2hlc1xuICAgIC8vIHRoaXMgYmVjYXVzZSB0b3VjaGV2ZW50cyBkb24ndCBoYXZlIGFsbCB0aGUgdG91Y2hlcyBvbiB0b3VjaHN0YXJ0LCBvciB0aGVcbiAgICAvLyB1c2VyIG11c3QgcGxhY2UgaGlzIGZpbmdlcnMgYXQgdGhlIEVYQUNUIHNhbWUgdGltZSBvbiB0aGUgc2NyZWVuLCB3aGljaCBpcyBub3QgcmVhbGlzdGljXG4gICAgLy8gYnV0LCBzb21ldGltZXMgaXQgaGFwcGVucyB0aGF0IGJvdGggZmluZ2VycyBhcmUgdG91Y2hpbmcgYXQgdGhlIEVYQUNUIHNhbWUgdGltZVxuICAgIGlmKHN0YXJ0RXYgJiYgKGV2LnRvdWNoZXMubGVuZ3RoICE9IHN0YXJ0RXYudG91Y2hlcy5sZW5ndGggfHwgZXYudG91Y2hlcyA9PT0gc3RhcnRFdi50b3VjaGVzKSkge1xuICAgICAgLy8gZXh0ZW5kIDEgbGV2ZWwgZGVlcCB0byBnZXQgdGhlIHRvdWNobGlzdCB3aXRoIHRoZSB0b3VjaCBvYmplY3RzXG4gICAgICBzdGFydEV2LnRvdWNoZXMgPSBbXTtcbiAgICAgIEhhbW1lci51dGlscy5lYWNoKGV2LnRvdWNoZXMsIGZ1bmN0aW9uKHRvdWNoKSB7XG4gICAgICAgIHN0YXJ0RXYudG91Y2hlcy5wdXNoKEhhbW1lci51dGlscy5leHRlbmQoe30sIHRvdWNoKSk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICB2YXIgZGVsdGFfdGltZSA9IGV2LnRpbWVTdGFtcCAtIHN0YXJ0RXYudGltZVN0YW1wXG4gICAgICAsIGRlbHRhX3ggPSBldi5jZW50ZXIucGFnZVggLSBzdGFydEV2LmNlbnRlci5wYWdlWFxuICAgICAgLCBkZWx0YV95ID0gZXYuY2VudGVyLnBhZ2VZIC0gc3RhcnRFdi5jZW50ZXIucGFnZVlcbiAgICAgICwgaW50ZXJpbUFuZ2xlXG4gICAgICAsIGludGVyaW1EaXJlY3Rpb25cbiAgICAgICwgdmVsb2NpdHkgPSB0aGlzLmN1cnJlbnQudmVsb2NpdHk7XG4gIFxuICAgIGlmIChsYXN0VkV2ICE9PSBmYWxzZSAmJiBldi50aW1lU3RhbXAgLSBsYXN0VkV2LnRpbWVTdGFtcCA+IEhhbW1lci5VUERBVEVfVkVMT0NJVFlfSU5URVJWQUwpIHtcbiAgXG4gICAgICAgIHZlbG9jaXR5ID0gIEhhbW1lci51dGlscy5nZXRWZWxvY2l0eShldi50aW1lU3RhbXAgLSBsYXN0VkV2LnRpbWVTdGFtcCwgZXYuY2VudGVyLnBhZ2VYIC0gbGFzdFZFdi5jZW50ZXIucGFnZVgsIGV2LmNlbnRlci5wYWdlWSAtIGxhc3RWRXYuY2VudGVyLnBhZ2VZKTtcbiAgICAgICAgdGhpcy5jdXJyZW50Lmxhc3RWRXZlbnQgPSBldjtcbiAgXG4gICAgICAgIGlmICh2ZWxvY2l0eS54ID4gMCAmJiB2ZWxvY2l0eS55ID4gMCkge1xuICAgICAgICAgICAgdGhpcy5jdXJyZW50LnZlbG9jaXR5ID0gdmVsb2NpdHk7XG4gICAgICAgIH1cbiAgXG4gICAgfSBlbHNlIGlmKHRoaXMuY3VycmVudC52ZWxvY2l0eSA9PT0gZmFsc2UpIHtcbiAgICAgICAgdmVsb2NpdHkgPSBIYW1tZXIudXRpbHMuZ2V0VmVsb2NpdHkoZGVsdGFfdGltZSwgZGVsdGFfeCwgZGVsdGFfeSk7XG4gICAgICAgIHRoaXMuY3VycmVudC52ZWxvY2l0eSA9IHZlbG9jaXR5O1xuICAgICAgICB0aGlzLmN1cnJlbnQubGFzdFZFdmVudCA9IGV2O1xuICAgIH1cblxuICAgIC8vIGVuZCBldmVudHMgKGUuZy4gZHJhZ2VuZCkgZG9uJ3QgaGF2ZSB1c2VmdWwgdmFsdWVzIGZvciBpbnRlcmltRGlyZWN0aW9uICYgaW50ZXJpbUFuZ2xlXG4gICAgLy8gYmVjYXVzZSB0aGUgcHJldmlvdXMgZXZlbnQgaGFzIGV4YWN0bHkgdGhlIHNhbWUgY29vcmRpbmF0ZXNcbiAgICAvLyBzbyBmb3IgZW5kIGV2ZW50cywgdGFrZSB0aGUgcHJldmlvdXMgdmFsdWVzIG9mIGludGVyaW1EaXJlY3Rpb24gJiBpbnRlcmltQW5nbGVcbiAgICAvLyBpbnN0ZWFkIG9mIHJlY2FsY3VsYXRpbmcgdGhlbSBhbmQgZ2V0dGluZyBhIHNwdXJpb3VzICcwJ1xuICAgIGlmKGV2LmV2ZW50VHlwZSA9PT0gJ2VuZCcpIHtcbiAgICAgIGludGVyaW1BbmdsZSA9IHRoaXMuY3VycmVudC5sYXN0RXZlbnQgJiYgdGhpcy5jdXJyZW50Lmxhc3RFdmVudC5pbnRlcmltQW5nbGU7XG4gICAgICBpbnRlcmltRGlyZWN0aW9uID0gdGhpcy5jdXJyZW50Lmxhc3RFdmVudCAmJiB0aGlzLmN1cnJlbnQubGFzdEV2ZW50LmludGVyaW1EaXJlY3Rpb247XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgaW50ZXJpbUFuZ2xlID0gdGhpcy5jdXJyZW50Lmxhc3RFdmVudCAmJiBIYW1tZXIudXRpbHMuZ2V0QW5nbGUodGhpcy5jdXJyZW50Lmxhc3RFdmVudC5jZW50ZXIsIGV2LmNlbnRlcik7XG4gICAgICBpbnRlcmltRGlyZWN0aW9uID0gdGhpcy5jdXJyZW50Lmxhc3RFdmVudCAmJiBIYW1tZXIudXRpbHMuZ2V0RGlyZWN0aW9uKHRoaXMuY3VycmVudC5sYXN0RXZlbnQuY2VudGVyLCBldi5jZW50ZXIpO1xuICAgIH1cblxuICAgIEhhbW1lci51dGlscy5leHRlbmQoZXYsIHtcbiAgICAgIGRlbHRhVGltZTogZGVsdGFfdGltZSxcblxuICAgICAgZGVsdGFYOiBkZWx0YV94LFxuICAgICAgZGVsdGFZOiBkZWx0YV95LFxuXG4gICAgICB2ZWxvY2l0eVg6IHZlbG9jaXR5LngsXG4gICAgICB2ZWxvY2l0eVk6IHZlbG9jaXR5LnksXG5cbiAgICAgIGRpc3RhbmNlOiBIYW1tZXIudXRpbHMuZ2V0RGlzdGFuY2Uoc3RhcnRFdi5jZW50ZXIsIGV2LmNlbnRlciksXG5cbiAgICAgIGFuZ2xlOiBIYW1tZXIudXRpbHMuZ2V0QW5nbGUoc3RhcnRFdi5jZW50ZXIsIGV2LmNlbnRlciksXG4gICAgICBpbnRlcmltQW5nbGU6IGludGVyaW1BbmdsZSxcblxuICAgICAgZGlyZWN0aW9uOiBIYW1tZXIudXRpbHMuZ2V0RGlyZWN0aW9uKHN0YXJ0RXYuY2VudGVyLCBldi5jZW50ZXIpLFxuICAgICAgaW50ZXJpbURpcmVjdGlvbjogaW50ZXJpbURpcmVjdGlvbixcblxuICAgICAgc2NhbGU6IEhhbW1lci51dGlscy5nZXRTY2FsZShzdGFydEV2LnRvdWNoZXMsIGV2LnRvdWNoZXMpLFxuICAgICAgcm90YXRpb246IEhhbW1lci51dGlscy5nZXRSb3RhdGlvbihzdGFydEV2LnRvdWNoZXMsIGV2LnRvdWNoZXMpLFxuXG4gICAgICBzdGFydEV2ZW50OiBzdGFydEV2XG4gICAgfSk7XG5cbiAgICByZXR1cm4gZXY7XG4gIH0sXG5cblxuICAvKipcbiAgICogcmVnaXN0ZXIgbmV3IGdlc3R1cmVcbiAgICogQHBhcmFtICAge09iamVjdH0gICAgZ2VzdHVyZSBvYmplY3QsIHNlZSBnZXN0dXJlcy5qcyBmb3IgZG9jdW1lbnRhdGlvblxuICAgKiBAcmV0dXJucyB7QXJyYXl9ICAgICBnZXN0dXJlc1xuICAgKi9cbiAgcmVnaXN0ZXI6IGZ1bmN0aW9uIHJlZ2lzdGVyKGdlc3R1cmUpIHtcbiAgICAvLyBhZGQgYW4gZW5hYmxlIGdlc3R1cmUgb3B0aW9ucyBpZiB0aGVyZSBpcyBubyBnaXZlblxuICAgIHZhciBvcHRpb25zID0gZ2VzdHVyZS5kZWZhdWx0cyB8fCB7fTtcbiAgICBpZihvcHRpb25zW2dlc3R1cmUubmFtZV0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgb3B0aW9uc1tnZXN0dXJlLm5hbWVdID0gdHJ1ZTtcbiAgICB9XG5cbiAgICAvLyBleHRlbmQgSGFtbWVyIGRlZmF1bHQgb3B0aW9ucyB3aXRoIHRoZSBIYW1tZXIuZ2VzdHVyZSBvcHRpb25zXG4gICAgSGFtbWVyLnV0aWxzLmV4dGVuZChIYW1tZXIuZGVmYXVsdHMsIG9wdGlvbnMsIHRydWUpO1xuXG4gICAgLy8gc2V0IGl0cyBpbmRleFxuICAgIGdlc3R1cmUuaW5kZXggPSBnZXN0dXJlLmluZGV4IHx8IDEwMDA7XG5cbiAgICAvLyBhZGQgSGFtbWVyLmdlc3R1cmUgdG8gdGhlIGxpc3RcbiAgICB0aGlzLmdlc3R1cmVzLnB1c2goZ2VzdHVyZSk7XG5cbiAgICAvLyBzb3J0IHRoZSBsaXN0IGJ5IGluZGV4XG4gICAgdGhpcy5nZXN0dXJlcy5zb3J0KGZ1bmN0aW9uKGEsIGIpIHtcbiAgICAgIGlmKGEuaW5kZXggPCBiLmluZGV4KSB7IHJldHVybiAtMTsgfVxuICAgICAgaWYoYS5pbmRleCA+IGIuaW5kZXgpIHsgcmV0dXJuIDE7IH1cbiAgICAgIHJldHVybiAwO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIHRoaXMuZ2VzdHVyZXM7XG4gIH1cbn07XG5cblxuLyoqXG4gKiBEcmFnXG4gKiBNb3ZlIHdpdGggeCBmaW5nZXJzIChkZWZhdWx0IDEpIGFyb3VuZCBvbiB0aGUgcGFnZS4gQmxvY2tpbmcgdGhlIHNjcm9sbGluZyB3aGVuXG4gKiBtb3ZpbmcgbGVmdCBhbmQgcmlnaHQgaXMgYSBnb29kIHByYWN0aWNlLiBXaGVuIGFsbCB0aGUgZHJhZyBldmVudHMgYXJlIGJsb2NraW5nXG4gKiB5b3UgZGlzYWJsZSBzY3JvbGxpbmcgb24gdGhhdCBhcmVhLlxuICogQGV2ZW50cyAgZHJhZywgZHJhcGxlZnQsIGRyYWdyaWdodCwgZHJhZ3VwLCBkcmFnZG93blxuICovXG5IYW1tZXIuZ2VzdHVyZXMuRHJhZyA9IHtcbiAgbmFtZSAgICAgOiAnZHJhZycsXG4gIGluZGV4ICAgIDogNTAsXG4gIGRlZmF1bHRzIDoge1xuICAgIGRyYWdfbWluX2Rpc3RhbmNlICAgICAgICAgICAgOiAxMCxcblxuICAgIC8vIFNldCBjb3JyZWN0X2Zvcl9kcmFnX21pbl9kaXN0YW5jZSB0byB0cnVlIHRvIG1ha2UgdGhlIHN0YXJ0aW5nIHBvaW50IG9mIHRoZSBkcmFnXG4gICAgLy8gYmUgY2FsY3VsYXRlZCBmcm9tIHdoZXJlIHRoZSBkcmFnIHdhcyB0cmlnZ2VyZWQsIG5vdCBmcm9tIHdoZXJlIHRoZSB0b3VjaCBzdGFydGVkLlxuICAgIC8vIFVzZWZ1bCB0byBhdm9pZCBhIGplcmstc3RhcnRpbmcgZHJhZywgd2hpY2ggY2FuIG1ha2UgZmluZS1hZGp1c3RtZW50c1xuICAgIC8vIHRocm91Z2ggZHJhZ2dpbmcgZGlmZmljdWx0LCBhbmQgYmUgdmlzdWFsbHkgdW5hcHBlYWxpbmcuXG4gICAgY29ycmVjdF9mb3JfZHJhZ19taW5fZGlzdGFuY2U6IHRydWUsXG5cbiAgICAvLyBzZXQgMCBmb3IgdW5saW1pdGVkLCBidXQgdGhpcyBjYW4gY29uZmxpY3Qgd2l0aCB0cmFuc2Zvcm1cbiAgICBkcmFnX21heF90b3VjaGVzICAgICAgICAgICAgIDogMSxcblxuICAgIC8vIHByZXZlbnQgZGVmYXVsdCBicm93c2VyIGJlaGF2aW9yIHdoZW4gZHJhZ2dpbmcgb2NjdXJzXG4gICAgLy8gYmUgY2FyZWZ1bCB3aXRoIGl0LCBpdCBtYWtlcyB0aGUgZWxlbWVudCBhIGJsb2NraW5nIGVsZW1lbnRcbiAgICAvLyB3aGVuIHlvdSBhcmUgdXNpbmcgdGhlIGRyYWcgZ2VzdHVyZSwgaXQgaXMgYSBnb29kIHByYWN0aWNlIHRvIHNldCB0aGlzIHRydWVcbiAgICBkcmFnX2Jsb2NrX2hvcml6b250YWwgICAgICAgIDogZmFsc2UsXG4gICAgZHJhZ19ibG9ja192ZXJ0aWNhbCAgICAgICAgICA6IGZhbHNlLFxuXG4gICAgLy8gZHJhZ19sb2NrX3RvX2F4aXMga2VlcHMgdGhlIGRyYWcgZ2VzdHVyZSBvbiB0aGUgYXhpcyB0aGF0IGl0IHN0YXJ0ZWQgb24sXG4gICAgLy8gSXQgZGlzYWxsb3dzIHZlcnRpY2FsIGRpcmVjdGlvbnMgaWYgdGhlIGluaXRpYWwgZGlyZWN0aW9uIHdhcyBob3Jpem9udGFsLCBhbmQgdmljZSB2ZXJzYS5cbiAgICBkcmFnX2xvY2tfdG9fYXhpcyAgICAgICAgICAgIDogZmFsc2UsXG5cbiAgICAvLyBkcmFnIGxvY2sgb25seSBraWNrcyBpbiB3aGVuIGRpc3RhbmNlID4gZHJhZ19sb2NrX21pbl9kaXN0YW5jZVxuICAgIC8vIFRoaXMgd2F5LCBsb2NraW5nIG9jY3VycyBvbmx5IHdoZW4gdGhlIGRpc3RhbmNlIGhhcyBiZWNvbWUgbGFyZ2UgZW5vdWdoIHRvIHJlbGlhYmx5IGRldGVybWluZSB0aGUgZGlyZWN0aW9uXG4gICAgZHJhZ19sb2NrX21pbl9kaXN0YW5jZSAgICAgICA6IDI1XG4gIH0sXG5cbiAgdHJpZ2dlcmVkOiBmYWxzZSxcbiAgaGFuZGxlciAgOiBmdW5jdGlvbiBkcmFnR2VzdHVyZShldiwgaW5zdCkge1xuICAgIC8vIGN1cnJlbnQgZ2VzdHVyZSBpc250IGRyYWcsIGJ1dCBkcmFnZ2VkIGlzIHRydWVcbiAgICAvLyB0aGlzIG1lYW5zIGFuIG90aGVyIGdlc3R1cmUgaXMgYnVzeS4gbm93IGNhbGwgZHJhZ2VuZFxuICAgIGlmKEhhbW1lci5kZXRlY3Rpb24uY3VycmVudC5uYW1lICE9IHRoaXMubmFtZSAmJiB0aGlzLnRyaWdnZXJlZCkge1xuICAgICAgaW5zdC50cmlnZ2VyKHRoaXMubmFtZSArICdlbmQnLCBldik7XG4gICAgICB0aGlzLnRyaWdnZXJlZCA9IGZhbHNlO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIG1heCB0b3VjaGVzXG4gICAgaWYoaW5zdC5vcHRpb25zLmRyYWdfbWF4X3RvdWNoZXMgPiAwICYmXG4gICAgICBldi50b3VjaGVzLmxlbmd0aCA+IGluc3Qub3B0aW9ucy5kcmFnX21heF90b3VjaGVzKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgc3dpdGNoKGV2LmV2ZW50VHlwZSkge1xuICAgICAgY2FzZSBIYW1tZXIuRVZFTlRfU1RBUlQ6XG4gICAgICAgIHRoaXMudHJpZ2dlcmVkID0gZmFsc2U7XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlIEhhbW1lci5FVkVOVF9NT1ZFOlxuICAgICAgICAvLyB3aGVuIHRoZSBkaXN0YW5jZSB3ZSBtb3ZlZCBpcyB0b28gc21hbGwgd2Ugc2tpcCB0aGlzIGdlc3R1cmVcbiAgICAgICAgLy8gb3Igd2UgY2FuIGJlIGFscmVhZHkgaW4gZHJhZ2dpbmdcbiAgICAgICAgaWYoZXYuZGlzdGFuY2UgPCBpbnN0Lm9wdGlvbnMuZHJhZ19taW5fZGlzdGFuY2UgJiZcbiAgICAgICAgICBIYW1tZXIuZGV0ZWN0aW9uLmN1cnJlbnQubmFtZSAhPSB0aGlzLm5hbWUpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyB3ZSBhcmUgZHJhZ2dpbmchXG4gICAgICAgIGlmKEhhbW1lci5kZXRlY3Rpb24uY3VycmVudC5uYW1lICE9IHRoaXMubmFtZSkge1xuICAgICAgICAgIEhhbW1lci5kZXRlY3Rpb24uY3VycmVudC5uYW1lID0gdGhpcy5uYW1lO1xuICAgICAgICAgIGlmKGluc3Qub3B0aW9ucy5jb3JyZWN0X2Zvcl9kcmFnX21pbl9kaXN0YW5jZSAmJiBldi5kaXN0YW5jZSA+IDApIHtcbiAgICAgICAgICAgIC8vIFdoZW4gYSBkcmFnIGlzIHRyaWdnZXJlZCwgc2V0IHRoZSBldmVudCBjZW50ZXIgdG8gZHJhZ19taW5fZGlzdGFuY2UgcGl4ZWxzIGZyb20gdGhlIG9yaWdpbmFsIGV2ZW50IGNlbnRlci5cbiAgICAgICAgICAgIC8vIFdpdGhvdXQgdGhpcyBjb3JyZWN0aW9uLCB0aGUgZHJhZ2dlZCBkaXN0YW5jZSB3b3VsZCBqdW1wc3RhcnQgYXQgZHJhZ19taW5fZGlzdGFuY2UgcGl4ZWxzIGluc3RlYWQgb2YgYXQgMC5cbiAgICAgICAgICAgIC8vIEl0IG1pZ2h0IGJlIHVzZWZ1bCB0byBzYXZlIHRoZSBvcmlnaW5hbCBzdGFydCBwb2ludCBzb21ld2hlcmVcbiAgICAgICAgICAgIHZhciBmYWN0b3IgPSBNYXRoLmFicyhpbnN0Lm9wdGlvbnMuZHJhZ19taW5fZGlzdGFuY2UgLyBldi5kaXN0YW5jZSk7XG4gICAgICAgICAgICBIYW1tZXIuZGV0ZWN0aW9uLmN1cnJlbnQuc3RhcnRFdmVudC5jZW50ZXIucGFnZVggKz0gZXYuZGVsdGFYICogZmFjdG9yO1xuICAgICAgICAgICAgSGFtbWVyLmRldGVjdGlvbi5jdXJyZW50LnN0YXJ0RXZlbnQuY2VudGVyLnBhZ2VZICs9IGV2LmRlbHRhWSAqIGZhY3RvcjtcblxuICAgICAgICAgICAgLy8gcmVjYWxjdWxhdGUgZXZlbnQgZGF0YSB1c2luZyBuZXcgc3RhcnQgcG9pbnRcbiAgICAgICAgICAgIGV2ID0gSGFtbWVyLmRldGVjdGlvbi5leHRlbmRFdmVudERhdGEoZXYpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGxvY2sgZHJhZyB0byBheGlzP1xuICAgICAgICBpZihIYW1tZXIuZGV0ZWN0aW9uLmN1cnJlbnQubGFzdEV2ZW50LmRyYWdfbG9ja2VkX3RvX2F4aXMgfHwgKGluc3Qub3B0aW9ucy5kcmFnX2xvY2tfdG9fYXhpcyAmJiBpbnN0Lm9wdGlvbnMuZHJhZ19sb2NrX21pbl9kaXN0YW5jZSA8PSBldi5kaXN0YW5jZSkpIHtcbiAgICAgICAgICBldi5kcmFnX2xvY2tlZF90b19heGlzID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgbGFzdF9kaXJlY3Rpb24gPSBIYW1tZXIuZGV0ZWN0aW9uLmN1cnJlbnQubGFzdEV2ZW50LmRpcmVjdGlvbjtcbiAgICAgICAgaWYoZXYuZHJhZ19sb2NrZWRfdG9fYXhpcyAmJiBsYXN0X2RpcmVjdGlvbiAhPT0gZXYuZGlyZWN0aW9uKSB7XG4gICAgICAgICAgLy8ga2VlcCBkaXJlY3Rpb24gb24gdGhlIGF4aXMgdGhhdCB0aGUgZHJhZyBnZXN0dXJlIHN0YXJ0ZWQgb25cbiAgICAgICAgICBpZihIYW1tZXIudXRpbHMuaXNWZXJ0aWNhbChsYXN0X2RpcmVjdGlvbikpIHtcbiAgICAgICAgICAgIGV2LmRpcmVjdGlvbiA9IChldi5kZWx0YVkgPCAwKSA/IEhhbW1lci5ESVJFQ1RJT05fVVAgOiBIYW1tZXIuRElSRUNUSU9OX0RPV047XG4gICAgICAgICAgfVxuICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZXYuZGlyZWN0aW9uID0gKGV2LmRlbHRhWCA8IDApID8gSGFtbWVyLkRJUkVDVElPTl9MRUZUIDogSGFtbWVyLkRJUkVDVElPTl9SSUdIVDtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBmaXJzdCB0aW1lLCB0cmlnZ2VyIGRyYWdzdGFydCBldmVudFxuICAgICAgICBpZighdGhpcy50cmlnZ2VyZWQpIHtcbiAgICAgICAgICBpbnN0LnRyaWdnZXIodGhpcy5uYW1lICsgJ3N0YXJ0JywgZXYpO1xuICAgICAgICAgIHRoaXMudHJpZ2dlcmVkID0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHRyaWdnZXIgbm9ybWFsIGV2ZW50XG4gICAgICAgIGluc3QudHJpZ2dlcih0aGlzLm5hbWUsIGV2KTtcblxuICAgICAgICAvLyBkaXJlY3Rpb24gZXZlbnQsIGxpa2UgZHJhZ2Rvd25cbiAgICAgICAgaW5zdC50cmlnZ2VyKHRoaXMubmFtZSArIGV2LmRpcmVjdGlvbiwgZXYpO1xuXG4gICAgICAgIC8vIGJsb2NrIHRoZSBicm93c2VyIGV2ZW50c1xuICAgICAgICBpZigoaW5zdC5vcHRpb25zLmRyYWdfYmxvY2tfdmVydGljYWwgJiYgSGFtbWVyLnV0aWxzLmlzVmVydGljYWwoZXYuZGlyZWN0aW9uKSkgfHxcbiAgICAgICAgICAoaW5zdC5vcHRpb25zLmRyYWdfYmxvY2tfaG9yaXpvbnRhbCAmJiAhSGFtbWVyLnV0aWxzLmlzVmVydGljYWwoZXYuZGlyZWN0aW9uKSkpIHtcbiAgICAgICAgICBldi5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlIEhhbW1lci5FVkVOVF9FTkQ6XG4gICAgICAgIC8vIHRyaWdnZXIgZHJhZ2VuZFxuICAgICAgICBpZih0aGlzLnRyaWdnZXJlZCkge1xuICAgICAgICAgIGluc3QudHJpZ2dlcih0aGlzLm5hbWUgKyAnZW5kJywgZXYpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy50cmlnZ2VyZWQgPSBmYWxzZTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIEhvbGRcbiAqIFRvdWNoIHN0YXlzIGF0IHRoZSBzYW1lIHBsYWNlIGZvciB4IHRpbWVcbiAqIEBldmVudHMgIGhvbGRcbiAqL1xuSGFtbWVyLmdlc3R1cmVzLkhvbGQgPSB7XG4gIG5hbWUgICAgOiAnaG9sZCcsXG4gIGluZGV4ICAgOiAxMCxcbiAgZGVmYXVsdHM6IHtcbiAgICBob2xkX3RpbWVvdXQgIDogNTAwLFxuICAgIGhvbGRfdGhyZXNob2xkOiAxXG4gIH0sXG4gIHRpbWVyICAgOiBudWxsLFxuICBoYW5kbGVyIDogZnVuY3Rpb24gaG9sZEdlc3R1cmUoZXYsIGluc3QpIHtcbiAgICBzd2l0Y2goZXYuZXZlbnRUeXBlKSB7XG4gICAgICBjYXNlIEhhbW1lci5FVkVOVF9TVEFSVDpcbiAgICAgICAgLy8gY2xlYXIgYW55IHJ1bm5pbmcgdGltZXJzXG4gICAgICAgIGNsZWFyVGltZW91dCh0aGlzLnRpbWVyKTtcblxuICAgICAgICAvLyBzZXQgdGhlIGdlc3R1cmUgc28gd2UgY2FuIGNoZWNrIGluIHRoZSB0aW1lb3V0IGlmIGl0IHN0aWxsIGlzXG4gICAgICAgIEhhbW1lci5kZXRlY3Rpb24uY3VycmVudC5uYW1lID0gdGhpcy5uYW1lO1xuXG4gICAgICAgIC8vIHNldCB0aW1lciBhbmQgaWYgYWZ0ZXIgdGhlIHRpbWVvdXQgaXQgc3RpbGwgaXMgaG9sZCxcbiAgICAgICAgLy8gd2UgdHJpZ2dlciB0aGUgaG9sZCBldmVudFxuICAgICAgICB0aGlzLnRpbWVyID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICBpZihIYW1tZXIuZGV0ZWN0aW9uLmN1cnJlbnQubmFtZSA9PSAnaG9sZCcpIHtcbiAgICAgICAgICAgIGluc3QudHJpZ2dlcignaG9sZCcsIGV2KTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sIGluc3Qub3B0aW9ucy5ob2xkX3RpbWVvdXQpO1xuICAgICAgICBicmVhaztcblxuICAgICAgLy8gd2hlbiB5b3UgbW92ZSBvciBlbmQgd2UgY2xlYXIgdGhlIHRpbWVyXG4gICAgICBjYXNlIEhhbW1lci5FVkVOVF9NT1ZFOlxuICAgICAgICBpZihldi5kaXN0YW5jZSA+IGluc3Qub3B0aW9ucy5ob2xkX3RocmVzaG9sZCkge1xuICAgICAgICAgIGNsZWFyVGltZW91dCh0aGlzLnRpbWVyKTtcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSBIYW1tZXIuRVZFTlRfRU5EOlxuICAgICAgICBjbGVhclRpbWVvdXQodGhpcy50aW1lcik7XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxufTtcblxuLyoqXG4gKiBSZWxlYXNlXG4gKiBDYWxsZWQgYXMgbGFzdCwgdGVsbHMgdGhlIHVzZXIgaGFzIHJlbGVhc2VkIHRoZSBzY3JlZW5cbiAqIEBldmVudHMgIHJlbGVhc2VcbiAqL1xuSGFtbWVyLmdlc3R1cmVzLlJlbGVhc2UgPSB7XG4gIG5hbWUgICA6ICdyZWxlYXNlJyxcbiAgaW5kZXggIDogSW5maW5pdHksXG4gIGhhbmRsZXI6IGZ1bmN0aW9uIHJlbGVhc2VHZXN0dXJlKGV2LCBpbnN0KSB7XG4gICAgaWYoZXYuZXZlbnRUeXBlID09IEhhbW1lci5FVkVOVF9FTkQpIHtcbiAgICAgIGluc3QudHJpZ2dlcih0aGlzLm5hbWUsIGV2KTtcbiAgICB9XG4gIH1cbn07XG5cbi8qKlxuICogU3dpcGVcbiAqIHRyaWdnZXJzIHN3aXBlIGV2ZW50cyB3aGVuIHRoZSBlbmQgdmVsb2NpdHkgaXMgYWJvdmUgdGhlIHRocmVzaG9sZFxuICogQGV2ZW50cyAgc3dpcGUsIHN3aXBlbGVmdCwgc3dpcGVyaWdodCwgc3dpcGV1cCwgc3dpcGVkb3duXG4gKi9cbkhhbW1lci5nZXN0dXJlcy5Td2lwZSA9IHtcbiAgbmFtZSAgICA6ICdzd2lwZScsXG4gIGluZGV4ICAgOiA0MCxcbiAgZGVmYXVsdHM6IHtcbiAgICAvLyBzZXQgMCBmb3IgdW5saW1pdGVkLCBidXQgdGhpcyBjYW4gY29uZmxpY3Qgd2l0aCB0cmFuc2Zvcm1cbiAgICBzd2lwZV9taW5fdG91Y2hlczogMSxcbiAgICBzd2lwZV9tYXhfdG91Y2hlczogMSxcbiAgICBzd2lwZV92ZWxvY2l0eSAgIDogMC43XG4gIH0sXG4gIGhhbmRsZXIgOiBmdW5jdGlvbiBzd2lwZUdlc3R1cmUoZXYsIGluc3QpIHtcbiAgICBpZihldi5ldmVudFR5cGUgPT0gSGFtbWVyLkVWRU5UX0VORCkge1xuICAgICAgLy8gbWF4IHRvdWNoZXNcbiAgICAgIGlmKGluc3Qub3B0aW9ucy5zd2lwZV9tYXhfdG91Y2hlcyA+IDAgJiZcbiAgICAgICAgZXYudG91Y2hlcy5sZW5ndGggPCBpbnN0Lm9wdGlvbnMuc3dpcGVfbWluX3RvdWNoZXMgJiZcbiAgICAgICAgZXYudG91Y2hlcy5sZW5ndGggPiBpbnN0Lm9wdGlvbnMuc3dpcGVfbWF4X3RvdWNoZXMpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICAvLyB3aGVuIHRoZSBkaXN0YW5jZSB3ZSBtb3ZlZCBpcyB0b28gc21hbGwgd2Ugc2tpcCB0aGlzIGdlc3R1cmVcbiAgICAgIC8vIG9yIHdlIGNhbiBiZSBhbHJlYWR5IGluIGRyYWdnaW5nXG4gICAgICBpZihldi52ZWxvY2l0eVggPiBpbnN0Lm9wdGlvbnMuc3dpcGVfdmVsb2NpdHkgfHxcbiAgICAgICAgZXYudmVsb2NpdHlZID4gaW5zdC5vcHRpb25zLnN3aXBlX3ZlbG9jaXR5KSB7XG4gICAgICAgIC8vIHRyaWdnZXIgc3dpcGUgZXZlbnRzXG4gICAgICAgIGluc3QudHJpZ2dlcih0aGlzLm5hbWUsIGV2KTtcbiAgICAgICAgaW5zdC50cmlnZ2VyKHRoaXMubmFtZSArIGV2LmRpcmVjdGlvbiwgZXYpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufTtcblxuLyoqXG4gKiBUYXAvRG91YmxlVGFwXG4gKiBRdWljayB0b3VjaCBhdCBhIHBsYWNlIG9yIGRvdWJsZSBhdCB0aGUgc2FtZSBwbGFjZVxuICogQGV2ZW50cyAgdGFwLCBkb3VibGV0YXBcbiAqL1xuSGFtbWVyLmdlc3R1cmVzLlRhcCA9IHtcbiAgbmFtZSAgICA6ICd0YXAnLFxuICBpbmRleCAgIDogMTAwLFxuICBkZWZhdWx0czoge1xuICAgIHRhcF9tYXhfdG91Y2h0aW1lIDogMjUwLFxuICAgIHRhcF9tYXhfZGlzdGFuY2UgIDogMTAsXG4gICAgdGFwX2Fsd2F5cyAgICAgICAgOiB0cnVlLFxuICAgIGRvdWJsZXRhcF9kaXN0YW5jZTogMjAsXG4gICAgZG91YmxldGFwX2ludGVydmFsOiAzMDBcbiAgfSxcbiAgaGFuZGxlciA6IGZ1bmN0aW9uIHRhcEdlc3R1cmUoZXYsIGluc3QpIHtcbiAgICBpZihldi5ldmVudFR5cGUgPT0gSGFtbWVyLkVWRU5UX01PVkUgJiYgIUhhbW1lci5kZXRlY3Rpb24uY3VycmVudC5yZWFjaGVkVGFwTWF4RGlzdGFuY2UpIHtcbiAgICAgIC8vVHJhY2sgdGhlIGRpc3RhbmNlIHdlJ3ZlIG1vdmVkLiBJZiBpdCdzIGFib3ZlIHRoZSBtYXggT05DRSwgcmVtZW1iZXIgdGhhdCAoZml4ZXMgIzQwNikuXG4gICAgICBIYW1tZXIuZGV0ZWN0aW9uLmN1cnJlbnQucmVhY2hlZFRhcE1heERpc3RhbmNlID0gKGV2LmRpc3RhbmNlID4gaW5zdC5vcHRpb25zLnRhcF9tYXhfZGlzdGFuY2UpO1xuICAgIH0gZWxzZSBpZihldi5ldmVudFR5cGUgPT0gSGFtbWVyLkVWRU5UX0VORCAmJiBldi5zcmNFdmVudC50eXBlICE9ICd0b3VjaGNhbmNlbCcpIHtcbiAgICAgIC8vIHByZXZpb3VzIGdlc3R1cmUsIGZvciB0aGUgZG91YmxlIHRhcCBzaW5jZSB0aGVzZSBhcmUgdHdvIGRpZmZlcmVudCBnZXN0dXJlIGRldGVjdGlvbnNcbiAgICAgIHZhciBwcmV2ID0gSGFtbWVyLmRldGVjdGlvbi5wcmV2aW91cyxcbiAgICAgICAgZGlkX2RvdWJsZXRhcCA9IGZhbHNlO1xuXG4gICAgICAvLyB3aGVuIHRoZSB0b3VjaHRpbWUgaXMgaGlnaGVyIHRoZW4gdGhlIG1heCB0b3VjaCB0aW1lXG4gICAgICAvLyBvciB3aGVuIHRoZSBtb3ZpbmcgZGlzdGFuY2UgaXMgdG9vIG11Y2hcbiAgICAgIGlmKEhhbW1lci5kZXRlY3Rpb24uY3VycmVudC5yZWFjaGVkVGFwTWF4RGlzdGFuY2UgfHwgZXYuZGVsdGFUaW1lID4gaW5zdC5vcHRpb25zLnRhcF9tYXhfdG91Y2h0aW1lKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgLy8gY2hlY2sgaWYgZG91YmxlIHRhcFxuICAgICAgaWYocHJldiAmJiBwcmV2Lm5hbWUgPT0gJ3RhcCcgJiZcbiAgICAgICAgKGV2LnRpbWVTdGFtcCAtIHByZXYubGFzdEV2ZW50LnRpbWVTdGFtcCkgPCBpbnN0Lm9wdGlvbnMuZG91YmxldGFwX2ludGVydmFsICYmXG4gICAgICAgIGV2LmRpc3RhbmNlIDwgaW5zdC5vcHRpb25zLmRvdWJsZXRhcF9kaXN0YW5jZSkge1xuICAgICAgICBpbnN0LnRyaWdnZXIoJ2RvdWJsZXRhcCcsIGV2KTtcbiAgICAgICAgZGlkX2RvdWJsZXRhcCA9IHRydWU7XG4gICAgICB9XG5cbiAgICAgIC8vIGRvIGEgc2luZ2xlIHRhcFxuICAgICAgaWYoIWRpZF9kb3VibGV0YXAgfHwgaW5zdC5vcHRpb25zLnRhcF9hbHdheXMpIHtcbiAgICAgICAgSGFtbWVyLmRldGVjdGlvbi5jdXJyZW50Lm5hbWUgPSAndGFwJztcbiAgICAgICAgaW5zdC50cmlnZ2VyKEhhbW1lci5kZXRlY3Rpb24uY3VycmVudC5uYW1lLCBldik7XG4gICAgICB9XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIFRvdWNoXG4gKiBDYWxsZWQgYXMgZmlyc3QsIHRlbGxzIHRoZSB1c2VyIGhhcyB0b3VjaGVkIHRoZSBzY3JlZW5cbiAqIEBldmVudHMgIHRvdWNoXG4gKi9cbkhhbW1lci5nZXN0dXJlcy5Ub3VjaCA9IHtcbiAgbmFtZSAgICA6ICd0b3VjaCcsXG4gIGluZGV4ICAgOiAtSW5maW5pdHksXG4gIGRlZmF1bHRzOiB7XG4gICAgLy8gY2FsbCBwcmV2ZW50RGVmYXVsdCBhdCB0b3VjaHN0YXJ0LCBhbmQgbWFrZXMgdGhlIGVsZW1lbnQgYmxvY2tpbmcgYnlcbiAgICAvLyBkaXNhYmxpbmcgdGhlIHNjcm9sbGluZyBvZiB0aGUgcGFnZSwgYnV0IGl0IGltcHJvdmVzIGdlc3R1cmVzIGxpa2VcbiAgICAvLyB0cmFuc2Zvcm1pbmcgYW5kIGRyYWdnaW5nLlxuICAgIC8vIGJlIGNhcmVmdWwgd2l0aCB1c2luZyB0aGlzLCBpdCBjYW4gYmUgdmVyeSBhbm5veWluZyBmb3IgdXNlcnMgdG8gYmUgc3R1Y2tcbiAgICAvLyBvbiB0aGUgcGFnZVxuICAgIHByZXZlbnRfZGVmYXVsdCAgICA6IGZhbHNlLFxuXG4gICAgLy8gZGlzYWJsZSBtb3VzZSBldmVudHMsIHNvIG9ubHkgdG91Y2ggKG9yIHBlbiEpIGlucHV0IHRyaWdnZXJzIGV2ZW50c1xuICAgIHByZXZlbnRfbW91c2VldmVudHM6IGZhbHNlXG4gIH0sXG4gIGhhbmRsZXIgOiBmdW5jdGlvbiB0b3VjaEdlc3R1cmUoZXYsIGluc3QpIHtcbiAgICBpZihpbnN0Lm9wdGlvbnMucHJldmVudF9tb3VzZWV2ZW50cyAmJiBldi5wb2ludGVyVHlwZSA9PSBIYW1tZXIuUE9JTlRFUl9NT1VTRSkge1xuICAgICAgZXYuc3RvcERldGVjdCgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmKGluc3Qub3B0aW9ucy5wcmV2ZW50X2RlZmF1bHQpIHtcbiAgICAgIGV2LnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuXG4gICAgaWYoZXYuZXZlbnRUeXBlID09IEhhbW1lci5FVkVOVF9TVEFSVCkge1xuICAgICAgaW5zdC50cmlnZ2VyKHRoaXMubmFtZSwgZXYpO1xuICAgIH1cbiAgfVxufTtcblxuXG4vKipcbiAqIFRyYW5zZm9ybVxuICogVXNlciB3YW50IHRvIHNjYWxlIG9yIHJvdGF0ZSB3aXRoIDIgZmluZ2Vyc1xuICogQGV2ZW50cyAgdHJhbnNmb3JtLCBwaW5jaCwgcGluY2hpbiwgcGluY2hvdXQsIHJvdGF0ZVxuICovXG5IYW1tZXIuZ2VzdHVyZXMuVHJhbnNmb3JtID0ge1xuICBuYW1lICAgICA6ICd0cmFuc2Zvcm0nLFxuICBpbmRleCAgICA6IDQ1LFxuICBkZWZhdWx0cyA6IHtcbiAgICAvLyBmYWN0b3IsIG5vIHNjYWxlIGlzIDEsIHpvb21pbiBpcyB0byAwIGFuZCB6b29tb3V0IHVudGlsIGhpZ2hlciB0aGVuIDFcbiAgICB0cmFuc2Zvcm1fbWluX3NjYWxlICAgOiAwLjAxLFxuICAgIC8vIHJvdGF0aW9uIGluIGRlZ3JlZXNcbiAgICB0cmFuc2Zvcm1fbWluX3JvdGF0aW9uOiAxLFxuICAgIC8vIHByZXZlbnQgZGVmYXVsdCBicm93c2VyIGJlaGF2aW9yIHdoZW4gdHdvIHRvdWNoZXMgYXJlIG9uIHRoZSBzY3JlZW5cbiAgICAvLyBidXQgaXQgbWFrZXMgdGhlIGVsZW1lbnQgYSBibG9ja2luZyBlbGVtZW50XG4gICAgLy8gd2hlbiB5b3UgYXJlIHVzaW5nIHRoZSB0cmFuc2Zvcm0gZ2VzdHVyZSwgaXQgaXMgYSBnb29kIHByYWN0aWNlIHRvIHNldCB0aGlzIHRydWVcbiAgICB0cmFuc2Zvcm1fYWx3YXlzX2Jsb2NrOiBmYWxzZVxuICB9LFxuICB0cmlnZ2VyZWQ6IGZhbHNlLFxuICBoYW5kbGVyICA6IGZ1bmN0aW9uIHRyYW5zZm9ybUdlc3R1cmUoZXYsIGluc3QpIHtcbiAgICAvLyBjdXJyZW50IGdlc3R1cmUgaXNudCBkcmFnLCBidXQgZHJhZ2dlZCBpcyB0cnVlXG4gICAgLy8gdGhpcyBtZWFucyBhbiBvdGhlciBnZXN0dXJlIGlzIGJ1c3kuIG5vdyBjYWxsIGRyYWdlbmRcbiAgICBpZihIYW1tZXIuZGV0ZWN0aW9uLmN1cnJlbnQubmFtZSAhPSB0aGlzLm5hbWUgJiYgdGhpcy50cmlnZ2VyZWQpIHtcbiAgICAgIGluc3QudHJpZ2dlcih0aGlzLm5hbWUgKyAnZW5kJywgZXYpO1xuICAgICAgdGhpcy50cmlnZ2VyZWQgPSBmYWxzZTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBhdGxlYXN0IG11bHRpdG91Y2hcbiAgICBpZihldi50b3VjaGVzLmxlbmd0aCA8IDIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBwcmV2ZW50IGRlZmF1bHQgd2hlbiB0d28gZmluZ2VycyBhcmUgb24gdGhlIHNjcmVlblxuICAgIGlmKGluc3Qub3B0aW9ucy50cmFuc2Zvcm1fYWx3YXlzX2Jsb2NrKSB7XG4gICAgICBldi5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIH1cblxuICAgIHN3aXRjaChldi5ldmVudFR5cGUpIHtcbiAgICAgIGNhc2UgSGFtbWVyLkVWRU5UX1NUQVJUOlxuICAgICAgICB0aGlzLnRyaWdnZXJlZCA9IGZhbHNlO1xuICAgICAgICBicmVhaztcblxuICAgICAgY2FzZSBIYW1tZXIuRVZFTlRfTU9WRTpcbiAgICAgICAgdmFyIHNjYWxlX3RocmVzaG9sZCA9IE1hdGguYWJzKDEgLSBldi5zY2FsZSk7XG4gICAgICAgIHZhciByb3RhdGlvbl90aHJlc2hvbGQgPSBNYXRoLmFicyhldi5yb3RhdGlvbik7XG5cbiAgICAgICAgLy8gd2hlbiB0aGUgZGlzdGFuY2Ugd2UgbW92ZWQgaXMgdG9vIHNtYWxsIHdlIHNraXAgdGhpcyBnZXN0dXJlXG4gICAgICAgIC8vIG9yIHdlIGNhbiBiZSBhbHJlYWR5IGluIGRyYWdnaW5nXG4gICAgICAgIGlmKHNjYWxlX3RocmVzaG9sZCA8IGluc3Qub3B0aW9ucy50cmFuc2Zvcm1fbWluX3NjYWxlICYmXG4gICAgICAgICAgcm90YXRpb25fdGhyZXNob2xkIDwgaW5zdC5vcHRpb25zLnRyYW5zZm9ybV9taW5fcm90YXRpb24pIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyB3ZSBhcmUgdHJhbnNmb3JtaW5nIVxuICAgICAgICBIYW1tZXIuZGV0ZWN0aW9uLmN1cnJlbnQubmFtZSA9IHRoaXMubmFtZTtcblxuICAgICAgICAvLyBmaXJzdCB0aW1lLCB0cmlnZ2VyIGRyYWdzdGFydCBldmVudFxuICAgICAgICBpZighdGhpcy50cmlnZ2VyZWQpIHtcbiAgICAgICAgICBpbnN0LnRyaWdnZXIodGhpcy5uYW1lICsgJ3N0YXJ0JywgZXYpO1xuICAgICAgICAgIHRoaXMudHJpZ2dlcmVkID0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGluc3QudHJpZ2dlcih0aGlzLm5hbWUsIGV2KTsgLy8gYmFzaWMgdHJhbnNmb3JtIGV2ZW50XG5cbiAgICAgICAgLy8gdHJpZ2dlciByb3RhdGUgZXZlbnRcbiAgICAgICAgaWYocm90YXRpb25fdGhyZXNob2xkID4gaW5zdC5vcHRpb25zLnRyYW5zZm9ybV9taW5fcm90YXRpb24pIHtcbiAgICAgICAgICBpbnN0LnRyaWdnZXIoJ3JvdGF0ZScsIGV2KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHRyaWdnZXIgcGluY2ggZXZlbnRcbiAgICAgICAgaWYoc2NhbGVfdGhyZXNob2xkID4gaW5zdC5vcHRpb25zLnRyYW5zZm9ybV9taW5fc2NhbGUpIHtcbiAgICAgICAgICBpbnN0LnRyaWdnZXIoJ3BpbmNoJywgZXYpO1xuICAgICAgICAgIGluc3QudHJpZ2dlcigncGluY2gnICsgKChldi5zY2FsZSA8IDEpID8gJ2luJyA6ICdvdXQnKSwgZXYpO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuXG4gICAgICBjYXNlIEhhbW1lci5FVkVOVF9FTkQ6XG4gICAgICAgIC8vIHRyaWdnZXIgZHJhZ2VuZFxuICAgICAgICBpZih0aGlzLnRyaWdnZXJlZCkge1xuICAgICAgICAgIGluc3QudHJpZ2dlcih0aGlzLm5hbWUgKyAnZW5kJywgZXYpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy50cmlnZ2VyZWQgPSBmYWxzZTtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG59O1xuXG4gIC8vIEJhc2VkIG9mZiBMby1EYXNoJ3MgZXhjZWxsZW50IFVNRCB3cmFwcGVyIChzbGlnaHRseSBtb2RpZmllZCkgLSBodHRwczovL2dpdGh1Yi5jb20vYmVzdGllanMvbG9kYXNoL2Jsb2IvbWFzdGVyL2xvZGFzaC5qcyNMNTUxNS1MNTU0M1xuICAvLyBzb21lIEFNRCBidWlsZCBvcHRpbWl6ZXJzLCBsaWtlIHIuanMsIGNoZWNrIGZvciBzcGVjaWZpYyBjb25kaXRpb24gcGF0dGVybnMgbGlrZSB0aGUgZm9sbG93aW5nOlxuICBpZih0eXBlb2YgZGVmaW5lID09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCkge1xuICAgIC8vIGRlZmluZSBhcyBhbiBhbm9ueW1vdXMgbW9kdWxlXG4gICAgZGVmaW5lKGZ1bmN0aW9uKCkgeyByZXR1cm4gSGFtbWVyOyB9KTtcbiAgfVxuXG4gIC8vIGNoZWNrIGZvciBgZXhwb3J0c2AgYWZ0ZXIgYGRlZmluZWAgaW4gY2FzZSBhIGJ1aWxkIG9wdGltaXplciBhZGRzIGFuIGBleHBvcnRzYCBvYmplY3RcbiAgZWxzZSBpZih0eXBlb2YgbW9kdWxlID09PSAnb2JqZWN0JyAmJiBtb2R1bGUuZXhwb3J0cykge1xuICAgIG1vZHVsZS5leHBvcnRzID0gSGFtbWVyO1xuICB9XG5cbiAgZWxzZSB7XG4gICAgd2luZG93LkhhbW1lciA9IEhhbW1lcjtcbiAgfVxuXG59KSh3aW5kb3cpO1xuIiwiLy8gQ29weXJpZ2h0IEpveWVudCwgSW5jLiBhbmQgb3RoZXIgTm9kZSBjb250cmlidXRvcnMuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGFcbi8vIGNvcHkgb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGVcbi8vIFwiU29mdHdhcmVcIiksIHRvIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZ1xuLy8gd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLFxuLy8gZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGwgY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdFxuLy8gcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpcyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlXG4vLyBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZFxuLy8gaW4gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTU1xuLy8gT1IgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRlxuLy8gTUVSQ0hBTlRBQklMSVRZLCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTlxuLy8gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sXG4vLyBEQU1BR0VTIE9SIE9USEVSIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1Jcbi8vIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLCBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEVcbi8vIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTiBUSEUgU09GVFdBUkUuXG5cbmZ1bmN0aW9uIEV2ZW50RW1pdHRlcigpIHtcbiAgdGhpcy5fZXZlbnRzID0gdGhpcy5fZXZlbnRzIHx8IHt9O1xuICB0aGlzLl9tYXhMaXN0ZW5lcnMgPSB0aGlzLl9tYXhMaXN0ZW5lcnMgfHwgdW5kZWZpbmVkO1xufVxubW9kdWxlLmV4cG9ydHMgPSBFdmVudEVtaXR0ZXI7XG5cbi8vIEJhY2t3YXJkcy1jb21wYXQgd2l0aCBub2RlIDAuMTAueFxuRXZlbnRFbWl0dGVyLkV2ZW50RW1pdHRlciA9IEV2ZW50RW1pdHRlcjtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5fZXZlbnRzID0gdW5kZWZpbmVkO1xuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5fbWF4TGlzdGVuZXJzID0gdW5kZWZpbmVkO1xuXG4vLyBCeSBkZWZhdWx0IEV2ZW50RW1pdHRlcnMgd2lsbCBwcmludCBhIHdhcm5pbmcgaWYgbW9yZSB0aGFuIDEwIGxpc3RlbmVycyBhcmVcbi8vIGFkZGVkIHRvIGl0LiBUaGlzIGlzIGEgdXNlZnVsIGRlZmF1bHQgd2hpY2ggaGVscHMgZmluZGluZyBtZW1vcnkgbGVha3MuXG5FdmVudEVtaXR0ZXIuZGVmYXVsdE1heExpc3RlbmVycyA9IDEwO1xuXG4vLyBPYnZpb3VzbHkgbm90IGFsbCBFbWl0dGVycyBzaG91bGQgYmUgbGltaXRlZCB0byAxMC4gVGhpcyBmdW5jdGlvbiBhbGxvd3Ncbi8vIHRoYXQgdG8gYmUgaW5jcmVhc2VkLiBTZXQgdG8gemVybyBmb3IgdW5saW1pdGVkLlxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5zZXRNYXhMaXN0ZW5lcnMgPSBmdW5jdGlvbihuKSB7XG4gIGlmICghaXNOdW1iZXIobikgfHwgbiA8IDAgfHwgaXNOYU4obikpXG4gICAgdGhyb3cgVHlwZUVycm9yKCduIG11c3QgYmUgYSBwb3NpdGl2ZSBudW1iZXInKTtcbiAgdGhpcy5fbWF4TGlzdGVuZXJzID0gbjtcbiAgcmV0dXJuIHRoaXM7XG59O1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLmVtaXQgPSBmdW5jdGlvbih0eXBlKSB7XG4gIHZhciBlciwgaGFuZGxlciwgbGVuLCBhcmdzLCBpLCBsaXN0ZW5lcnM7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHMpXG4gICAgdGhpcy5fZXZlbnRzID0ge307XG5cbiAgLy8gSWYgdGhlcmUgaXMgbm8gJ2Vycm9yJyBldmVudCBsaXN0ZW5lciB0aGVuIHRocm93LlxuICBpZiAodHlwZSA9PT0gJ2Vycm9yJykge1xuICAgIGlmICghdGhpcy5fZXZlbnRzLmVycm9yIHx8XG4gICAgICAgIChpc09iamVjdCh0aGlzLl9ldmVudHMuZXJyb3IpICYmICF0aGlzLl9ldmVudHMuZXJyb3IubGVuZ3RoKSkge1xuICAgICAgZXIgPSBhcmd1bWVudHNbMV07XG4gICAgICBpZiAoZXIgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICB0aHJvdyBlcjsgLy8gVW5oYW5kbGVkICdlcnJvcicgZXZlbnRcbiAgICAgIH1cbiAgICAgIHRocm93IFR5cGVFcnJvcignVW5jYXVnaHQsIHVuc3BlY2lmaWVkIFwiZXJyb3JcIiBldmVudC4nKTtcbiAgICB9XG4gIH1cblxuICBoYW5kbGVyID0gdGhpcy5fZXZlbnRzW3R5cGVdO1xuXG4gIGlmIChpc1VuZGVmaW5lZChoYW5kbGVyKSlcbiAgICByZXR1cm4gZmFsc2U7XG5cbiAgaWYgKGlzRnVuY3Rpb24oaGFuZGxlcikpIHtcbiAgICBzd2l0Y2ggKGFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgIC8vIGZhc3QgY2FzZXNcbiAgICAgIGNhc2UgMTpcbiAgICAgICAgaGFuZGxlci5jYWxsKHRoaXMpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMjpcbiAgICAgICAgaGFuZGxlci5jYWxsKHRoaXMsIGFyZ3VtZW50c1sxXSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAzOlxuICAgICAgICBoYW5kbGVyLmNhbGwodGhpcywgYXJndW1lbnRzWzFdLCBhcmd1bWVudHNbMl0pO1xuICAgICAgICBicmVhaztcbiAgICAgIC8vIHNsb3dlclxuICAgICAgZGVmYXVsdDpcbiAgICAgICAgbGVuID0gYXJndW1lbnRzLmxlbmd0aDtcbiAgICAgICAgYXJncyA9IG5ldyBBcnJheShsZW4gLSAxKTtcbiAgICAgICAgZm9yIChpID0gMTsgaSA8IGxlbjsgaSsrKVxuICAgICAgICAgIGFyZ3NbaSAtIDFdID0gYXJndW1lbnRzW2ldO1xuICAgICAgICBoYW5kbGVyLmFwcGx5KHRoaXMsIGFyZ3MpO1xuICAgIH1cbiAgfSBlbHNlIGlmIChpc09iamVjdChoYW5kbGVyKSkge1xuICAgIGxlbiA9IGFyZ3VtZW50cy5sZW5ndGg7XG4gICAgYXJncyA9IG5ldyBBcnJheShsZW4gLSAxKTtcbiAgICBmb3IgKGkgPSAxOyBpIDwgbGVuOyBpKyspXG4gICAgICBhcmdzW2kgLSAxXSA9IGFyZ3VtZW50c1tpXTtcblxuICAgIGxpc3RlbmVycyA9IGhhbmRsZXIuc2xpY2UoKTtcbiAgICBsZW4gPSBsaXN0ZW5lcnMubGVuZ3RoO1xuICAgIGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKylcbiAgICAgIGxpc3RlbmVyc1tpXS5hcHBseSh0aGlzLCBhcmdzKTtcbiAgfVxuXG4gIHJldHVybiB0cnVlO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5hZGRMaXN0ZW5lciA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIHZhciBtO1xuXG4gIGlmICghaXNGdW5jdGlvbihsaXN0ZW5lcikpXG4gICAgdGhyb3cgVHlwZUVycm9yKCdsaXN0ZW5lciBtdXN0IGJlIGEgZnVuY3Rpb24nKTtcblxuICBpZiAoIXRoaXMuX2V2ZW50cylcbiAgICB0aGlzLl9ldmVudHMgPSB7fTtcblxuICAvLyBUbyBhdm9pZCByZWN1cnNpb24gaW4gdGhlIGNhc2UgdGhhdCB0eXBlID09PSBcIm5ld0xpc3RlbmVyXCIhIEJlZm9yZVxuICAvLyBhZGRpbmcgaXQgdG8gdGhlIGxpc3RlbmVycywgZmlyc3QgZW1pdCBcIm5ld0xpc3RlbmVyXCIuXG4gIGlmICh0aGlzLl9ldmVudHMubmV3TGlzdGVuZXIpXG4gICAgdGhpcy5lbWl0KCduZXdMaXN0ZW5lcicsIHR5cGUsXG4gICAgICAgICAgICAgIGlzRnVuY3Rpb24obGlzdGVuZXIubGlzdGVuZXIpID9cbiAgICAgICAgICAgICAgbGlzdGVuZXIubGlzdGVuZXIgOiBsaXN0ZW5lcik7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgLy8gT3B0aW1pemUgdGhlIGNhc2Ugb2Ygb25lIGxpc3RlbmVyLiBEb24ndCBuZWVkIHRoZSBleHRyYSBhcnJheSBvYmplY3QuXG4gICAgdGhpcy5fZXZlbnRzW3R5cGVdID0gbGlzdGVuZXI7XG4gIGVsc2UgaWYgKGlzT2JqZWN0KHRoaXMuX2V2ZW50c1t0eXBlXSkpXG4gICAgLy8gSWYgd2UndmUgYWxyZWFkeSBnb3QgYW4gYXJyYXksIGp1c3QgYXBwZW5kLlxuICAgIHRoaXMuX2V2ZW50c1t0eXBlXS5wdXNoKGxpc3RlbmVyKTtcbiAgZWxzZVxuICAgIC8vIEFkZGluZyB0aGUgc2Vjb25kIGVsZW1lbnQsIG5lZWQgdG8gY2hhbmdlIHRvIGFycmF5LlxuICAgIHRoaXMuX2V2ZW50c1t0eXBlXSA9IFt0aGlzLl9ldmVudHNbdHlwZV0sIGxpc3RlbmVyXTtcblxuICAvLyBDaGVjayBmb3IgbGlzdGVuZXIgbGVha1xuICBpZiAoaXNPYmplY3QodGhpcy5fZXZlbnRzW3R5cGVdKSAmJiAhdGhpcy5fZXZlbnRzW3R5cGVdLndhcm5lZCkge1xuICAgIHZhciBtO1xuICAgIGlmICghaXNVbmRlZmluZWQodGhpcy5fbWF4TGlzdGVuZXJzKSkge1xuICAgICAgbSA9IHRoaXMuX21heExpc3RlbmVycztcbiAgICB9IGVsc2Uge1xuICAgICAgbSA9IEV2ZW50RW1pdHRlci5kZWZhdWx0TWF4TGlzdGVuZXJzO1xuICAgIH1cblxuICAgIGlmIChtICYmIG0gPiAwICYmIHRoaXMuX2V2ZW50c1t0eXBlXS5sZW5ndGggPiBtKSB7XG4gICAgICB0aGlzLl9ldmVudHNbdHlwZV0ud2FybmVkID0gdHJ1ZTtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJyhub2RlKSB3YXJuaW5nOiBwb3NzaWJsZSBFdmVudEVtaXR0ZXIgbWVtb3J5ICcgK1xuICAgICAgICAgICAgICAgICAgICAnbGVhayBkZXRlY3RlZC4gJWQgbGlzdGVuZXJzIGFkZGVkLiAnICtcbiAgICAgICAgICAgICAgICAgICAgJ1VzZSBlbWl0dGVyLnNldE1heExpc3RlbmVycygpIHRvIGluY3JlYXNlIGxpbWl0LicsXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX2V2ZW50c1t0eXBlXS5sZW5ndGgpO1xuICAgICAgaWYgKHR5cGVvZiBjb25zb2xlLnRyYWNlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIC8vIG5vdCBzdXBwb3J0ZWQgaW4gSUUgMTBcbiAgICAgICAgY29uc29sZS50cmFjZSgpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5vbiA9IEV2ZW50RW1pdHRlci5wcm90b3R5cGUuYWRkTGlzdGVuZXI7XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub25jZSA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIGlmICghaXNGdW5jdGlvbihsaXN0ZW5lcikpXG4gICAgdGhyb3cgVHlwZUVycm9yKCdsaXN0ZW5lciBtdXN0IGJlIGEgZnVuY3Rpb24nKTtcblxuICB2YXIgZmlyZWQgPSBmYWxzZTtcblxuICBmdW5jdGlvbiBnKCkge1xuICAgIHRoaXMucmVtb3ZlTGlzdGVuZXIodHlwZSwgZyk7XG5cbiAgICBpZiAoIWZpcmVkKSB7XG4gICAgICBmaXJlZCA9IHRydWU7XG4gICAgICBsaXN0ZW5lci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH1cbiAgfVxuXG4gIGcubGlzdGVuZXIgPSBsaXN0ZW5lcjtcbiAgdGhpcy5vbih0eXBlLCBnKTtcblxuICByZXR1cm4gdGhpcztcbn07XG5cbi8vIGVtaXRzIGEgJ3JlbW92ZUxpc3RlbmVyJyBldmVudCBpZmYgdGhlIGxpc3RlbmVyIHdhcyByZW1vdmVkXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLnJlbW92ZUxpc3RlbmVyID0gZnVuY3Rpb24odHlwZSwgbGlzdGVuZXIpIHtcbiAgdmFyIGxpc3QsIHBvc2l0aW9uLCBsZW5ndGgsIGk7XG5cbiAgaWYgKCFpc0Z1bmN0aW9uKGxpc3RlbmVyKSlcbiAgICB0aHJvdyBUeXBlRXJyb3IoJ2xpc3RlbmVyIG11c3QgYmUgYSBmdW5jdGlvbicpO1xuXG4gIGlmICghdGhpcy5fZXZlbnRzIHx8ICF0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgcmV0dXJuIHRoaXM7XG5cbiAgbGlzdCA9IHRoaXMuX2V2ZW50c1t0eXBlXTtcbiAgbGVuZ3RoID0gbGlzdC5sZW5ndGg7XG4gIHBvc2l0aW9uID0gLTE7XG5cbiAgaWYgKGxpc3QgPT09IGxpc3RlbmVyIHx8XG4gICAgICAoaXNGdW5jdGlvbihsaXN0Lmxpc3RlbmVyKSAmJiBsaXN0Lmxpc3RlbmVyID09PSBsaXN0ZW5lcikpIHtcbiAgICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuICAgIGlmICh0aGlzLl9ldmVudHMucmVtb3ZlTGlzdGVuZXIpXG4gICAgICB0aGlzLmVtaXQoJ3JlbW92ZUxpc3RlbmVyJywgdHlwZSwgbGlzdGVuZXIpO1xuXG4gIH0gZWxzZSBpZiAoaXNPYmplY3QobGlzdCkpIHtcbiAgICBmb3IgKGkgPSBsZW5ndGg7IGktLSA+IDA7KSB7XG4gICAgICBpZiAobGlzdFtpXSA9PT0gbGlzdGVuZXIgfHxcbiAgICAgICAgICAobGlzdFtpXS5saXN0ZW5lciAmJiBsaXN0W2ldLmxpc3RlbmVyID09PSBsaXN0ZW5lcikpIHtcbiAgICAgICAgcG9zaXRpb24gPSBpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAocG9zaXRpb24gPCAwKVxuICAgICAgcmV0dXJuIHRoaXM7XG5cbiAgICBpZiAobGlzdC5sZW5ndGggPT09IDEpIHtcbiAgICAgIGxpc3QubGVuZ3RoID0gMDtcbiAgICAgIGRlbGV0ZSB0aGlzLl9ldmVudHNbdHlwZV07XG4gICAgfSBlbHNlIHtcbiAgICAgIGxpc3Quc3BsaWNlKHBvc2l0aW9uLCAxKTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fZXZlbnRzLnJlbW92ZUxpc3RlbmVyKVxuICAgICAgdGhpcy5lbWl0KCdyZW1vdmVMaXN0ZW5lcicsIHR5cGUsIGxpc3RlbmVyKTtcbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVBbGxMaXN0ZW5lcnMgPSBmdW5jdGlvbih0eXBlKSB7XG4gIHZhciBrZXksIGxpc3RlbmVycztcblxuICBpZiAoIXRoaXMuX2V2ZW50cylcbiAgICByZXR1cm4gdGhpcztcblxuICAvLyBub3QgbGlzdGVuaW5nIGZvciByZW1vdmVMaXN0ZW5lciwgbm8gbmVlZCB0byBlbWl0XG4gIGlmICghdGhpcy5fZXZlbnRzLnJlbW92ZUxpc3RlbmVyKSB7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDApXG4gICAgICB0aGlzLl9ldmVudHMgPSB7fTtcbiAgICBlbHNlIGlmICh0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gZW1pdCByZW1vdmVMaXN0ZW5lciBmb3IgYWxsIGxpc3RlbmVycyBvbiBhbGwgZXZlbnRzXG4gIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKSB7XG4gICAgZm9yIChrZXkgaW4gdGhpcy5fZXZlbnRzKSB7XG4gICAgICBpZiAoa2V5ID09PSAncmVtb3ZlTGlzdGVuZXInKSBjb250aW51ZTtcbiAgICAgIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKGtleSk7XG4gICAgfVxuICAgIHRoaXMucmVtb3ZlQWxsTGlzdGVuZXJzKCdyZW1vdmVMaXN0ZW5lcicpO1xuICAgIHRoaXMuX2V2ZW50cyA9IHt9O1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgbGlzdGVuZXJzID0gdGhpcy5fZXZlbnRzW3R5cGVdO1xuXG4gIGlmIChpc0Z1bmN0aW9uKGxpc3RlbmVycykpIHtcbiAgICB0aGlzLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGxpc3RlbmVycyk7XG4gIH0gZWxzZSB7XG4gICAgLy8gTElGTyBvcmRlclxuICAgIHdoaWxlIChsaXN0ZW5lcnMubGVuZ3RoKVxuICAgICAgdGhpcy5yZW1vdmVMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcnNbbGlzdGVuZXJzLmxlbmd0aCAtIDFdKTtcbiAgfVxuICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuXG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5saXN0ZW5lcnMgPSBmdW5jdGlvbih0eXBlKSB7XG4gIHZhciByZXQ7XG4gIGlmICghdGhpcy5fZXZlbnRzIHx8ICF0aGlzLl9ldmVudHNbdHlwZV0pXG4gICAgcmV0ID0gW107XG4gIGVsc2UgaWYgKGlzRnVuY3Rpb24odGhpcy5fZXZlbnRzW3R5cGVdKSlcbiAgICByZXQgPSBbdGhpcy5fZXZlbnRzW3R5cGVdXTtcbiAgZWxzZVxuICAgIHJldCA9IHRoaXMuX2V2ZW50c1t0eXBlXS5zbGljZSgpO1xuICByZXR1cm4gcmV0O1xufTtcblxuRXZlbnRFbWl0dGVyLmxpc3RlbmVyQ291bnQgPSBmdW5jdGlvbihlbWl0dGVyLCB0eXBlKSB7XG4gIHZhciByZXQ7XG4gIGlmICghZW1pdHRlci5fZXZlbnRzIHx8ICFlbWl0dGVyLl9ldmVudHNbdHlwZV0pXG4gICAgcmV0ID0gMDtcbiAgZWxzZSBpZiAoaXNGdW5jdGlvbihlbWl0dGVyLl9ldmVudHNbdHlwZV0pKVxuICAgIHJldCA9IDE7XG4gIGVsc2VcbiAgICByZXQgPSBlbWl0dGVyLl9ldmVudHNbdHlwZV0ubGVuZ3RoO1xuICByZXR1cm4gcmV0O1xufTtcblxuZnVuY3Rpb24gaXNGdW5jdGlvbihhcmcpIHtcbiAgcmV0dXJuIHR5cGVvZiBhcmcgPT09ICdmdW5jdGlvbic7XG59XG5cbmZ1bmN0aW9uIGlzTnVtYmVyKGFyZykge1xuICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gJ251bWJlcic7XG59XG5cbmZ1bmN0aW9uIGlzT2JqZWN0KGFyZykge1xuICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gJ29iamVjdCcgJiYgYXJnICE9PSBudWxsO1xufVxuXG5mdW5jdGlvbiBpc1VuZGVmaW5lZChhcmcpIHtcbiAgcmV0dXJuIGFyZyA9PT0gdm9pZCAwO1xufVxuIl19 +/******/ }); \ No newline at end of file diff --git a/dist/skifree.min.js b/dist/skifree.min.js index e2e70f7..53300d4 100644 --- a/dist/skifree.min.js +++ b/dist/skifree.min.js @@ -1,2 +1,6 @@ -(function e(t,n,r){function i(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(s)return s(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 i(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var s=typeof require=="function"&&require;for(var o=0;o2?i=.1:i+=.1;if(e>=0)return"sEast"+Math.ceil(i);if(e<0)return"sWest"+Math.ceil(i)};return n(e,r())},t.startEating=u,t}e.monster=t})(this),typeof t!="undefined"&&(t.exports=this.monster)},{"./sprite":11}],8:[function(e,t,n){(function(){var e,t=function(){},n=["assert","clear","count","debug","dir","dirxml","error","exception","group","groupCollapsed","groupEnd","info","log","markTimeline","profile","profileEnd","table","time","timeEnd","timeStamp","trace","warn"],r=n.length,i=window.console=window.console||{};while(r--)e=n[r],i[e]||(i[e]=t)})()},{}],9:[function(e,t,n){var r=e("./sprite");typeof navigator!="undefined"?navigator.vibrate=navigator.vibrate||navigator.webkitVibrate||navigator.mozVibrate||navigator.msVibrate:navigator={vibrate:!1},function(e){function t(e){function b(){n.setSpeed(c),n.isMoving=!0,n.hasBeenHit=!1,n.isJumping=!1,n.isPerformingTrick=!1,u&&clearInterval(u),n.setMapPosition(undefined,undefined,0)}function w(){n.isMoving=!1,n.hasBeenHit=!0,n.isJumping=!1,n.isPerformingTrick=!1,u&&clearInterval(u),n.setMapPosition(undefined,undefined,0)}function E(){var e=n.getSpeed();n.setSpeed(e+2),n.setSpeedY(e+2),n.isMoving=!0,n.hasBeenHit=!1,n.isJumping=!0,n.setMapPosition(undefined,undefined,1)}function S(){if(n.direction)return n.direction<=90?"east":n.direction>90&&n.direction<150?"esEast":n.direction>=150&&n.direction<180?"sEast":n.direction===180?"south":n.direction>180&&n.direction<=210?"sWest":n.direction>210&&n.direction<270?"wsWest":n.direction>=270?"west":"south";var e=n.movingToward[0]-n.mapPosition[0],t=n.movingToward[1]-n.mapPosition[1];return t<=0?e>0?"east":"west":s.esEast(e)?"esEast":s.sEast(e)?"sEast":s.wsWest(e)?"wsWest":s.sWest(e)?"sWest":"south"}function x(e){t[e]&&n.setDirection(t[e]),e==="west"||e==="east"?n.isMoving=!1:n.isMoving=!0}function T(){return"blank"}function N(){return"jumping"}function C(){return console.log("Trick step is",y),y===0?"jumping":y===1?"somersault1":"somersault2"}function k(e,t,r){return r===0||r===1?t:(et&&(e-=n.getSpeed()*(r/p)),e)}var t={west:270,wsWest:240,sWest:195,south:180,sEast:165,esEast:120,east:90},n=new r(e),i={draw:n.superior("draw"),cycle:n.superior("cycle"),getSpeedX:n.superior("getSpeedX"),getSpeedY:n.superior("getSpeedY"),hits:n.superior("hits")},s={esEast:function(e){return e>300},sEast:function(e){return e>75},wsWest:function(e){return e<-300},sWest:function(e){return e<-75}},o,u,a=!0,f=[],l=0,c=5,h=2,p=70,d=0,v=0,m=0,g=1,y=0;return n.isMoving=!0,n.hasBeenHit=!1,n.isJumping=!1,n.isPerformingTrick=!1,n.onHitObstacleCb=function(){},n.setSpeed(c),n.reset=function(){f=[],l=0,n.isMoving=!0,n.hasBeenHit=!1,a=!0,b()},n.stop=function(){n.direction>180?x("west"):x("east")},n.turnEast=function(){var e=S();switch(e){case"west":x("wsWest");break;case"wsWest":x("sWest");break;case"sWest":x("south");break;case"south":x("sEast");break;case"sEast":x("esEast");break;case"esEast":x("east");break;default:x("south")}},n.turnWest=function(){var e=S();switch(e){case"east":x("esEast");break;case"esEast":x("sEast");break;case"sEast":x("south");break;case"south":x("sWest");break;case"sWest":x("wsWest");break;case"wsWest":x("west");break;default:x("south")}},n.stepWest=function(){n.mapPosition[0]-=n.speed*2},n.stepEast=function(){n.mapPosition[0]+=n.speed*2},n.setMapPositionTarget=function(e,t){if(n.hasBeenHit)return;Math.abs(n.mapPosition[0]-e)<=75&&(e=n.mapPosition[0]),n.movingToward=[e,t]},n.startMovingIfPossible=function(){!n.hasBeenHit&&!n.isBeingEaten&&(n.isMoving=!0)},n.setTurnEaseCycles=function(e){p=e},n.getPixelsTravelledDownMountain=function(){return l},n.resetSpeed=function(){n.setSpeed(c)},n.cycle=function(){n.getSpeedX()<=0&&n.getSpeedY()<=0&&(n.isMoving=!1),n.isMoving&&(l+=n.speed),n.isJumping&&n.setMapPositionTarget(undefined,n.mapPosition[1]+n.getSpeed()),i.cycle(),n.checkHittableObjects()},n.draw=function(e){var t=function(){return n.isBeingEaten?T():n.isJumping?n.isPerformingTrick?C():N():n.hasBeenHit?"hit":S()};return i.draw(e,t())},n.hits=function(e){return f.indexOf(e.id)!==-1?!1:e.occupiesZIndex(n.mapPosition[2])?i.hits(e)?!0:!1:!1},n.speedBoost=function(){var e=n.speed;a&&(a=!1,n.setSpeed(n.speed*h),setTimeout(function(){n.setSpeed(e),setTimeout(function(){a=!0},1e4)},2e3))},n.attemptTrick=function(){n.isJumping&&(n.isPerformingTrick=!0,u=setInterval(function(){y>=2?y=0:y+=1},300))},n.getStandardSpeed=function(){return c},n.getSpeedX=function(){return S()==="esEast"||S()==="wsWest"?(v=.5,d=k(d,n.getSpeed()*v,v),d):S()==="sEast"||S()==="sWest"?(v=.33,d=k(d,n.getSpeed()*v,v),d):(d=k(d,0,v),d)},n.setSpeedY=function(e){m=e},n.getSpeedY=function(){var e;return n.isJumping?m:S()==="esEast"||S()==="wsWest"?(g=.6,m=k(m,n.getSpeed()*.6,.6),m):S()==="sEast"||S()==="sWest"?(g=.85,m=k(m,n.getSpeed()*.85,.85),m):S()==="east"||S()==="west"?(g=1,m=0,m):(m=k(m,n.getSpeed(),g),m)},n.hasHitObstacle=function(e){w(),navigator.vibrate&&navigator.vibrate(500),f.push(e.id),n.resetSpeed(),n.onHitObstacleCb(e),o&&clearTimeout(o),o=setTimeout(function(){b()},1500)},n.hasHitJump=function(){E(),o&&clearTimeout(o),o=setTimeout(function(){b()},1e3)},n.isEatenBy=function(e,t){n.hasHitObstacle(e),e.startEating(t),f.push(e.id),n.isMoving=!1,n.isBeingEaten=!0},n.reset=function(){f=[],l=0,n.isMoving=!0,n.isJumping=!1,n.hasBeenHit=!1,a=!0},n.setHitObstacleCb=function(e){n.onHitObstacleCb=e||function(){}},n}e.skier=t}(this),typeof t!="undefined"&&(t.exports=this.skier)},{"./sprite":11}],10:[function(e,t,n){var r=e("./sprite");(function(e){function t(e){function o(){var e=t.movingToward[0]-t.mapPosition[0],n=t.movingToward[1]-t.mapPosition[1];return i.sEast(e)?"sEast":"sWest"}var t=new r(e),n={draw:t.superior("draw"),cycle:t.superior("cycle")},i={sEast:function(e){return e>0},sWest:function(e){return e<=0}},s=3;return t.setSpeed(s),t.cycle=function(e){Number.random(10)===1&&(t.setMapPositionTarget(e.getRandomlyInTheCentreOfMap()),t.setSpeed(s+Number.random(-1,1))),t.setMapPositionTarget(undefined,e.getMapBelowViewport()+600),n.cycle()},t.draw=function(e){var t=function(){return o()};return n.draw(e,t())},t}e.snowboarder=t})(this),typeof t!="undefined"&&(t.exports=this.snowboarder)},{"./sprite":11}],11:[function(e,t,n){(function(t){function r(e){function o(e){i.canvasX+=e.toNumber()}function u(e){i.canvasY+=e.toNumber()}function a(t){if(i.data.hitBoxes&&e.hitBoxes[t])return e.hitBoxes[t]}function f(e){return e=Math.round(e*2)/2,e}function l(){if(!i.isMoving)return;var e=i.mapPosition[0],t=i.mapPosition[1];if(typeof i.direction!="undefined"){var n=i.direction-90;n<0&&(n=360+n),e+=f(i.speed*Math.cos(n*(Math.PI/180))),t+=f(i.speed*Math.sin(n*(Math.PI/180)))}else typeof i.movingToward[0]!="undefined"&&(e>i.movingToward[0]?e-=Math.min(i.getSpeedX(),Math.abs(e-i.movingToward[0])):ei.movingToward[1]?t-=Math.min(i.getSpeedY(),Math.abs(t-i.movingToward[1])):t75?0-e:0,r=-t;return[n,r]},this.checkHittableObjects=function(){Object.keys(t,function(e,n){n.object.deleted?delete t[e]:n.object.hits(i)&&n.callbacks.each(function(e){e(i,n.object)})})},this.cycle=function(){i.checkHittableObjects(),s&&i.setMapPositionTarget(s.mapPosition[0],s.mapPosition[1],!0),l()},this.setMapPositionTarget=function(e,t,n){n&&(i.movingWithConviction=!1),i.movingWithConviction||(typeof e=="undefined"&&(e=i.movingToward[0]),typeof t=="undefined"&&(t=i.movingToward[1]),i.movingToward=[e,t],i.movingWithConviction=!1)},this.setDirection=function(e){e>=360&&(e=360-e),i.direction=e,i.movingToward=undefined},this.resetDirection=function(){i.direction=undefined},this.setMapPositionTargetWithConviction=function(e,t){i.setMapPositionTarget(e,t),i.movingWithConviction=!0},this.follow=function(e){s=e},this.stopFollowing=function(){s=!1},this.onHitting=function(e,n){if(t[e.id])return t[e.id].callbacks.push(n);t[e.id]={object:e,callbacks:[n]}},this.deleteOnNextCycle=function(){i.deleted=!0},this.occupiesZIndex=function(e){return r.indexOf(e)>=0},this.hits=function(e){var t=!1,n=!1;return e.getTopHitBoxEdge(i.mapPosition[2])<=i.getBottomHitBoxEdge(i.mapPosition[2])&&e.getBottomHitBoxEdge(i.mapPosition[2])>=i.getBottomHitBoxEdge(i.mapPosition[2])&&(t=!0),e.getTopHitBoxEdge(i.mapPosition[2])<=i.getTopHitBoxEdge(i.mapPosition[2])&&e.getBottomHitBoxEdge(i.mapPosition[2])>=i.getTopHitBoxEdge(i.mapPosition[2])&&(t=!0),e.getLeftHitBoxEdge(i.mapPosition[2])<=i.getRightHitBoxEdge(i.mapPosition[2])&&e.getRightHitBoxEdge(i.mapPosition[2])>=i.getRightHitBoxEdge(i.mapPosition[2])&&(n=!0),e.getLeftHitBoxEdge(i.mapPosition[2])<=i.getLeftHitBoxEdge(i.mapPosition[2])&&e.getRightHitBoxEdge(i.mapPosition[2])>=i.getLeftHitBoxEdge(i.mapPosition[2])&&(n=!0),t&&n},this.isAboveOnCanvas=function(e){return i.canvasY+i.heighte},i}var n=e("./guid");r.createObjects=function(t,n){function i(e){var t=n.position;if(Number.random(100+n.rateModifier)<=e.dropRate){var i=new r(e.sprite);return i.setSpeed(0),Object.isFunction(t)&&(t=t()),i.setMapPosition(t[0],t[1]),e.sprite.hitBehaviour&&e.sprite.hitBehaviour.skier&&n.player&&i.onHitting(n.player,e.sprite.hitBehaviour.skier),i}}Array.isArray(t)||(t=[t]),n=Object.merge(n,{rateModifier:0,dropRate:1,position:[0,0]},!1,!1);var s=t.map(i).remove(undefined);return s},t.sprite=r})(this),typeof t!="undefined"&&(t.exports=this.sprite)},{"./guid":4}],12:[function(e,t,n){(function(e){function t(){return this.pushHandlers=[],this}t.prototype=Object.create(Array.prototype),t.prototype.onPush=function(e,t){this.pushHandlers.push(e),t&&this.each(e)},t.prototype.push=function(e){Array.prototype.push.call(this,e),this.pushHandlers.each(function(t){t(e)})},t.prototype.cull=function(){this.each(function(e,t){if(e.deleted)return delete this[t]})},e.spriteArray=t})(this),typeof t!="undefined"&&(t.exports=this.spriteArray)},{}],13:[function(e,t,n){function C(e,t){function i(){n+=1,n===e.length&&t(r)}var n=0,r={};e.each(function(e){var t=new Image;t.onload=i,t.src=e,d.storeLoadedImage(e,t)})}function k(e,t){t.isEatenBy(e,function(){S-=1,e.isFull=!0,e.isEating=!1,t.isBeingEaten=!1,e.setSpeed(t.getSpeed()),e.stopFollowing();var n=d.getRandomMapPositionAboveViewport();e.setMapPositionTarget(n[0],n[1])})}function L(e){function v(){w=0,S=5,x=localStorage.getItem("highScore"),o.reset(),o.addStaticObject(n)}function m(){o.isPaused()||(x=localStorage.setItem("highScore",w),s.setLines(["Game over!","Hit space to restart"]),o.pause(),o.cycle())}function C(e,t){var n=Math.max(800-p.width,0);Number.random(1e3+n)<=t&&e()}function L(){var e=new u(y.monster),n=d.getRandomMapPositionAboveViewport();e.setMapPosition(n[0],n[1]),e.follow(t),e.setSpeed(t.getStandardSpeed()),e.onHitting(t,k),o.addMovingObject(e,"monster")}function A(){var e=new f(y.snowboarder),n=d.getRandomMapPositionAboveViewport(),r=d.getRandomMapPositionBelowViewport();e.setMapPosition(n[0],n[1]),e.setMapPositionTarget(r[0],r[1]),e.onHitting(t,y.snowboarder.hitBehaviour.skier),o.addMovingObject(e)}var t,n,s,o;t=new l(y.skier),t.setMapPosition(0,0),t.setMapPositionTarget(0,-10),T&&t.setHitObstacleCb(function(){S-=1}),o=new h(p,t),n=new a(y.signStart),o.addStaticObject(n),n.setMapPosition(-50,0),d.followSprite(t),s=new c({initialLines:["SkiFree.js",g,"Travelled 0m","High Score: "+x,"Skiers left: "+S,"Created by Dan Hough (@basicallydan)"],position:{top:15,right:10}}),o.beforeCycle(function(){var e=[];t.isMoving&&(e=a.createObjects([{sprite:y.smallTree,dropRate:N.smallTree},{sprite:y.tallTree,dropRate:N.tallTree},{sprite:y.jump,dropRate:N.jump},{sprite:y.thickSnow,dropRate:N.thickSnow},{sprite:y.rock,dropRate:N.rock}],{rateModifier:Math.max(800-p.width,0),position:function(){return d.getRandomMapPositionBelowViewport()},player:t})),o.isPaused()||(o.addStaticObjects(e),C(A,.1),w=parseFloat(t.getPixelsTravelledDownMountain()/b).toFixed(1),w>E&&C(L,.001),s.setLines(["SkiFree.js",g,"Travelled "+w+"m","Skiers left: "+S,"High Score: "+x,"Created by Dan Hough (@basicallydan)","Current Speed: "+t.getSpeed()]))}),o.afterCycle(function(){S===0&&m()}),o.addUIElement(s),$(p).mousemove(function(e){o.setMouseX(e.pageX),o.setMouseY(e.pageY),t.resetDirection(),t.startMovingIfPossible()}).bind("click",function(e){o.setMouseX(e.pageX),o.setMouseY(e.pageY),t.resetDirection(),t.startMovingIfPossible()}).focus(),i.bind("f",t.speedBoost),i.bind("t",t.attemptTrick),i.bind(["w","up"],function(){t.stop()}),i.bind(["a","left"],function(){t.direction===270?t.stepWest():t.turnWest()}),i.bind(["s","down"],function(){t.setDirection(180),t.startMovingIfPossible()}),i.bind(["d","right"],function(){t.direction===90?t.stepEast():t.turnEast()}),i.bind("m",L),i.bind("b",A),i.bind("space",v);var O=r(p).on("press",function(e){e.preventDefault(),o.setMouseX(e.center.x),o.setMouseY(e.center.y)}).on("tap",function(e){o.setMouseX(e.center.x),o.setMouseY(e.center.y)}).on("pan",function(e){o.setMouseX(e.center.x),o.setMouseY(e.center.y),t.resetDirection(),t.startMovingIfPossible()}).on("doubletap",function(e){t.speedBoost()});t.isMoving=!1,t.setDirection(270),o.start()}function A(){p.width=window.innerWidth,p.height=window.innerHeight}e("./lib/canvasRenderingContext2DExtensions"),e("./lib/extenders"),e("./lib/plugins");var r=e("hammerjs"),i=e("br-mousetrap"),s=e("./lib/isMobileDevice"),o=e("./lib/spriteArray"),u=e("./lib/monster"),a=e("./lib/sprite"),f=e("./lib/snowboarder"),l=e("./lib/skier"),c=e("./lib/infoBox"),h=e("./lib/game"),p=document.getElementById("skifree-canvas"),d=p.getContext("2d"),v=["sprite-characters.png","skifree-objects.png"],m=this,g="Use the mouse or WASD to control the player";s()&&(g="Tap or drag on the piste to control the player");var y=e("./spriteInfo"),b=18,w=0,E=2e3,S=5,x=0,T=!1,N={smallTree:4,tallTree:2,jump:1,thickSnow:1,rock:1};localStorage.getItem("highScore")&&(x=localStorage.getItem("highScore")),window.addEventListener("resize",A,!1),A(),C(v,L),this.exports=window},{"./lib/canvasRenderingContext2DExtensions":1,"./lib/extenders":2,"./lib/game":3,"./lib/infoBox":5,"./lib/isMobileDevice":6,"./lib/monster":7,"./lib/plugins":8,"./lib/skier":9,"./lib/snowboarder":10,"./lib/sprite":11,"./lib/spriteArray":12,"./spriteInfo":14,"br-mousetrap":15,hammerjs:18}],14:[function(e,t,n){(function(e){function n(e){e.deleteOnNextCycle()}function r(e,t){t.deleteOnNextCycle()}function i(e,t){e.hasHitObstacle(t)}function s(e,t){t.hasHitObstacle(e)}function o(e,t){t.hasHitObstacle(e)}function u(e,t){e.hasHitJump(t)}function a(e,t){t.hasHitJump(e)}function f(e,t){t.hasHitObstacle(e)}var t={skier:{$imageFile:"sprite-characters.png",parts:{blank:[0,0,0,0],east:[0,0,24,34],esEast:[24,0,24,34],sEast:[49,0,17,34],south:[65,0,17,34],sWest:[49,37,17,34],wsWest:[24,37,24,34],west:[0,37,24,34],hit:[0,78,31,31],jumping:[84,0,32,34],somersault1:[116,0,32,34],somersault2:[148,0,32,34]},hitBoxes:{0:[7,20,27,34]},id:"player",hitBehaviour:{}},smallTree:{$imageFile:"skifree-objects.png",parts:{main:[0,28,30,34]},hitBoxes:{0:[0,18,30,34]},hitBehaviour:{}},tallTree:{$imageFile:"skifree-objects.png",parts:{main:[95,66,32,64]},zIndexesOccupied:[0,1],hitBoxes:{0:[0,54,32,64],1:[0,10,32,54]},hitBehaviour:{}},thickSnow:{$imageFile:"skifree-objects.png",parts:{main:[143,53,43,10]},hitBehaviour:{}},rock:{$imageFile:"skifree-objects.png",parts:{main:[30,52,23,11]},hitBehaviour:{}},monster:{$imageFile:"sprite-characters.png",parts:{sEast1:[64,112,26,43],sEast2:[90,112,32,43],sWest1:[64,158,26,43],sWest2:[90,158,32,43],eating1:[122,112,34,43],eating2:[156,112,31,43],eating3:[187,112,31,43],eating4:[219,112,25,43],eating5:[243,112,26,43]},hitBehaviour:{}},jump:{$imageFile:"skifree-objects.png",parts:{main:[109,55,32,8]},hitBehaviour:{}},signStart:{$imageFile:"skifree-objects.png",parts:{main:[260,103,42,27]},hitBehaviour:{}},snowboarder:{$imageFile:"sprite-characters.png",parts:{sEast:[73,229,20,29],sWest:[95,228,26,30]},hitBehaviour:{}},emptyChairLift:{$imageFile:"skifree-objects.png",parts:{main:[92,136,26,30]},zIndexesOccupied:[1]}};t.monster.hitBehaviour.tree=n,t.smallTree.hitBehaviour.monster=r,t.tallTree.hitBehaviour.monster=r,t.smallTree.hitBehaviour.skier=s,t.tallTree.hitBehaviour.skier=s,t.rock.hitBehaviour.skier=o,t.jump.hitBehaviour.skier=a,t.snowboarder.hitBehaviour.skier=f,e.spriteInfo=t})(this),typeof t!="undefined"&&(t.exports=this.spriteInfo)},{}],15:[function(e,t,n){(function(){function p(e,t,n){if(e.addEventListener){e.addEventListener(t,n,!1);return}e.attachEvent("on"+t,n)}function d(t){return t.type=="keypress"?String.fromCharCode(t.which):e[t.which]?e[t.which]:n[t.which]?n[t.which]:String.fromCharCode(t.which).toLowerCase()}function v(e,t){return e.sort().join(",")===t.sort().join(",")}function m(e){e=e||{};var t=!1,n;for(n in a){if(e[n]){t=!0;continue}a[n]=0}t||(c=!1)}function g(e,t,n,r,i){var s,u,f=[],l=n.type;if(!o[e])return[];l=="keyup"&&S(e)&&(t=[e]);for(s=0;s95&&t<112)continue;e.hasOwnProperty(t)&&(s[e[t]]=t)}}return s}function N(e,t,n){return n||(n=T()[e]?"keydown":"keypress"),n=="keypress"&&t.length&&(n="keydown"),n}function C(e,t,n,r){a[e]=0,r||(r=N(t[0],[]));var i=function(t){c=r,++a[e],x()},s=function(e){b(n,e),r!=="keyup"&&(l=d(e)),setTimeout(m,10)},o;for(o=0;o1){C(e,a,t,n);return}c=e==="+"?["+"]:e.split("+");for(f=0;f":".","?":"/","|":"\\"},i={option:"alt",command:"meta","return":"enter",escape:"esc"},s,o={},u={},a={},f,l=!1,c=!1;for(var h=1;h<20;++h)e[111+h]="f"+h;for(h=0;h<=9;++h)e[h+96]=h;p(document,"keypress",E),p(document,"keydown",E),p(document,"keyup",E);var A={bind:function(e,t,n){return L(e instanceof Array?e:[e],t,n),u[e+":"+n]=t,this},unbind:function(e,t){return u[e+":"+t]&&(delete u[e+":"+t],this.bind(e,function(){},t)),this},trigger:function(e,t){return u[e+":"+t](),this},reset:function(){return o={},u={},this},stopCallback:function(e,t){return(" "+t.className+" ").indexOf(" mousetrap ")>-1?!1:t.tagName=="INPUT"||t.tagName=="SELECT"||t.tagName=="TEXTAREA"||t.contentEditable&&t.contentEditable=="true"}};window.Mousetrap=A,typeof define=="function"&&define.amd&&define("mousetrap",function(){return A}),typeof t=="object"&&t.exports&&(t.exports=A)})()},{}],16:[function(e,t,n){(function(r){(function(){function a(e){var t=1,n=o.min(e);while(t!==0)t=o.reduce(e,function(e,t){return e+t%n},0),t!==0&&(n-=10);return n}function f(e){var t=u.exec(e);if(!t)throw new Error("I don't understand that particular interval");var n=+t[1],r=t[2]||"ms";if(r==="s")n*=1e3;else if(r==="m")n=n*1e3*60;else if(r==="h")n=n*1e3*60*60;else if(!!r&&r!=="ms")throw new Error("You can only specify intervals of ms, s, m, or h");if(n<10||n%10!==0)throw new Error("You can only specify 10s of milliseconds, trust me on this one");return{amount:n,type:r}}function l(){this.intervalId=undefined,this.intervalLength=undefined,this.intervalsToEmit={},this.currentTick=1,this.maxTicks=0,this.listeningForFocus=!1;var e=function(){var e=a(o.keys(this.intervalsToEmit)),t=!1;return this.intervalLength?e!==this.intervalLength&&(this.intervalLength=e,t=!0):this.intervalLength=e,this.maxTicks=o.max(o.map(o.keys(this.intervalsToEmit),function(e){return+e}))/this.intervalLength,t}.bind(this);this.on("newListener",function(t){if(t==="removeListener"||t==="newListener")return;var n=f(t),r=n.amount;this.intervalsToEmit[+r]=o.union(this.intervalsToEmit[+r]||[],[t]),e()&&this.isStarted()&&this.stop().start()}),this.on("removeListener",function(t){if(s.listenerCount(this,t)>0)return;var n=f(t),r=n.amount,i=this.intervalsToEmit[+r].removeOne(t);this.intervalsToEmit[+r].length===0&&delete this.intervalsToEmit[+r],console.log("Determining interval length after removal of",i),e(),e()&&this.isStarted()&&this.stop().start()})}var i=this,s=e("events").EventEmitter,o=e("underscore"),u=/([0-9\.]+)(ms|s|m|h)?/,i=r||window;typeof Function.prototype.inherits=="undefined"&&(Function.prototype.inherits=function(e){this.prototype=Object.create(e.prototype)}),typeof Array.prototype.removeOne=="undefined"&&(Array.prototype.removeOne=function(){var e,t=arguments,n=t.length,r;while(n&&this.length){e=t[--n];while((r=this.indexOf(e))!==-1)return this.splice(r,1)}}),l.inherits(s),l.prototype.tick=function(){var e=this.currentTick*this.intervalLength;return o.each(this.intervalsToEmit,function(t,n){e%n===0&&o.each(t,function(e){this.emit(e,e,n)}.bind(this))}.bind(this)),this.currentTick+=1,this.currentTick>this.maxTicks&&(this.currentTick=1),this},l.prototype.start=function(){if(!this.intervalLength)throw new Error("You haven't specified any interval callbacks. Use EventedLoop.on('500ms', function () { ... }) to do so, and then you can start");return this.intervalId?console.log("No need to start the loop again, it's already started."):(this.intervalId=setInterval(this.tick.bind(this),this.intervalLength),i&&!this.listeningForFocus&&i.addEventListener&&(i.addEventListener("focus",function(){this.start()}.bind(this)),i.addEventListener("blur",function(){this.stop()}.bind(this)),this.listeningForFocus=!0),this)},l.prototype.stop=function(){return clearInterval(this.intervalId),this.intervalId=undefined,this},l.prototype.isStarted=function(){return!!this.intervalId},l.prototype.every=l.prototype.on,typeof n!="undefined"&&(typeof t!="undefined"&&t.exports&&(n=t.exports=l),n.EventedLoop=l),typeof window!="undefined"&&(window.EventedLoop=l)}).call(this)}).call(this,typeof global!="undefined"?global:typeof self!="undefined"?self:typeof window!="undefined"?window:{})},{events:19,underscore:17}],17:[function(e,t,n){(function(){var e=this,r=e._,i={},s=Array.prototype,o=Object.prototype,u=Function.prototype,a=s.push,f=s.slice,l=s.concat,c=o.toString,h=o.hasOwnProperty,p=s.forEach,d=s.map,v=s.reduce,m=s.reduceRight,g=s.filter,y=s.every,b=s.some,w=s.indexOf,E=s.lastIndexOf,S=Array.isArray,x=Object.keys,T=u.bind,N=function(e){if(e instanceof N)return e;if(!(this instanceof N))return new N(e);this._wrapped=e};typeof n!="undefined"?(typeof t!="undefined"&&t.exports&&(n=t.exports=N),n._=N):e._=N,N.VERSION="1.6.0";var C=N.each=N.forEach=function(e,t,n){if(e==null)return e;if(p&&e.forEach===p)e.forEach(t,n);else if(e.length===+e.length){for(var r=0,s=e.length;r2;e==null&&(e=[]);if(v&&e.reduce===v)return r&&(t=N.bind(t,r)),i?e.reduce(t,n -):e.reduce(t);C(e,function(e,s,o){i?n=t.call(r,n,e,s,o):(n=e,i=!0)});if(!i)throw new TypeError(k);return n},N.reduceRight=N.foldr=function(e,t,n,r){var i=arguments.length>2;e==null&&(e=[]);if(m&&e.reduceRight===m)return r&&(t=N.bind(t,r)),i?e.reduceRight(t,n):e.reduceRight(t);var s=e.length;if(s!==+s){var o=N.keys(e);s=o.length}C(e,function(u,a,f){a=o?o[--s]:--s,i?n=t.call(r,n,e[a],a,f):(n=e[a],i=!0)});if(!i)throw new TypeError(k);return n},N.find=N.detect=function(e,t,n){var r;return L(e,function(e,i,s){if(t.call(n,e,i,s))return r=e,!0}),r},N.filter=N.select=function(e,t,n){var r=[];return e==null?r:g&&e.filter===g?e.filter(t,n):(C(e,function(e,i,s){t.call(n,e,i,s)&&r.push(e)}),r)},N.reject=function(e,t,n){return N.filter(e,function(e,r,i){return!t.call(n,e,r,i)},n)},N.every=N.all=function(e,t,n){t||(t=N.identity);var r=!0;return e==null?r:y&&e.every===y?e.every(t,n):(C(e,function(e,s,o){if(!(r=r&&t.call(n,e,s,o)))return i}),!!r)};var L=N.some=N.any=function(e,t,n){t||(t=N.identity);var r=!1;return e==null?r:b&&e.some===b?e.some(t,n):(C(e,function(e,s,o){if(r||(r=t.call(n,e,s,o)))return i}),!!r)};N.contains=N.include=function(e,t){return e==null?!1:w&&e.indexOf===w?e.indexOf(t)!=-1:L(e,function(e){return e===t})},N.invoke=function(e,t){var n=f.call(arguments,2),r=N.isFunction(t);return N.map(e,function(e){return(r?t:e[t]).apply(e,n)})},N.pluck=function(e,t){return N.map(e,N.property(t))},N.where=function(e,t){return N.filter(e,N.matches(t))},N.findWhere=function(e,t){return N.find(e,N.matches(t))},N.max=function(e,t,n){if(!t&&N.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.max.apply(Math,e);var r=-Infinity,i=-Infinity;return C(e,function(e,s,o){var u=t?t.call(n,e,s,o):e;u>i&&(r=e,i=u)}),r},N.min=function(e,t,n){if(!t&&N.isArray(e)&&e[0]===+e[0]&&e.length<65535)return Math.min.apply(Math,e);var r=Infinity,i=Infinity;return C(e,function(e,s,o){var u=t?t.call(n,e,s,o):e;ur||n===void 0)return 1;if(n>>1;n.call(r,e[u])=0;n--)t=[e[n].apply(this,t)];return t[0]}},N.after=function(e,t){return function(){if(--e<1)return t.apply(this,arguments)}},N.keys=function(e){if(!N.isObject(e))return[];if(x)return x(e);var t=[];for(var n in e)N.has(e,n)&&t.push(n);return t},N.values=function(e){var t=N.keys(e),n=t.length,r=new Array(n);for(var i=0;i":">",'"':""","'":"'"}};P.unescape=N.invert(P.escape);var H={escape:new RegExp("["+N.keys(P.escape).join("")+"]","g"),unescape:new RegExp("("+N.keys(P.unescape).join("|")+")","g")};N.each(["escape","unescape"],function(e){N[e]=function(t){return t==null?"":(""+t).replace(H[e],function(t){return P[e][t]})}}),N.result=function(e,t){if(e==null)return void 0;var n=e[t];return N.isFunction(n)?n.call(e):n},N.mixin=function(e){C(N.functions(e),function(t){var n=N[t]=e[t];N.prototype[t]=function(){var e=[this._wrapped];return a.apply(e,arguments),q.call(this,n.apply(N,e))}})};var B=0;N.uniqueId=function(e){var t=++B+"";return e?e+t:t},N.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var j=/(.)^/,F={"'":"'","\\":"\\","\r":"r","\n":"n"," ":"t","\u2028":"u2028","\u2029":"u2029"},I=/\\|'|\r|\n|\t|\u2028|\u2029/g;N.template=function(e,t,n){var r;n=N.defaults({},n,N.templateSettings);var i=new RegExp([(n.escape||j).source,(n.interpolate||j).source,(n.evaluate||j).source].join("|")+"|$","g"),s=0,o="__p+='";e.replace(i,function(t,n,r,i,u){return o+=e.slice(s,u).replace(I,function(e){return"\\"+F[e]}),n&&(o+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'"),r&&(o+="'+\n((__t=("+r+"))==null?'':__t)+\n'"),i&&(o+="';\n"+i+"\n__p+='"),s=u+t.length,t}),o+="';\n",n.variable||(o="with(obj||{}){\n"+o+"}\n"),o="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+o+"return __p;\n";try{r=new Function(n.variable||"obj","_",o)}catch(u){throw u.source=o,u}if(t)return r(t,N);var a=function(e){return r.call(this,e,N)};return a.source="function("+(n.variable||"obj")+"){\n"+o+"}",a},N.chain=function(e){return N(e).chain()};var q=function(e){return this._chain?N(e).chain():e};N.mixin(N),C(["pop","push","reverse","shift","sort","splice","unshift"],function(e){var t=s[e];N.prototype[e]=function(){var n=this._wrapped;return t.apply(n,arguments),(e=="shift"||e=="splice")&&n.length===0&&delete n[0],q.call(this,n)}}),C(["concat","join","slice"],function(e){var t=s[e];N.prototype[e]=function(){return q.call(this,t.apply(this._wrapped,arguments))}}),N.extend(N.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}}),typeof define=="function"&&define.amd&&define("underscore",[],function(){return N})}).call(this)},{}],18:[function(e,t,n){(function(e,n){"use strict";function i(){if(r.READY)return;r.event.determineEventTypes(),r.utils.each(r.gestures,function(e){r.detection.register(e)}),r.event.onTouch(r.DOCUMENT,r.EVENT_MOVE,r.detection.detect),r.event.onTouch(r.DOCUMENT,r.EVENT_END,r.detection.detect),r.READY=!0}var r=function(e,t){return new r.Instance(e,t||{})};r.defaults={stop_browser_behavior:{userSelect:"none",touchAction:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}},r.HAS_POINTEREVENTS=e.navigator.pointerEnabled||e.navigator.msPointerEnabled,r.HAS_TOUCHEVENTS="ontouchstart"in e,r.MOBILE_REGEX=/mobile|tablet|ip(ad|hone|od)|android|silk/i,r.NO_MOUSEEVENTS=r.HAS_TOUCHEVENTS&&e.navigator.userAgent.match(r.MOBILE_REGEX),r.EVENT_TYPES={},r.DIRECTION_DOWN="down",r.DIRECTION_LEFT="left",r.DIRECTION_UP="up",r.DIRECTION_RIGHT="right",r.POINTER_MOUSE="mouse",r.POINTER_TOUCH="touch",r.POINTER_PEN="pen",r.UPDATE_VELOCITY_INTERVAL=20,r.EVENT_START="start",r.EVENT_MOVE="move",r.EVENT_END="end",r.DOCUMENT=e.document,r.plugins=r.plugins||{},r.gestures=r.gestures||{},r.READY=!1,r.utils={extend:function(t,r,i){for(var s in r){if(t[s]!==n&&i)continue;t[s]=r[s]}return t},each:function(e,t,r){var i,s;if("forEach"in e)e.forEach(t,r);else if(e.length!==n){for(i=0,s=e.length;i=s?t.pageX-n.pageX>0?r.DIRECTION_LEFT:r.DIRECTION_RIGHT:t.pageY-n.pageY>0?r.DIRECTION_UP:r.DIRECTION_DOWN},getDistance:function(t,n){var r=n.pageX-t.pageX,i=n.pageY-t.pageY;return Math.sqrt(r*r+i*i)},getScale:function(t,n){return t.length>=2&&n.length>=2?this.getDistance(n[0],n[1])/this.getDistance(t[0],t[1]):1},getRotation:function(t,n){return t.length>=2&&n.length>=2?this.getAngle(n[1],n[0])-this.getAngle(t[1],t[0]):0},isVertical:function(t){return t==r.DIRECTION_UP||t==r.DIRECTION_DOWN},stopDefaultBrowserBehavior:function(t,n){if(!n||!t||!t.style)return;r.utils.each(["webkit","khtml","moz","Moz","ms","o",""],function(e){r.utils.each(n,function(n,r){e&&(r=e+r.substring(0,1).toUpperCase()+r.substring(1)),r in t.style&&(t.style[r]=n)})}),n.userSelect=="none"&&(t.onselectstart=function(){return!1}),n.userDrag=="none"&&(t.ondragstart=function(){return!1})},startDefaultBrowserBehavior:function(t,n){if(!n||!t||!t.style)return;r.utils.each(["webkit","khtml","moz","Moz","ms","o",""],function(e){r.utils.each(n,function(n,r){e&&(r=e+r.substring(0,1).toUpperCase()+r.substring(1)),r in t.style&&(t.style[r]="")})}),n.userSelect=="none"&&(t.onselectstart=null),n.userDrag=="none"&&(t.ondragstart=null)}},r.Instance=function(e,t){var n=this;return i(),this.element=e,this.enabled=!0,this.options=r.utils.extend(r.utils.extend({},r.defaults),t||{}),this.options.stop_browser_behavior&&r.utils.stopDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),this._eventStartHandler=r.event.onTouch(e,r.EVENT_START,function(e){n.enabled&&r.detection.startDetect(n,e)}),this._eventHandler=[],this},r.Instance.prototype={on:function(t,n){var i=t.split(" ");return r.utils.each(i,function(e){this.element.addEventListener(e,n,!1),this._eventHandler.push({gesture:e,handler:n})},this),this},off:function(t,n){var i=t.split(" ");return r.utils.each(i,function(e){this.element.removeEventListener(e,n,!1);var t=-1;r.utils.each(this._eventHandler,function(r,i){t===-1&&r.gesture===e&&r.handler===n&&(t=i)},this),t>-1&&this._eventHandler.splice(t,1)},this),this},trigger:function(t,n){n||(n={});var i=r.DOCUMENT.createEvent("Event");i.initEvent(t,!0,!0),i.gesture=n;var s=this.element;return r.utils.hasParent(n.target,s)&&(s=n.target),s.dispatchEvent(i),this},enable:function(t){return this.enabled=t,this},dispose:function(){return this.options.stop_browser_behavior&&r.utils.startDefaultBrowserBehavior(this.element,this.options.stop_browser_behavior),r.utils.each(this._eventHandler,function(e){this.element.removeEventListener(e.gesture,e.handler,!1)},this),this._eventHandler.length=0,r.event.unbindDom(this.element,r.EVENT_TYPES[r.EVENT_START],this._eventStartHandler),this}};var s=null,o=!1,u=!1;r.event={bindDom:function(e,t,n){var i=t.split(" ");r.utils.each(i,function(t){e.addEventListener(t,n,!1)})},unbindDom:function(e,t,n){var i=t.split(" ");r.utils.each(i,function(t){e.removeEventListener(t,n,!1)})},onTouch:function(t,n,i){var a=this,f=function(f){var l=f.type.toLowerCase();if(l.match(/mouse/)&&u)return;l.match(/touch/)||l.match(/pointerdown/)||l.match(/mouse/)&&f.which===1?o=!0:l.match(/mouse/)&&!f.which&&(o=!1),l.match(/touch|pointer/)&&(u=!0);var c=0;if(o){r.HAS_POINTEREVENTS&&n!=r.EVENT_END?c=r.PointerEvent.updatePointer(n,f):l.match(/touch/)?c=f.touches.length:u||(c=l.match(/up/)?0:1),c>0&&n==r.EVENT_END?n=r.EVENT_MOVE:c||(n=r.EVENT_END);if(c||s===null)s=f;i.call(r.detection,a.collectEventData(t,n,a.getTouchList(s,n),f)),r.HAS_POINTEREVENTS&&n==r.EVENT_END&&(c=r.PointerEvent.updatePointer(n,f))}c||(s=null,o=!1,u=!1,r.PointerEvent.reset())};return this.bindDom(t,r.EVENT_TYPES[n],f),f},determineEventTypes:function(){var t;r.HAS_POINTEREVENTS?t=r.PointerEvent.getEvents():r.NO_MOUSEEVENTS?t=["touchstart","touchmove","touchend touchcancel"]:t=["touchstart mousedown","touchmove mousemove","touchend touchcancel mouseup"],r.EVENT_TYPES[r.EVENT_START]=t[0],r.EVENT_TYPES[r.EVENT_MOVE]=t[1],r.EVENT_TYPES[r.EVENT_END]=t[2]},getTouchList:function(t){return r.HAS_POINTEREVENTS?r.PointerEvent.getTouchList():t.touches?t.touches:(t.identifier=1,[t])},collectEventData:function(t,n,i,s){var o=r.POINTER_TOUCH;if(s.type.match(/mouse/)||r.PointerEvent.matchType(r.POINTER_MOUSE,s))o=r.POINTER_MOUSE;return{center:r.utils.getCenter(i),timeStamp:(new Date).getTime(),target:s.target,touches:i,eventType:n,pointerType:o,srcEvent:s,preventDefault:function(){this.srcEvent.preventManipulation&&this.srcEvent.preventManipulation(),this.srcEvent.preventDefault&&this.srcEvent.preventDefault()},stopPropagation:function(){this.srcEvent.stopPropagation()},stopDetect:function(){return r.detection.stopDetect()}}}},r.PointerEvent={pointers:{},getTouchList:function(){var e=this,t=[];return r.utils.each(e.pointers,function(e){t.push(e)}),t},updatePointer:function(e,t){return e==r.EVENT_END?delete this.pointers[t.pointerId]:(t.identifier=t.pointerId,this.pointers[t.pointerId]=t),Object.keys(this.pointers).length},matchType:function(e,t){if(!t.pointerType)return!1;var n=t.pointerType,i={};return i[r.POINTER_MOUSE]=n===t.MSPOINTER_TYPE_MOUSE||n===r.POINTER_MOUSE,i[r.POINTER_TOUCH]=n===t.MSPOINTER_TYPE_TOUCH||n===r.POINTER_TOUCH,i[r.POINTER_PEN]=n===t.MSPOINTER_TYPE_PEN||n===r.POINTER_PEN,i[e]},getEvents:function(){return["pointerdown MSPointerDown","pointermove MSPointerMove","pointerup pointercancel MSPointerUp MSPointerCancel"]},reset:function(){this.pointers={}}},r.detection={gestures:[],current:null,previous:null,stopped:!1,startDetect:function(t,n){if(this.current)return;this.stopped=!1,this.current={inst:t,startEvent:r.utils.extend({},n),lastEvent:!1,lastVEvent:!1,velocity:!1,name:""},this.detect(n)},detect:function(t){if(!this.current||this.stopped)return;t=this.extendEventData(t);var n=this.current.inst.options;return r.utils.each(this.gestures,function(e){if(!this.stopped&&n[e.name]!==!1&&e.handler.call(e,t,this.current.inst)===!1)return this.stopDetect(),!1},this),this.current&&(this.current.lastEvent=t),t.eventType==r.EVENT_END&&!t.touches.length-1&&this.stopDetect(),t},stopDetect:function(){this.previous=r.utils.extend({},this.current),this.current=null,this.stopped=!0},extendEventData:function(t){var n=this.current.startEvent,i=this.current.lastVEvent;n&&(t.touches.length!=n.touches.length||t.touches===n.touches)&&(n.touches=[],r.utils.each(t.touches,function(e){n.touches.push(r.utils.extend({},e))}));var s=t.timeStamp-n.timeStamp,o=t.center.pageX-n.center.pageX,u=t.center.pageY-n.center.pageY,a,f,l=this.current.velocity;return i!==!1&&t.timeStamp-i.timeStamp>r.UPDATE_VELOCITY_INTERVAL?(l=r.utils.getVelocity(t.timeStamp-i.timeStamp,t.center.pageX-i.center.pageX,t.center.pageY-i.center.pageY),this.current.lastVEvent=t,l.x>0&&l.y>0&&(this.current.velocity=l)):this.current.velocity===!1&&(l=r.utils.getVelocity(s,o,u),this.current.velocity=l,this.current.lastVEvent=t),t.eventType==="end"?(a=this.current.lastEvent&&this.current.lastEvent.interimAngle,f=this.current.lastEvent&&this.current.lastEvent.interimDirection):(a=this.current.lastEvent&&r.utils.getAngle(this.current.lastEvent.center,t.center),f=this.current.lastEvent&&r.utils.getDirection(this.current.lastEvent.center,t.center)),r.utils.extend(t,{deltaTime:s,deltaX:o,deltaY:u,velocityX:l.x,velocityY:l.y,distance:r.utils.getDistance(n.center,t.center),angle:r.utils.getAngle(n.center,t.center),interimAngle:a,direction:r.utils.getDirection(n.center,t.center),interimDirection:f,scale:r.utils.getScale(n.touches,t.touches),rotation:r.utils.getRotation(n.touches,t.touches),startEvent:n}),t},register:function(t){var i=t.defaults||{};return i[t.name]===n&&(i[t.name]=!0),r.utils.extend(r.defaults,i,!0),t.index=t.index||1e3,this.gestures.push(t),this.gestures.sort(function(e,t){return e.indext.index?1:0}),this.gestures}},r.gestures.Drag={name:"drag",index:50,defaults:{drag_min_distance:10,correct_for_drag_min_distance:!0,drag_max_touches:1,drag_block_horizontal:!1,drag_block_vertical:!1,drag_lock_to_axis:!1,drag_lock_min_distance:25},triggered:!1,handler:function(t,n){if(r.detection.current.name!=this.name&&this.triggered){n.trigger(this.name+"end",t),this.triggered=!1;return}if(n.options.drag_max_touches>0&&t.touches.length>n.options.drag_max_touches)return;switch(t.eventType){case r.EVENT_START:this.triggered=!1;break;case r.EVENT_MOVE:if(t.distance0){var i=Math.abs(n.options.drag_min_distance/t.distance);r.detection.current.startEvent.center.pageX+=t.deltaX*i,r.detection.current.startEvent.center.pageY+=t.deltaY*i,t=r.detection.extendEventData(t)}}if(r.detection.current.lastEvent.drag_locked_to_axis||n.options.drag_lock_to_axis&&n.options.drag_lock_min_distance<=t.distance)t.drag_locked_to_axis=!0;var s=r.detection.current.lastEvent.direction;t.drag_locked_to_axis&&s!==t.direction&&(r.utils.isVertical(s)?t.direction=t.deltaY<0?r.DIRECTION_UP:r.DIRECTION_DOWN:t.direction=t.deltaX<0?r.DIRECTION_LEFT:r.DIRECTION_RIGHT),this.triggered||(n.trigger(this.name+"start",t),this.triggered=!0),n.trigger(this.name,t),n.trigger(this.name+t.direction,t),(n.options.drag_block_vertical&&r.utils.isVertical(t.direction)||n.options.drag_block_horizontal&&!r.utils.isVertical(t.direction))&&t.preventDefault();break;case r.EVENT_END:this.triggered&&n.trigger(this.name+"end",t),this.triggered=!1}}},r.gestures.Hold={name:"hold",index:10,defaults:{hold_timeout:500,hold_threshold:1},timer:null,handler:function(t,n){switch(t.eventType){case r.EVENT_START:clearTimeout(this.timer),r.detection.current.name=this.name,this.timer=setTimeout(function(){r.detection.current.name=="hold"&&n.trigger("hold",t)},n.options.hold_timeout);break;case r.EVENT_MOVE:t.distance>n.options.hold_threshold&&clearTimeout(this.timer);break;case r.EVENT_END:clearTimeout(this.timer)}}},r.gestures.Release={name:"release",index:Infinity,handler:function(t,n){t.eventType==r.EVENT_END&&n.trigger(this.name,t)}},r.gestures.Swipe={name:"swipe",index:40,defaults:{swipe_min_touches:1,swipe_max_touches:1,swipe_velocity:.7},handler:function(t,n){if(t.eventType==r.EVENT_END){if(n.options.swipe_max_touches>0&&t.touches.lengthn.options.swipe_max_touches)return;if(t.velocityX>n.options.swipe_velocity||t.velocityY>n.options.swipe_velocity)n.trigger(this.name,t),n.trigger(this.name+t.direction,t)}}},r.gestures.Tap={name:"tap",index:100,defaults:{tap_max_touchtime:250,tap_max_distance:10,tap_always:!0,doubletap_distance:20,doubletap_interval:300},handler:function(t,n){if(t.eventType==r.EVENT_MOVE&&!r.detection.current.reachedTapMaxDistance)r.detection.current.reachedTapMaxDistance=t.distance>n.options.tap_max_distance;else if(t.eventType==r.EVENT_END&&t.srcEvent.type!="touchcancel"){var i=r.detection.previous,s=!1;if(r.detection.current.reachedTapMaxDistance||t.deltaTime>n.options.tap_max_touchtime)return;i&&i.name=="tap"&&t.timeStamp-i.lastEvent.timeStampn.options.transform_min_rotation&&n.trigger("rotate",t),i>n.options.transform_min_scale&&(n.trigger("pinch",t),n.trigger("pinch"+(t.scale<1?"in":"out"),t));break;case r.EVENT_END:this.triggered&&n.trigger(this.name+"end",t),this.triggered=!1}}},typeof define=="function"&&define.amd?define(function(){return r}):typeof t=="object"&&t.exports?t.exports=r:e.Hammer=r})(window)},{}],19:[function(e,t,n){function r(){this._events=this._events||{},this._maxListeners=this._maxListeners||undefined}function i(e){return typeof e=="function"}function s(e){return typeof e=="number"}function o(e){return typeof e=="object"&&e!==null}function u(e){return e===void 0}t.exports=r,r.EventEmitter=r,r.prototype._events=undefined,r.prototype._maxListeners=undefined,r.defaultMaxListeners=10,r.prototype.setMaxListeners=function(e){if(!s(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},r.prototype.emit=function(e){var t,n,r,s,a,f;this._events||(this._events={});if(e==="error")if(!this._events.error||o(this._events.error)&&!this._events.error.length)throw t=arguments[1],t instanceof Error?t:TypeError('Uncaught, unspecified "error" event.');n=this._events[e];if(u(n))return!1;if(i(n))switch(arguments.length){case 1:n.call(this);break;case 2:n.call(this,arguments[1]);break;case 3:n.call(this,arguments[1],arguments[2]);break;default:r=arguments.length,s=new Array(r-1);for(a=1;a0&&this._events[e].length>n&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),typeof console.trace=="function"&&console.trace())}return this},r.prototype.on=r.prototype.addListener,r.prototype.once=function(e,t){function r(){this.removeListener(e,r),n||(n=!0,t.apply(this,arguments))}if(!i(t))throw TypeError("listener must be a function");var n=!1;return r.listener=t,this.on(e,r),this},r.prototype.removeListener=function(e,t){var n,r,s,u;if(!i(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;n=this._events[e],s=n.length,r=-1;if(n===t||i(n.listener)&&n.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(o(n)){for(u=s;u-->0;)if(n[u]===t||n[u].listener&&n[u].listener===t){r=u;break}if(r<0)return this;n.length===1?(n.length=0,delete this._events[e]):n.splice(r,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},r.prototype.removeAllListeners=function(e){var t,n;if(!this._events)return this;if(!this._events.removeListener)return arguments.length===0?this._events={}:this._events[e]&&delete this._events[e],this;if(arguments.length===0){for(t in this._events){if(t==="removeListener")continue;this.removeAllListeners(t)}return this.removeAllListeners("removeListener"),this._events={},this}n=this._events[e];if(i(n))this.removeListener(e,n);else while(n.length)this.removeListener(e,n[n.length-1]);return delete this._events[e],this},r.prototype.listeners=function(e){var t;return!this._events||!this._events[e]?t=[]:i(this._events[e])?t=[this._events[e]]:t=this._events[e].slice(),t},r.listenerCount=function(e,t){var n;return!e._events||!e._events[t]?n=0:i(e._events[t])?n=1:n=e._events[t].length,n}},{}]},{},[13]); \ No newline at end of file +!function(t){var e={};function n(i){if(e[i])return e[i].exports;var r=e[i]={i:i,l:!1,exports:{}};return t[i].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)n.d(i,r,function(e){return t[e]}.bind(null,r));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=2)}([function(t,e,n){!function(t){var e=n(10);function i(t){var n,i={},r=[0],o=this;function s(e){if(o.data.hitBoxes&&t.hitBoxes[e])return t.hitBoxes[e]}function a(t){return t=Math.round(2*t)/2}return o.direction=void 0,o.mapPosition=[0,0,0],o.id=e(),o.canvasX=0,o.canvasY=0,o.canvasZ=0,o.height=0,o.speed=0,o.data=t||{parts:{}},o.movingToward=[0,0],o.metresDownTheMountain=0,o.movingWithConviction=!1,o.deleted=!1,o.maxHeight=Object.values(o.data.parts).map((function(t){return t[3]})).max(),o.isMoving=!0,o.data.parts||(o.data.parts={}),t&&t.id&&(o.id=t.id),t&&t.zIndexesOccupied&&(r=t.zIndexesOccupied),this.draw=function(t,e){var n=o.data.parts[e];o.height=n[3],o.width=n[2];var i=t.mapPositionToCanvasPosition(o.mapPosition);o.setCanvasPosition(i[0],i[1]),t.drawImage(t.getLoadedImage(o.data.$imageFile),n[0],n[1],n[2],n[3],o.canvasX,o.canvasY,n[2],n[3])},this.setMapPosition=function(t,e,n){void 0===t&&(t=o.mapPosition[0]),void 0===e&&(e=o.mapPosition[1]),void 0===n?n=o.mapPosition[2]:o.zIndexesOccupied=[n],o.mapPosition=[t,e,n]},this.setCanvasPosition=function(t,e){var n;t&&(!Object.isString(t)||"+"!==t.first()&&"-"!==t.first()?o.canvasX=t:(n=t,o.canvasX+=n.toNumber())),e&&(!Object.isString(e)||"+"!==e.first()&&"-"!==e.first()?o.canvasY=e:function(t){o.canvasY+=t.toNumber()}(e))},this.getCanvasPositionX=function(){return o.canvasX},this.getCanvasPositionY=function(){return o.canvasY},this.getLeftHitBoxEdge=function(t){t=t||0;var e=this.getCanvasPositionX();return s(t)&&(e+=s(t)[0]),e},this.getTopHitBoxEdge=function(t){t=t||0;var e=this.getCanvasPositionY();return s(t)&&(e+=s(t)[1]),e},this.getRightHitBoxEdge=function(t){return s(t=t||0)?o.canvasX+s(t)[2]:o.canvasX+o.width},this.getBottomHitBoxEdge=function(t){return s(t=t||0)?o.canvasY+s(t)[3]:o.canvasY+o.height},this.getPositionInFrontOf=function(){return[o.canvasX,o.canvasY+o.height]},this.setSpeed=function(t){o.speed=t,o.speedX=t,o.speedY=t},this.incrementSpeedBy=function(t){o.speed+=t},o.getSpeed=function(){return o.speed},o.getSpeedX=function(){return o.speed},o.getSpeedY=function(){return o.speed},this.setHeight=function(t){o.height=t},this.setWidth=function(t){o.width=t},this.getMaxHeight=function(){return o.maxHeight},o.getMovingTowardOpposite=function(){if(!o.isMoving)return[0,0];var t=o.movingToward[0]-o.mapPosition[0],e=o.movingToward[1]-o.mapPosition[1];return[Math.abs(t)>75?0-t:0,-e]},this.checkHittableObjects=function(){Object.keys(i,(function(t,e){e.object.deleted?delete i[t]:e.object.hits(o)&&e.callbacks.each((function(t){t(o,e.object)}))}))},this.cycle=function(){o.checkHittableObjects(),n&&o.setMapPositionTarget(n.mapPosition[0],n.mapPosition[1],!0),function(){if(o.isMoving){var t=o.mapPosition[0],e=o.mapPosition[1];if(void 0!==o.direction){var n=o.direction-90;n<0&&(n=360+n),t+=a(o.speed*Math.cos(n*(Math.PI/180))),e+=a(o.speed*Math.sin(n*(Math.PI/180)))}else void 0!==o.movingToward[0]&&(t>o.movingToward[0]?t-=Math.min(o.getSpeedX(),Math.abs(t-o.movingToward[0])):to.movingToward[1]?e-=Math.min(o.getSpeedY(),Math.abs(e-o.movingToward[1])):e=360&&(t=360-t),o.direction=t,o.movingToward=void 0},this.resetDirection=function(){o.direction=void 0},this.setMapPositionTargetWithConviction=function(t,e){o.setMapPositionTarget(t,e),o.movingWithConviction=!0},this.follow=function(t){n=t},this.stopFollowing=function(){n=!1},this.onHitting=function(t,e){if(i[t.id])return i[t.id].callbacks.push(e);i[t.id]={object:t,callbacks:[e]}},this.deleteOnNextCycle=function(){o.deleted=!0},this.occupiesZIndex=function(t){return r.indexOf(t)>=0},this.hits=function(t){var e=!1,n=!1;return t.getTopHitBoxEdge(o.mapPosition[2])<=o.getBottomHitBoxEdge(o.mapPosition[2])&&t.getBottomHitBoxEdge(o.mapPosition[2])>=o.getBottomHitBoxEdge(o.mapPosition[2])&&(e=!0),t.getTopHitBoxEdge(o.mapPosition[2])<=o.getTopHitBoxEdge(o.mapPosition[2])&&t.getBottomHitBoxEdge(o.mapPosition[2])>=o.getTopHitBoxEdge(o.mapPosition[2])&&(e=!0),t.getLeftHitBoxEdge(o.mapPosition[2])<=o.getRightHitBoxEdge(o.mapPosition[2])&&t.getRightHitBoxEdge(o.mapPosition[2])>=o.getRightHitBoxEdge(o.mapPosition[2])&&(n=!0),t.getLeftHitBoxEdge(o.mapPosition[2])<=o.getLeftHitBoxEdge(o.mapPosition[2])&&t.getRightHitBoxEdge(o.mapPosition[2])>=o.getLeftHitBoxEdge(o.mapPosition[2])&&(n=!0),e&&n},this.isAboveOnCanvas=function(t){return o.canvasY+o.heightt},o}i.createObjects=function(t,e){return Array.isArray(t)||(t=[t]),e=Object.merge(e,{rateModifier:0,dropRate:1,position:[0,0]},!1,!1),t.map((function(t){var n=e.position;if(Number.random(100+e.rateModifier)<=t.dropRate){var r=new i(t.sprite);return r.setSpeed(0),Object.isFunction(n)&&(n=n()),r.setMapPosition(n[0],n[1]),t.sprite.hitBehaviour&&t.sprite.hitBehaviour.skier&&e.player&&r.onHitting(e.player,t.sprite.hitBehaviour.skier),r}})).remove(void 0)},t.sprite=i}(this),t.exports=this.sprite},function(t,e,n){!function(t){function e(){return this.pushHandlers=[],this}e.prototype=Object.create(Array.prototype),e.prototype.onPush=function(t,e){this.pushHandlers.push(t),e&&this.each(t)},e.prototype.push=function(t){Array.prototype.push.call(this,t),this.pushHandlers.each((function(e){e(t)}))},e.prototype.cull=function(){this.each((function(t,e){if(t.deleted)return delete this[e]}))},t.spriteArray=e}(this),t.exports=this.spriteArray},function(t,e,n){n(3),n(4),n(5);var i=n(6),r=n(7),o=n(8),s=(n(1),n(9)),a=n(0),u=n(11),c=n(12),l=n(13),p=n(14),h=document.getElementById("skifree-canvas"),f=h.getContext("2d"),v="Use the mouse or WASD to control the player";o()&&(v="Tap or drag on the piste to control the player");var d=n(19),g=18,m=0,y=2e3,b=5,w=0,T=!1,E={smallTree:4,tallTree:2,jump:1,thickSnow:1,rock:1};function k(t,e){e.isEatenBy(t,(function(){b-=1,t.isFull=!0,t.isEating=!1,e.isBeingEaten=!1,t.setSpeed(e.getSpeed()),t.stopFollowing();var n=f.getRandomMapPositionAboveViewport();t.setMapPositionTarget(n[0],n[1])}))}function P(){h.width=window.innerWidth,h.height=window.innerHeight}localStorage.getItem("highScore")&&(w=localStorage.getItem("highScore")),window.addEventListener("resize",P,!1),P(),function(t,e){var n=0,i={};function r(){(n+=1)===t.length&&e(i)}t.each((function(t){var e=new Image;e.onload=r,e.src=t,f.storeLoadedImage(t,e)}))}(["sprite-characters.png","skifree-objects.png"],(function(t){var e,n,o,P;function x(t,e){var n=Math.max(800-h.width,0);Number.random(1e3+n)<=e&&t()}function _(){var t=new s(d.monster),n=f.getRandomMapPositionAboveViewport();t.setMapPosition(n[0],n[1]),t.follow(e),t.setSpeed(e.getStandardSpeed()),t.onHitting(e,k),P.addMovingObject(t,"monster")}function O(){var t=new u(d.snowboarder),n=f.getRandomMapPositionAboveViewport(),i=f.getRandomMapPositionBelowViewport();t.setMapPosition(n[0],n[1]),t.setMapPositionTarget(i[0],i[1]),t.onHitting(e,d.snowboarder.hitBehaviour.skier),P.addMovingObject(t)}(e=new c(d.skier)).setMapPosition(0,0),e.setMapPositionTarget(0,-10),T&&e.setHitObstacleCb((function(){b-=1})),P=new p(h,e),n=new a(d.signStart),P.addStaticObject(n),n.setMapPosition(-50,0),f.followSprite(e),o=new l({initialLines:["SkiFree.js",v,"Travelled 0m","High Score: "+w,"Skiers left: "+b,"Created by Dan Hough (@basicallydan)"],position:{top:15,right:10}}),P.beforeCycle((function(){var t=[];e.isMoving&&(t=a.createObjects([{sprite:d.smallTree,dropRate:E.smallTree},{sprite:d.tallTree,dropRate:E.tallTree},{sprite:d.jump,dropRate:E.jump},{sprite:d.thickSnow,dropRate:E.thickSnow},{sprite:d.rock,dropRate:E.rock}],{rateModifier:Math.max(800-h.width,0),position:function(){return f.getRandomMapPositionBelowViewport()},player:e})),P.isPaused()||(P.addStaticObjects(t),x(O,.1),(m=parseFloat(e.getPixelsTravelledDownMountain()/g).toFixed(1))>y&&x(_,.001),o.setLines(["SkiFree.js",v,"Travelled "+m+"m","Skiers left: "+b,"High Score: "+w,"Created by Dan Hough (@basicallydan)","Current Speed: "+e.getSpeed()]))})),P.afterCycle((function(){0===b&&(P.isPaused()||(w=localStorage.setItem("highScore",m),o.setLines(["Game over!","Hit space to restart"]),P.pause(),P.cycle()))})),P.addUIElement(o),$(h).mousemove((function(t){P.setMouseX(t.pageX),P.setMouseY(t.pageY),e.resetDirection(),e.startMovingIfPossible()})).bind("click",(function(t){P.setMouseX(t.pageX),P.setMouseY(t.pageY),e.resetDirection(),e.startMovingIfPossible()})).focus(),r.bind("f",e.speedBoost),r.bind("t",e.attemptTrick),r.bind(["w","up"],(function(){e.stop()})),r.bind(["a","left"],(function(){270===e.direction?e.stepWest():e.turnWest()})),r.bind(["s","down"],(function(){e.setDirection(180),e.startMovingIfPossible()})),r.bind(["d","right"],(function(){90===e.direction?e.stepEast():e.turnEast()})),r.bind("m",_),r.bind("b",O),r.bind("space",(function(){m=0,b=5,w=localStorage.getItem("highScore"),P.reset(),P.addStaticObject(n)})),i(h).on("press",(function(t){t.preventDefault(),P.setMouseX(t.gesture.center.x),P.setMouseY(t.gesture.center.y)})).on("tap",(function(t){P.setMouseX(t.gesture.center.x),P.setMouseY(t.gesture.center.y)})).on("pan",(function(t){P.setMouseX(t.gesture.center.x),P.setMouseY(t.gesture.center.y),e.resetDirection(),e.startMovingIfPossible()})).on("doubletap",(function(t){e.speedBoost()})),e.isMoving=!1,e.setDirection(270),P.start()})),this.exports=window},function(t,e){CanvasRenderingContext2D.prototype.storeLoadedImage=function(t,e){this.images||(this.images={}),this.images[t]=e},CanvasRenderingContext2D.prototype.getLoadedImage=function(t){if(this.images[t])return this.images[t]},CanvasRenderingContext2D.prototype.followSprite=function(t){this.centralSprite=t},CanvasRenderingContext2D.prototype.getCentralPosition=function(){return{map:this.centralSprite.mapPosition,canvas:[Math.round(.5*this.canvas.width),Math.round(.5*this.canvas.height),0]}},CanvasRenderingContext2D.prototype.mapPositionToCanvasPosition=function(t){var e=this.getCentralPosition(),n=e.map,i=e.canvas,r=n[0]-t[0],o=n[1]-t[1];return[i[0]-r,i[1]-o]},CanvasRenderingContext2D.prototype.canvasPositionToMapPosition=function(t){var e=this.getCentralPosition(),n=e.map,i=e.canvas,r=i[0]-t[0],o=i[1]-t[1];return[n[0]-r,n[1]-o]},CanvasRenderingContext2D.prototype.getCentreOfViewport=function(){return(this.canvas.width/2).floor()},CanvasRenderingContext2D.prototype.getMiddleOfViewport=function(){return(this.canvas.height/2).floor()},CanvasRenderingContext2D.prototype.getBelowViewport=function(){return this.canvas.height.floor()},CanvasRenderingContext2D.prototype.getMapBelowViewport=function(){var t=this.getBelowViewport();return this.canvasPositionToMapPosition([0,t])[1]},CanvasRenderingContext2D.prototype.getRandomlyInTheCentreOfCanvas=function(t){var e=0,n=this.canvas.width;return t&&(e-=t,n+=t),Number.random(e,n)},CanvasRenderingContext2D.prototype.getRandomlyInTheCentreOfMap=function(t){var e=this.getRandomlyInTheCentreOfCanvas(t);return this.canvasPositionToMapPosition([e,0])[0]},CanvasRenderingContext2D.prototype.getRandomMapPositionBelowViewport=function(){var t=this.getRandomlyInTheCentreOfCanvas(),e=this.getBelowViewport();return this.canvasPositionToMapPosition([t,e])},CanvasRenderingContext2D.prototype.getRandomMapPositionAboveViewport=function(){var t=this.getRandomlyInTheCentreOfCanvas(),e=this.getAboveViewport();return this.canvasPositionToMapPosition([t,e])},CanvasRenderingContext2D.prototype.getTopOfViewport=function(){return this.canvasPositionToMapPosition([0,0])[1]},CanvasRenderingContext2D.prototype.getAboveViewport=function(){return 0-(this.canvas.height/4).floor()}},function(t,e){Function.prototype.method=function(t,e){return this.prototype[t]=e,this},Object.method("superior",(function(t){var e=this,n=e[t];return function(){return n.apply(e,arguments)}}))},function(t,e){!function(){for(var t,e=function(){},n=["assert","clear","count","debug","dir","dirxml","error","exception","group","groupCollapsed","groupEnd","info","log","markTimeline","profile","profileEnd","table","time","timeEnd","timeStamp","trace","warn"],i=n.length,r=window.console=window.console||{};i--;)r[t=n[i]]||(r[t]=e)}()},function(t,e,n){var i; +/*! Hammer.JS - v2.0.8 - 2016-09-30 + * http://hammerjs.github.io/ + * + * Copyright (c) Jorik Tangelder; + * Licensed under the MIT license */!function(r,o,s,a){"use strict";function u(t,e){return t===a?e:t}var c=["","webkit","Moz","MS","ms","o"],l=o.createElement("div"),p="function",h=Math.round,f=Math.abs,v=Date.now;function d(t,e){for(var n=void 0,i=void 0,r=e[0].toUpperCase()+e.slice(1),o=0;o-1&&this.requireFail.splice(e,1),this}},{key:"hasRequireFailures",value:function(){return this.requireFail.length>0}},{key:"canRecognizeWith",value:function(t){return!!this.simultaneous[t.id]}},{key:"emit",value:function(t){var e=this,n=this.state;function i(n){e.manager.emit(n,t)}n=V&&i(e.options.event+ut(n))}},{key:"tryEmit",value:function(t){if(this.canEmit())return this.emit(t);this.state=32}},{key:"canEmit",value:function(){for(var t=0;tthis.options.threshold||this.state&X)}}]),e}(lt);pt.prototype.defaults={event:"rotate",threshold:0,pointers:2};var ht=function(t){function e(){return tt(this,e),rt(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return it(e,t),et(e,[{key:"getTouchAction",value:function(){return[w]}},{key:"attrTest",value:function(t){return nt(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"attrTest",this).call(this,t)&&(Math.abs(t.scale-1)>this.options.threshold||this.state&X)}},{key:"emit",value:function(t){if(1!==t.scale){var n=t.scale<1?"in":"out";t.additionalEvent=this.options.event+n}nt(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"emit",this).call(this,t)}}]),e}(lt);function ft(t){return t===L?"down":t===R?"up":t===A?"left":t===B?"right":""}ht.prototype.defaults={event:"pinch",threshold:0,pointers:2};var vt=function(t){function e(){tt(this,e);var t=rt(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments));return t.pX=null,t.pY=null,t}return it(e,t),et(e,[{key:"getTouchAction",value:function(){var t=this.options.direction,e=[];return t&D&&e.push(E),t&F&&e.push(T),e}},{key:"directionTest",value:function(t){var e=this.options,n=!0,i=t.distance,r=t.direction,o=t.deltaX,s=t.deltaY;return r&e.direction||(e.direction&D?(r=0===o?I:o<0?A:B,n=o!==this.pX,i=Math.abs(t.deltaX)):(r=0===s?I:s<0?R:L,n=s!==this.pY,i=Math.abs(t.deltaY))),t.direction=r,n&&i>e.threshold&&r&e.direction}},{key:"attrTest",value:function(t){return lt.prototype.attrTest.call(this,t)&&(this.state&X||!(this.state&X)&&this.directionTest(t))}},{key:"emit",value:function(t){this.pX=t.deltaX,this.pY=t.deltaY;var n=ft(t.direction);n&&(t.additionalEvent=this.options.event+n),nt(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"emit",this).call(this,t)}}]),e}(lt);vt.prototype.defaults={event:"pan",threshold:10,pointers:1,direction:H};var dt=function(t){function e(){return tt(this,e),rt(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments))}return it(e,t),et(e,[{key:"getTouchAction",value:function(){return vt.prototype.getTouchAction.call(this)}},{key:"attrTest",value:function(t){var n=this.options.direction,i=void 0;return n&(D|F)?i=t.overallVelocity:n&D?i=t.overallVelocityX:n&F&&(i=t.overallVelocityY),nt(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"attrTest",this).call(this,t)&&n&t.offsetDirection&&t.distance>this.options.threshold&&t.maxPointers===this.options.pointers&&f(i)>this.options.velocity&&t.eventType&C}},{key:"emit",value:function(t){var e=ft(t.offsetDirection);e&&this.manager.emit(this.options.event+e,t),this.manager.emit(this.options.event,t)}}]),e}(lt);function gt(t,e){return function(){return t.apply(e,arguments)}}function mt(t,e,n){return setTimeout(gt(t,n),e)}function yt(t,e,n){n||(n=W);var i=e[n[0]]-t[n[0]],r=e[n[1]]-t[n[1]];return Math.sqrt(i*i+r*r)}dt.prototype.defaults={event:"swipe",threshold:10,velocity:.3,direction:D|F,pointers:1};var bt=function(t){function e(){tt(this,e);var t=rt(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments));return t.pTime=!1,t.pCenter=!1,t._timer=null,t._input=null,t.count=0,t}return it(e,t),et(e,[{key:"getTouchAction",value:function(){return[b]}},{key:"process",value:function(t){var e=this,n=this.options,i=t.pointers.length===n.pointers,r=t.distancen.time;if(this._input=t,!r||!i||t.eventType&(C|j)&&!o)this.reset();else if(t.eventType&M)this.reset(),this._timer=mt((function(){e.state=q,e.tryEmit()}),n.time,this);else if(t.eventType&C)return q;return 32}},{key:"reset",value:function(){clearTimeout(this._timer)}},{key:"emit",value:function(t){this.state===q&&(t&&t.eventType&C?this.manager.emit(this.options.event+"up",t):(this._input.timeStamp=v(),this.manager.emit(this.options.event,this._input)))}}]),e}(ct);function Tt(t,e){return t.indexOf(e)>-1}wt.prototype.defaults={event:"press",pointers:1,time:251,threshold:9};var Et=function(){function t(e,n){tt(this,t),this.manager=e,this.set(n)}return et(t,[{key:"set",value:function(t){"compute"===t&&(t=this.compute()),m&&this.manager.element.style&&k[t]&&(this.manager.element.style[g]=t),this.actions=t.toLowerCase().trim()}},{key:"update",value:function(){this.set(this.manager.options.touchAction)}},{key:"compute",value:function(){var t=[];return K(this.manager.recognizers,(function(e){st(e.options.enable,[e])&&(t=t.concat(e.getTouchAction()))})),function(t){if(Tt(t,w))return w;var e=Tt(t,T),n=Tt(t,E);return e&&n?w:e||n?e?T:E:Tt(t,b)?b:y}(t.join(" "))}},{key:"preventDefaults",value:function(t){var e=t.srcEvent,n=t.offsetDirection;if(this.manager.session.prevented)e.preventDefault();else{var i=this.actions,r=Tt(i,w)&&!k[w],o=Tt(i,E)&&!k[E],s=Tt(i,T)&&!k[T];if(r){var a=1===t.pointers.length,u=t.distance<2,c=t.deltaTime<250;if(a&&u&&c)return}if(!s||!o)return r||o&&n&D||s&&n&F?this.preventSrc(e):void 0}}},{key:"preventSrc",value:function(t){this.manager.session.prevented=!0,t.preventDefault()}}]),t}();function kt(t,e){for(;t;){if(t===e)return!0;t=t.parentNode}return!1}function Pt(t){var e=t.length;if(1===e)return{x:h(t[0].clientX),y:h(t[0].clientY)};for(var n=0,i=0,r=0;r=f(e)?t<0?A:B:e<0?R:L}function Mt(t,e,n){return{x:e/t||0,y:n/t||0}}function St(t,e){var n=t.session,i=e.pointers,r=i.length;n.firstInput||(n.firstInput=xt(e)),r>1&&!n.firstMultiple?n.firstMultiple=xt(e):1===r&&(n.firstMultiple=!1);var o=n.firstInput,s=n.firstMultiple,u=s?s.center:o.center,c=e.center=Pt(i);e.timeStamp=v(),e.deltaTime=e.timeStamp-o.timeStamp,e.angle=_t(u,c),e.distance=yt(u,c),function(t,e){var n=e.center,i=t.offsetDelta||{},r=t.prevDelta||{},o=t.prevInput||{};e.eventType!==M&&o.eventType!==C||(r=t.prevDelta={x:o.deltaX||0,y:o.deltaY||0},i=t.offsetDelta={x:n.x,y:n.y}),e.deltaX=r.x+(n.x-i.x),e.deltaY=r.y+(n.y-i.y)}(n,e),e.offsetDirection=Ot(e.deltaX,e.deltaY);var l,p,h=Mt(e.deltaTime,e.deltaX,e.deltaY);e.overallVelocityX=h.x,e.overallVelocityY=h.y,e.overallVelocity=f(h.x)>f(h.y)?h.x:h.y,e.scale=s?(l=s.pointers,yt((p=i)[0],p[1],Y)/yt(l[0],l[1],Y)):1,e.rotation=s?function(t,e){return _t(e[1],e[0],Y)+_t(t[1],t[0],Y)}(s.pointers,i):0,e.maxPointers=n.prevInput?e.pointers.length>n.prevInput.maxPointers?e.pointers.length:n.prevInput.maxPointers:e.pointers.length,function(t,e){var n=t.lastInterval||e,i=e.timeStamp-n.timeStamp,r=void 0,o=void 0,s=void 0,u=void 0;if(e.eventType!==j&&(i>O||n.velocity===a)){var c=e.deltaX-n.deltaX,l=e.deltaY-n.deltaY,p=Mt(i,c,l);o=p.x,s=p.y,r=f(p.x)>f(p.y)?p.x:p.y,u=Ot(c,l),t.lastInterval=e}else r=n.velocity,o=n.velocityX,s=n.velocityY,u=n.direction;e.velocity=r,e.velocityX=o,e.velocityY=s,e.direction=u}(n,e);var d=t.element;kt(e.srcEvent.target,d)&&(d=e.srcEvent.target),e.target=d}function Ct(t,e,n){var i=n.pointers.length,r=n.changedPointers.length,o=e&M&&i-r==0,s=e&(C|j)&&i-r==0;n.isFirst=!!o,n.isFinal=!!s,o&&(t.session={}),n.eventType=e,St(t,n),t.emit("hammer.input",n),t.recognize(n),t.session.prevInput=n}function jt(t){return t.trim().split(/\s+/g)}function It(t,e,n){K(jt(e),(function(e){t.addEventListener(e,n,!1)}))}function At(t,e,n){K(jt(e),(function(e){t.removeEventListener(e,n,!1)}))}function Bt(t){var e=t.ownerDocument||t;return e.defaultView||e.parentWindow||r}var Rt=function(){function t(e,n){tt(this,t);var i=this;this.manager=e,this.callback=n,this.element=e.element,this.target=e.options.inputTarget,this.domHandler=function(t){st(e.options.enable,[e])&&i.handler(t)},this.init()}return et(t,[{key:"handler",value:function(){}},{key:"init",value:function(){this.evEl&&It(this.element,this.evEl,this.domHandler),this.evTarget&&It(this.target,this.evTarget,this.domHandler),this.evWin&&It(Bt(this.element),this.evWin,this.domHandler)}},{key:"destroy",value:function(){this.evEl&&At(this.element,this.evEl,this.domHandler),this.evTarget&&At(this.target,this.evTarget,this.domHandler),this.evWin&&At(Bt(this.element),this.evWin,this.domHandler)}}]),t}(),Lt={pointerdown:M,pointermove:S,pointerup:C,pointercancel:j,pointerout:j},Dt={2:"touch",3:"pen",4:"mouse",5:"kinect"},Ft="pointerdown",Ht="pointermove pointerup pointercancel";r.MSPointerEvent&&!r.PointerEvent&&(Ft="MSPointerDown",Ht="MSPointerMove MSPointerUp MSPointerCancel");var Wt=function(t){function e(){tt(this,e);var t=rt(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments));return t.evEl=Ft,t.evWin=Ht,t.store=t.manager.session.pointerEvents=[],t}return it(e,t),et(e,[{key:"handler",value:function(t){var e=this.store,n=!1,i=t.type.toLowerCase().replace("ms",""),r=Lt[i],o=Dt[t.pointerType]||t.pointerType,s="touch"===o,a=G(e,t.pointerId,"pointerId");r&M&&(0===t.button||s)?a<0&&(e.push(t),a=e.length-1):r&(C|j)&&(n=!0),a<0||(e[a]=t,this.callback(this.manager,r,{pointers:e,changedPointers:[t],pointerType:o,srcEvent:t}),n&&e.splice(a,1))}}]),e}(Rt);function Yt(t){return Array.prototype.slice.call(t,0)}function Nt(t,e,n){for(var i=[],r=[],o=0;on[e]})):i.sort()),i}var Xt={touchstart:M,touchmove:S,touchend:C,touchcancel:j},zt="touchstart touchmove touchend touchcancel",Vt=function(t){function e(){tt(this,e),e.prototype.evTarget=zt,e.prototype.targetIds={};var t=rt(this,(e.__proto__||Object.getPrototypeOf(e)).apply(this,arguments));return t.evTarget=zt,t.targetIds={},t}return it(e,t),et(e,[{key:"handler",value:function(t){var e=Xt[t.type],n=qt.call(this,t,e);n&&this.callback(this.manager,e,{pointers:n[0],changedPointers:n[1],pointerType:"touch",srcEvent:t})}}]),e}(Rt);function qt(t,e){var n=Yt(t.touches),i=this.targetIds;if(e&(M|S)&&1===n.length)return i[n[0].identifier]=!0,[n,n];var r=void 0,o=void 0,s=Yt(t.changedTouches),a=[],u=this.target;if(o=n.filter((function(t){return kt(t.target,u)})),e===M)for(r=0;r-1&&i.splice(e,1)}),Zt)}()}function ne(t){for(var e=t.srcEvent.clientX,n=t.srcEvent.clientY,i=0;i\s*\(/gm,"{anonymous}()@"):"Unknown Stack Trace",o=r.console&&(r.console.warn||r.console.log);return o&&o.call(r.console,i,n),t.apply(this,arguments)}}var he=pe((function(t,e,n){for(var i=Object.keys(e),r=0;r":".","?":"/","|":"\\"},c={option:"alt",command:"meta",return:"enter",escape:"esc"},l={},p={},h={},f=!1,v=!1,d=1;d<20;++d)s[111+d]="f"+d;for(d=0;d<=9;++d)s[d+96]=d;function g(t,e,n){t.addEventListener?t.addEventListener(e,n,!1):t.attachEvent("on"+e,n)}function m(t){return"keypress"==t.type?String.fromCharCode(t.which):s[t.which]?s[t.which]:a[t.which]?a[t.which]:String.fromCharCode(t.which).toLowerCase()}function y(t){t=t||{};var e,n=!1;for(e in h)t[e]?n=!0:h[e]=0;n||(v=!1)}function b(t,e,n,i,r){var o,s,a,u,c=[],p=n.type;if(!l[t])return[];for("keyup"==p&&E(t)&&(e=[t]),o=0;o95&&t<112||s.hasOwnProperty(t)&&(r[s[t]]=t);return r}()[t]?"keydown":"keypress"),"keypress"==n&&e.length&&(n="keydown"),n}function P(t,e,n,i){h[t]=0,i||(i=k(e[0],[]));var r,s=function(e){v=i,++h[t],clearTimeout(o),o=setTimeout(y,1e3)},a=function(t){w(n,t),"keyup"!==i&&(f=m(t)),setTimeout(y,10)};for(r=0;r1)P(t,p,e,n);else{for(a="+"===t?["+"]:t.split("+"),o=0;o-1)&&("INPUT"==e.tagName||"SELECT"==e.tagName||"TEXTAREA"==e.tagName||e.contentEditable&&"true"==e.contentEditable)}};window.Mousetrap=_,void 0===(i=function(){return _}.call(e,n,e,t))||(t.exports=i),t.exports&&(t.exports=_)}()},function(t,e){t.exports=function(){return!!(navigator.userAgent.match(/Android/i)||navigator.userAgent.match(/webOS/i)||navigator.userAgent.match(/iPhone/i)||navigator.userAgent.match(/iPad/i)||navigator.userAgent.match(/iPod/i)||navigator.userAgent.match(/BlackBerry/i)||navigator.userAgent.match(/Windows Phone/i))}},function(t,e,n){var i=n(0);this.monster=function(t){var e=new i(t),n=e.superior("draw"),r=1,o=0;return e.isEating=!1,e.isFull=!1,e.setSpeed(6),e.draw=function(t){var i;return n(t,(i=e.movingToward[0]-e.canvasX,e.isEating?"eating"+o:(r+.1>2?r=.1:r+=.1,i>=0?"sEast"+Math.ceil(r):i<0?"sWest"+Math.ceil(r):void 0)))},e.startEating=function t(n){o+=1,e.isEating=!0,e.isMoving=!1,o<6?setTimeout((function(){t(n)}),300):(o=0,e.isEating=!1,e.isMoving=!0,n())},e},t.exports=this.monster},function(t,e,n){this.guid=function(){var t=function(){return Math.floor(65536*Math.random()).toString(16)};return t()+t()+"-"+t()+"-"+t()+"-"+t()+"-"+t()+t()+t()},t.exports=this.guid},function(t,e,n){var i=n(0);this.snowboarder=function(t){var e=new i(t),n={draw:e.superior("draw"),cycle:e.superior("cycle")},r={sEast:function(t){return t>0},sWest:function(t){return t<=0}};return e.setSpeed(3),e.cycle=function(t){1===Number.random(10)&&(e.setMapPositionTarget(t.getRandomlyInTheCentreOfMap()),e.setSpeed(3+Number.random(-1,1))),e.setMapPositionTarget(void 0,t.getMapBelowViewport()+600),n.cycle()},e.draw=function(t){var i;return n.draw(t,(i=e.movingToward[0]-e.mapPosition[0],e.movingToward[1],e.mapPosition[1],r.sEast(i)?"sEast":"sWest"))},e},t.exports=this.snowboarder},function(t,e,n){var i=n(0);"undefined"!=typeof navigator?navigator.vibrate=navigator.vibrate||navigator.webkitVibrate||navigator.mozVibrate||navigator.msVibrate:navigator={vibrate:!1},this.skier=function(t){var e,n,r={west:270,wsWest:240,sWest:195,south:180,sEast:165,esEast:120,east:90},o=new i(t),s={draw:o.superior("draw"),cycle:o.superior("cycle"),getSpeedX:o.superior("getSpeedX"),getSpeedY:o.superior("getSpeedY"),hits:o.superior("hits")},a={esEast:function(t){return t>300},sEast:function(t){return t>75},wsWest:function(t){return t<-300},sWest:function(t){return t<-75}},u=!0,c=[],l=0,p=5,h=70,f=0,v=0,d=0,g=1,m=0;function y(){o.setSpeed(p),o.isMoving=!0,o.hasBeenHit=!1,o.isJumping=!1,o.isPerformingTrick=!1,n&&clearInterval(n),o.setMapPosition(void 0,void 0,0)}function b(){if(o.direction)return o.direction<=90?"east":o.direction>90&&o.direction<150?"esEast":o.direction>=150&&o.direction<180?"sEast":180===o.direction?"south":o.direction>180&&o.direction<=210?"sWest":o.direction>210&&o.direction<270?"wsWest":o.direction>=270?"west":"south";var t=o.movingToward[0]-o.mapPosition[0];return o.movingToward[1]-o.mapPosition[1]<=0?t>0?"east":"west":a.esEast(t)?"esEast":a.sEast(t)?"sEast":a.wsWest(t)?"wsWest":a.sWest(t)?"sWest":"south"}function w(t){r[t]&&o.setDirection(r[t]),o.isMoving="west"!==t&&"east"!==t}function T(t,e,n){return 0===n||1===n?e:(te&&(t-=o.getSpeed()*(n/h)),t)}return o.isMoving=!0,o.hasBeenHit=!1,o.isJumping=!1,o.isPerformingTrick=!1,o.onHitObstacleCb=function(){},o.setSpeed(p),o.reset=function(){c=[],l=0,o.isMoving=!0,o.hasBeenHit=!1,u=!0,y()},o.stop=function(){o.direction>180?w("west"):w("east")},o.turnEast=function(){switch(b()){case"west":w("wsWest");break;case"wsWest":w("sWest");break;case"sWest":w("south");break;case"south":w("sEast");break;case"sEast":w("esEast");break;case"esEast":w("east");break;default:w("south")}},o.turnWest=function(){switch(b()){case"east":w("esEast");break;case"esEast":w("sEast");break;case"sEast":w("south");break;case"south":w("sWest");break;case"sWest":w("wsWest");break;case"wsWest":w("west");break;default:w("south")}},o.stepWest=function(){o.mapPosition[0]-=2*o.speed},o.stepEast=function(){o.mapPosition[0]+=2*o.speed},o.setMapPositionTarget=function(t,e){o.hasBeenHit||(Math.abs(o.mapPosition[0]-t)<=75&&(t=o.mapPosition[0]),o.movingToward=[t,e])},o.startMovingIfPossible=function(){o.hasBeenHit||o.isBeingEaten||(o.isMoving=!0)},o.setTurnEaseCycles=function(t){h=t},o.getPixelsTravelledDownMountain=function(){return l},o.resetSpeed=function(){o.setSpeed(p)},o.cycle=function(){o.getSpeedX()<=0&&o.getSpeedY()<=0&&(o.isMoving=!1),o.isMoving&&(l+=o.speed),o.isJumping&&o.setMapPositionTarget(void 0,o.mapPosition[1]+o.getSpeed()),s.cycle(),o.checkHittableObjects()},o.draw=function(t){return s.draw(t,o.isBeingEaten?"blank":o.isJumping?o.isPerformingTrick?(console.log("Trick step is",m),0===m?"jumping":1===m?"somersault1":"somersault2"):"jumping":o.hasBeenHit?"hit":b())},o.hits=function(t){return-1===c.indexOf(t.id)&&!!t.occupiesZIndex(o.mapPosition[2])&&!!s.hits(t)},o.speedBoost=function(){var t=o.speed;u&&(u=!1,o.setSpeed(2*o.speed),setTimeout((function(){o.setSpeed(t),setTimeout((function(){u=!0}),1e4)}),2e3))},o.attemptTrick=function(){o.isJumping&&(o.isPerformingTrick=!0,n=setInterval((function(){m>=2?m=0:m+=1}),300))},o.getStandardSpeed=function(){return p},o.getSpeedX=function(){return"esEast"===b()||"wsWest"===b()?(v=.5,f=T(f,o.getSpeed()*v,v)):"sEast"===b()||"sWest"===b()?(v=.33,f=T(f,o.getSpeed()*v,v)):f=T(f,0,v)},o.setSpeedY=function(t){d=t},o.getSpeedY=function(){return o.isJumping?d:"esEast"===b()||"wsWest"===b()?(g=.6,d=T(d,.6*o.getSpeed(),.6)):"sEast"===b()||"sWest"===b()?(g=.85,d=T(d,.85*o.getSpeed(),.85)):"east"===b()||"west"===b()?(g=1,d=0):d=T(d,o.getSpeed(),g)},o.hasHitObstacle=function(t){o.isMoving=!1,o.hasBeenHit=!0,o.isJumping=!1,o.isPerformingTrick=!1,n&&clearInterval(n),o.setMapPosition(void 0,void 0,0),navigator.vibrate&&navigator.vibrate(500),c.push(t.id),o.resetSpeed(),o.onHitObstacleCb(t),e&&clearTimeout(e),e=setTimeout((function(){y()}),1500)},o.hasHitJump=function(){var t;t=o.getSpeed(),o.setSpeed(t+2),o.setSpeedY(t+2),o.isMoving=!0,o.hasBeenHit=!1,o.isJumping=!0,o.setMapPosition(void 0,void 0,1),e&&clearTimeout(e),e=setTimeout((function(){y()}),1e3)},o.isEatenBy=function(t,e){o.hasHitObstacle(t),t.startEating(e),c.push(t.id),o.isMoving=!1,o.isBeingEaten=!0},o.reset=function(){c=[],l=0,o.isMoving=!0,o.isJumping=!1,o.hasBeenHit=!1,u=!0},o.setHitObstacleCb=function(t){o.onHitObstacleCb=t||function(){}},o},t.exports=this.skier},function(t,e,n){t.exports=function(t){var e=this;return e.lines=t.initialLines,e.top=t.position.top,e.right=t.position.right,e.bottom=t.position.bottom,e.left=t.position.left,e.width=t.width,e.height=t.height,e.setLines=function(t){e.lines=t},e.draw=function(t){t.font="11px monospace";var n=0;e.lines.each((function(i){var r,o,s=+t.font.slice(0,2),a=t.measureText(i).width,u=1.5*s;e.top?o=e.top+n:e.bottom&&(o=t.canvas.height-e.top-u+n),e.right?r=t.canvas.width-e.right-a:e.left&&(r=e.left),n+=u,t.fillText(i,r,o)}))},e}},function(t,e,n){var i=n(1),r=n(15);this.game=function(t,e){var n=new i,o=new i,s=new i,a=t.getContext("2d"),u=a.getCentreOfViewport(),c=0,l=!1,p=[],h=[],f=new r;this.addStaticObject=function(t){n.push(t)},this.addStaticObjects=function(t){t.forEach(this.addStaticObject.bind(this))},this.addMovingObject=function(t,e){e&&n.onPush((function(n){n.data&&n.data.hitBehaviour[e]&&n.onHitting(t,n.data.hitBehaviour[e])}),!0),o.push(t)},this.addUIElement=function(t){s.push(t)},this.beforeCycle=function(t){p.push(t)},this.afterCycle=function(t){h.push(t)},this.setMouseX=function(t){u=t},this.setMouseY=function(t){c=t},e.setMapPosition(0,0),e.setMapPositionTarget(0,-10),a.followSprite(e),this.cycle=function(){p.each((function(t){t()}));var t=a.canvasPositionToMapPosition([u,c]);e.isJumping||e.setMapPositionTarget(t[0],t[1]),e.cycle(),o.each((function(t,e){t.cycle(a)})),n.cull(),n.each((function(t,e){t.cycle&&t.cycle()})),s.each((function(t,e){t.cycle&&t.cycle()})),h.each((function(t){t()}))},this.draw=function(){t.width=t.width,e.draw(a),e.cycle(),o.each((function(t,e){t.draw(a)})),n.each((function(t,e){t.draw&&t.draw(a,"main")})),s.each((function(t,e){t.draw&&t.draw(a,"main")}))},this.start=function(){f.start()},this.pause=function(){l=!0,f.stop()},this.isPaused=function(){return l},this.reset=function(){l=!1,n=new i,o=new i,u=a.getCentreOfViewport(),c=0,e.reset(),e.setMapPosition(0,0,0),this.start()}.bind(this),f.on("20",this.cycle),f.on("20",this.draw)},t.exports=this.game},function(t,e,n){(function(i){(function(){var r=this,o=n(17).EventEmitter,s=n(18),a=/([0-9\.]+)(ms|s|m|h)?/;r=i||window;function u(t){var e=a.exec(t);if(!e)throw new Error("I don't understand that particular interval");var n=+e[1],i=e[2]||"ms";if("s"===i)n*=1e3;else if("m"===i)n=1e3*n*60;else if("h"===i)n=1e3*n*60*60;else if(i&&"ms"!==i)throw new Error("You can only specify intervals of ms, s, m, or h");if(n<10||n%10!=0)throw new Error("You can only specify 10s of milliseconds, trust me on this one");return{amount:n,type:i}}function c(){this.intervalId=void 0,this.intervalLength=void 0,this.intervalsToEmit={},this.currentTick=1,this.maxTicks=0,this.listeningForFocus=!1;var t=function(){var t=function(t){for(var e=1,n=s.min(t);0!==e;)0!==(e=s.reduce(t,(function(t,e){return t+e%n}),0))&&(n-=10);return n}(s.keys(this.intervalsToEmit)),e=!1;return this.intervalLength?t!==this.intervalLength&&(this.intervalLength=t,e=!0):this.intervalLength=t,this.maxTicks=s.max(s.map(s.keys(this.intervalsToEmit),(function(t){return+t})))/this.intervalLength,e}.bind(this);this.on("newListener",(function(e){if("removeListener"!==e&&"newListener"!==e){var n=u(e).amount;this.intervalsToEmit[+n]=s.union(this.intervalsToEmit[+n]||[],[e]),t()&&this.isStarted()&&this.stop().start()}})),this.on("removeListener",(function(e){if(!(o.listenerCount(this,e)>0)){var n=u(e).amount,i=this.intervalsToEmit[+n].removeOne(e);0===this.intervalsToEmit[+n].length&&delete this.intervalsToEmit[+n],console.log("Determining interval length after removal of",i),t(),t()&&this.isStarted()&&this.stop().start()}}))}void 0===Function.prototype.inherits&&(Function.prototype.inherits=function(t){this.prototype=Object.create(t.prototype)}),void 0===Array.prototype.removeOne&&(Array.prototype.removeOne=function(){for(var t,e,n=arguments,i=n.length;i&&this.length;)for(t=n[--i];-1!==(e=this.indexOf(t));)return this.splice(e,1)}),c.inherits(o),c.prototype.tick=function(){var t=this.currentTick*this.intervalLength;return s.each(this.intervalsToEmit,function(e,n){t%n==0&&s.each(e,function(t){this.emit(t,t,n)}.bind(this))}.bind(this)),this.currentTick+=1,this.currentTick>this.maxTicks&&(this.currentTick=1),this},c.prototype.start=function(){if(!this.intervalLength)throw new Error("You haven't specified any interval callbacks. Use EventedLoop.on('500ms', function () { ... }) to do so, and then you can start");return this.intervalId?console.log("No need to start the loop again, it's already started."):(this.intervalId=setInterval(this.tick.bind(this),this.intervalLength),r&&!this.listeningForFocus&&r.addEventListener&&(r.addEventListener("focus",function(){this.start()}.bind(this)),r.addEventListener("blur",function(){this.stop()}.bind(this)),this.listeningForFocus=!0),this)},c.prototype.stop=function(){return clearInterval(this.intervalId),this.intervalId=void 0,this},c.prototype.isStarted=function(){return!!this.intervalId},c.prototype.every=c.prototype.on,t.exports&&(e=t.exports=c),e.EventedLoop=c,"undefined"!=typeof window&&(window.EventedLoop=c)}).call(this)}).call(this,n(16))},function(t,e){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(t){"object"==typeof window&&(n=window)}t.exports=n},function(t,e,n){"use strict";var i,r="object"==typeof Reflect?Reflect:null,o=r&&"function"==typeof r.apply?r.apply:function(t,e,n){return Function.prototype.apply.call(t,e,n)};i=r&&"function"==typeof r.ownKeys?r.ownKeys:Object.getOwnPropertySymbols?function(t){return Object.getOwnPropertyNames(t).concat(Object.getOwnPropertySymbols(t))}:function(t){return Object.getOwnPropertyNames(t)};var s=Number.isNaN||function(t){return t!=t};function a(){a.init.call(this)}t.exports=a,a.EventEmitter=a,a.prototype._events=void 0,a.prototype._eventsCount=0,a.prototype._maxListeners=void 0;var u=10;function c(t){return void 0===t._maxListeners?a.defaultMaxListeners:t._maxListeners}function l(t,e,n,i){var r,o,s,a;if("function"!=typeof n)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof n);if(void 0===(o=t._events)?(o=t._events=Object.create(null),t._eventsCount=0):(void 0!==o.newListener&&(t.emit("newListener",e,n.listener?n.listener:n),o=t._events),s=o[e]),void 0===s)s=o[e]=n,++t._eventsCount;else if("function"==typeof s?s=o[e]=i?[n,s]:[s,n]:i?s.unshift(n):s.push(n),(r=c(t))>0&&s.length>r&&!s.warned){s.warned=!0;var u=new Error("Possible EventEmitter memory leak detected. "+s.length+" "+String(e)+" listeners added. Use emitter.setMaxListeners() to increase limit");u.name="MaxListenersExceededWarning",u.emitter=t,u.type=e,u.count=s.length,a=u,console&&console.warn&&console.warn(a)}return t}function p(){for(var t=[],e=0;e0&&(s=e[0]),s instanceof Error)throw s;var a=new Error("Unhandled error."+(s?" ("+s.message+")":""));throw a.context=s,a}var u=r[t];if(void 0===u)return!1;if("function"==typeof u)o(u,this,e);else{var c=u.length,l=d(u,c);for(n=0;n=0;o--)if(n[o]===e||n[o].listener===e){s=n[o].listener,r=o;break}if(r<0)return this;0===r?n.shift():function(t,e){for(;e+1=0;i--)this.removeListener(t,e[i]);return this},a.prototype.listeners=function(t){return f(this,t,!0)},a.prototype.rawListeners=function(t){return f(this,t,!1)},a.listenerCount=function(t,e){return"function"==typeof t.listenerCount?t.listenerCount(e):v.call(t,e)},a.prototype.listenerCount=v,a.prototype.eventNames=function(){return this._eventsCount>0?i(this._events):[]}},function(t,e,n){var i;(function(){var n=this,r=n._,o={},s=Array.prototype,a=Object.prototype,u=Function.prototype,c=s.push,l=s.slice,p=s.concat,h=a.toString,f=a.hasOwnProperty,v=s.forEach,d=s.map,g=s.reduce,m=s.reduceRight,y=s.filter,b=s.every,w=s.some,T=s.indexOf,E=s.lastIndexOf,k=Array.isArray,P=Object.keys,x=u.bind,_=function(t){return t instanceof _?t:this instanceof _?void(this._wrapped=t):new _(t)};t.exports&&(e=t.exports=_),e._=_,_.VERSION="1.6.0";var O=_.each=_.forEach=function(t,e,n){if(null==t)return t;if(v&&t.forEach===v)t.forEach(e,n);else if(t.length===+t.length){for(var i=0,r=t.length;i2;if(null==t&&(t=[]),g&&t.reduce===g)return i&&(e=_.bind(e,i)),r?t.reduce(e,n):t.reduce(e);if(O(t,(function(t,o,s){r?n=e.call(i,n,t,o,s):(n=t,r=!0)})),!r)throw new TypeError(M);return n},_.reduceRight=_.foldr=function(t,e,n,i){var r=arguments.length>2;if(null==t&&(t=[]),m&&t.reduceRight===m)return i&&(e=_.bind(e,i)),r?t.reduceRight(e,n):t.reduceRight(e);var o=t.length;if(o!==+o){var s=_.keys(t);o=s.length}if(O(t,(function(a,u,c){u=s?s[--o]:--o,r?n=e.call(i,n,t[u],u,c):(n=t[u],r=!0)})),!r)throw new TypeError(M);return n},_.find=_.detect=function(t,e,n){var i;return S(t,(function(t,r,o){if(e.call(n,t,r,o))return i=t,!0})),i},_.filter=_.select=function(t,e,n){var i=[];return null==t?i:y&&t.filter===y?t.filter(e,n):(O(t,(function(t,r,o){e.call(n,t,r,o)&&i.push(t)})),i)},_.reject=function(t,e,n){return _.filter(t,(function(t,i,r){return!e.call(n,t,i,r)}),n)},_.every=_.all=function(t,e,n){e||(e=_.identity);var i=!0;return null==t?i:b&&t.every===b?t.every(e,n):(O(t,(function(t,r,s){if(!(i=i&&e.call(n,t,r,s)))return o})),!!i)};var S=_.some=_.any=function(t,e,n){e||(e=_.identity);var i=!1;return null==t?i:w&&t.some===w?t.some(e,n):(O(t,(function(t,r,s){if(i||(i=e.call(n,t,r,s)))return o})),!!i)};_.contains=_.include=function(t,e){return null!=t&&(T&&t.indexOf===T?-1!=t.indexOf(e):S(t,(function(t){return t===e})))},_.invoke=function(t,e){var n=l.call(arguments,2),i=_.isFunction(e);return _.map(t,(function(t){return(i?e:t[e]).apply(t,n)}))},_.pluck=function(t,e){return _.map(t,_.property(e))},_.where=function(t,e){return _.filter(t,_.matches(e))},_.findWhere=function(t,e){return _.find(t,_.matches(e))},_.max=function(t,e,n){if(!e&&_.isArray(t)&&t[0]===+t[0]&&t.length<65535)return Math.max.apply(Math,t);var i=-1/0,r=-1/0;return O(t,(function(t,o,s){var a=e?e.call(n,t,o,s):t;a>r&&(i=t,r=a)})),i},_.min=function(t,e,n){if(!e&&_.isArray(t)&&t[0]===+t[0]&&t.length<65535)return Math.min.apply(Math,t);var i=1/0,r=1/0;return O(t,(function(t,o,s){var a=e?e.call(n,t,o,s):t;ai||void 0===n)return 1;if(n>>1;n.call(i,t[a])=0;n--)e=[t[n].apply(this,e)];return e[0]}},_.after=function(t,e){return function(){if(--t<1)return e.apply(this,arguments)}},_.keys=function(t){if(!_.isObject(t))return[];if(P)return P(t);var e=[];for(var n in t)_.has(t,n)&&e.push(n);return e},_.values=function(t){for(var e=_.keys(t),n=e.length,i=new Array(n),r=0;r":">",'"':""","'":"'"}};R.unescape=_.invert(R.escape);var L={escape:new RegExp("["+_.keys(R.escape).join("")+"]","g"),unescape:new RegExp("("+_.keys(R.unescape).join("|")+")","g")};_.each(["escape","unescape"],(function(t){_[t]=function(e){return null==e?"":(""+e).replace(L[t],(function(e){return R[t][e]}))}})),_.result=function(t,e){if(null!=t){var n=t[e];return _.isFunction(n)?n.call(t):n}},_.mixin=function(t){O(_.functions(t),(function(e){var n=_[e]=t[e];_.prototype[e]=function(){var t=[this._wrapped];return c.apply(t,arguments),Y.call(this,n.apply(_,t))}}))};var D=0;_.uniqueId=function(t){var e=++D+"";return t?t+e:e},_.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var F=/(.)^/,H={"'":"'","\\":"\\","\r":"r","\n":"n","\t":"t","\u2028":"u2028","\u2029":"u2029"},W=/\\|'|\r|\n|\t|\u2028|\u2029/g;_.template=function(t,e,n){var i;n=_.defaults({},n,_.templateSettings);var r=new RegExp([(n.escape||F).source,(n.interpolate||F).source,(n.evaluate||F).source].join("|")+"|$","g"),o=0,s="__p+='";t.replace(r,(function(e,n,i,r,a){return s+=t.slice(o,a).replace(W,(function(t){return"\\"+H[t]})),n&&(s+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'"),i&&(s+="'+\n((__t=("+i+"))==null?'':__t)+\n'"),r&&(s+="';\n"+r+"\n__p+='"),o=a+e.length,e})),s+="';\n",n.variable||(s="with(obj||{}){\n"+s+"}\n"),s="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+s+"return __p;\n";try{i=new Function(n.variable||"obj","_",s)}catch(t){throw t.source=s,t}if(e)return i(e,_);var a=function(t){return i.call(this,t,_)};return a.source="function("+(n.variable||"obj")+"){\n"+s+"}",a},_.chain=function(t){return _(t).chain()};var Y=function(t){return this._chain?_(t).chain():t};_.mixin(_),O(["pop","push","reverse","shift","sort","splice","unshift"],(function(t){var e=s[t];_.prototype[t]=function(){var n=this._wrapped;return e.apply(n,arguments),"shift"!=t&&"splice"!=t||0!==n.length||delete n[0],Y.call(this,n)}})),O(["concat","join","slice"],(function(t){var e=s[t];_.prototype[t]=function(){return Y.call(this,e.apply(this._wrapped,arguments))}})),_.extend(_.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}}),void 0===(i=function(){return _}.apply(e,[]))||(t.exports=i)}).call(this)},function(t,e,n){!function(t){var e={skier:{$imageFile:"sprite-characters.png",parts:{blank:[0,0,0,0],east:[0,0,24,34],esEast:[24,0,24,34],sEast:[49,0,17,34],south:[65,0,17,34],sWest:[49,37,17,34],wsWest:[24,37,24,34],west:[0,37,24,34],hit:[0,78,31,31],jumping:[84,0,32,34],somersault1:[116,0,32,34],somersault2:[148,0,32,34]},hitBoxes:{0:[7,20,27,34]},id:"player",hitBehaviour:{}},smallTree:{$imageFile:"skifree-objects.png",parts:{main:[0,28,30,34]},hitBoxes:{0:[0,18,30,34]},hitBehaviour:{}},tallTree:{$imageFile:"skifree-objects.png",parts:{main:[95,66,32,64]},zIndexesOccupied:[0,1],hitBoxes:{0:[0,54,32,64],1:[0,10,32,54]},hitBehaviour:{}},thickSnow:{$imageFile:"skifree-objects.png",parts:{main:[143,53,43,10]},hitBehaviour:{}},rock:{$imageFile:"skifree-objects.png",parts:{main:[30,52,23,11]},hitBehaviour:{}},monster:{$imageFile:"sprite-characters.png",parts:{sEast1:[64,112,26,43],sEast2:[90,112,32,43],sWest1:[64,158,26,43],sWest2:[90,158,32,43],eating1:[122,112,34,43],eating2:[156,112,31,43],eating3:[187,112,31,43],eating4:[219,112,25,43],eating5:[243,112,26,43]},hitBehaviour:{}},jump:{$imageFile:"skifree-objects.png",parts:{main:[109,55,32,8]},hitBehaviour:{}},signStart:{$imageFile:"skifree-objects.png",parts:{main:[260,103,42,27]},hitBehaviour:{}},snowboarder:{$imageFile:"sprite-characters.png",parts:{sEast:[73,229,20,29],sWest:[95,228,26,30]},hitBehaviour:{}},emptyChairLift:{$imageFile:"skifree-objects.png",parts:{main:[92,136,26,30]},zIndexesOccupied:[1]}};function n(t,e){e.deleteOnNextCycle()}function i(t,e){e.hasHitObstacle(t)}e.monster.hitBehaviour.tree=function(t){t.deleteOnNextCycle()},e.smallTree.hitBehaviour.monster=n,e.tallTree.hitBehaviour.monster=n,e.smallTree.hitBehaviour.skier=i,e.tallTree.hitBehaviour.skier=i,e.rock.hitBehaviour.skier=function(t,e){e.hasHitObstacle(t)},e.jump.hitBehaviour.skier=function(t,e){e.hasHitJump(t)},e.snowboarder.hitBehaviour.skier=function(t,e){e.hasHitObstacle(t)},t.spriteInfo=e}(this),t.exports=this.spriteInfo}]); \ No newline at end of file diff --git a/js/lib/game.js b/js/lib/game.js index 26bb539..2f87e56 100644 --- a/js/lib/game.js +++ b/js/lib/game.js @@ -1,161 +1,158 @@ -var SpriteArray = require('./spriteArray'); -var EventedLoop = require('eventedloop'); - -(function (global) { - function Game (mainCanvas, player) { - var staticObjects = new SpriteArray(); - var movingObjects = new SpriteArray(); - var uiElements = new SpriteArray(); - var dContext = mainCanvas.getContext('2d'); - var mouseX = dContext.getCentreOfViewport(); - var mouseY = 0; - var paused = false; - var that = this; - var beforeCycleCallbacks = []; - var afterCycleCallbacks = []; - var gameLoop = new EventedLoop(); - - this.addStaticObject = function (sprite) { - staticObjects.push(sprite); - }; - - this.addStaticObjects = function (sprites) { - sprites.forEach(this.addStaticObject.bind(this)); - }; - - this.addMovingObject = function (movingObject, movingObjectType) { - if (movingObjectType) { - staticObjects.onPush(function (obj) { - if (obj.data && obj.data.hitBehaviour[movingObjectType]) { - obj.onHitting(movingObject, obj.data.hitBehaviour[movingObjectType]); - } - }, true); - } +import SpriteArray from './spriteArray'; +import EventedLoop from 'eventedloop'; + +class Game { + constructor(mainCanvas, player) { + this.mainCanvas = mainCanvas; + this.player = player; + + this.staticObjects = new SpriteArray(); + this.movingObjects = new SpriteArray(); + this.uiElements = new SpriteArray(); + this.dContext = this.mainCanvas.getContext('2d'); + this.mouseX = this.dContext.getCentreOfViewport(); + this.mouseY = 0; + this.paused = false; + this.beforeCycleCallbacks = []; + this.afterCycleCallbacks = []; + this.gameLoop = new EventedLoop(); + + this.player.setMapPosition(0, 0); + this.player.setMapPositionTarget(0, -10); + this.dContext.followSprite(this.player); + + this.intervalNum = 0; + + this.gameLoop.on('20', this.cycle.bind(this)); + this.gameLoop.on('20', this.draw.bind(this)); + } - movingObjects.push(movingObject); - }; + addStaticObject(sprite) { + this.staticObjects.push(sprite); + } - this.addUIElement = function (element) { - uiElements.push(element); - }; + addStaticObjects(sprites) { + sprites.forEach(this.addStaticObject.bind(this)); + } - this.beforeCycle = function (callback) { - beforeCycleCallbacks.push(callback); - }; + addMovingObject(movingObject, movingObjectType) { + if (movingObjectType) { + this.staticObjects.onPush(function (obj) { + if (obj.data && obj.data.hitBehaviour[movingObjectType]) { + obj.onHitting(movingObject, obj.data.hitBehaviour[movingObjectType]); + } + }, true); + } - this.afterCycle = function (callback) { - afterCycleCallbacks.push(callback); - }; + this.movingObjects.push(movingObject); + } - this.setMouseX = function (x) { - mouseX = x; - }; + addUIElement(element) { + this.uiElements.push(element); + } - this.setMouseY = function (y) { - mouseY = y; - }; + beforeCycle(callback) { + this.beforeCycleCallbacks.push(callback); + } - player.setMapPosition(0, 0); - player.setMapPositionTarget(0, -10); - dContext.followSprite(player); + afterCycle(callback) { + this.afterCycleCallbacks.push(callback); + } - var intervalNum = 0; + setMouseX(x) { + this.mouseX = x; + } - this.cycle = function () { - beforeCycleCallbacks.each(function(c) { - c(); - }); + setMouseY(y) { + this.mouseY = y; + } - // Clear canvas - var mouseMapPosition = dContext.canvasPositionToMapPosition([mouseX, mouseY]); + cycle() { + this.beforeCycleCallbacks.each(function(c) { + c(); + }); - if (!player.isJumping) { - player.setMapPositionTarget(mouseMapPosition[0], mouseMapPosition[1]); - } + // Clear canvas + var mouseMapPosition = this.dContext.canvasPositionToMapPosition([this.mouseX, this.mouseY]); - intervalNum++; + if (!this.player.isJumping) { + this.player.setMapPositionTarget(mouseMapPosition[0], mouseMapPosition[1]); + } - player.cycle(); + this.intervalNum++; - movingObjects.each(function (movingObject, i) { - movingObject.cycle(dContext); - }); - - staticObjects.cull(); - staticObjects.each(function (staticObject, i) { - if (staticObject.cycle) { - staticObject.cycle(); - } - }); + this.player.cycle(); - uiElements.each(function (uiElement, i) { - if (uiElement.cycle) { - uiElement.cycle(); - } - }); + this.movingObjects.each(movingObject => { + movingObject.cycle(this.dContext); + }); + + this.staticObjects.cull(); + this.staticObjects.each(staticObject => { + if (staticObject.cycle) { + staticObject.cycle(); + } + }); - afterCycleCallbacks.each(function(c) { - c(); - }); - }; + this.uiElements.each(uiElement => { + if (uiElement.cycle) { + uiElement.cycle(); + } + }); - that.draw = function () { - // Clear canvas - mainCanvas.width = mainCanvas.width; + this.afterCycleCallbacks.each(c => { + c(); + }); + } - player.draw(dContext); + draw() { + // Clear canvas + this.mainCanvas.width = this.mainCanvas.width; - player.cycle(); + this.player.draw(this.dContext); - movingObjects.each(function (movingObject, i) { - movingObject.draw(dContext); - }); - - staticObjects.each(function (staticObject, i) { - if (staticObject.draw) { - staticObject.draw(dContext, 'main'); - } - }); + this.player.cycle(); - uiElements.each(function (uiElement, i) { - if (uiElement.draw) { - uiElement.draw(dContext, 'main'); - } - }); - }; - - this.start = function () { - gameLoop.start(); - }; - - this.pause = function () { - paused = true; - gameLoop.stop(); - }; - - this.isPaused = function () { - return paused; - }; - - this.reset = function () { - paused = false; - staticObjects = new SpriteArray(); - movingObjects = new SpriteArray(); - mouseX = dContext.getCentreOfViewport(); - mouseY = 0; - player.reset(); - player.setMapPosition(0, 0, 0); - this.start(); - }.bind(this); - - gameLoop.on('20', this.cycle); - gameLoop.on('20', this.draw); + this.movingObjects.each((movingObject, i) => { + movingObject.draw(this.dContext); + }); + + this.staticObjects.each((staticObject, i) => { + if (staticObject.draw) { + staticObject.draw(this.dContext, 'main'); + } + }); + + this.uiElements.each((uiElement, i) => { + if (uiElement.draw) { + uiElement.draw(this.dContext, 'main'); + } + }); + } + + start() { + this.gameLoop.start(); } - global.game = Game; -})( this ); + pause() { + this.paused = true; + this.gameLoop.stop(); + } + isPaused() { + return this.paused; + } -if (typeof module !== 'undefined') { - module.exports = this.game; -} \ No newline at end of file + reset() { + paused = false; + staticObjects = new SpriteArray(); + movingObjects = new SpriteArray(); + mouseX = dContext.getCentreOfViewport(); + mouseY = 0; + player.reset(); + player.setMapPosition(0, 0, 0); + this.start(); + } +} + +export default Game; diff --git a/js/lib/monster.js b/js/lib/monster.js index 235d771..2cef05b 100644 --- a/js/lib/monster.js +++ b/js/lib/monster.js @@ -1,65 +1,55 @@ -var Sprite = require('./sprite'); - -(function(global) { - function Monster(data) { - var that = new Sprite(data); - var super_draw = that.superior('draw'); - var spriteVersion = 1; - var eatingStage = 0; - var standardSpeed = 6; - - that.isEating = false; - that.isFull = false; - that.setSpeed(standardSpeed); - - that.draw = function(dContext) { - var spritePartToUse = function () { - var xDiff = that.movingToward[0] - that.canvasX; - - if (that.isEating) { - return 'eating' + eatingStage; - } +import Sprite from './sprite'; + +class Monster extends Sprite { + constructor(data) { + super(data); + this.spriteVersion = 1; + this.eatingStage = 0; + this.standardSpeed = 6; + + this.isEating = false; + this.isFull = false; + this.setSpeed(this.standardSpeed); + } - if (spriteVersion + 0.1 > 2) { - spriteVersion = 0.1; - } else { - spriteVersion += 0.1; - } - if (xDiff >= 0) { - return 'sEast' + Math.ceil(spriteVersion); - } else if (xDiff < 0) { - return 'sWest' + Math.ceil(spriteVersion); - } - }; + draw(dContext) { + var spritePartToUse = function () { + var xDiff = this.movingToward[0] - this.canvasX; - return super_draw(dContext, spritePartToUse()); - }; + if (this.isEating) { + return 'eating' + eatingStage; + } - function startEating (whenDone) { - eatingStage += 1; - that.isEating = true; - that.isMoving = false; - if (eatingStage < 6) { - setTimeout(function () { - startEating(whenDone); - }, 300); + if (this.spriteVersion + 0.1 > 2) { + this.spriteVersion = 0.1; } else { - eatingStage = 0; - that.isEating = false; - that.isMoving = true; - whenDone(); + this.spriteVersion += 0.1; } - } - - that.startEating = startEating; + if (xDiff >= 0) { + return 'sEast' + Math.ceil(this.spriteVersion); + } else if (xDiff < 0) { + return 'sWest' + Math.ceil(this.spriteVersion); + } + }; - return that; + return super.draw(dContext, spritePartToUse()); + }; + + startEating (whenDone) { + this.eatingStage += 1; + this.isEating = true; + this.isMoving = false; + if (eatingStage < 6) { + setTimeout(function () { + startEating(whenDone); + }, 300); + } else { + eatingStage = 0; + this.isEating = false; + this.isMoving = true; + whenDone(); + } } +} - global.monster = Monster; -})( this ); - - -if (typeof module !== 'undefined') { - module.exports = this.monster; -} \ No newline at end of file +export default Monster; diff --git a/js/lib/skier.js b/js/lib/skier.js index 1f90a70..9f9b365 100644 --- a/js/lib/skier.js +++ b/js/lib/skier.js @@ -1,4 +1,4 @@ -var Sprite = require('./sprite'); +import Sprite from './sprite'; if (typeof navigator !== 'undefined') { navigator.vibrate = navigator.vibrate || navigator.webkitVibrate || @@ -10,9 +10,10 @@ if (typeof navigator !== 'undefined') { }; } -(function(global) { - function Skier(data) { - var discreteDirections = { +class Skier extends Sprite { + constructor(data) { + super(data) + this.discreteDirections = { 'west': 270, 'wsWest': 240, 'sWest': 195, @@ -21,483 +22,478 @@ if (typeof navigator !== 'undefined') { 'esEast': 120, 'east': 90 }; - var that = new Sprite(data); - var sup = { - draw: that.superior('draw'), - cycle: that.superior('cycle'), - getSpeedX: that.superior('getSpeedX'), - getSpeedY: that.superior('getSpeedY'), - hits: that.superior('hits') + this.sup = { + draw: this.superior('draw'), + cycle: this.superior('cycle'), + getSpeedX: this.superior('getSpeedX'), + getSpeedY: this.superior('getSpeedY'), + hits: this.superior('hits') }; - var directions = { + this.directions = { esEast: function(xDiff) { return xDiff > 300; }, sEast: function(xDiff) { return xDiff > 75; }, wsWest: function(xDiff) { return xDiff < -300; }, sWest: function(xDiff) { return xDiff < -75; } }; + + this.cancelableStateTimeout; + this.cancelableStateInterval; + + this.canSpeedBoost = true; + + this.obstaclesHit = []; + this.pixelsTravelled = 0; + this.standardSpeed = 5; + this.boostMultiplier = 2; + this.turnEaseCycles = 70; + this.speedX = 0; + this.speedXFactor = 0; + this.speedY = 0; + this.speedYFactor = 1; + this.trickStep = 0; // There are three of these + + this.isMoving = true; + this.hasBeenHit = false; + this.isJumping = false; + this.isPerformingTrick = false; + this.onHitObstacleCb = function() {}; + this.setSpeed(this.standardSpeed); + } - var cancelableStateTimeout; - var cancelableStateInterval; - - var canSpeedBoost = true; - - var obstaclesHit = []; - var pixelsTravelled = 0; - var standardSpeed = 5; - var boostMultiplier = 2; - var turnEaseCycles = 70; - var speedX = 0; - var speedXFactor = 0; - var speedY = 0; - var speedYFactor = 1; - var trickStep = 0; // There are three of these - - that.isMoving = true; - that.hasBeenHit = false; - that.isJumping = false; - that.isPerformingTrick = false; - that.onHitObstacleCb = function() {}; - that.setSpeed(standardSpeed); - - that.reset = function () { - obstaclesHit = []; - pixelsTravelled = 0; - that.isMoving = true; - that.hasBeenHit = false; - canSpeedBoost = true; - setNormal(); - }; + reset() { + this.obstaclesHit = []; + this.pixelsTravelled = 0; + this.isMoving = true; + this.hasBeenHit = false; + this.canSpeedBoost = true; + this.setNormal(); + } - function setNormal() { - that.setSpeed(standardSpeed); - that.isMoving = true; - that.hasBeenHit = false; - that.isJumping = false; - that.isPerformingTrick = false; - if (cancelableStateInterval) { - clearInterval(cancelableStateInterval); - } - that.setMapPosition(undefined, undefined, 0); + setNormal() { + // console.log('back to normal') + this.setSpeed(this.standardSpeed); + this.isMoving = true; + this.hasBeenHit = false; + this.isJumping = false; + this.isPerformingTrick = false; + if (this.cancelableStateInterval) { + this.clearInterval(this.cancelableStateInterval); } + this.setMapPosition(undefined, undefined, 0); + } - function setCrashed() { - that.isMoving = false; - that.hasBeenHit = true; - that.isJumping = false; - that.isPerformingTrick = false; - if (cancelableStateInterval) { - clearInterval(cancelableStateInterval); - } - that.setMapPosition(undefined, undefined, 0); + setCrashed() { + this.isMoving = false; + this.hasBeenHit = true; + this.isJumping = false; + this.isPerformingTrick = false; + if (this.cancelableStateInterval) { + clearInterval(this.cancelableStateInterval); } + this.setMapPosition(undefined, undefined, 0); + } - function setJumping() { - var currentSpeed = that.getSpeed(); - that.setSpeed(currentSpeed + 2); - that.setSpeedY(currentSpeed + 2); - that.isMoving = true; - that.hasBeenHit = false; - that.isJumping = true; - that.setMapPosition(undefined, undefined, 1); - } + setJumping() { + var currentSpeed = this.getSpeed(); + this.setSpeed(currentSpeed + 2); + this.setSpeedY(currentSpeed + 2); + this.isMoving = true; + this.hasBeenHit = false; + this.isJumping = true; + this.setMapPosition(undefined, undefined, 1); + } - function getDiscreteDirection() { - if (that.direction) { - if (that.direction <= 90) { + getDiscreteDirection() { + if (this.direction) { + if (this.direction <= 90) { + return 'east'; + } else if (this.direction > 90 && this.direction < 150) { + return 'esEast'; + } else if (this.direction >= 150 && this.direction < 180) { + return 'sEast'; + } else if (this.direction === 180) { + return 'south'; + } else if (this.direction > 180 && this.direction <= 210) { + return 'sWest'; + } else if (this.direction > 210 && this.direction < 270) { + return 'wsWest'; + } else if (this.direction >= 270) { + return 'west'; + } else { + return 'south'; + } + } else { + var xDiff = this.movingToward[0] - this.mapPosition[0]; + var yDiff = this.movingToward[1] - this.mapPosition[1]; + if (yDiff <= 0) { + if (xDiff > 0) { return 'east'; - } else if (that.direction > 90 && that.direction < 150) { - return 'esEast'; - } else if (that.direction >= 150 && that.direction < 180) { - return 'sEast'; - } else if (that.direction === 180) { - return 'south'; - } else if (that.direction > 180 && that.direction <= 210) { - return 'sWest'; - } else if (that.direction > 210 && that.direction < 270) { - return 'wsWest'; - } else if (that.direction >= 270) { - return 'west'; } else { - return 'south'; - } - } else { - var xDiff = that.movingToward[0] - that.mapPosition[0]; - var yDiff = that.movingToward[1] - that.mapPosition[1]; - if (yDiff <= 0) { - if (xDiff > 0) { - return 'east'; - } else { - return 'west'; - } - } - - if (directions.esEast(xDiff)) { - return 'esEast'; - } else if (directions.sEast(xDiff)) { - return 'sEast'; - } else if (directions.wsWest(xDiff)) { - return 'wsWest'; - } else if (directions.sWest(xDiff)) { - return 'sWest'; + return 'west'; } } - return 'south'; - } - function setDiscreteDirection(d) { - if (discreteDirections[d]) { - that.setDirection(discreteDirections[d]); + if (this.directions.esEast(xDiff)) { + return 'esEast'; + } else if (this.directions.sEast(xDiff)) { + return 'sEast'; + } else if (this.directions.wsWest(xDiff)) { + return 'wsWest'; + } else if (this.directions.sWest(xDiff)) { + return 'sWest'; } + } + return 'south'; + } - if (d === 'west' || d === 'east') { - that.isMoving = false; - } else { - that.isMoving = true; - } + setDiscreteDirection(d) { + if (this.discreteDirections[d]) { + this.setDirection(this.discreteDirections[d]); } - function getBeingEatenSprite() { - return 'blank'; + if (d === 'west' || d === 'east') { + this.isMoving = false; + } else { + this.isMoving = true; } + } + + getBeingEatenSprite() { + return 'blank'; + } + + getJumpingSprite() { + return 'jumping'; + } - function getJumpingSprite() { + getTrickSprite() { + console.log('Trick step is', this.trickStep); + if (this.trickStep === 0) { return 'jumping'; + } else if (this.trickStep === 1) { + return 'somersault1'; + } else { + return 'somersault2'; } + } - function getTrickSprite() { - console.log('Trick step is', trickStep); - if (trickStep === 0) { - return 'jumping'; - } else if (trickStep === 1) { - return 'somersault1'; - } else { - return 'somersault2'; - } + stop() { + if (this.direction > 180) { + this.setDiscreteDirection('west'); + } else { + this.setDiscreteDirection('east'); } + } - that.stop = function () { - if (that.direction > 180) { - setDiscreteDirection('west'); - } else { - setDiscreteDirection('east'); - } - }; - - that.turnEast = function () { - var discreteDirection = getDiscreteDirection(); - - switch (discreteDirection) { - case 'west': - setDiscreteDirection('wsWest'); - break; - case 'wsWest': - setDiscreteDirection('sWest'); - break; - case 'sWest': - setDiscreteDirection('south'); - break; - case 'south': - setDiscreteDirection('sEast'); - break; - case 'sEast': - setDiscreteDirection('esEast'); - break; - case 'esEast': - setDiscreteDirection('east'); - break; - default: - setDiscreteDirection('south'); - break; - } - }; - - that.turnWest = function () { - var discreteDirection = getDiscreteDirection(); - - switch (discreteDirection) { - case 'east': - setDiscreteDirection('esEast'); - break; - case 'esEast': - setDiscreteDirection('sEast'); - break; - case 'sEast': - setDiscreteDirection('south'); - break; - case 'south': - setDiscreteDirection('sWest'); - break; - case 'sWest': - setDiscreteDirection('wsWest'); - break; - case 'wsWest': - setDiscreteDirection('west'); - break; - default: - setDiscreteDirection('south'); - break; - } - }; + turnEast() { + var discreteDirection = this.getDiscreteDirection(); + + switch (discreteDirection) { + case 'west': + this.setDiscreteDirection('wsWest'); + break; + case 'wsWest': + this.setDiscreteDirection('sWest'); + break; + case 'sWest': + this.setDiscreteDirection('south'); + break; + case 'south': + this.setDiscreteDirection('sEast'); + break; + case 'sEast': + this.setDiscreteDirection('esEast'); + break; + case 'esEast': + this.setDiscreteDirection('east'); + break; + default: + this.setDiscreteDirection('south'); + break; + } + } - that.stepWest = function () { - that.mapPosition[0] -= that.speed * 2; - }; + turnWest() { + var discreteDirection = this.getDiscreteDirection(); + + switch (discreteDirection) { + case 'east': + this.setDiscreteDirection('esEast'); + break; + case 'esEast': + this.setDiscreteDirection('sEast'); + break; + case 'sEast': + this.setDiscreteDirection('south'); + break; + case 'south': + this.setDiscreteDirection('sWest'); + break; + case 'sWest': + this.setDiscreteDirection('wsWest'); + break; + case 'wsWest': + this.setDiscreteDirection('west'); + break; + default: + this.setDiscreteDirection('south'); + break; + } + } - that.stepEast = function () { - that.mapPosition[0] += that.speed * 2; - }; + stepWest() { + this.mapPosition[0] -= this.speed * 2; + } - that.setMapPositionTarget = function (x, y) { - if (that.hasBeenHit) return; + stepEast() { + this.mapPosition[0] += this.speed * 2; + } - if (Math.abs(that.mapPosition[0] - x) <= 75) { - x = that.mapPosition[0]; - } + setMapPositionTarget(x, y) { + if (this.hasBeenHit) return; - that.movingToward = [ x, y ]; + if (Math.abs(this.mapPosition[0] - x) <= 75) { + x = this.mapPosition[0]; + } - // that.resetDirection(); - }; + this.movingToward = [ x, y ]; - that.startMovingIfPossible = function () { - if (!that.hasBeenHit && !that.isBeingEaten) { - that.isMoving = true; - } - }; + // this.resetDirection(); + } - that.setTurnEaseCycles = function (c) { - turnEaseCycles = c; - }; + startMovingIfPossible() { + if (!this.hasBeenHit && !this.isBeingEaten) { + this.isMoving = true; + } + } - that.getPixelsTravelledDownMountain = function () { - return pixelsTravelled; - }; + setTurnEaseCycles(c) { + this.turnEaseCycles = c; + } - that.resetSpeed = function () { - that.setSpeed(standardSpeed); - }; + getPixelsTravelledDownMountain() { + return this.pixelsTravelled; + } - that.cycle = function () { - if ( that.getSpeedX() <= 0 && that.getSpeedY() <= 0 ) { - that.isMoving = false; - } - if (that.isMoving) { - pixelsTravelled += that.speed; - } + resetSpeed() { + this.setSpeed(this.standardSpeed); + } - if (that.isJumping) { - that.setMapPositionTarget(undefined, that.mapPosition[1] + that.getSpeed()); - } + cycle() { + if (this.getSpeedX() <= 0 && this.getSpeedY() <= 0) { + this.isMoving = false; + } + if (this.isMoving) { + this.pixelsTravelled += this.speed; + } - sup.cycle(); - - that.checkHittableObjects(); - }; + if (this.isJumping) { + this.setMapPositionTarget(undefined, this.mapPosition[1] + this.getSpeed()); + } - that.draw = function(dContext) { - var spritePartToUse = function () { - if (that.isBeingEaten) { - return getBeingEatenSprite(); - } + super.cycle(); + + this.checkHittableObjects(); + } - if (that.isJumping) { - if (that.isPerformingTrick) { - return getTrickSprite(); - } - return getJumpingSprite(); - } + draw(dContext) { + const spritePartToUse = () => { + if (this.isBeingEaten) { + return getBeingEatenSprite(); + } - if (that.hasBeenHit) { - return 'hit'; + if (this.isJumping) { + if (this.isPerformingTrick) { + return getTrickSprite(); } + return getJumpingSprite(); + } - return getDiscreteDirection(); - }; + if (this.hasBeenHit) { + return 'hit'; + } - return sup.draw(dContext, spritePartToUse()); + return this.getDiscreteDirection(); }; - that.hits = function (obs) { - if (obstaclesHit.indexOf(obs.id) !== -1) { - return false; - } - - if (!obs.occupiesZIndex(that.mapPosition[2])) { - return false; - } + return super.draw(dContext, spritePartToUse()); + } - if (sup.hits(obs)) { - return true; - } + hits(obs) { + if (this.obstaclesHit.indexOf(obs.id) !== -1) { + return false; + } + if (!obs.occupiesZIndex(this.mapPosition[2])) { return false; - }; + } - that.speedBoost = function () { - var originalSpeed = that.speed; - if (canSpeedBoost) { - canSpeedBoost = false; - that.setSpeed(that.speed * boostMultiplier); - setTimeout(function () { - that.setSpeed(originalSpeed); - setTimeout(function () { - canSpeedBoost = true; - }, 10000); - }, 2000); - } - }; + if (super.hits(obs)) { + return true; + } - that.attemptTrick = function () { - if (that.isJumping) { - that.isPerformingTrick = true; - cancelableStateInterval = setInterval(function () { - if (trickStep >= 2) { - trickStep = 0; - } else { - trickStep += 1; - } - }, 300); - } - }; + return false; + } - that.getStandardSpeed = function () { - return standardSpeed; - }; + speedBoost() { + var originalSpeed = this.speed; + if (this.canSpeedBoost) { + this.canSpeedBoost = false; + this.setSpeed(this.speed * this.boostMultiplier); + setTimeout(() => { + this.setSpeed(originalSpeed); + setTimeout(() => { + this.canSpeedBoost = true; + }, 10000); + }, 2000); + } + } - function easeSpeedToTargetUsingFactor(sp, targetSpeed, f) { - if (f === 0 || f === 1) { - return targetSpeed; - } + attemptTrick() { + if (this.isJumping) { + this.isPerformingTrick = true; + this.cancelableStateInterval = setInterval(() => { + if (this.trickStep >= 2) { + this.trickStep = 0; + } else { + this.trickStep += 1; + } + }, 300); + } + } - if (sp < targetSpeed) { - sp += that.getSpeed() * (f / turnEaseCycles); - } + getStandardSpeed() { + return this.standardSpeed; + } - if (sp > targetSpeed) { - sp -= that.getSpeed() * (f / turnEaseCycles); - } + easeSpeedToTargetUsingFactor(sp, targetSpeed, f) { + if (f === 0 || f === 1) { + return targetSpeed; + } - return sp; + if (sp < targetSpeed) { + sp += this.getSpeed() * (f / this.turnEaseCycles); } - that.getSpeedX = function () { - if (getDiscreteDirection() === 'esEast' || getDiscreteDirection() === 'wsWest') { - speedXFactor = 0.5; - speedX = easeSpeedToTargetUsingFactor(speedX, that.getSpeed() * speedXFactor, speedXFactor); + if (sp > targetSpeed) { + sp -= this.getSpeed() * (f / this.turnEaseCycles); + } - return speedX; - } + return sp; + } - if (getDiscreteDirection() === 'sEast' || getDiscreteDirection() === 'sWest') { - speedXFactor = 0.33; - speedX = easeSpeedToTargetUsingFactor(speedX, that.getSpeed() * speedXFactor, speedXFactor); + getSpeedX() { + if (this.getDiscreteDirection() === 'esEast' || this.getDiscreteDirection() === 'wsWest') { + this.speedXFactor = 0.5; + this.speedX = this.easeSpeedToTargetUsingFactor(this.speedX, this.getSpeed() * this.speedXFactor, this.speedXFactor); - return speedX; - } + return this.speedX; + } - // So it must be south + if (this.getDiscreteDirection() === 'sEast' || this.getDiscreteDirection() === 'sWest') { + this.speedXFactor = 0.33; + this.speedX = this.easeSpeedToTargetUsingFactor(this.speedX, this.getSpeed() * this.speedXFactor, this.speedXFactor); - speedX = easeSpeedToTargetUsingFactor(speedX, 0, speedXFactor); + return this.speedX; + } - return speedX; - }; + // So it must be south - that.setSpeedY = function(sy) { - speedY = sy; - }; + this.speedX = this.easeSpeedToTargetUsingFactor(this.speedX, 0, this.speedXFactor); - that.getSpeedY = function () { - var targetSpeed; + return this.speedX; + } - if (that.isJumping) { - return speedY; - } + setSpeedY(sy) { + this.speedY = sy; + } - if (getDiscreteDirection() === 'esEast' || getDiscreteDirection() === 'wsWest') { - speedYFactor = 0.6; - speedY = easeSpeedToTargetUsingFactor(speedY, that.getSpeed() * 0.6, 0.6); + getSpeedY() { + var targetSpeed; - return speedY; - } + if (this.isJumping) { + return this.speedY; + } - if (getDiscreteDirection() === 'sEast' || getDiscreteDirection() === 'sWest') { - speedYFactor = 0.85; - speedY = easeSpeedToTargetUsingFactor(speedY, that.getSpeed() * 0.85, 0.85); + if (this.getDiscreteDirection() === 'esEast' || this.getDiscreteDirection() === 'wsWest') { + this.speedYFactor = 0.6; + this.speedY = this.easeSpeedToTargetUsingFactor(this.speedY, this.getSpeed() * 0.6, 0.6); - return speedY; - } + return this.speedY; + } - if (getDiscreteDirection() === 'east' || getDiscreteDirection() === 'west') { - speedYFactor = 1; - speedY = 0; + if (this.getDiscreteDirection() === 'sEast' || this.getDiscreteDirection() === 'sWest') { + this.speedYFactor = 0.85; + this.speedY = this.easeSpeedToTargetUsingFactor(this.speedY, this.getSpeed() * 0.85, 0.85); - return speedY; - } + return this.speedY; + } - // So it must be south + if (this.getDiscreteDirection() === 'east' || this.getDiscreteDirection() === 'west') { + this.speedYFactor = 1; + this.speedY = 0; - speedY = easeSpeedToTargetUsingFactor(speedY, that.getSpeed(), speedYFactor); + return this.speedY; + } - return speedY; - }; + // So it must be south - that.hasHitObstacle = function (obs) { - setCrashed(); + this.speedY = this.easeSpeedToTargetUsingFactor(this.speedY, this.getSpeed(), this.speedYFactor); - if (navigator.vibrate) { - navigator.vibrate(500); - } + return this.speedY; + } - obstaclesHit.push(obs.id); + hasHitObstacle(obs) { + this.setCrashed(); - that.resetSpeed(); - that.onHitObstacleCb(obs); + if (navigator.vibrate) { + navigator.vibrate(500); + } - if (cancelableStateTimeout) { - clearTimeout(cancelableStateTimeout); - } - cancelableStateTimeout = setTimeout(function() { - setNormal(); - }, 1500); - }; + this.obstaclesHit.push(obs.id); - that.hasHitJump = function () { - setJumping(); + this.resetSpeed(); + this.onHitObstacleCb(obs); - if (cancelableStateTimeout) { - clearTimeout(cancelableStateTimeout); - } - cancelableStateTimeout = setTimeout(function() { - setNormal(); - }, 1000); - }; + if (this.cancelableStateTimeout) { + clearTimeout(this.cancelableStateTimeout); + } + this.cancelableStateTimeout = setTimeout(() => { + this.setNormal(); + }, 1500); + } - that.isEatenBy = function (monster, whenEaten) { - that.hasHitObstacle(monster); - monster.startEating(whenEaten); - obstaclesHit.push(monster.id); - that.isMoving = false; - that.isBeingEaten = true; - }; + hasHitJump() { + this.setJumping(); - that.reset = function () { - obstaclesHit = []; - pixelsTravelled = 0; - that.isMoving = true; - that.isJumping = false; - that.hasBeenHit = false; - canSpeedBoost = true; - }; + if (this.cancelableStateTimeout) { + clearTimeout(this.cancelableStateTimeout); + } + this.cancelableStateTimeout = setTimeout(() => { + this.setNormal(); + }, 1000); + } - that.setHitObstacleCb = function (fn) { - that.onHitObstacleCb = fn || function() {}; - }; - return that; + isEatenBy(monster, whenEaten) { + this.hasHitObstacle(monster); + monster.startEating(whenEaten); + this.obstaclesHit.push(monster.id); + this.isMoving = false; + this.isBeingEaten = true; } - global.skier = Skier; -})(this); + reset() { + this.obstaclesHit = []; + this.pixelsTravelled = 0; + this.isMoving = true; + this.isJumping = false; + this.hasBeenHit = false; + this.canSpeedBoost = true; + } -if (typeof module !== 'undefined') { - module.exports = this.skier; + setHitObstacleCb(fn) { + this.onHitObstacleCb = fn || function() {}; + } } + +export default Skier \ No newline at end of file diff --git a/js/lib/snowboarder.js b/js/lib/snowboarder.js index 372b40f..694c0c1 100644 --- a/js/lib/snowboarder.js +++ b/js/lib/snowboarder.js @@ -1,57 +1,41 @@ -var Sprite = require('./sprite'); - -(function(global) { - function Snowboarder(data) { - var that = new Sprite(data); - var sup = { - draw: that.superior('draw'), - cycle: that.superior('cycle') - }; - var directions = { +import Sprite from './sprite'; + +class Snowboarder extends Sprite { + constructor(data) { + super(data); + this.directions = { sEast: function(xDiff) { return xDiff > 0; }, sWest: function(xDiff) { return xDiff <= 0; } }; var standardSpeed = 3; + + this.setSpeed(standardSpeed); + } - that.setSpeed(standardSpeed); - - function getDirection() { - var xDiff = that.movingToward[0] - that.mapPosition[0]; - var yDiff = that.movingToward[1] - that.mapPosition[1]; + getDirection() { + var xDiff = this.movingToward[0] - this.mapPosition[0]; - if (directions.sEast(xDiff)) { - return 'sEast'; - } else { - return 'sWest'; - } + if (this.directions.sEast(xDiff)) { + return 'sEast'; + } else { + return 'sWest'; } + } - that.cycle = function (dContext) { - if (Number.random(10) === 1) { - that.setMapPositionTarget(dContext.getRandomlyInTheCentreOfMap()); - that.setSpeed(standardSpeed + Number.random(-1, 1)); - } - - that.setMapPositionTarget(undefined, dContext.getMapBelowViewport() + 600); - - sup.cycle(); - }; - - that.draw = function(dContext) { - var spritePartToUse = function () { - return getDirection(); - }; + cycle(dContext) { + if (Number.random(10) === 1) { + this.setMapPositionTarget(dContext.getRandomlyInTheCentreOfMap()); + this.setSpeed(this.standardSpeed + Number.random(-1, 1)); + } - return sup.draw(dContext, spritePartToUse()); - }; + this.setMapPositionTarget(undefined, dContext.getMapBelowViewport() + 600); - return that; + super.cycle(); } - global.snowboarder = Snowboarder; -})( this ); - + draw(dContext) { + return super.draw(dContext, this.getDirection()); + } +} -if (typeof module !== 'undefined') { - module.exports = this.snowboarder; -} \ No newline at end of file +export default Snowboarder \ No newline at end of file diff --git a/js/lib/sprite.js b/js/lib/sprite.js index 16b2683..de687a6 100644 --- a/js/lib/sprite.js +++ b/js/lib/sprite.js @@ -1,399 +1,390 @@ -(function (global) { - var GUID = require('./guid'); - function Sprite (data) { - var hittableObjects = {}; - var zIndexesOccupied = [ 0 ]; - var that = this; - var trackedSpriteToMoveToward; - that.direction = undefined; - that.mapPosition = [0, 0, 0]; - that.id = GUID(); - that.canvasX = 0; - that.canvasY = 0; - that.canvasZ = 0; - that.height = 0; - that.speed = 0; - that.data = data || { parts : {} }; - that.movingToward = [ 0, 0 ]; - that.metresDownTheMountain = 0; - that.movingWithConviction = false; - that.deleted = false; - that.maxHeight = (function () { - return Object.values(that.data.parts).map(function (p) { return p[3]; }).max(); - }()); - that.isMoving = true; - - if (!that.data.parts) { - that.data.parts = {}; +import GUID from './guid'; + +class Sprite { + constructor(data) { + this.data = data || { parts : {} } + this.hittableObjects = {} + this.zIndexesOccupied = [ 0 ]; + this.trackedSpriteToMoveToward; + this.direction = undefined; + this.mapPosition = [0, 0, 0]; + this.id = GUID(); + this.canvasX = 0; + this.canvasY = 0; + this.canvasZ = 0; + this.height = 0; + this.speed = 0; + this.movingToward = [ 0, 0 ]; + this.metresDownTheMountain = 0; + this.movingWithConviction = false; + this.deleted = false; + this.maxHeight = Object.values(this.data.parts).map(p => p[3]).max(); + this.isMoving = true; + + if (!this.data.parts) { + this.data.parts = {} } - - if (data && data.id){ - that.id = data.id; + + if (this.data && this.data.id){ + this.id = this.data.id; } - - if (data && data.zIndexesOccupied) { - zIndexesOccupied = data.zIndexesOccupied; + + if (this.data && this.data.zIndexesOccupied) { + this.zIndexesOccupied = this.data.zIndexesOccupied; } + } - function incrementX(amount) { - that.canvasX += amount.toNumber(); - } + incrementX(amount) { + this.canvasX += amount.toNumber(); + } - function incrementY(amount) { - that.canvasY += amount.toNumber(); - } + incrementY(amount) { + this.canvasY += amount.toNumber(); + } - function getHitBox(forZIndex) { - if (that.data.hitBoxes) { - if (data.hitBoxes[forZIndex]) { - return data.hitBoxes[forZIndex]; - } + getHitBox(forZIndex) { + if (this.data.hitBoxes) { + if (this.data.hitBoxes[forZIndex]) { + return this.data.hitBoxes[forZIndex]; } } + } - function roundHalf(num) { - num = Math.round(num*2)/2; - return num; - } - - function move() { - if (!that.isMoving) { - return; - } + roundHalf(num) { + num = Math.round(num*2)/2; + return num; + } - var currentX = that.mapPosition[0]; - var currentY = that.mapPosition[1]; + move() { + if (!this.isMoving) { + return; + } - if (typeof that.direction !== 'undefined') { - // For this we need to modify the that.direction so it relates to the horizontal - var d = that.direction - 90; - if (d < 0) d = 360 + d; - currentX += roundHalf(that.speed * Math.cos(d * (Math.PI / 180))); - currentY += roundHalf(that.speed * Math.sin(d * (Math.PI / 180))); - } else { - if (typeof that.movingToward[0] !== 'undefined') { - if (currentX > that.movingToward[0]) { - currentX -= Math.min(that.getSpeedX(), Math.abs(currentX - that.movingToward[0])); - } else if (currentX < that.movingToward[0]) { - currentX += Math.min(that.getSpeedX(), Math.abs(currentX - that.movingToward[0])); - } + var currentX = this.mapPosition[0]; + var currentY = this.mapPosition[1]; + + if (typeof this.direction !== 'undefined') { + // For this we need to modify the this.direction so it relates to the horizontal + var d = this.direction - 90; + if (d < 0) d = 360 + d; + currentX += this.roundHalf(this.speed * Math.cos(d * (Math.PI / 180))); + currentY += this.roundHalf(this.speed * Math.sin(d * (Math.PI / 180))); + } else { + if (typeof this.movingToward[0] !== 'undefined') { + if (currentX > this.movingToward[0]) { + currentX -= Math.min(this.getSpeedX(), Math.abs(currentX - this.movingToward[0])); + } else if (currentX < this.movingToward[0]) { + currentX += Math.min(this.getSpeedX(), Math.abs(currentX - this.movingToward[0])); } - - if (typeof that.movingToward[1] !== 'undefined') { - if (currentY > that.movingToward[1]) { - currentY -= Math.min(that.getSpeedY(), Math.abs(currentY - that.movingToward[1])); - } else if (currentY < that.movingToward[1]) { - currentY += Math.min(that.getSpeedY(), Math.abs(currentY - that.movingToward[1])); - } + } + + if (typeof this.movingToward[1] !== 'undefined') { + if (currentY > this.movingToward[1]) { + currentY -= Math.min(this.getSpeedY(), Math.abs(currentY - this.movingToward[1])); + } else if (currentY < this.movingToward[1]) { + currentY += Math.min(this.getSpeedY(), Math.abs(currentY - this.movingToward[1])); } } - - that.setMapPosition(currentX, currentY); } - this.draw = function (dCtx, spriteFrame) { - var fr = that.data.parts[spriteFrame]; - that.height = fr[3]; - that.width = fr[2]; + this.setMapPosition(currentX, currentY); + } - var newCanvasPosition = dCtx.mapPositionToCanvasPosition(that.mapPosition); - that.setCanvasPosition(newCanvasPosition[0], newCanvasPosition[1]); + draw(dCtx, spriteFrame) { + var fr = this.data.parts[spriteFrame]; + this.height = fr[3]; + this.width = fr[2]; - dCtx.drawImage(dCtx.getLoadedImage(that.data.$imageFile), fr[0], fr[1], fr[2], fr[3], that.canvasX, that.canvasY, fr[2], fr[3]); - }; + var newCanvasPosition = dCtx.mapPositionToCanvasPosition(this.mapPosition); + this.setCanvasPosition(newCanvasPosition[0], newCanvasPosition[1]); - this.setMapPosition = function (x, y, z) { - if (typeof x === 'undefined') { - x = that.mapPosition[0]; - } - if (typeof y === 'undefined') { - y = that.mapPosition[1]; - } - if (typeof z === 'undefined') { - z = that.mapPosition[2]; - } else { - that.zIndexesOccupied = [ z ]; - } - that.mapPosition = [x, y, z]; - }; + dCtx.drawImage(dCtx.getLoadedImage(this.data.$imageFile), fr[0], fr[1], fr[2], fr[3], this.canvasX, this.canvasY, fr[2], fr[3]); + } - this.setCanvasPosition = function (cx, cy) { - if (cx) { - if (Object.isString(cx) && (cx.first() === '+' || cx.first() === '-')) incrementX(cx); - else that.canvasX = cx; - } - - if (cy) { - if (Object.isString(cy) && (cy.first() === '+' || cy.first() === '-')) incrementY(cy); - else that.canvasY = cy; - } - }; + setMapPosition(x, y, z) { + if (typeof x === 'undefined') { + x = this.mapPosition[0]; + } + if (typeof y === 'undefined') { + y = this.mapPosition[1]; + } + if (typeof z === 'undefined') { + z = this.mapPosition[2]; + } else { + this.zIndexesOccupied = [ z ]; + } + this.mapPosition = [x, y, z]; + } - this.getCanvasPositionX = function () { - return that.canvasX; - }; + setCanvasPosition(cx, cy) { + if (cx) { + if (Object.isString(cx) && (cx.first() === '+' || cx.first() === '-')) this.incrementX(cx); + else this.canvasX = cx; + } + + if (cy) { + if (Object.isString(cy) && (cy.first() === '+' || cy.first() === '-')) this.incrementY(cy); + else this.canvasY = cy; + } + } - this.getCanvasPositionY = function () { - return that.canvasY; - }; + getCanvasPositionX() { + return this.canvasX; + } - this.getLeftHitBoxEdge = function (zIndex) { - zIndex = zIndex || 0; - var lhbe = this.getCanvasPositionX(); - if (getHitBox(zIndex)) { - lhbe += getHitBox(zIndex)[0]; - } - return lhbe; - }; - - this.getTopHitBoxEdge = function (zIndex) { - zIndex = zIndex || 0; - var thbe = this.getCanvasPositionY(); - if (getHitBox(zIndex)) { - thbe += getHitBox(zIndex)[1]; - } - return thbe; - }; + getCanvasPositionY() { + return this.canvasY; + } - this.getRightHitBoxEdge = function (zIndex) { - zIndex = zIndex || 0; + getLeftHitBoxEdge(zIndex) { + zIndex = zIndex || 0; + var lhbe = this.getCanvasPositionX(); + if (this.getHitBox(zIndex)) { + lhbe += this.getHitBox(zIndex)[0]; + } + return lhbe; + } - if (getHitBox(zIndex)) { - return that.canvasX + getHitBox(zIndex)[2]; - } + getTopHitBoxEdge(zIndex) { + zIndex = zIndex || 0; + var thbe = this.getCanvasPositionY(); + if (this.getHitBox(zIndex)) { + thbe += this.getHitBox(zIndex)[1]; + } + return thbe; + } - return that.canvasX + that.width; - }; + getRightHitBoxEdge(zIndex) { + zIndex = zIndex || 0; - this.getBottomHitBoxEdge = function (zIndex) { - zIndex = zIndex || 0; + if (this.getHitBox(zIndex)) { + return this.canvasX + this.getHitBox(zIndex)[2]; + } - if (getHitBox(zIndex)) { - return that.canvasY + getHitBox(zIndex)[3]; - } + return this.canvasX + this.width; + } - return that.canvasY + that.height; - }; + getBottomHitBoxEdge(zIndex) { + zIndex = zIndex || 0; - this.getPositionInFrontOf = function () { - return [that.canvasX, that.canvasY + that.height]; - }; + if (this.getHitBox(zIndex)) { + return this.canvasY + this.getHitBox(zIndex)[3]; + } - this.setSpeed = function (s) { - that.speed = s; - that.speedX = s; - that.speedY = s; - }; + return this.canvasY + this.height; + } - this.incrementSpeedBy = function (s) { - that.speed += s; - }; + getPositionInFrontOf() { + return [this.canvasX, this.canvasY + this.height]; + } - that.getSpeed = function getSpeed () { - return that.speed; - }; + setSpeed(s) { + this.speed = s; + this.speedX = s; + this.speedY = s; + } - that.getSpeedX = function () { - return that.speed; - }; + incrementSpeedBy(s) { + this.speed += s; + } - that.getSpeedY = function () { - return that.speed; - }; + getSpeed() { + return this.speed; + } - this.setHeight = function (h) { - that.height = h; - }; + getSpeedX() { + return this.speed; + } - this.setWidth = function (w) { - that.width = w; - }; + getSpeedY() { + return this.speed; + } - this.getMaxHeight = function () { - return that.maxHeight; - }; + setHeight(h) { + this.height = h; + } - that.getMovingTowardOpposite = function () { - if (!that.isMoving) { - return [0, 0]; - } + setWidth(w) { + this.width = w; + } - var dx = (that.movingToward[0] - that.mapPosition[0]); - var dy = (that.movingToward[1] - that.mapPosition[1]); - - var oppositeX = (Math.abs(dx) > 75 ? 0 - dx : 0); - var oppositeY = -dy; - - return [ oppositeX, oppositeY ]; - }; - - this.checkHittableObjects = function () { - Object.keys(hittableObjects, function (k, objectData) { - if (objectData.object.deleted) { - delete hittableObjects[k]; - } else { - if (objectData.object.hits(that)) { - objectData.callbacks.each(function (callback) { - callback(that, objectData.object); - }); - } - } - }); - }; + getMaxHeight() { + return this.maxHeight; + } - this.cycle = function () { - that.checkHittableObjects(); + getMovingTowardOpposite() { + if (!this.isMoving) { + return [0, 0]; + } - if (trackedSpriteToMoveToward) { - that.setMapPositionTarget(trackedSpriteToMoveToward.mapPosition[0], trackedSpriteToMoveToward.mapPosition[1], true); - } + var dx = (this.movingToward[0] - this.mapPosition[0]); + var dy = (this.movingToward[1] - this.mapPosition[1]); - move(); - }; + var oppositeX = (Math.abs(dx) > 75 ? 0 - dx : 0); + var oppositeY = -dy; - this.setMapPositionTarget = function (x, y, override) { - if (override) { - that.movingWithConviction = false; - } + return [ oppositeX, oppositeY ]; + } - if (!that.movingWithConviction) { - if (typeof x === 'undefined') { - x = that.movingToward[0]; + checkHittableObjects() { + Object.keys(this.hittableObjects, (k, objectData) => { + if (objectData.object.deleted) { + delete this.hittableObjects[k]; + } else { + if (objectData.object.hits(this)) { + objectData.callbacks.each(function (callback) { + callback(this, objectData.object); + }); } + } + }); + } - if (typeof y === 'undefined') { - y = that.movingToward[1]; - } + cycle() { + this.checkHittableObjects(); - that.movingToward = [ x, y ]; + if (this.trackedSpriteToMoveToward) { + this.setMapPositionTarget(this.trackedSpriteToMoveToward.mapPosition[0], this.trackedSpriteToMoveToward.mapPosition[1], true); + } - that.movingWithConviction = false; - } + this.move(); + } - // that.resetDirection(); - }; + setMapPositionTarget(x, y, override) { + if (override) { + this.movingWithConviction = false; + } - this.setDirection = function (angle) { - if (angle >= 360) { - angle = 360 - angle; + if (!this.movingWithConviction) { + if (typeof x === 'undefined') { + x = this.movingToward[0]; } - that.direction = angle; - that.movingToward = undefined; - }; - - this.resetDirection = function () { - that.direction = undefined; - }; - - this.setMapPositionTargetWithConviction = function (cx, cy) { - that.setMapPositionTarget(cx, cy); - that.movingWithConviction = true; - // that.resetDirection(); - }; - - this.follow = function (sprite) { - trackedSpriteToMoveToward = sprite; - // that.resetDirection(); - }; - - this.stopFollowing = function () { - trackedSpriteToMoveToward = false; - }; - - this.onHitting = function (objectToHit, callback) { - if (hittableObjects[objectToHit.id]) { - return hittableObjects[objectToHit.id].callbacks.push(callback); + + if (typeof y === 'undefined') { + y = this.movingToward[1]; } - hittableObjects[objectToHit.id] = { - object: objectToHit, - callbacks: [ callback ] - }; - }; + this.movingToward = [ x, y ]; - this.deleteOnNextCycle = function () { - that.deleted = true; - }; + this.movingWithConviction = false; + } - this.occupiesZIndex = function (z) { - return zIndexesOccupied.indexOf(z) >= 0; - }; + // this.resetDirection(); + } - this.hits = function (other) { - var verticalIntersect = false; - var horizontalIntersect = false; + setDirection(angle) { + if (angle >= 360) { + angle = 360 - angle; + } + this.direction = angle; + this.movingToward = undefined; + } - // Test that THIS has a bottom edge inside of the other object - if (other.getTopHitBoxEdge(that.mapPosition[2]) <= that.getBottomHitBoxEdge(that.mapPosition[2]) && other.getBottomHitBoxEdge(that.mapPosition[2]) >= that.getBottomHitBoxEdge(that.mapPosition[2])) { - verticalIntersect = true; - } + resetDirection() { + this.direction = undefined; + } - // Test that THIS has a top edge inside of the other object - if (other.getTopHitBoxEdge(that.mapPosition[2]) <= that.getTopHitBoxEdge(that.mapPosition[2]) && other.getBottomHitBoxEdge(that.mapPosition[2]) >= that.getTopHitBoxEdge(that.mapPosition[2])) { - verticalIntersect = true; - } + setMapPositionTargetWithConviction(cx, cy) { + this.setMapPositionTarget(cx, cy); + this.movingWithConviction = true; + // this.resetDirection(); + } - // Test that THIS has a right edge inside of the other object - if (other.getLeftHitBoxEdge(that.mapPosition[2]) <= that.getRightHitBoxEdge(that.mapPosition[2]) && other.getRightHitBoxEdge(that.mapPosition[2]) >= that.getRightHitBoxEdge(that.mapPosition[2])) { - horizontalIntersect = true; - } + follow(sprite) { + this.trackedSpriteToMoveToward = sprite; + // this.resetDirection(); + } - // Test that THIS has a left edge inside of the other object - if (other.getLeftHitBoxEdge(that.mapPosition[2]) <= that.getLeftHitBoxEdge(that.mapPosition[2]) && other.getRightHitBoxEdge(that.mapPosition[2]) >= that.getLeftHitBoxEdge(that.mapPosition[2])) { - horizontalIntersect = true; - } + stopFollowing() { + this.trackedSpriteToMoveToward = false; + } - return verticalIntersect && horizontalIntersect; - }; + onHitting(objectToHit, callback) { + if (this.hittableObjects[objectToHit.id]) { + return this.hittableObjects[objectToHit.id].callbacks.push(callback); + } - this.isAboveOnCanvas = function (cy) { - return (that.canvasY + that.height) < cy; - }; + this.hittableObjects[objectToHit.id] = { + object: objectToHit, + callbacks: [ callback ] + } + } - this.isBelowOnCanvas = function (cy) { - return (that.canvasY) > cy; - }; + deleteOnNextCycle() { + this.deleted = true; + } - return that; + occupiesZIndex(z) { + return this.zIndexesOccupied.indexOf(z) >= 0; } - Sprite.createObjects = function createObjects(spriteInfoArray, opts) { - if (!Array.isArray(spriteInfoArray)) spriteInfoArray = [ spriteInfoArray ]; - opts = Object.merge(opts, { - rateModifier: 0, - dropRate: 1, - position: [0, 0] - }, false, false); + hits(other) { + var verticalIntersect = false; + var horizontalIntersect = false; - function createOne (spriteInfo) { - var position = opts.position; - if (Number.random(100 + opts.rateModifier) <= spriteInfo.dropRate) { - var sprite = new Sprite(spriteInfo.sprite); - sprite.setSpeed(0); + // Test this.THIS has a bottom edge inside of the other object + if (other.getTopHitBoxEdge(this.mapPosition[2]) <= this.getBottomHitBoxEdge(this.mapPosition[2]) && other.getBottomHitBoxEdge(this.mapPosition[2]) >= this.getBottomHitBoxEdge(this.mapPosition[2])) { + verticalIntersect = true; + } - if (Object.isFunction(position)) { - position = position(); - } + // Test this.THIS has a top edge inside of the other object + if (other.getTopHitBoxEdge(this.mapPosition[2]) <= this.getTopHitBoxEdge(this.mapPosition[2]) && other.getBottomHitBoxEdge(this.mapPosition[2]) >= this.getTopHitBoxEdge(this.mapPosition[2])) { + verticalIntersect = true; + } - sprite.setMapPosition(position[0], position[1]); + // Test this.THIS has a right edge inside of the other object + if (other.getLeftHitBoxEdge(this.mapPosition[2]) <= this.getRightHitBoxEdge(this.mapPosition[2]) && other.getRightHitBoxEdge(this.mapPosition[2]) >= this.getRightHitBoxEdge(this.mapPosition[2])) { + horizontalIntersect = true; + } - if (spriteInfo.sprite.hitBehaviour && spriteInfo.sprite.hitBehaviour.skier && opts.player) { - sprite.onHitting(opts.player, spriteInfo.sprite.hitBehaviour.skier); - } + // Test this.THIS has a left edge inside of the other object + if (other.getLeftHitBoxEdge(this.mapPosition[2]) <= this.getLeftHitBoxEdge(this.mapPosition[2]) && other.getRightHitBoxEdge(this.mapPosition[2]) >= this.getLeftHitBoxEdge(this.mapPosition[2])) { + horizontalIntersect = true; + } + + return verticalIntersect && horizontalIntersect; + } + + isAboveOnCanvas(cy) { + return (this.canvasY + this.height) < cy; + } - return sprite; + isBelowOnCanvas(cy) { + return (this.canvasY) > cy; + } +} + +Sprite.createObjects = function createObjects(spriteInfoArray, opts) { + if (!Array.isArray(spriteInfoArray)) spriteInfoArray = [ spriteInfoArray ]; + opts = Object.merge(opts, { + rateModifier: 0, + dropRate: 1, + position: [0, 0] + }, false, false); + + function createOne (spriteInfo) { + var position = opts.position; + if (Number.random(100 + opts.rateModifier) <= spriteInfo.dropRate) { + var sprite = new Sprite(spriteInfo.sprite); + sprite.setSpeed(0); + + if (Object.isFunction(position)) { + position = position(); } - } - var objects = spriteInfoArray.map(createOne).remove(undefined); + sprite.setMapPosition(position[0], position[1]); + + if (spriteInfo.sprite.hitBehaviour && spriteInfo.sprite.hitBehaviour.skier && opts.player) { + sprite.onHitting(opts.player, spriteInfo.sprite.hitBehaviour.skier); + } - return objects; - }; + return sprite; + } + } - global.sprite = Sprite; -})( this ); + var objects = spriteInfoArray.map(createOne).remove(undefined); + return objects; +} -if (typeof module !== 'undefined') { - module.exports = this.sprite; -} \ No newline at end of file +export default Sprite; diff --git a/js/lib/spriteArray.js b/js/lib/spriteArray.js index cce2e5a..81acab1 100644 --- a/js/lib/spriteArray.js +++ b/js/lib/spriteArray.js @@ -1,39 +1,71 @@ -(function (global) { - function SpriteArray() { +class SpriteArray extends Array { + constructor(...items) { + super(...items); this.pushHandlers = []; - - return this; } - SpriteArray.prototype = Object.create(Array.prototype); - - SpriteArray.prototype.onPush = function(f, retroactive) { + onPush(f, retroactive) { this.pushHandlers.push(f); if (retroactive) { this.each(f); } - }; + } - SpriteArray.prototype.push = function(obj) { + push(obj) { Array.prototype.push.call(this, obj); this.pushHandlers.each(function(handler) { handler(obj); }); - }; + } - SpriteArray.prototype.cull = function() { + cull() { this.each(function (obj, i) { if (obj.deleted) { return (delete this[i]); } }); - }; + } +} + +export default SpriteArray; + +// (function (global) { +// function SpriteArray() { +// this.pushHandlers = []; + +// return this; +// } + +// SpriteArray.prototype = Object.create(Array.prototype); + +// SpriteArray.prototype.onPush = function(f, retroactive) { +// this.pushHandlers.push(f); + +// if (retroactive) { +// this.each(f); +// } +// }; + +// SpriteArray.prototype.push = function(obj) { +// Array.prototype.push.call(this, obj); +// this.pushHandlers.each(function(handler) { +// handler(obj); +// }); +// }; + +// SpriteArray.prototype.cull = function() { +// this.each(function (obj, i) { +// if (obj.deleted) { +// return (delete this[i]); +// } +// }); +// }; - global.spriteArray = SpriteArray; -})(this); +// global.spriteArray = SpriteArray; +// })(this); -if (typeof module !== 'undefined') { - module.exports = this.spriteArray; -} \ No newline at end of file +// if (typeof module !== 'undefined') { +// module.exports = this.spriteArray; +// } \ No newline at end of file diff --git a/js/main.js b/js/main.js index 5751213..8933e11 100644 --- a/js/main.js +++ b/js/main.js @@ -1,34 +1,32 @@ // Global dependencies which return no modules -require('./lib/canvasRenderingContext2DExtensions'); -require('./lib/extenders'); -require('./lib/plugins'); +import './lib/canvasRenderingContext2DExtensions'; +import './lib/extenders'; +import './lib/plugins'; // External dependencies -var Hammer = require('hammerjs'); -var Mousetrap = require('br-mousetrap'); +import Hammer from 'hammerjs'; +import Mousetrap from 'br-mousetrap'; // Method modules -var isMobileDevice = require('./lib/isMobileDevice'); +import isMobileDevice from './lib/isMobileDevice'; // Game Objects -var SpriteArray = require('./lib/spriteArray'); -var Monster = require('./lib/monster'); -var Sprite = require('./lib/sprite'); -var Snowboarder = require('./lib/snowboarder'); -var Skier = require('./lib/skier'); -var InfoBox = require('./lib/infoBox'); -var Game = require('./lib/game'); +import Monster from './lib/monster'; +import Sprite from './lib/sprite'; +import Snowboarder from './lib/snowboarder'; +import Skier from './lib/skier'; +import InfoBox from './lib/infoBox'; +import Game from './lib/game'; // Local variables for starting the game -var mainCanvas = document.getElementById('skifree-canvas'); -var dContext = mainCanvas.getContext('2d'); -var imageSources = [ 'sprite-characters.png', 'skifree-objects.png' ]; -var global = this; +const mainCanvas = document.getElementById('skifree-canvas'); +const dContext = mainCanvas.getContext('2d'); +const imageSources = [ 'sprite-characters.png', 'skifree-objects.png' ]; var infoBoxControls = 'Use the mouse or WASD to control the player'; if (isMobileDevice()) infoBoxControls = 'Tap or drag on the piste to control the player'; -var sprites = require('./spriteInfo'); +import sprites from './spriteInfo'; -var pixelsPerMetre = 18; +const pixelsPerMetre = 18; var distanceTravelledInMetres = 0; var monsterDistanceThreshold = 2000; var livesLeft = 5; @@ -246,19 +244,24 @@ function startNeverEndingGame (images) { Mousetrap.bind('b', spawnBoarder); Mousetrap.bind('space', resetGame); - var hammertime = Hammer(mainCanvas).on('press', function (e) { + var hammertime = new Hammer(mainCanvas) + + hammertime.on('press', function (e) { e.preventDefault(); game.setMouseX(e.gesture.center.x); game.setMouseY(e.gesture.center.y); - }).on('tap', function (e) { + }); + hammertime.on('tap', function (e) { game.setMouseX(e.gesture.center.x); game.setMouseY(e.gesture.center.y); - }).on('pan', function (e) { + }); + hammertime.on('pan', function (e) { game.setMouseX(e.gesture.center.x); game.setMouseY(e.gesture.center.y); player.resetDirection(); player.startMovingIfPossible(); - }).on('doubletap', function (e) { + }); + hammertime.on('doubletap', function (e) { player.speedBoost(); }); @@ -278,5 +281,3 @@ window.addEventListener('resize', resizeCanvas, false); resizeCanvas(); loadImages(imageSources, startNeverEndingGame); - -this.exports = window; diff --git a/makefile b/makefile deleted file mode 100644 index 9d3373e..0000000 --- a/makefile +++ /dev/null @@ -1,21 +0,0 @@ -VERSION ?= edge - -CFLAGS = -c -g -D $(VERSION) - -help: - @echo " deps install dependencies" - @echo " test runs tests" - @echo " compile sets up your js files for production" - @echo " serve run the webserver" - -deps: - npm install - -test: - npm test - -compile: - browserify js/main.js -d -o dist/skifree.js - uglifyjs dist/skifree.js -d -c > dist/skifree.min.js -serve: - ruby -rwebrick -e'WEBrick::HTTPServer.new(:Port => 3000, :DocumentRoot => Dir.pwd).start' diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index d3c98b4..daff337 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,26 +1,4090 @@ { "name": "SkiFree.js", "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, "dependencies": { + "@webassemblyjs/ast": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", + "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "mamacro": "^0.0.3" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", + "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", + "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", + "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", + "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/helper-wasm-section": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-opt": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", + "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", + "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", + "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", + "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/floating-point-hex-parser": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-code-frame": "1.8.5", + "@webassemblyjs/helper-fsm": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", + "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "acorn": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", + "dev": true + }, + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "bluebird": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", + "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, "br-mousetrap": { "version": "1.1.3", - "from": "br-mousetrap@", - "resolved": "https://registry.npmjs.org/br-mousetrap/-/br-mousetrap-1.1.3.tgz" + "resolved": "https://registry.npmjs.org/br-mousetrap/-/br-mousetrap-1.1.3.tgz", + "integrity": "sha1-XzxAd8azbugdJ27FlXBmOvIsrLc=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "cacache": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", + "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "chownr": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "des.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", + "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "elliptic": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz", + "integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz", + "integrity": "sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true }, "eventedloop": { "version": "1.0.1", - "from": "eventedloop@~1.0.1", + "resolved": "https://registry.npmjs.org/eventedloop/-/eventedloop-1.0.1.tgz", + "integrity": "sha1-xx6oLj7Uvq+rvOcZQKgEjk9ioYU=", + "requires": { + "underscore": "~1.6.0" + }, "dependencies": { "underscore": { "version": "1.6.0", - "from": "underscore@~1.6.0" + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=" + } + } + }, + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } } } }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "figgy-pudding": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", + "dev": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + }, + "dependencies": { + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + } + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + }, "hammerjs": { - "version": "1.0.7-dev", - "from": "hammerjs@git://github.com/EightMedia/hammer.js", - "resolved": "git://github.com/EightMedia/hammer.js#d0bac7f9daa6793219a7d823dfee8d9e98b7ed75" + "version": "git://github.com/EightMedia/hammer.js#d0bac7f9daa6793219a7d823dfee8d9e98b7ed75", + "from": "hammerjs@git://github.com/EightMedia/hammer.js" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true + }, + "invert-kv": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "lcid": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", + "dev": true, + "requires": { + "invert-kv": "^2.0.0" + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", + "dev": true + }, + "map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "dev": true, + "requires": { + "p-defer": "^1.0.0" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "mem": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", + "dev": true, + "requires": { + "map-age-cleaner": "^0.1.1", + "mimic-fn": "^2.0.0", + "p-is-promise": "^2.0.0" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-locale": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "lcid": "^2.0.0", + "mem": "^4.0.0" + } + }, + "p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==", + "dev": true + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pako": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", + "dev": true + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "dependencies": { + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + } + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "serialize-javascript": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.9.1.tgz", + "integrity": "sha512-0Vb/54WJ6k5v8sSWN09S0ora+Hnr+cX40r9F170nT+mSkaxltoE/7R3OrIdBSUv1OoiobH1QoWQbCnAO+e8J1A==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "terser": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.4.0.tgz", + "integrity": "sha512-oDG16n2WKm27JO8h4y/w3iqBGAOSCtq7k8dRmrn4Wf9NouL0b2WpMHGChFGZq4nFAQy1FsNJrVQHfurXOSTmOA==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz", + "integrity": "sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^1.7.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "timers-browserify": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "v8-compile-cache": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", + "integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==", + "dev": true + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "watchpack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "dev": true, + "requires": { + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + } + }, + "webpack": { + "version": "4.41.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.2.tgz", + "integrity": "sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/wasm-edit": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.1", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" + } + }, + "webpack-cli": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.10.tgz", + "integrity": "sha512-u1dgND9+MXaEt74sJR4PR7qkPxXUSQ0RXYq8x1L6Jg1MYVEmGPrH6Ah6C4arD4r0J1P5HKjRqpab36k0eIzPqg==", + "dev": true, + "requires": { + "chalk": "2.4.2", + "cross-spawn": "6.0.5", + "enhanced-resolve": "4.1.0", + "findup-sync": "3.0.0", + "global-modules": "2.0.0", + "import-local": "2.0.0", + "interpret": "1.2.0", + "loader-utils": "1.2.3", + "supports-color": "6.1.0", + "v8-compile-cache": "2.0.3", + "yargs": "13.2.4" + }, + "dependencies": { + "enhanced-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz", + "integrity": "sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.4.0", + "tapable": "^1.0.0" + } + } + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yargs": { + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.4.tgz", + "integrity": "sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "os-locale": "^3.1.0", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.0" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } } } } diff --git a/package.json b/package.json index 3ced1d1..7ebd8e1 100644 --- a/package.json +++ b/package.json @@ -19,12 +19,19 @@ } ], "scripts": { + "start": "webpack --watch --mode=development", + "build": "webpack && cp dist/skifree.js dist/skifree.min.js", "test": "mocha" }, "devDependencies": { - "sugar": "1.3.x", + "@babel/core": "^7.7.2", + "@babel/preset-env": "^7.7.1", + "babel-loader": "^8.0.6", "mocha": "1.8.x", - "should": "1.2.x" + "should": "1.2.x", + "sugar": "1.3.x", + "webpack": "https://registry.npmjs.org/webpack/-/webpack-4.41.2.tgz", + "webpack-cli": "^3.3.10" }, "dependencies": { "eventedloop": "~1.0.1", diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..df75276 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,23 @@ +const path = require('path'); + +module.exports = { + entry: './js/main.js', + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'skifree.js' + }, + module: { + rules: [ + { + test: /\.m?js$/, + exclude: /(node_modules|bower_components)/, + use: { + loader: 'babel-loader', + options: { + presets: ['@babel/preset-env'] + } + } + } + ] + } +}; \ No newline at end of file