diff --git a/js/animation3a.js b/js/animation3a.js index b8a8edd..bc0e32e 100644 --- a/js/animation3a.js +++ b/js/animation3a.js @@ -1,7 +1,6 @@ import Rx, { Observable } from 'rxjs'; import Grid from './grid'; import Particle from './particle'; -import Store from './store'; import Controls from './controls'; import { CONTROLS, ENTITIES } from './enums'; @@ -30,7 +29,6 @@ function Animation3a() { this.updateAnimating(this.options.animating); this.updateCount(this.options.count); - // TODO extract Arc // TODO get "top" leader, once...don't update each time? // TODO if leader sees follower, assign to this leader? // TODO X dimension modified by core UI, maybe recalc grid in animation start? diff --git a/js/arc.js b/js/arc.js new file mode 100644 index 0000000..db5e147 --- /dev/null +++ b/js/arc.js @@ -0,0 +1,133 @@ +import { RAD } from './enums'; +import Random from './random'; + +const Arc = { + create: function(bounds, grids) { + let arc = { + centerX: Random.num(0, bounds.width), + centerY: Random.num(0, bounds.height), + clockwise: Random.bool(), + endX: 0, + endY: 0, + length: Random.num(RAD.t90, RAD.t360), + radius: Random.num(100, 200), + theta: Random.num(RAD.t90, RAD.t360) + }; + + arc.endX = arc.centerX + arc.radius * Math.cos(arc.theta); + arc.endY = arc.centerY - arc.radius * Math.sin(arc.theta); + + arc = Arc.overflow(arc, bounds); + + const x = arc.endX - arc.endX % 5; + const y = arc.endY - arc.endY % 5; + + // If starting in a hazard, recurse. + // if (grids.global[x] !== undefined && grids.global[x][y] !== undefined) { + // arc = createArc(bounds, grids); + // } + + return arc; + }, + + step: function(arc, { bounds, speed }) { + // Ensure constant velocity and theta between 0 and 2π. + const delta = speed / arc.radius; + arc.length -= delta; + + arc.theta += (arc.clockwise ? -delta : +delta); + arc.theta = (arc.theta > 0 ? arc.theta % RAD.t360 : RAD.t360 + arc.theta); + + arc.endX = arc.centerX + arc.radius * Math.cos(arc.theta); // TODO perf here + arc.endY = arc.centerY - arc.radius * Math.sin(arc.theta); // TODO perf here + + // Overflow. + arc = Arc.overflow(arc, bounds); + + return arc; + }, + + randomize: function(arc) { + arc.length = Random.num(RAD.t90, RAD.t360); + + arc = Arc.changeRadius(arc, Random.num(100, 200)); + + if (Random.bool(0.8)) { + arc = Arc.reverse(arc); + } + + return arc; + }, + + overflow: function(arc, bounds) { + if (arc.endX < 0) { + arc.endX += bounds.width; + arc.centerX += bounds.width + } else if (arc.endX > bounds.width) { + arc.endX -= bounds.width; + arc.centerX -= bounds.width + } + + if (arc.endY < 0) { + arc.endY += bounds.height; + arc.centerY += bounds.height + } else if (arc.endY > bounds.height) { + arc.endY -= bounds.height; + arc.centerY -= bounds.height + } + + return arc; + }, + + changeRadius: function(arc, newRadius) { + const r0 = arc.radius; + const r1 = newRadius; + + // Moves arc center to new radius while keeping theta constant. + arc.centerX -= (r1 - r0) * Math.cos(arc.theta); // TODO perf here + arc.centerY += (r1 - r0) * Math.sin(arc.theta); // TODO perf here + arc.radius = r1; + + return arc; + }, + + reverse: function(arc) { + arc.clockwise = !arc.clockwise; + + arc.theta = (arc.theta + RAD.t180) % RAD.t360; + + arc.centerX -= (2 * arc.radius) * Math.cos(arc.theta); // TODO perf here + arc.centerY += (2 * arc.radius) * Math.sin(arc.theta); // TODO perf here + + return arc; + }, + + follow: function(arc, arcToFollow) { + if (arc.clockwise !== arcToFollow.clockwise) { + arc = Arc.reverse(arc); + } + + if (Math.abs(arc.theta - arcToFollow.theta) > 0.1) { + arc = Arc.changeRadius(arc, 20); + } else { + arc = Arc.changeRadius(arc, arcToFollow.radius); + } + + return arc; + }, + + evade: function(arc, visionGrid) { + // const danger = visionGrid.reduce((acc, v) => acc || v.touch, false); + // + // if (danger === false) { + // return arc; + // } + // + // const evasionArc = moveArc(arc, 20); + // evasionArc.length = 1; + // + // return evasionArc; + } +} + +export default Arc; diff --git a/js/bundle.js b/js/bundle.js index b988c80..0b71847 100644 --- a/js/bundle.js +++ b/js/bundle.js @@ -271,18 +271,7 @@ eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n}); eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _rxjs = __webpack_require__(/*! rxjs */ 13);\n\nvar _rxjs2 = _interopRequireDefault(_rxjs);\n\nvar _enums = __webpack_require__(/*! ./enums */ 15);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction Controls(container, _ref, customNodes) {\n var animating = _ref.animating,\n count = _ref.count,\n maxCount = _ref.maxCount,\n speed = _ref.speed;\n\n this.nodes = {\n animating: createAnimatingControl(animating),\n count: createCountControl(count, maxCount),\n speed: createSpeedControl(speed)\n };\n\n container.appendChild(this.nodes.count);\n container.appendChild(this.nodes.speed);\n\n if (customNodes !== undefined) {\n customNodes.forEach(function (node) {\n container.appendChild(node);\n });\n }\n\n container.appendChild(this.nodes.animating);\n\n this.updateOptions({ key: _enums.CONTROLS.ANIMATING, value: animating });\n this.updateOptions({ key: _enums.CONTROLS.COUNT, value: count });\n this.updateOptions({ key: _enums.CONTROLS.SPEED, value: speed });\n}\n\nControls.prototype.updateOptions = function (_ref2) {\n var key = _ref2.key,\n value = _ref2.value;\n\n if (key === _enums.CONTROLS.COUNT) {\n this.nodes.count.querySelector('span').innerHTML = value == 1 ? '1 particle' : value + ' particles';\n }\n\n if (key === _enums.CONTROLS.SPEED) {\n this.nodes.speed.querySelector('span').innerHTML = 'Speed: ' + value;\n }\n\n if (key === _enums.CONTROLS.ANIMATING) {\n this.nodes.animating.querySelector('span').innerHTML = value ? '◼ Stop' : '▶ Start';\n }\n};\n\nControls.prototype.mount = function (customNodes) {\n var animating$ = _rxjs2.default.Observable.fromEvent(this.nodes.animating, 'change').map(function (evt) {\n return { key: _enums.CONTROLS.ANIMATING, value: evt.target.checked };\n });\n\n var count$ = _rxjs2.default.Observable.fromEvent(this.nodes.count, 'input').map(function (evt) {\n return { key: _enums.CONTROLS.COUNT, value: evt.target.value * 1 };\n });\n\n var speed$ = _rxjs2.default.Observable.fromEvent(this.nodes.speed, 'input').map(function (evt) {\n return { key: _enums.CONTROLS.SPEED, value: evt.target.value * 1 };\n });\n\n var eventStack$ = _rxjs2.default.Observable.merge(animating$, count$, speed$);\n\n eventStack$.subscribe(this.updateOptions.bind(this));\n\n return eventStack$;\n};\n\nfunction createAnimatingControl(value) {\n var label = document.createElement('label');\n label.className = 'controls-label';\n label.className = 'controls-animating';\n\n var text = document.createElement('span');\n text.innerHTML = '...';\n\n var checkbox = document.createElement('input');\n checkbox.type = 'checkbox';\n checkbox.checked = value;\n\n label.appendChild(checkbox);\n label.appendChild(text);\n\n return label;\n}\n\nfunction createCountControl(value, max) {\n var label = document.createElement('label');\n label.className = 'controls-range';\n\n var text = document.createElement('span');\n text.innerHTML = '...';\n text.className = 'controls-range-text';\n\n var slider = document.createElement('input');\n slider.type = 'range';\n slider.min = 1;\n slider.max = max;\n slider.value = value;\n slider.className = 'controls-range-input';\n\n label.appendChild(text);\n label.appendChild(slider);\n\n return label;\n}\n\nfunction createSpeedControl(value) {\n var label = document.createElement('label');\n label.className = 'controls-range';\n\n var text = document.createElement('span');\n text.className = 'controls-range-text';\n\n var slider = document.createElement('input');\n slider.type = 'range';\n slider.min = 1;\n slider.max = 15;\n slider.value = value;\n slider.className = 'controls-range-input';\n\n label.appendChild(text);\n label.appendChild(slider);\n\n return label;\n}\n\nexports.default = Controls;//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMTYuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vanMvY29udHJvbHMuanM/ZTk5YiJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUngsIHsgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgQ09OVFJPTFMgfSBmcm9tICcuL2VudW1zJztcblxuZnVuY3Rpb24gQ29udHJvbHMoY29udGFpbmVyLCB7IGFuaW1hdGluZywgY291bnQsIG1heENvdW50LCBzcGVlZCB9LCBjdXN0b21Ob2Rlcykge1xuICAgIHRoaXMubm9kZXMgPSB7XG4gICAgICAgIGFuaW1hdGluZzogY3JlYXRlQW5pbWF0aW5nQ29udHJvbChhbmltYXRpbmcpLFxuICAgICAgICBjb3VudDogY3JlYXRlQ291bnRDb250cm9sKGNvdW50LCBtYXhDb3VudCksXG4gICAgICAgIHNwZWVkOiBjcmVhdGVTcGVlZENvbnRyb2woc3BlZWQpLFxuICAgIH1cblxuICAgIGNvbnRhaW5lci5hcHBlbmRDaGlsZCh0aGlzLm5vZGVzLmNvdW50KTtcbiAgICBjb250YWluZXIuYXBwZW5kQ2hpbGQodGhpcy5ub2Rlcy5zcGVlZCk7XG5cbiAgICBpZiAoY3VzdG9tTm9kZXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjdXN0b21Ob2Rlcy5mb3JFYWNoKG5vZGUgPT4geyBjb250YWluZXIuYXBwZW5kQ2hpbGQobm9kZSk7IH0pO1xuICAgIH1cblxuICAgIGNvbnRhaW5lci5hcHBlbmRDaGlsZCh0aGlzLm5vZGVzLmFuaW1hdGluZyk7XG5cbiAgICB0aGlzLnVwZGF0ZU9wdGlvbnMoeyBrZXk6IENPTlRST0xTLkFOSU1BVElORywgdmFsdWU6IGFuaW1hdGluZyB9KTtcbiAgICB0aGlzLnVwZGF0ZU9wdGlvbnMoeyBrZXk6IENPTlRST0xTLkNPVU5ULCB2YWx1ZTogY291bnQgfSk7XG4gICAgdGhpcy51cGRhdGVPcHRpb25zKHsga2V5OiBDT05UUk9MUy5TUEVFRCwgdmFsdWU6IHNwZWVkIH0pO1xufVxuXG5Db250cm9scy5wcm90b3R5cGUudXBkYXRlT3B0aW9ucyA9IGZ1bmN0aW9uKHsga2V5LCB2YWx1ZX0pIHtcbiAgICBpZiAoa2V5ID09PSBDT05UUk9MUy5DT1VOVCkge1xuICAgICAgICB0aGlzLm5vZGVzLmNvdW50LnF1ZXJ5U2VsZWN0b3IoJ3NwYW4nKS5pbm5lckhUTUwgPVxuICAgICAgICAgICAgKHZhbHVlID09IDEpID8gJzEgcGFydGljbGUnIDogYCR7dmFsdWV9IHBhcnRpY2xlc2A7XG4gICAgfVxuXG4gICAgaWYgKGtleSA9PT0gQ09OVFJPTFMuU1BFRUQpIHtcbiAgICAgICAgdGhpcy5ub2Rlcy5zcGVlZC5xdWVyeVNlbGVjdG9yKCdzcGFuJykuaW5uZXJIVE1MID1cbiAgICAgICAgICAgIGBTcGVlZDogJHt2YWx1ZX1gO1xuICAgIH1cblxuICAgIGlmIChrZXkgPT09IENPTlRST0xTLkFOSU1BVElORykge1xuICAgICAgICB0aGlzLm5vZGVzLmFuaW1hdGluZy5xdWVyeVNlbGVjdG9yKCdzcGFuJykuaW5uZXJIVE1MID1cbiAgICAgICAgICAgICh2YWx1ZSA/ICcmIzk3MjQ7IFN0b3AnIDogJyYjOTY1NDsgU3RhcnQnKTtcbiAgICB9XG59XG5cbkNvbnRyb2xzLnByb3RvdHlwZS5tb3VudCA9IGZ1bmN0aW9uKGN1c3RvbU5vZGVzKSB7XG4gICAgY29uc3QgYW5pbWF0aW5nJCA9IFJ4Lk9ic2VydmFibGUuZnJvbUV2ZW50KHRoaXMubm9kZXMuYW5pbWF0aW5nLCAnY2hhbmdlJylcbiAgICAgICAgLm1hcChldnQgPT4gKHsga2V5OiBDT05UUk9MUy5BTklNQVRJTkcsIHZhbHVlOiBldnQudGFyZ2V0LmNoZWNrZWQgfSkpO1xuXG4gICAgY29uc3QgY291bnQkID0gUnguT2JzZXJ2YWJsZS5mcm9tRXZlbnQodGhpcy5ub2Rlcy5jb3VudCwgJ2lucHV0JylcbiAgICAgICAgLm1hcChldnQgPT4gKHsga2V5OiBDT05UUk9MUy5DT1VOVCwgdmFsdWU6IGV2dC50YXJnZXQudmFsdWUgKiAxIH0pKTtcblxuICAgIGNvbnN0IHNwZWVkJCA9IFJ4Lk9ic2VydmFibGUuZnJvbUV2ZW50KHRoaXMubm9kZXMuc3BlZWQsICdpbnB1dCcpXG4gICAgICAgIC5tYXAoZXZ0ID0+ICh7IGtleTogQ09OVFJPTFMuU1BFRUQsIHZhbHVlOiBldnQudGFyZ2V0LnZhbHVlICogMSB9KSk7XG5cbiAgICBjb25zdCBldmVudFN0YWNrJCA9IFJ4Lk9ic2VydmFibGUubWVyZ2UoXG4gICAgICAgIGFuaW1hdGluZyQsXG4gICAgICAgIGNvdW50JCxcbiAgICAgICAgc3BlZWQkXG4gICAgKTtcblxuICAgIGV2ZW50U3RhY2skLnN1YnNjcmliZSh0aGlzLnVwZGF0ZU9wdGlvbnMuYmluZCh0aGlzKSk7XG5cbiAgICByZXR1cm4gZXZlbnRTdGFjayQ7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUFuaW1hdGluZ0NvbnRyb2wodmFsdWUpIHtcbiAgICBjb25zdCBsYWJlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2xhYmVsJyk7XG4gICAgbGFiZWwuY2xhc3NOYW1lID0gJ2NvbnRyb2xzLWxhYmVsJztcbiAgICBsYWJlbC5jbGFzc05hbWUgPSAnY29udHJvbHMtYW5pbWF0aW5nJztcblxuICAgIGNvbnN0IHRleHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG4gICAgdGV4dC5pbm5lckhUTUwgPSAnLi4uJztcblxuICAgIGNvbnN0IGNoZWNrYm94ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaW5wdXQnKTtcbiAgICBjaGVja2JveC50eXBlID0gJ2NoZWNrYm94JztcbiAgICBjaGVja2JveC5jaGVja2VkID0gdmFsdWU7XG5cbiAgICBsYWJlbC5hcHBlbmRDaGlsZChjaGVja2JveCk7XG4gICAgbGFiZWwuYXBwZW5kQ2hpbGQodGV4dCk7XG5cbiAgICByZXR1cm4gbGFiZWw7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUNvdW50Q29udHJvbCh2YWx1ZSwgbWF4KSB7XG4gICAgY29uc3QgbGFiZWwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdsYWJlbCcpO1xuICAgIGxhYmVsLmNsYXNzTmFtZSA9ICdjb250cm9scy1yYW5nZSc7XG5cbiAgICBjb25zdCB0ZXh0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpO1xuICAgIHRleHQuaW5uZXJIVE1MID0gJy4uLic7XG4gICAgdGV4dC5jbGFzc05hbWUgPSAnY29udHJvbHMtcmFuZ2UtdGV4dCc7XG5cbiAgICBjb25zdCBzbGlkZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpbnB1dCcpO1xuICAgIHNsaWRlci50eXBlID0gJ3JhbmdlJztcbiAgICBzbGlkZXIubWluID0gMTtcbiAgICBzbGlkZXIubWF4ID0gbWF4O1xuICAgIHNsaWRlci52YWx1ZSA9IHZhbHVlO1xuICAgIHNsaWRlci5jbGFzc05hbWUgPSAnY29udHJvbHMtcmFuZ2UtaW5wdXQnO1xuXG4gICAgbGFiZWwuYXBwZW5kQ2hpbGQodGV4dCk7XG4gICAgbGFiZWwuYXBwZW5kQ2hpbGQoc2xpZGVyKTtcblxuICAgIHJldHVybiBsYWJlbDtcbn1cblxuZnVuY3Rpb24gY3JlYXRlU3BlZWRDb250cm9sKHZhbHVlKSB7XG4gICAgY29uc3QgbGFiZWwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdsYWJlbCcpO1xuICAgIGxhYmVsLmNsYXNzTmFtZSA9ICdjb250cm9scy1yYW5nZSc7XG5cbiAgICBjb25zdCB0ZXh0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpO1xuICAgIHRleHQuY2xhc3NOYW1lID0gJ2NvbnRyb2xzLXJhbmdlLXRleHQnO1xuXG4gICAgY29uc3Qgc2xpZGVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaW5wdXQnKTtcbiAgICBzbGlkZXIudHlwZSA9ICdyYW5nZSc7XG4gICAgc2xpZGVyLm1pbiA9IDE7XG4gICAgc2xpZGVyLm1heCA9IDE1O1xuICAgIHNsaWRlci52YWx1ZSA9IHZhbHVlO1xuICAgIHNsaWRlci5jbGFzc05hbWUgPSAnY29udHJvbHMtcmFuZ2UtaW5wdXQnO1xuXG4gICAgbGFiZWwuYXBwZW5kQ2hpbGQodGV4dCk7XG4gICAgbGFiZWwuYXBwZW5kQ2hpbGQoc2xpZGVyKTtcblxuICAgIHJldHVybiBsYWJlbDtcbn1cblxuZXhwb3J0IGRlZmF1bHQgQ29udHJvbHM7XG5cblxuXG4vLyBXRUJQQUNLIEZPT1RFUiAvL1xuLy8ganMvY29udHJvbHMuanMiXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBO0FBQ0E7OztBQUFBO0FBQ0E7OztBQUNBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBSEE7QUFDQTtBQUtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VSb290IjoiIn0="); /***/ }), -/* 17 */ -/* unknown exports provided */ -/* all exports used */ -/*!*********************!*\ - !*** ./js/store.js ***! - \*********************/ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nvar Store = function Store(initialProps) {\n this.state = Object.freeze(initialProps);\n};\n\nStore.prototype.set = function (props) {\n this.state = Object.freeze(Object.assign({}, this.state, props));\n return this.state;\n};\n\nStore.prototype.get = function () {\n return this.state;\n};\n\nexports.default = Store;//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMTcuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vanMvc3RvcmUuanM/MzNmZiJdLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCBTdG9yZSA9IGZ1bmN0aW9uKGluaXRpYWxQcm9wcykge1xuICAgIHRoaXMuc3RhdGUgPSBPYmplY3QuZnJlZXplKGluaXRpYWxQcm9wcyk7XG59XG5cblN0b3JlLnByb3RvdHlwZS5zZXQgPSBmdW5jdGlvbihwcm9wcykge1xuICAgIHRoaXMuc3RhdGUgPSBPYmplY3QuZnJlZXplKE9iamVjdC5hc3NpZ24oe30sIHRoaXMuc3RhdGUsIHByb3BzKSk7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGU7XG59O1xuXG5TdG9yZS5wcm90b3R5cGUuZ2V0ID0gZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RhdGU7XG59XG5cbmV4cG9ydCBkZWZhdWx0IFN0b3JlO1xuXG5cblxuLy8gV0VCUEFDSyBGT09URVIgLy9cbi8vIGpzL3N0b3JlLmpzIl0sIm1hcHBpbmdzIjoiOzs7OztBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VSb290IjoiIn0="); - -/***/ }), +/* 17 */, /* 18 */ /* unknown exports provided */ /* all exports used */ @@ -304,7 +293,7 @@ eval("\nvar ConnectableObservable_1 = __webpack_require__(/*! ../observable/Conn /***/ (function(module, exports, __webpack_require__) { "use strict"; -eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _rxjs = __webpack_require__(/*! rxjs */ 13);\n\nvar _rxjs2 = _interopRequireDefault(_rxjs);\n\nvar _enums = __webpack_require__(/*! ./enums */ 15);\n\nvar _store = __webpack_require__(/*! ./store */ 17);\n\nvar _store2 = _interopRequireDefault(_store);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar random = {\n bool: function bool(weight) {\n return Math.random() < (weight || 0.5);\n },\n color: function color() {\n return 'rgb(\\n ' + Math.floor(Math.random() * 230) + ',\\n ' + Math.floor(Math.random() * 230) + ',\\n ' + Math.floor(Math.random() * 230) + '\\n )';\n },\n id: function id() {\n return String.fromCharCode(random.num(65, 90), random.num(97, 122), random.num(97, 122)\n // random.num(97, 122), random.num(97, 122), random.num(97, 122)\n );\n },\n num: function num(min, max) {\n return min + Math.round(Math.random() * (max - min));\n }\n};\n\n// ===== Constructor =====\n\nfunction Particle(parent, bounds, config, globalGrid) {\n Object.defineProperty(this, 'config', {\n value: Object.assign({}, {\n behavior: _enums.BEHAVIOR.COHESION,\n bounds: bounds,\n color: random.color(),\n gridSize: 5,\n randomize: true,\n showMovementCircle: false,\n showVisionGrid: false,\n speed: 4,\n visionRadius: 50\n }, config)\n });\n\n Object.defineProperty(this, 'grids', {\n value: {\n global: globalGrid || {},\n vision: createVisionGrid(this.config)\n }\n });\n\n Object.defineProperty(this, 'id', {\n value: random.id(6)\n });\n\n Object.defineProperty(this, 'nodes', {\n value: {\n body: createBodyNode(this.config),\n circle: undefined,\n container: createContainerNode(this.config, this.id),\n parent: parent,\n visionGrid: undefined\n }\n });\n\n // TODO encapsulate better\n this.isLeader = false;\n this.leader = null;\n\n this.nodes.container.appendChild(this.nodes.body);\n parent.appendChild(this.nodes.container);\n\n this.arc = createArc(bounds, this.grids);\n this.updateConfig(this.config);\n this.nextFrame(globalGrid);\n};\n\n// ===== PROTOTYPE =====\n\nParticle.prototype.remove = function () {\n this.nodes.parent.removeChild(this.nodes.container);\n return this;\n};\n\nParticle.prototype.nextFrame = function (globalGrid) {\n var _this = this;\n\n // Randomly change radius and rotation direction.\n if (this.arc.length <= 0 && this.config.randomize) {\n this.arc = randomizeArc(this.arc);\n }\n\n this.arc = step(this.arc, this.config);\n\n if (this.leader !== null) {\n this.arc = followArc(this.arc, this.leader.arc);\n }\n\n this.grids.global = globalGrid;\n this.grids.vision = updateVisionGrid(this.arc, this.config, this.grids);\n\n var _look = look(this.arc, this.grids),\n hazards = _look.hazards,\n particles = _look.particles;\n\n if (this.leader === null && particles.length > 0) {\n var candidates = particles.filter(function (v) {\n return v.leader ? v.leader.id !== _this.id : true;\n });\n\n var leader = candidates.find(function (v) {\n return v.isLeader;\n }) || candidates[0];\n\n if (leader !== undefined) {\n leader.isLeader = true;\n\n // console.log(`${this.id} is now following ${leader.id}`);\n\n this.isLeader = false;\n this.leader = leader;\n }\n }\n\n this.updateLeader();\n\n // if (hazards.length) {\n // this.arc = evade(this.arc, this.grids.vision);\n // }\n\n repaintContainer(this.nodes.container, this.arc);\n repaintBody(this.nodes.body, this.arc, this.isLeader);\n repaintCircle(this.nodes.circle, this.arc);\n repaintVisionGrid(this.nodes.visionGrid, this.arc, this.grids);\n};\n\nParticle.prototype.updateConfig = function (config) {\n Object.assign(this.config, config);\n\n var _config = this.config,\n showMovementCircle = _config.showMovementCircle,\n showVisionGrid = _config.showVisionGrid;\n\n\n if (showMovementCircle === true && this.nodes.circle === undefined) {\n this.nodes.circle = createCircleNode(config);\n this.nodes.container.appendChild(this.nodes.circle);\n }\n\n if (showMovementCircle === false && this.nodes.circle !== undefined) {\n this.nodes.container.removeChild(this.nodes.circle);\n delete this.nodes.circle;\n }\n\n if (showVisionGrid === true && this.nodes.visionGrid === undefined) {\n this.nodes.visionGrid = createVisionGridNodes(this.config, this.grids, this.nodes);\n }\n\n if (showVisionGrid === false && this.nodes.visionGrid !== undefined) {\n delete this.nodex.visionGrid;\n }\n};\n\nParticle.prototype.updateLeader = function () {\n if (this.leader === null) {\n return;\n }\n\n while (this.leader.leader !== null) {\n this.leader.isLeader = false;\n this.leader = this.leader.leader;\n // console.error(this.id, 'is now following', this.leader.id)\n }\n\n // Prevents circular leadership, where a leader sees its tail.\n if (this.leader.id === this.id) {\n this.leader = null;\n }\n};\n\n// ===== CREATION =====\n\nfunction createArc(bounds, grids) {\n var arc = {\n centerX: random.num(0, bounds.width),\n centerY: random.num(0, bounds.height),\n clockwise: random.bool(),\n endX: 0,\n endY: 0,\n length: random.num(_enums.RAD.t90, _enums.RAD.t360),\n radius: random.num(100, 200),\n theta: random.num(_enums.RAD.t90, _enums.RAD.t360)\n };\n\n arc.endX = arc.centerX + arc.radius * Math.cos(arc.theta);\n arc.endY = arc.centerY - arc.radius * Math.sin(arc.theta);\n\n arc = overflowArc(arc, bounds);\n\n var x = arc.endX - arc.endX % 5;\n var y = arc.endY - arc.endY % 5;\n\n // If starting in a hazard, recurse.\n if (grids.global[x] !== undefined && grids.global[x][y] !== undefined) {\n arc = createArc(bounds, grids);\n }\n\n return arc;\n}\n\nfunction createBodyNode(config) {\n var node = document.createElement('div');\n node.className = 'particle-body';\n node.style.backgroundColor = config.color;\n return node;\n}\n\nfunction createCircleNode(config) {\n if (config.showMovementCircle === false) {\n return undefined;\n }\n\n var node = document.createElement('div');\n node.className = 'particle-movement-circle';\n node.style.borderColor = config.color;\n return node;\n}\n\nfunction createContainerNode(config, id) {\n var node = document.createElement('div');\n node.className = 'particle-container';\n node.id = id;\n return node;\n}\n\nfunction createVisionGrid(config) {\n var side = config.gridSize,\n radius = config.visionRadius;\n\n var r0 = radius;\n var r1 = 30;\n\n var points = [];\n\n for (var x = -radius; x <= radius; x += side) {\n for (var y = -radius; y <= radius; y += side) {\n // Omit large slices of unused circle\n if (x > y || x < -y) {\n continue;\n }\n\n // Include vision band\n var r = Math.pow(Math.pow(x, 2) + Math.pow(y, 2), 0.5);\n if (r > r0 || r < r1) {\n continue;\n }\n\n var alpha = Math.atan(y / x);\n if (x < 0) {\n alpha += _enums.RAD.t180;\n }\n\n points.push({ x: x, y: y, r: r, alpha: alpha, touch: false });\n }\n }\n\n return points;\n}\n\nfunction createVisionGridNodes(config, grids, nodes) {\n if (config.showVisionGrid === false) {\n return undefined;\n }\n\n return grids.vision.reduce(function (acc, _ref) {\n var x = _ref.x,\n y = _ref.y;\n\n var div = document.createElement('div');\n div.className = 'particle-vision-dot';\n div.style.backgroundColor = config.color;\n nodes.container.appendChild(div);\n\n acc.push(div);\n\n return acc;\n }, []);\n}\n\n// ===== CALCULATIONS =====\n\nfunction step(arc, _ref2) {\n var bounds = _ref2.bounds,\n speed = _ref2.speed;\n\n // Ensure constant velocity and theta between 0 and 2π.\n var delta = speed / arc.radius;\n arc.length -= delta;\n\n arc.theta += arc.clockwise ? -delta : +delta;\n arc.theta = arc.theta > 0 ? arc.theta % _enums.RAD.t360 : _enums.RAD.t360 + arc.theta;\n\n arc.endX = arc.centerX + arc.radius * Math.cos(arc.theta); // TODO perf here\n arc.endY = arc.centerY - arc.radius * Math.sin(arc.theta); // TODO perf here\n\n // Overflow.\n arc = overflowArc(arc, bounds);\n\n return arc;\n}\n\nfunction randomizeArc(arc) {\n arc.length = random.num(_enums.RAD.t90, _enums.RAD.t360);\n\n arc = moveArc(arc, random.num(100, 200));\n\n if (random.bool(0.8)) {\n arc = reverseArc(arc);\n }\n\n return arc;\n}\n\nfunction overflowArc(arc, bounds) {\n if (arc.endX < 0) {\n arc.endX += bounds.width;\n arc.centerX += bounds.width;\n } else if (arc.endX > bounds.width) {\n arc.endX -= bounds.width;\n arc.centerX -= bounds.width;\n }\n\n if (arc.endY < 0) {\n arc.endY += bounds.height;\n arc.centerY += bounds.height;\n } else if (arc.endY > bounds.height) {\n arc.endY -= bounds.height;\n arc.centerY -= bounds.height;\n }\n\n return arc;\n}\n\nfunction moveArc(arc, newRadius) {\n var r0 = arc.radius;\n var r1 = newRadius;\n\n // Moves arc center to new radius while keeping theta constant.\n arc.centerX -= (r1 - r0) * Math.cos(arc.theta); // TODO perf here\n arc.centerY += (r1 - r0) * Math.sin(arc.theta); // TODO perf here\n arc.radius = r1;\n\n return arc;\n}\n\nfunction reverseArc(arc) {\n arc.clockwise = !arc.clockwise;\n\n arc.theta = (arc.theta + _enums.RAD.t180) % _enums.RAD.t360;\n\n arc.centerX -= 2 * arc.radius * Math.cos(arc.theta); // TODO perf here\n arc.centerY += 2 * arc.radius * Math.sin(arc.theta); // TODO perf here\n\n return arc;\n}\n\nfunction followArc(arc, arcToFollow) {\n if (arc.clockwise !== arcToFollow.clockwise) {\n arc = reverseArc(arc);\n }\n\n if (Math.abs(arc.theta - arcToFollow.theta) > 0.1) {\n arc = moveArc(arc, 20);\n } else {\n arc = moveArc(arc, arcToFollow.radius);\n }\n\n return arc;\n}\n\nfunction updateVisionGrid(arc, config, grids) {\n var global = grids.global,\n vision = grids.vision;\n\n\n return vision.reduce(function (acc, point) {\n var rad = arc.clockwise ? point.alpha - arc.theta : point.alpha - arc.theta + _enums.RAD.t180;\n\n point.x = point.r * Math.cos(rad);\n point.y = point.r * Math.sin(rad);\n\n return acc.concat(point);\n }, []);\n}\n\n// ===== ACTIONS =====\nfunction look(arc, grids) {\n var global = grids.global,\n vision = grids.vision;\n\n\n return vision.reduce(function (acc, point) {\n var x = arc.endX + point.x;\n var y = arc.endY + point.y;\n var p = global.getPoint({ x: x, y: y, type: _enums.ENTITIES.PARTICLE });\n\n if (p) {\n acc.particles.push(p);\n }\n\n // if (global.getPoint({ x, y, type: ENTITIES.HAZARD })) {\n // acc.hazards.push({ x, y });\n // }\n\n return acc;\n }, { hazards: [], particles: [] });\n}\n\nfunction evade(arc, visionGrid) {}\n// const danger = visionGrid.reduce((acc, v) => acc || v.touch, false);\n//\n// if (danger === false) {\n// return arc;\n// }\n//\n// const evasionArc = moveArc(arc, 20);\n// evasionArc.length = 1;\n//\n// return evasionArc;\n\n\n// ===== RENDERING =====\nfunction repaintContainer(node, arc) {\n node.style.left = arc.endX + 'px';\n node.style.top = arc.endY + 'px';\n}\n\nfunction repaintBody(node, arc, isLeader) {\n var rad = arc.clockwise ? _enums.RAD.t180 - arc.theta : _enums.RAD.t360 - arc.theta;\n\n node.style.transform = 'rotate(' + (rad + _enums.RAD.t45) + 'rad)';\n\n isLeader ? node.style.outline = '1px solid red' : node.style.outline = '';\n}\n\nfunction repaintCircle(node, arc) {\n if (node === undefined) {\n return;\n }\n\n node.style.width = 2 * arc.radius + 'px';\n node.style.height = 2 * arc.radius + 'px';\n\n node.style.left = '-' + (arc.radius + arc.radius * Math.cos(arc.theta)) + 'px'; // TODO perf here\n node.style.top = '-' + (arc.radius - arc.radius * Math.sin(arc.theta)) + 'px'; // TODO perf here\n\n node.style.borderRadius = arc.radius + 'px';\n}\n\nfunction repaintVisionGrid(nodes, arc, grids) {\n if (nodes === undefined) {\n return;\n }\n\n grids.vision.forEach(function (_ref3, i) {\n var x = _ref3.x,\n y = _ref3.y,\n touch = _ref3.touch;\n\n nodes[i].style.left = x + 'px';\n nodes[i].style.top = y + 'px';\n\n nodes[i].style.border = touch ? '2px solid red' : '0';\n });\n}\n\nexports.default = Particle;//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMTkuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vanMvcGFydGljbGUuanM/M2JkZSJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUngsIHsgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgQkVIQVZJT1IsIEVOVElUSUVTLCBSQUQgfSBmcm9tICcuL2VudW1zJztcbmltcG9ydCBTdG9yZSBmcm9tICcuL3N0b3JlJztcblxuY29uc3QgcmFuZG9tID0ge1xuICAgIGJvb2w6ICh3ZWlnaHQpID0+IE1hdGgucmFuZG9tKCkgPCAod2VpZ2h0IHx8IDAuNSksXG4gICAgY29sb3I6ICgpID0+IGByZ2IoXG4gICAgICAgICR7TWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMjMwKX0sXG4gICAgICAgICR7TWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMjMwKX0sXG4gICAgICAgICR7TWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMjMwKX1cbiAgICApYCxcbiAgICBpZDogKCkgPT4gU3RyaW5nLmZyb21DaGFyQ29kZShcbiAgICAgICAgcmFuZG9tLm51bSg2NSwgOTApLCByYW5kb20ubnVtKDk3LCAxMjIpLCByYW5kb20ubnVtKDk3LCAxMjIpXG4gICAgICAgIC8vIHJhbmRvbS5udW0oOTcsIDEyMiksIHJhbmRvbS5udW0oOTcsIDEyMiksIHJhbmRvbS5udW0oOTcsIDEyMilcbiAgICApLFxuICAgIG51bTogKG1pbiwgbWF4KSA9PiBtaW4gKyBNYXRoLnJvdW5kKE1hdGgucmFuZG9tKCkgKiAobWF4IC0gbWluKSksXG59XG5cbi8vID09PT09IENvbnN0cnVjdG9yID09PT09XG5cbmZ1bmN0aW9uIFBhcnRpY2xlKHBhcmVudCwgYm91bmRzLCBjb25maWcsIGdsb2JhbEdyaWQpIHtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ2NvbmZpZycsIHtcbiAgICAgICAgdmFsdWU6IE9iamVjdC5hc3NpZ24oe30sIHtcbiAgICAgICAgICAgIGJlaGF2aW9yOiBCRUhBVklPUi5DT0hFU0lPTixcbiAgICAgICAgICAgIGJvdW5kcyxcbiAgICAgICAgICAgIGNvbG9yOiByYW5kb20uY29sb3IoKSxcbiAgICAgICAgICAgIGdyaWRTaXplOiA1LFxuICAgICAgICAgICAgcmFuZG9taXplOiB0cnVlLFxuICAgICAgICAgICAgc2hvd01vdmVtZW50Q2lyY2xlOiBmYWxzZSxcbiAgICAgICAgICAgIHNob3dWaXNpb25HcmlkOiBmYWxzZSxcbiAgICAgICAgICAgIHNwZWVkOiA0LFxuICAgICAgICAgICAgdmlzaW9uUmFkaXVzOiA1MFxuICAgICAgICB9LCBjb25maWcpXG4gICAgfSk7XG5cbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ2dyaWRzJywge1xuICAgICAgICB2YWx1ZToge1xuICAgICAgICAgICAgZ2xvYmFsOiBnbG9iYWxHcmlkIHx8IHt9LFxuICAgICAgICAgICAgdmlzaW9uOiBjcmVhdGVWaXNpb25HcmlkKHRoaXMuY29uZmlnKVxuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ2lkJywge1xuICAgICAgICB2YWx1ZTogcmFuZG9tLmlkKDYpXG4gICAgfSk7XG5cbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ25vZGVzJywge1xuICAgICAgICB2YWx1ZToge1xuICAgICAgICAgICAgYm9keTogY3JlYXRlQm9keU5vZGUodGhpcy5jb25maWcpLFxuICAgICAgICAgICAgY2lyY2xlOiB1bmRlZmluZWQsXG4gICAgICAgICAgICBjb250YWluZXI6IGNyZWF0ZUNvbnRhaW5lck5vZGUodGhpcy5jb25maWcsIHRoaXMuaWQpLFxuICAgICAgICAgICAgcGFyZW50LFxuICAgICAgICAgICAgdmlzaW9uR3JpZDogdW5kZWZpbmVkLFxuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICAvLyBUT0RPIGVuY2Fwc3VsYXRlIGJldHRlclxuICAgIHRoaXMuaXNMZWFkZXIgPSBmYWxzZTtcbiAgICB0aGlzLmxlYWRlciA9IG51bGw7XG5cbiAgICB0aGlzLm5vZGVzLmNvbnRhaW5lci5hcHBlbmRDaGlsZCh0aGlzLm5vZGVzLmJvZHkpO1xuICAgIHBhcmVudC5hcHBlbmRDaGlsZCh0aGlzLm5vZGVzLmNvbnRhaW5lcik7XG5cbiAgICB0aGlzLmFyYyA9IGNyZWF0ZUFyYyhib3VuZHMsIHRoaXMuZ3JpZHMpO1xuICAgIHRoaXMudXBkYXRlQ29uZmlnKHRoaXMuY29uZmlnKTtcbiAgICB0aGlzLm5leHRGcmFtZShnbG9iYWxHcmlkKTtcbn07XG5cbi8vID09PT09IFBST1RPVFlQRSA9PT09PVxuXG5QYXJ0aWNsZS5wcm90b3R5cGUucmVtb3ZlID0gZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5ub2Rlcy5wYXJlbnQucmVtb3ZlQ2hpbGQodGhpcy5ub2Rlcy5jb250YWluZXIpO1xuICAgIHJldHVybiB0aGlzO1xufVxuXG5QYXJ0aWNsZS5wcm90b3R5cGUubmV4dEZyYW1lID0gZnVuY3Rpb24oZ2xvYmFsR3JpZCkge1xuICAgIC8vIFJhbmRvbWx5IGNoYW5nZSByYWRpdXMgYW5kIHJvdGF0aW9uIGRpcmVjdGlvbi5cbiAgICBpZiAodGhpcy5hcmMubGVuZ3RoIDw9IDAgJiYgdGhpcy5jb25maWcucmFuZG9taXplKSB7XG4gICAgICAgIHRoaXMuYXJjID0gcmFuZG9taXplQXJjKHRoaXMuYXJjKTtcbiAgICB9XG5cbiAgICB0aGlzLmFyYyA9IHN0ZXAodGhpcy5hcmMsIHRoaXMuY29uZmlnKTtcblxuICAgIGlmICh0aGlzLmxlYWRlciAhPT0gbnVsbCkge1xuICAgICAgICB0aGlzLmFyYyA9IGZvbGxvd0FyYyh0aGlzLmFyYywgdGhpcy5sZWFkZXIuYXJjKTtcbiAgICB9XG5cbiAgICB0aGlzLmdyaWRzLmdsb2JhbCA9IGdsb2JhbEdyaWQ7XG4gICAgdGhpcy5ncmlkcy52aXNpb24gPSB1cGRhdGVWaXNpb25HcmlkKHRoaXMuYXJjLCB0aGlzLmNvbmZpZywgdGhpcy5ncmlkcyk7XG5cbiAgICBjb25zdCB7IGhhemFyZHMsIHBhcnRpY2xlcyB9ID0gbG9vayh0aGlzLmFyYywgdGhpcy5ncmlkcyk7XG5cbiAgICBpZiAodGhpcy5sZWFkZXIgPT09IG51bGwgJiYgcGFydGljbGVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgY29uc3QgY2FuZGlkYXRlcyA9IHBhcnRpY2xlc1xuICAgICAgICAgICAgLmZpbHRlcih2ID0+IHYubGVhZGVyID8gKHYubGVhZGVyLmlkICE9PSB0aGlzLmlkKSA6IHRydWUpO1xuXG4gICAgICAgIGNvbnN0IGxlYWRlciA9IGNhbmRpZGF0ZXMuZmluZCh2ID0+IHYuaXNMZWFkZXIpIHx8IGNhbmRpZGF0ZXNbMF07XG5cbiAgICAgICAgaWYgKGxlYWRlciAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBsZWFkZXIuaXNMZWFkZXIgPSB0cnVlO1xuXG4gICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhgJHt0aGlzLmlkfSBpcyBub3cgZm9sbG93aW5nICR7bGVhZGVyLmlkfWApO1xuXG4gICAgICAgICAgICB0aGlzLmlzTGVhZGVyID0gZmFsc2U7XG4gICAgICAgICAgICB0aGlzLmxlYWRlciA9IGxlYWRlcjtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMudXBkYXRlTGVhZGVyKCk7XG5cbiAgICAvLyBpZiAoaGF6YXJkcy5sZW5ndGgpIHtcbiAgICAgICAgLy8gdGhpcy5hcmMgPSBldmFkZSh0aGlzLmFyYywgdGhpcy5ncmlkcy52aXNpb24pO1xuICAgIC8vIH1cblxuICAgIHJlcGFpbnRDb250YWluZXIodGhpcy5ub2Rlcy5jb250YWluZXIsIHRoaXMuYXJjKTtcbiAgICByZXBhaW50Qm9keSh0aGlzLm5vZGVzLmJvZHksIHRoaXMuYXJjLCB0aGlzLmlzTGVhZGVyKTtcbiAgICByZXBhaW50Q2lyY2xlKHRoaXMubm9kZXMuY2lyY2xlLCB0aGlzLmFyYyk7XG4gICAgcmVwYWludFZpc2lvbkdyaWQodGhpcy5ub2Rlcy52aXNpb25HcmlkLCB0aGlzLmFyYywgdGhpcy5ncmlkcyk7XG59XG5cblBhcnRpY2xlLnByb3RvdHlwZS51cGRhdGVDb25maWcgPSBmdW5jdGlvbihjb25maWcpIHtcbiAgICBPYmplY3QuYXNzaWduKHRoaXMuY29uZmlnLCBjb25maWcpO1xuXG4gICAgY29uc3QgeyBzaG93TW92ZW1lbnRDaXJjbGUsIHNob3dWaXNpb25HcmlkIH0gPSB0aGlzLmNvbmZpZztcblxuICAgIGlmIChzaG93TW92ZW1lbnRDaXJjbGUgPT09IHRydWUgJiYgdGhpcy5ub2Rlcy5jaXJjbGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aGlzLm5vZGVzLmNpcmNsZSA9IGNyZWF0ZUNpcmNsZU5vZGUoY29uZmlnKTtcbiAgICAgICAgdGhpcy5ub2Rlcy5jb250YWluZXIuYXBwZW5kQ2hpbGQodGhpcy5ub2Rlcy5jaXJjbGUpO1xuICAgIH1cblxuICAgIGlmIChzaG93TW92ZW1lbnRDaXJjbGUgPT09IGZhbHNlICYmIHRoaXMubm9kZXMuY2lyY2xlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5ub2Rlcy5jb250YWluZXIucmVtb3ZlQ2hpbGQodGhpcy5ub2Rlcy5jaXJjbGUpO1xuICAgICAgICBkZWxldGUgdGhpcy5ub2Rlcy5jaXJjbGU7XG4gICAgfVxuXG4gICAgaWYgKHNob3dWaXNpb25HcmlkID09PSB0cnVlICYmIHRoaXMubm9kZXMudmlzaW9uR3JpZCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRoaXMubm9kZXMudmlzaW9uR3JpZCA9IGNyZWF0ZVZpc2lvbkdyaWROb2Rlcyh0aGlzLmNvbmZpZywgdGhpcy5ncmlkcywgdGhpcy5ub2Rlcyk7XG4gICAgfVxuXG4gICAgaWYgKHNob3dWaXNpb25HcmlkID09PSBmYWxzZSAmJiB0aGlzLm5vZGVzLnZpc2lvbkdyaWQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBkZWxldGUgdGhpcy5ub2RleC52aXNpb25HcmlkO1xuICAgIH1cbn1cblxuUGFydGljbGUucHJvdG90eXBlLnVwZGF0ZUxlYWRlciA9IGZ1bmN0aW9uKCkge1xuICAgIGlmICh0aGlzLmxlYWRlciA9PT0gbnVsbCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgd2hpbGUgKHRoaXMubGVhZGVyLmxlYWRlciAhPT0gbnVsbCkge1xuICAgICAgICB0aGlzLmxlYWRlci5pc0xlYWRlciA9IGZhbHNlO1xuICAgICAgICB0aGlzLmxlYWRlciA9IHRoaXMubGVhZGVyLmxlYWRlcjtcbiAgICAgICAgLy8gY29uc29sZS5lcnJvcih0aGlzLmlkLCAnaXMgbm93IGZvbGxvd2luZycsIHRoaXMubGVhZGVyLmlkKVxuICAgIH1cblxuICAgIC8vIFByZXZlbnRzIGNpcmN1bGFyIGxlYWRlcnNoaXAsIHdoZXJlIGEgbGVhZGVyIHNlZXMgaXRzIHRhaWwuXG4gICAgaWYgKHRoaXMubGVhZGVyLmlkID09PSB0aGlzLmlkKSB7XG4gICAgICAgIHRoaXMubGVhZGVyID0gbnVsbDtcbiAgICB9XG59XG5cbi8vID09PT09IENSRUFUSU9OID09PT09XG5cbmZ1bmN0aW9uIGNyZWF0ZUFyYyhib3VuZHMsIGdyaWRzKSB7XG4gICAgbGV0IGFyYyA9IHtcbiAgICAgICAgY2VudGVyWDogcmFuZG9tLm51bSgwLCBib3VuZHMud2lkdGgpLFxuICAgICAgICBjZW50ZXJZOiByYW5kb20ubnVtKDAsIGJvdW5kcy5oZWlnaHQpLFxuICAgICAgICBjbG9ja3dpc2U6IHJhbmRvbS5ib29sKCksXG4gICAgICAgIGVuZFg6IDAsXG4gICAgICAgIGVuZFk6IDAsXG4gICAgICAgIGxlbmd0aDogcmFuZG9tLm51bShSQUQudDkwLCBSQUQudDM2MCksXG4gICAgICAgIHJhZGl1czogcmFuZG9tLm51bSgxMDAsIDIwMCksXG4gICAgICAgIHRoZXRhOiByYW5kb20ubnVtKFJBRC50OTAsIFJBRC50MzYwKSxcbiAgICB9O1xuXG4gICAgYXJjLmVuZFggPSBhcmMuY2VudGVyWCArIGFyYy5yYWRpdXMgKiBNYXRoLmNvcyhhcmMudGhldGEpO1xuICAgIGFyYy5lbmRZID0gYXJjLmNlbnRlclkgLSBhcmMucmFkaXVzICogTWF0aC5zaW4oYXJjLnRoZXRhKTtcblxuICAgIGFyYyA9IG92ZXJmbG93QXJjKGFyYywgYm91bmRzKTtcblxuICAgIGNvbnN0IHggPSBhcmMuZW5kWCAtIGFyYy5lbmRYICUgNTtcbiAgICBjb25zdCB5ID0gYXJjLmVuZFkgLSBhcmMuZW5kWSAlIDU7XG5cbiAgICAvLyBJZiBzdGFydGluZyBpbiBhIGhhemFyZCwgcmVjdXJzZS5cbiAgICBpZiAoZ3JpZHMuZ2xvYmFsW3hdICE9PSB1bmRlZmluZWQgJiYgZ3JpZHMuZ2xvYmFsW3hdW3ldICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgYXJjID0gY3JlYXRlQXJjKGJvdW5kcywgZ3JpZHMpO1xuICAgIH1cblxuICAgIHJldHVybiBhcmM7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUJvZHlOb2RlKGNvbmZpZykge1xuICAgIGNvbnN0IG5vZGUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICBub2RlLmNsYXNzTmFtZSA9ICdwYXJ0aWNsZS1ib2R5JztcbiAgICBub2RlLnN0eWxlLmJhY2tncm91bmRDb2xvciA9IGNvbmZpZy5jb2xvcjtcbiAgICByZXR1cm4gbm9kZTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlQ2lyY2xlTm9kZShjb25maWcpIHtcbiAgICBpZiAoY29uZmlnLnNob3dNb3ZlbWVudENpcmNsZSA9PT0gZmFsc2UpIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBjb25zdCBub2RlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgbm9kZS5jbGFzc05hbWUgPSAncGFydGljbGUtbW92ZW1lbnQtY2lyY2xlJztcbiAgICBub2RlLnN0eWxlLmJvcmRlckNvbG9yID0gY29uZmlnLmNvbG9yO1xuICAgIHJldHVybiBub2RlO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVDb250YWluZXJOb2RlKGNvbmZpZywgaWQpIHtcbiAgICBjb25zdCBub2RlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgbm9kZS5jbGFzc05hbWUgPSAncGFydGljbGUtY29udGFpbmVyJztcbiAgICBub2RlLmlkID0gaWQ7XG4gICAgcmV0dXJuIG5vZGU7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZVZpc2lvbkdyaWQoY29uZmlnKSB7XG4gICAgY29uc3QgeyBncmlkU2l6ZTogc2lkZSwgdmlzaW9uUmFkaXVzOiByYWRpdXMgfSA9IGNvbmZpZztcbiAgICBjb25zdCByMCA9IHJhZGl1cztcbiAgICBjb25zdCByMSA9IDMwO1xuXG4gICAgY29uc3QgcG9pbnRzID0gW107XG5cbiAgICBmb3IgKGxldCB4ID0gLXJhZGl1czsgeCA8PSByYWRpdXM7IHggKz0gc2lkZSkge1xuICAgICAgICBmb3IgKGxldCB5ID0gLXJhZGl1czsgeSA8PSByYWRpdXM7IHkgKz0gc2lkZSkge1xuICAgICAgICAgICAgLy8gT21pdCBsYXJnZSBzbGljZXMgb2YgdW51c2VkIGNpcmNsZVxuICAgICAgICAgICAgaWYgKHggPiB5IHx8IHggPCAteSkge1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBJbmNsdWRlIHZpc2lvbiBiYW5kXG4gICAgICAgICAgICBjb25zdCByID0gTWF0aC5wb3coTWF0aC5wb3coeCwgMikgKyBNYXRoLnBvdyh5LCAyKSwgMC41KTtcbiAgICAgICAgICAgIGlmIChyID4gcjAgfHwgciA8IHIxKSB7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGxldCBhbHBoYSA9IE1hdGguYXRhbih5IC8geCk7XG4gICAgICAgICAgICBpZiAoeCA8IDApIHtcbiAgICAgICAgICAgICAgICBhbHBoYSArPSBSQUQudDE4MDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcG9pbnRzLnB1c2goeyB4LCB5LCByLCBhbHBoYSwgdG91Y2g6IGZhbHNlIH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHBvaW50cztcbn1cblxuZnVuY3Rpb24gY3JlYXRlVmlzaW9uR3JpZE5vZGVzKGNvbmZpZywgZ3JpZHMsIG5vZGVzKSB7XG4gICAgaWYgKGNvbmZpZy5zaG93VmlzaW9uR3JpZCA9PT0gZmFsc2UpIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICByZXR1cm4gZ3JpZHMudmlzaW9uLnJlZHVjZSgoYWNjLCB7IHgsIHkgfSkgPT4ge1xuICAgICAgICBjb25zdCBkaXYgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICAgICAgZGl2LmNsYXNzTmFtZSA9ICdwYXJ0aWNsZS12aXNpb24tZG90JztcbiAgICAgICAgZGl2LnN0eWxlLmJhY2tncm91bmRDb2xvciA9IGNvbmZpZy5jb2xvcjtcbiAgICAgICAgbm9kZXMuY29udGFpbmVyLmFwcGVuZENoaWxkKGRpdik7XG5cbiAgICAgICAgYWNjLnB1c2goZGl2KTtcblxuICAgICAgICByZXR1cm4gYWNjO1xuICAgIH0sIFtdKTtcbn1cblxuLy8gPT09PT0gQ0FMQ1VMQVRJT05TID09PT09XG5cbmZ1bmN0aW9uIHN0ZXAoYXJjLCB7IGJvdW5kcywgc3BlZWQgfSkge1xuICAgIC8vIEVuc3VyZSBjb25zdGFudCB2ZWxvY2l0eSBhbmQgdGhldGEgYmV0d2VlbiAwIGFuZCAyz4AuXG4gICAgY29uc3QgZGVsdGEgPSBzcGVlZCAvIGFyYy5yYWRpdXM7XG4gICAgYXJjLmxlbmd0aCAtPSBkZWx0YTtcblxuICAgIGFyYy50aGV0YSArPSAoYXJjLmNsb2Nrd2lzZSA/IC1kZWx0YSA6ICtkZWx0YSk7XG4gICAgYXJjLnRoZXRhID0gKGFyYy50aGV0YSA+IDAgPyBhcmMudGhldGEgJSBSQUQudDM2MCA6IFJBRC50MzYwICsgYXJjLnRoZXRhKTtcblxuICAgIGFyYy5lbmRYID0gYXJjLmNlbnRlclggKyBhcmMucmFkaXVzICogTWF0aC5jb3MoYXJjLnRoZXRhKTsgLy8gVE9ETyBwZXJmIGhlcmVcbiAgICBhcmMuZW5kWSA9IGFyYy5jZW50ZXJZIC0gYXJjLnJhZGl1cyAqIE1hdGguc2luKGFyYy50aGV0YSk7IC8vIFRPRE8gcGVyZiBoZXJlXG5cbiAgICAvLyBPdmVyZmxvdy5cbiAgICBhcmMgPSBvdmVyZmxvd0FyYyhhcmMsIGJvdW5kcyk7XG5cbiAgICByZXR1cm4gYXJjO1xufVxuXG5mdW5jdGlvbiByYW5kb21pemVBcmMoYXJjKSB7XG4gICAgYXJjLmxlbmd0aCA9IHJhbmRvbS5udW0oUkFELnQ5MCwgUkFELnQzNjApO1xuXG4gICAgYXJjID0gbW92ZUFyYyhhcmMsIHJhbmRvbS5udW0oMTAwLCAyMDApKTtcblxuICAgIGlmIChyYW5kb20uYm9vbCgwLjgpKSB7XG4gICAgICAgIGFyYyA9IHJldmVyc2VBcmMoYXJjKTtcbiAgICB9XG5cbiAgICByZXR1cm4gYXJjO1xufVxuXG5mdW5jdGlvbiBvdmVyZmxvd0FyYyhhcmMsIGJvdW5kcykge1xuICAgIGlmIChhcmMuZW5kWCA8IDApIHtcbiAgICAgICAgYXJjLmVuZFggKz0gYm91bmRzLndpZHRoO1xuICAgICAgICBhcmMuY2VudGVyWCArPSBib3VuZHMud2lkdGhcbiAgICB9IGVsc2UgaWYgKGFyYy5lbmRYID4gYm91bmRzLndpZHRoKSB7XG4gICAgICAgIGFyYy5lbmRYIC09IGJvdW5kcy53aWR0aDtcbiAgICAgICAgYXJjLmNlbnRlclggLT0gYm91bmRzLndpZHRoXG4gICAgfVxuXG4gICAgaWYgKGFyYy5lbmRZIDwgMCkge1xuICAgICAgICBhcmMuZW5kWSArPSBib3VuZHMuaGVpZ2h0O1xuICAgICAgICBhcmMuY2VudGVyWSArPSBib3VuZHMuaGVpZ2h0XG4gICAgfSBlbHNlIGlmIChhcmMuZW5kWSA+IGJvdW5kcy5oZWlnaHQpIHtcbiAgICAgICAgYXJjLmVuZFkgLT0gYm91bmRzLmhlaWdodDtcbiAgICAgICAgYXJjLmNlbnRlclkgLT0gYm91bmRzLmhlaWdodFxuICAgIH1cblxuICAgIHJldHVybiBhcmM7XG59XG5cbmZ1bmN0aW9uIG1vdmVBcmMoYXJjLCBuZXdSYWRpdXMpIHtcbiAgICBjb25zdCByMCA9IGFyYy5yYWRpdXM7XG4gICAgY29uc3QgcjEgPSBuZXdSYWRpdXM7XG5cbiAgICAvLyBNb3ZlcyBhcmMgY2VudGVyIHRvIG5ldyByYWRpdXMgd2hpbGUga2VlcGluZyB0aGV0YSBjb25zdGFudC5cbiAgICBhcmMuY2VudGVyWCAtPSAocjEgLSByMCkgKiBNYXRoLmNvcyhhcmMudGhldGEpOyAvLyBUT0RPIHBlcmYgaGVyZVxuICAgIGFyYy5jZW50ZXJZICs9IChyMSAtIHIwKSAqIE1hdGguc2luKGFyYy50aGV0YSk7IC8vIFRPRE8gcGVyZiBoZXJlXG4gICAgYXJjLnJhZGl1cyA9IHIxO1xuXG4gICAgcmV0dXJuIGFyYztcbn1cblxuZnVuY3Rpb24gcmV2ZXJzZUFyYyhhcmMpIHtcbiAgICBhcmMuY2xvY2t3aXNlID0gIWFyYy5jbG9ja3dpc2U7XG5cbiAgICBhcmMudGhldGEgPSAoYXJjLnRoZXRhICsgUkFELnQxODApICUgUkFELnQzNjA7XG5cbiAgICBhcmMuY2VudGVyWCAtPSAoMiAqIGFyYy5yYWRpdXMpICogTWF0aC5jb3MoYXJjLnRoZXRhKTsgLy8gVE9ETyBwZXJmIGhlcmVcbiAgICBhcmMuY2VudGVyWSArPSAoMiAqIGFyYy5yYWRpdXMpICogTWF0aC5zaW4oYXJjLnRoZXRhKTsgLy8gVE9ETyBwZXJmIGhlcmVcblxuICAgIHJldHVybiBhcmM7XG59XG5cbmZ1bmN0aW9uIGZvbGxvd0FyYyhhcmMsIGFyY1RvRm9sbG93KSB7XG4gICAgaWYgKGFyYy5jbG9ja3dpc2UgIT09IGFyY1RvRm9sbG93LmNsb2Nrd2lzZSkge1xuICAgICAgICBhcmMgPSByZXZlcnNlQXJjKGFyYyk7XG4gICAgfVxuXG4gICAgaWYgKE1hdGguYWJzKGFyYy50aGV0YSAtIGFyY1RvRm9sbG93LnRoZXRhKSA+IDAuMSkge1xuICAgICAgICBhcmMgPSBtb3ZlQXJjKGFyYywgMjApO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGFyYyA9IG1vdmVBcmMoYXJjLCBhcmNUb0ZvbGxvdy5yYWRpdXMpO1xuICAgIH1cblxuICAgIHJldHVybiBhcmM7XG59XG5cbmZ1bmN0aW9uIHVwZGF0ZVZpc2lvbkdyaWQoYXJjLCBjb25maWcsIGdyaWRzKSB7XG4gICAgY29uc3QgeyBnbG9iYWwsIHZpc2lvbiB9ID0gZ3JpZHM7XG5cbiAgICByZXR1cm4gdmlzaW9uLnJlZHVjZSgoYWNjLCBwb2ludCkgPT4ge1xuICAgICAgICBjb25zdCByYWQgPSBhcmMuY2xvY2t3aXNlXG4gICAgICAgICAgICA/IHBvaW50LmFscGhhIC0gYXJjLnRoZXRhXG4gICAgICAgICAgICA6IHBvaW50LmFscGhhIC0gYXJjLnRoZXRhICsgUkFELnQxODA7XG5cbiAgICAgICAgcG9pbnQueCA9IHBvaW50LnIgKiBNYXRoLmNvcyhyYWQpO1xuICAgICAgICBwb2ludC55ID0gcG9pbnQuciAqIE1hdGguc2luKHJhZCk7XG5cbiAgICAgICAgcmV0dXJuIGFjYy5jb25jYXQocG9pbnQpO1xuICAgIH0sIFtdKTtcbn1cblxuLy8gPT09PT0gQUNUSU9OUyA9PT09PVxuZnVuY3Rpb24gbG9vayhhcmMsIGdyaWRzKSB7XG4gICAgY29uc3QgeyBnbG9iYWwsIHZpc2lvbiB9ID0gZ3JpZHM7XG5cbiAgICByZXR1cm4gdmlzaW9uLnJlZHVjZSgoYWNjLCBwb2ludCkgPT4ge1xuICAgICAgICBjb25zdCB4ID0gYXJjLmVuZFggKyBwb2ludC54O1xuICAgICAgICBjb25zdCB5ID0gYXJjLmVuZFkgKyBwb2ludC55O1xuICAgICAgICBjb25zdCBwID0gZ2xvYmFsLmdldFBvaW50KHsgeCwgeSwgdHlwZTogRU5USVRJRVMuUEFSVElDTEUgfSk7XG5cbiAgICAgICAgaWYgKHApIHtcbiAgICAgICAgICAgIGFjYy5wYXJ0aWNsZXMucHVzaChwKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGlmIChnbG9iYWwuZ2V0UG9pbnQoeyB4LCB5LCB0eXBlOiBFTlRJVElFUy5IQVpBUkQgfSkpIHtcbiAgICAgICAgLy8gICAgIGFjYy5oYXphcmRzLnB1c2goeyB4LCB5IH0pO1xuICAgICAgICAvLyB9XG5cbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICB9LCB7IGhhemFyZHM6IFtdLCBwYXJ0aWNsZXM6IFtdIH0pO1xufVxuXG5mdW5jdGlvbiBldmFkZShhcmMsIHZpc2lvbkdyaWQpIHtcbiAgICAvLyBjb25zdCBkYW5nZXIgPSB2aXNpb25HcmlkLnJlZHVjZSgoYWNjLCB2KSA9PiBhY2MgfHwgdi50b3VjaCwgZmFsc2UpO1xuICAgIC8vXG4gICAgLy8gaWYgKGRhbmdlciA9PT0gZmFsc2UpIHtcbiAgICAvLyAgICAgcmV0dXJuIGFyYztcbiAgICAvLyB9XG4gICAgLy9cbiAgICAvLyBjb25zdCBldmFzaW9uQXJjID0gbW92ZUFyYyhhcmMsIDIwKTtcbiAgICAvLyBldmFzaW9uQXJjLmxlbmd0aCA9IDE7XG4gICAgLy9cbiAgICAvLyByZXR1cm4gZXZhc2lvbkFyYztcbn1cblxuLy8gPT09PT0gUkVOREVSSU5HID09PT09XG5mdW5jdGlvbiByZXBhaW50Q29udGFpbmVyKG5vZGUsIGFyYykge1xuICAgIG5vZGUuc3R5bGUubGVmdCA9IGAke2FyYy5lbmRYfXB4YDtcbiAgICBub2RlLnN0eWxlLnRvcCA9IGAke2FyYy5lbmRZfXB4YDtcbn1cblxuZnVuY3Rpb24gcmVwYWludEJvZHkobm9kZSwgYXJjLCBpc0xlYWRlcikge1xuICAgIGNvbnN0IHJhZCA9IGFyYy5jbG9ja3dpc2VcbiAgICAgICAgPyBSQUQudDE4MCAtIGFyYy50aGV0YVxuICAgICAgICA6IFJBRC50MzYwIC0gYXJjLnRoZXRhO1xuXG4gICAgbm9kZS5zdHlsZS50cmFuc2Zvcm0gPSBgcm90YXRlKCR7cmFkICsgUkFELnQ0NX1yYWQpYDtcblxuICAgIGlzTGVhZGVyID8gbm9kZS5zdHlsZS5vdXRsaW5lID0gJzFweCBzb2xpZCByZWQnIDogbm9kZS5zdHlsZS5vdXRsaW5lID0gJyc7XG59XG5cbmZ1bmN0aW9uIHJlcGFpbnRDaXJjbGUobm9kZSwgYXJjKSB7XG4gICAgaWYgKG5vZGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbm9kZS5zdHlsZS53aWR0aCA9IGAkezIgKiBhcmMucmFkaXVzfXB4YDtcbiAgICBub2RlLnN0eWxlLmhlaWdodCA9IGAkezIgKiBhcmMucmFkaXVzfXB4YDtcblxuICAgIG5vZGUuc3R5bGUubGVmdCA9IGAtJHthcmMucmFkaXVzICsgYXJjLnJhZGl1cyAqIE1hdGguY29zKGFyYy50aGV0YSl9cHhgOyAgLy8gVE9ETyBwZXJmIGhlcmVcbiAgICBub2RlLnN0eWxlLnRvcCA9IGAtJHthcmMucmFkaXVzIC0gYXJjLnJhZGl1cyAqIE1hdGguc2luKGFyYy50aGV0YSl9cHhgOyAgIC8vIFRPRE8gcGVyZiBoZXJlXG5cbiAgICBub2RlLnN0eWxlLmJvcmRlclJhZGl1cyA9IGAke2FyYy5yYWRpdXN9cHhgO1xufVxuXG5mdW5jdGlvbiByZXBhaW50VmlzaW9uR3JpZChub2RlcywgYXJjLCBncmlkcykge1xuICAgIGlmIChub2RlcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBncmlkcy52aXNpb24uZm9yRWFjaCgoeyB4LCB5LCB0b3VjaCB9LCBpKSA9PiB7XG4gICAgICAgIG5vZGVzW2ldLnN0eWxlLmxlZnQgPSBgJHt4fXB4YDtcbiAgICAgICAgbm9kZXNbaV0uc3R5bGUudG9wID0gYCR7eX1weGA7XG5cbiAgICAgICAgbm9kZXNbaV0uc3R5bGUuYm9yZGVyID0gKHRvdWNoID8gJzJweCBzb2xpZCByZWQnIDogJzAnKTtcbiAgICB9KTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgUGFydGljbGU7XG5cblxuXG4vLyBXRUJQQUNLIEZPT1RFUiAvL1xuLy8ganMvcGFydGljbGUuanMiXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBO0FBQ0E7OztBQUFBO0FBQ0E7QUFBQTtBQUNBOzs7OztBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQ0E7QUFBQTtBQUFBO0FBS0E7QUFBQTtBQUVBO0FBRkE7QUFBQTtBQUlBO0FBQUE7QUFBQTtBQVhBO0FBQ0E7QUFhQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBVEE7QUFEQTtBQUNBO0FBYUE7QUFDQTtBQUNBO0FBQ0E7QUFGQTtBQURBO0FBQ0E7QUFNQTtBQUNBO0FBREE7QUFDQTtBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBTEE7QUFEQTtBQUNBO0FBU0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBZEE7QUFBQTtBQUFBO0FBQ0E7QUFnQkE7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFGQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBUkE7QUFDQTtBQVVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlUm9vdCI6IiJ9"); +eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _rxjs = __webpack_require__(/*! rxjs */ 13);\n\nvar _rxjs2 = _interopRequireDefault(_rxjs);\n\nvar _enums = __webpack_require__(/*! ./enums */ 15);\n\nvar _arc = __webpack_require__(/*! ./arc */ 360);\n\nvar _arc2 = _interopRequireDefault(_arc);\n\nvar _random = __webpack_require__(/*! ./random */ 361);\n\nvar _random2 = _interopRequireDefault(_random);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\n// ===== Constructor =====\n\nfunction Particle(parent, bounds, config, globalGrid) {\n Object.defineProperty(this, 'config', {\n value: Object.assign({}, {\n behavior: _enums.BEHAVIOR.COHESION,\n bounds: bounds,\n color: _random2.default.color(),\n gridSize: 5,\n randomize: true,\n showMovementCircle: false,\n showVisionGrid: false,\n speed: 4,\n visionRadius: 50\n }, config)\n });\n\n Object.defineProperty(this, 'grids', {\n value: {\n global: globalGrid || {},\n vision: createVisionGrid(this.config)\n }\n });\n\n Object.defineProperty(this, 'id', {\n value: _random2.default.id(6)\n });\n\n Object.defineProperty(this, 'nodes', {\n value: {\n body: createBodyNode(this.config),\n circle: undefined,\n container: createContainerNode(this.config, this.id),\n parent: parent,\n visionGrid: undefined\n }\n });\n\n // TODO encapsulate better\n this.isLeader = false;\n this.leader = null;\n\n this.nodes.container.appendChild(this.nodes.body);\n parent.appendChild(this.nodes.container);\n\n this.arc = _arc2.default.create(bounds, this.grids);\n this.updateConfig(this.config);\n this.nextFrame(globalGrid);\n};\n\n// ===== PROTOTYPE =====\n\nParticle.prototype.remove = function () {\n this.nodes.parent.removeChild(this.nodes.container);\n return this;\n};\n\nParticle.prototype.nextFrame = function (globalGrid) {\n var _this = this;\n\n // Randomly change radius and rotation direction.\n if (this.arc.length <= 0 && this.config.randomize) {\n this.arc = _arc2.default.randomize(this.arc);\n }\n\n this.arc = _arc2.default.step(this.arc, this.config);\n\n if (this.leader !== null) {\n this.arc = _arc2.default.follow(this.arc, this.leader.arc);\n }\n\n this.grids.global = globalGrid;\n this.grids.vision = updateVisionGrid(this.arc, this.config, this.grids);\n\n var _look = look(this.arc, this.grids),\n hazards = _look.hazards,\n particles = _look.particles;\n\n if (this.leader === null && particles.length > 0) {\n var candidates = particles.filter(function (v) {\n return v.leader ? v.leader.id !== _this.id : true;\n });\n\n var leader = candidates.find(function (v) {\n return v.isLeader;\n }) || candidates[0];\n\n if (leader !== undefined) {\n leader.isLeader = true;\n\n // console.log(`${this.id} is now following ${leader.id}`);\n\n this.isLeader = false;\n this.leader = leader;\n }\n }\n\n this.updateLeader();\n\n // if (hazards.length) {\n // this.arc = evade(this.arc, this.grids.vision);\n // }\n\n repaintContainer(this.nodes.container, this.arc);\n repaintBody(this.nodes.body, this.arc, this.isLeader);\n repaintCircle(this.nodes.circle, this.arc);\n repaintVisionGrid(this.nodes.visionGrid, this.arc, this.grids);\n};\n\nParticle.prototype.updateConfig = function (config) {\n Object.assign(this.config, config);\n\n var _config = this.config,\n showMovementCircle = _config.showMovementCircle,\n showVisionGrid = _config.showVisionGrid;\n\n\n if (showMovementCircle === true && this.nodes.circle === undefined) {\n this.nodes.circle = createCircleNode(config);\n this.nodes.container.appendChild(this.nodes.circle);\n }\n\n if (showMovementCircle === false && this.nodes.circle !== undefined) {\n this.nodes.container.removeChild(this.nodes.circle);\n delete this.nodes.circle;\n }\n\n if (showVisionGrid === true && this.nodes.visionGrid === undefined) {\n this.nodes.visionGrid = createVisionGridNodes(this.config, this.grids, this.nodes);\n }\n\n if (showVisionGrid === false && this.nodes.visionGrid !== undefined) {\n delete this.nodex.visionGrid;\n }\n};\n\nParticle.prototype.updateLeader = function () {\n if (this.leader === null) {\n return;\n }\n\n while (this.leader.leader !== null) {\n this.leader.isLeader = false;\n this.leader = this.leader.leader;\n // console.error(this.id, 'is now following', this.leader.id)\n }\n\n // Prevents circular leadership, where a leader sees its tail.\n if (this.leader.id === this.id) {\n this.leader = null;\n }\n};\n\nfunction look(arc, grids) {\n var global = grids.global,\n vision = grids.vision;\n\n\n return vision.reduce(function (acc, point) {\n var x = arc.endX + point.x;\n var y = arc.endY + point.y;\n var p = global.getPoint({ x: x, y: y, type: _enums.ENTITIES.PARTICLE });\n\n if (p) {\n acc.particles.push(p);\n }\n\n // if (global.getPoint({ x, y, type: ENTITIES.HAZARD })) {\n // acc.hazards.push({ x, y });\n // }\n\n return acc;\n }, { hazards: [], particles: [] });\n}\n\n// ===== DOM CREATION =====\n\nfunction createBodyNode(config) {\n var node = document.createElement('div');\n node.className = 'particle-body';\n node.style.backgroundColor = config.color;\n return node;\n}\n\nfunction createCircleNode(config) {\n if (config.showMovementCircle === false) {\n return undefined;\n }\n\n var node = document.createElement('div');\n node.className = 'particle-movement-circle';\n node.style.borderColor = config.color;\n return node;\n}\n\nfunction createContainerNode(config, id) {\n var node = document.createElement('div');\n node.className = 'particle-container';\n node.id = id;\n return node;\n}\n\nfunction createVisionGrid(config) {\n var side = config.gridSize,\n radius = config.visionRadius;\n\n var r0 = radius;\n var r1 = 30;\n\n var points = [];\n\n for (var x = -radius; x <= radius; x += side) {\n for (var y = -radius; y <= radius; y += side) {\n // Omit large slices of unused circle\n if (x > y || x < -y) {\n continue;\n }\n\n // Include vision band\n var r = Math.pow(Math.pow(x, 2) + Math.pow(y, 2), 0.5);\n if (r > r0 || r < r1) {\n continue;\n }\n\n var alpha = Math.atan(y / x);\n if (x < 0) {\n alpha += _enums.RAD.t180;\n }\n\n points.push({ x: x, y: y, r: r, alpha: alpha, touch: false });\n }\n }\n\n return points;\n}\n\nfunction createVisionGridNodes(config, grids, nodes) {\n if (config.showVisionGrid === false) {\n return undefined;\n }\n\n return grids.vision.reduce(function (acc, _ref) {\n var x = _ref.x,\n y = _ref.y;\n\n var div = document.createElement('div');\n div.className = 'particle-vision-dot';\n div.style.backgroundColor = config.color;\n nodes.container.appendChild(div);\n\n acc.push(div);\n\n return acc;\n }, []);\n}\n\nfunction updateVisionGrid(arc, config, grids) {\n var global = grids.global,\n vision = grids.vision;\n\n\n return vision.reduce(function (acc, point) {\n var rad = arc.clockwise ? point.alpha - arc.theta : point.alpha - arc.theta + _enums.RAD.t180;\n\n point.x = point.r * Math.cos(rad);\n point.y = point.r * Math.sin(rad);\n\n return acc.concat(point);\n }, []);\n}\n\n// ===== DOM RENDERING =====\nfunction repaintContainer(node, arc) {\n node.style.left = arc.endX + 'px';\n node.style.top = arc.endY + 'px';\n}\n\nfunction repaintBody(node, arc, isLeader) {\n var rad = arc.clockwise ? _enums.RAD.t180 - arc.theta : _enums.RAD.t360 - arc.theta;\n\n node.style.transform = 'rotate(' + (rad + _enums.RAD.t45) + 'rad)';\n\n isLeader ? node.style.outline = '1px solid red' : node.style.outline = '';\n}\n\nfunction repaintCircle(node, arc) {\n if (node === undefined) {\n return;\n }\n\n node.style.width = 2 * arc.radius + 'px';\n node.style.height = 2 * arc.radius + 'px';\n\n node.style.left = '-' + (arc.radius + arc.radius * Math.cos(arc.theta)) + 'px'; // TODO perf here\n node.style.top = '-' + (arc.radius - arc.radius * Math.sin(arc.theta)) + 'px'; // TODO perf here\n\n node.style.borderRadius = arc.radius + 'px';\n}\n\nfunction repaintVisionGrid(nodes, arc, grids) {\n if (nodes === undefined) {\n return;\n }\n\n grids.vision.forEach(function (_ref2, i) {\n var x = _ref2.x,\n y = _ref2.y,\n touch = _ref2.touch;\n\n nodes[i].style.left = x + 'px';\n nodes[i].style.top = y + 'px';\n\n nodes[i].style.border = touch ? '2px solid red' : '0';\n });\n}\n\nexports.default = Particle;//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMTkuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vanMvcGFydGljbGUuanM/M2JkZSJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUngsIHsgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgQkVIQVZJT1IsIEVOVElUSUVTLCBSQUQgfSBmcm9tICcuL2VudW1zJztcbmltcG9ydCBBcmMgZnJvbSAnLi9hcmMnO1xuaW1wb3J0IFJhbmRvbSBmcm9tICcuL3JhbmRvbSc7XG5cbi8vID09PT09IENvbnN0cnVjdG9yID09PT09XG5cbmZ1bmN0aW9uIFBhcnRpY2xlKHBhcmVudCwgYm91bmRzLCBjb25maWcsIGdsb2JhbEdyaWQpIHtcbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ2NvbmZpZycsIHtcbiAgICAgICAgdmFsdWU6IE9iamVjdC5hc3NpZ24oe30sIHtcbiAgICAgICAgICAgIGJlaGF2aW9yOiBCRUhBVklPUi5DT0hFU0lPTixcbiAgICAgICAgICAgIGJvdW5kcyxcbiAgICAgICAgICAgIGNvbG9yOiBSYW5kb20uY29sb3IoKSxcbiAgICAgICAgICAgIGdyaWRTaXplOiA1LFxuICAgICAgICAgICAgcmFuZG9taXplOiB0cnVlLFxuICAgICAgICAgICAgc2hvd01vdmVtZW50Q2lyY2xlOiBmYWxzZSxcbiAgICAgICAgICAgIHNob3dWaXNpb25HcmlkOiBmYWxzZSxcbiAgICAgICAgICAgIHNwZWVkOiA0LFxuICAgICAgICAgICAgdmlzaW9uUmFkaXVzOiA1MFxuICAgICAgICB9LCBjb25maWcpXG4gICAgfSk7XG5cbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ2dyaWRzJywge1xuICAgICAgICB2YWx1ZToge1xuICAgICAgICAgICAgZ2xvYmFsOiBnbG9iYWxHcmlkIHx8IHt9LFxuICAgICAgICAgICAgdmlzaW9uOiBjcmVhdGVWaXNpb25HcmlkKHRoaXMuY29uZmlnKVxuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ2lkJywge1xuICAgICAgICB2YWx1ZTogUmFuZG9tLmlkKDYpXG4gICAgfSk7XG5cbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgJ25vZGVzJywge1xuICAgICAgICB2YWx1ZToge1xuICAgICAgICAgICAgYm9keTogY3JlYXRlQm9keU5vZGUodGhpcy5jb25maWcpLFxuICAgICAgICAgICAgY2lyY2xlOiB1bmRlZmluZWQsXG4gICAgICAgICAgICBjb250YWluZXI6IGNyZWF0ZUNvbnRhaW5lck5vZGUodGhpcy5jb25maWcsIHRoaXMuaWQpLFxuICAgICAgICAgICAgcGFyZW50LFxuICAgICAgICAgICAgdmlzaW9uR3JpZDogdW5kZWZpbmVkLFxuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICAvLyBUT0RPIGVuY2Fwc3VsYXRlIGJldHRlclxuICAgIHRoaXMuaXNMZWFkZXIgPSBmYWxzZTtcbiAgICB0aGlzLmxlYWRlciA9IG51bGw7XG5cbiAgICB0aGlzLm5vZGVzLmNvbnRhaW5lci5hcHBlbmRDaGlsZCh0aGlzLm5vZGVzLmJvZHkpO1xuICAgIHBhcmVudC5hcHBlbmRDaGlsZCh0aGlzLm5vZGVzLmNvbnRhaW5lcik7XG5cbiAgICB0aGlzLmFyYyA9IEFyYy5jcmVhdGUoYm91bmRzLCB0aGlzLmdyaWRzKTtcbiAgICB0aGlzLnVwZGF0ZUNvbmZpZyh0aGlzLmNvbmZpZyk7XG4gICAgdGhpcy5uZXh0RnJhbWUoZ2xvYmFsR3JpZCk7XG59O1xuXG4vLyA9PT09PSBQUk9UT1RZUEUgPT09PT1cblxuUGFydGljbGUucHJvdG90eXBlLnJlbW92ZSA9IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMubm9kZXMucGFyZW50LnJlbW92ZUNoaWxkKHRoaXMubm9kZXMuY29udGFpbmVyKTtcbiAgICByZXR1cm4gdGhpcztcbn1cblxuUGFydGljbGUucHJvdG90eXBlLm5leHRGcmFtZSA9IGZ1bmN0aW9uKGdsb2JhbEdyaWQpIHtcbiAgICAvLyBSYW5kb21seSBjaGFuZ2UgcmFkaXVzIGFuZCByb3RhdGlvbiBkaXJlY3Rpb24uXG4gICAgaWYgKHRoaXMuYXJjLmxlbmd0aCA8PSAwICYmIHRoaXMuY29uZmlnLnJhbmRvbWl6ZSkge1xuICAgICAgICB0aGlzLmFyYyA9IEFyYy5yYW5kb21pemUodGhpcy5hcmMpO1xuICAgIH1cblxuICAgIHRoaXMuYXJjID0gQXJjLnN0ZXAodGhpcy5hcmMsIHRoaXMuY29uZmlnKTtcblxuICAgIGlmICh0aGlzLmxlYWRlciAhPT0gbnVsbCkge1xuICAgICAgICB0aGlzLmFyYyA9IEFyYy5mb2xsb3codGhpcy5hcmMsIHRoaXMubGVhZGVyLmFyYyk7XG4gICAgfVxuXG4gICAgdGhpcy5ncmlkcy5nbG9iYWwgPSBnbG9iYWxHcmlkO1xuICAgIHRoaXMuZ3JpZHMudmlzaW9uID0gdXBkYXRlVmlzaW9uR3JpZCh0aGlzLmFyYywgdGhpcy5jb25maWcsIHRoaXMuZ3JpZHMpO1xuXG4gICAgY29uc3QgeyBoYXphcmRzLCBwYXJ0aWNsZXMgfSA9IGxvb2sodGhpcy5hcmMsIHRoaXMuZ3JpZHMpO1xuXG4gICAgaWYgKHRoaXMubGVhZGVyID09PSBudWxsICYmIHBhcnRpY2xlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgIGNvbnN0IGNhbmRpZGF0ZXMgPSBwYXJ0aWNsZXNcbiAgICAgICAgICAgIC5maWx0ZXIodiA9PiB2LmxlYWRlciA/ICh2LmxlYWRlci5pZCAhPT0gdGhpcy5pZCkgOiB0cnVlKTtcblxuICAgICAgICBjb25zdCBsZWFkZXIgPSBjYW5kaWRhdGVzLmZpbmQodiA9PiB2LmlzTGVhZGVyKSB8fCBjYW5kaWRhdGVzWzBdO1xuXG4gICAgICAgIGlmIChsZWFkZXIgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgbGVhZGVyLmlzTGVhZGVyID0gdHJ1ZTtcblxuICAgICAgICAgICAgLy8gY29uc29sZS5sb2coYCR7dGhpcy5pZH0gaXMgbm93IGZvbGxvd2luZyAke2xlYWRlci5pZH1gKTtcblxuICAgICAgICAgICAgdGhpcy5pc0xlYWRlciA9IGZhbHNlO1xuICAgICAgICAgICAgdGhpcy5sZWFkZXIgPSBsZWFkZXI7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLnVwZGF0ZUxlYWRlcigpO1xuXG4gICAgLy8gaWYgKGhhemFyZHMubGVuZ3RoKSB7XG4gICAgICAgIC8vIHRoaXMuYXJjID0gZXZhZGUodGhpcy5hcmMsIHRoaXMuZ3JpZHMudmlzaW9uKTtcbiAgICAvLyB9XG5cbiAgICByZXBhaW50Q29udGFpbmVyKHRoaXMubm9kZXMuY29udGFpbmVyLCB0aGlzLmFyYyk7XG4gICAgcmVwYWludEJvZHkodGhpcy5ub2Rlcy5ib2R5LCB0aGlzLmFyYywgdGhpcy5pc0xlYWRlcik7XG4gICAgcmVwYWludENpcmNsZSh0aGlzLm5vZGVzLmNpcmNsZSwgdGhpcy5hcmMpO1xuICAgIHJlcGFpbnRWaXNpb25HcmlkKHRoaXMubm9kZXMudmlzaW9uR3JpZCwgdGhpcy5hcmMsIHRoaXMuZ3JpZHMpO1xufVxuXG5QYXJ0aWNsZS5wcm90b3R5cGUudXBkYXRlQ29uZmlnID0gZnVuY3Rpb24oY29uZmlnKSB7XG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLmNvbmZpZywgY29uZmlnKTtcblxuICAgIGNvbnN0IHsgc2hvd01vdmVtZW50Q2lyY2xlLCBzaG93VmlzaW9uR3JpZCB9ID0gdGhpcy5jb25maWc7XG5cbiAgICBpZiAoc2hvd01vdmVtZW50Q2lyY2xlID09PSB0cnVlICYmIHRoaXMubm9kZXMuY2lyY2xlID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgdGhpcy5ub2Rlcy5jaXJjbGUgPSBjcmVhdGVDaXJjbGVOb2RlKGNvbmZpZyk7XG4gICAgICAgIHRoaXMubm9kZXMuY29udGFpbmVyLmFwcGVuZENoaWxkKHRoaXMubm9kZXMuY2lyY2xlKTtcbiAgICB9XG5cbiAgICBpZiAoc2hvd01vdmVtZW50Q2lyY2xlID09PSBmYWxzZSAmJiB0aGlzLm5vZGVzLmNpcmNsZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRoaXMubm9kZXMuY29udGFpbmVyLnJlbW92ZUNoaWxkKHRoaXMubm9kZXMuY2lyY2xlKTtcbiAgICAgICAgZGVsZXRlIHRoaXMubm9kZXMuY2lyY2xlO1xuICAgIH1cblxuICAgIGlmIChzaG93VmlzaW9uR3JpZCA9PT0gdHJ1ZSAmJiB0aGlzLm5vZGVzLnZpc2lvbkdyaWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aGlzLm5vZGVzLnZpc2lvbkdyaWQgPSBjcmVhdGVWaXNpb25HcmlkTm9kZXModGhpcy5jb25maWcsIHRoaXMuZ3JpZHMsIHRoaXMubm9kZXMpO1xuICAgIH1cblxuICAgIGlmIChzaG93VmlzaW9uR3JpZCA9PT0gZmFsc2UgJiYgdGhpcy5ub2Rlcy52aXNpb25HcmlkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgZGVsZXRlIHRoaXMubm9kZXgudmlzaW9uR3JpZDtcbiAgICB9XG59XG5cblBhcnRpY2xlLnByb3RvdHlwZS51cGRhdGVMZWFkZXIgPSBmdW5jdGlvbigpIHtcbiAgICBpZiAodGhpcy5sZWFkZXIgPT09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHdoaWxlICh0aGlzLmxlYWRlci5sZWFkZXIgIT09IG51bGwpIHtcbiAgICAgICAgdGhpcy5sZWFkZXIuaXNMZWFkZXIgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5sZWFkZXIgPSB0aGlzLmxlYWRlci5sZWFkZXI7XG4gICAgICAgIC8vIGNvbnNvbGUuZXJyb3IodGhpcy5pZCwgJ2lzIG5vdyBmb2xsb3dpbmcnLCB0aGlzLmxlYWRlci5pZClcbiAgICB9XG5cbiAgICAvLyBQcmV2ZW50cyBjaXJjdWxhciBsZWFkZXJzaGlwLCB3aGVyZSBhIGxlYWRlciBzZWVzIGl0cyB0YWlsLlxuICAgIGlmICh0aGlzLmxlYWRlci5pZCA9PT0gdGhpcy5pZCkge1xuICAgICAgICB0aGlzLmxlYWRlciA9IG51bGw7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBsb29rKGFyYywgZ3JpZHMpIHtcbiAgICBjb25zdCB7IGdsb2JhbCwgdmlzaW9uIH0gPSBncmlkcztcblxuICAgIHJldHVybiB2aXNpb24ucmVkdWNlKChhY2MsIHBvaW50KSA9PiB7XG4gICAgICAgIGNvbnN0IHggPSBhcmMuZW5kWCArIHBvaW50Lng7XG4gICAgICAgIGNvbnN0IHkgPSBhcmMuZW5kWSArIHBvaW50Lnk7XG4gICAgICAgIGNvbnN0IHAgPSBnbG9iYWwuZ2V0UG9pbnQoeyB4LCB5LCB0eXBlOiBFTlRJVElFUy5QQVJUSUNMRSB9KTtcblxuICAgICAgICBpZiAocCkge1xuICAgICAgICAgICAgYWNjLnBhcnRpY2xlcy5wdXNoKHApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gaWYgKGdsb2JhbC5nZXRQb2ludCh7IHgsIHksIHR5cGU6IEVOVElUSUVTLkhBWkFSRCB9KSkge1xuICAgICAgICAvLyAgICAgYWNjLmhhemFyZHMucHVzaCh7IHgsIHkgfSk7XG4gICAgICAgIC8vIH1cblxuICAgICAgICByZXR1cm4gYWNjO1xuICAgIH0sIHsgaGF6YXJkczogW10sIHBhcnRpY2xlczogW10gfSk7XG59XG5cbi8vID09PT09IERPTSBDUkVBVElPTiA9PT09PVxuXG5mdW5jdGlvbiBjcmVhdGVCb2R5Tm9kZShjb25maWcpIHtcbiAgICBjb25zdCBub2RlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgbm9kZS5jbGFzc05hbWUgPSAncGFydGljbGUtYm9keSc7XG4gICAgbm9kZS5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSBjb25maWcuY29sb3I7XG4gICAgcmV0dXJuIG5vZGU7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZUNpcmNsZU5vZGUoY29uZmlnKSB7XG4gICAgaWYgKGNvbmZpZy5zaG93TW92ZW1lbnRDaXJjbGUgPT09IGZhbHNlKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgY29uc3Qgbm9kZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgIG5vZGUuY2xhc3NOYW1lID0gJ3BhcnRpY2xlLW1vdmVtZW50LWNpcmNsZSc7XG4gICAgbm9kZS5zdHlsZS5ib3JkZXJDb2xvciA9IGNvbmZpZy5jb2xvcjtcbiAgICByZXR1cm4gbm9kZTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlQ29udGFpbmVyTm9kZShjb25maWcsIGlkKSB7XG4gICAgY29uc3Qgbm9kZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgIG5vZGUuY2xhc3NOYW1lID0gJ3BhcnRpY2xlLWNvbnRhaW5lcic7XG4gICAgbm9kZS5pZCA9IGlkO1xuICAgIHJldHVybiBub2RlO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVWaXNpb25HcmlkKGNvbmZpZykge1xuICAgIGNvbnN0IHsgZ3JpZFNpemU6IHNpZGUsIHZpc2lvblJhZGl1czogcmFkaXVzIH0gPSBjb25maWc7XG4gICAgY29uc3QgcjAgPSByYWRpdXM7XG4gICAgY29uc3QgcjEgPSAzMDtcblxuICAgIGNvbnN0IHBvaW50cyA9IFtdO1xuXG4gICAgZm9yIChsZXQgeCA9IC1yYWRpdXM7IHggPD0gcmFkaXVzOyB4ICs9IHNpZGUpIHtcbiAgICAgICAgZm9yIChsZXQgeSA9IC1yYWRpdXM7IHkgPD0gcmFkaXVzOyB5ICs9IHNpZGUpIHtcbiAgICAgICAgICAgIC8vIE9taXQgbGFyZ2Ugc2xpY2VzIG9mIHVudXNlZCBjaXJjbGVcbiAgICAgICAgICAgIGlmICh4ID4geSB8fCB4IDwgLXkpIHtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gSW5jbHVkZSB2aXNpb24gYmFuZFxuICAgICAgICAgICAgY29uc3QgciA9IE1hdGgucG93KE1hdGgucG93KHgsIDIpICsgTWF0aC5wb3coeSwgMiksIDAuNSk7XG4gICAgICAgICAgICBpZiAociA+IHIwIHx8IHIgPCByMSkge1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBsZXQgYWxwaGEgPSBNYXRoLmF0YW4oeSAvIHgpO1xuICAgICAgICAgICAgaWYgKHggPCAwKSB7XG4gICAgICAgICAgICAgICAgYWxwaGEgKz0gUkFELnQxODA7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHBvaW50cy5wdXNoKHsgeCwgeSwgciwgYWxwaGEsIHRvdWNoOiBmYWxzZSB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBwb2ludHM7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZVZpc2lvbkdyaWROb2Rlcyhjb25maWcsIGdyaWRzLCBub2Rlcykge1xuICAgIGlmIChjb25maWcuc2hvd1Zpc2lvbkdyaWQgPT09IGZhbHNlKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIGdyaWRzLnZpc2lvbi5yZWR1Y2UoKGFjYywgeyB4LCB5IH0pID0+IHtcbiAgICAgICAgY29uc3QgZGl2ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgICAgIGRpdi5jbGFzc05hbWUgPSAncGFydGljbGUtdmlzaW9uLWRvdCc7XG4gICAgICAgIGRpdi5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSBjb25maWcuY29sb3I7XG4gICAgICAgIG5vZGVzLmNvbnRhaW5lci5hcHBlbmRDaGlsZChkaXYpO1xuXG4gICAgICAgIGFjYy5wdXNoKGRpdik7XG5cbiAgICAgICAgcmV0dXJuIGFjYztcbiAgICB9LCBbXSk7XG59XG5cblxuZnVuY3Rpb24gdXBkYXRlVmlzaW9uR3JpZChhcmMsIGNvbmZpZywgZ3JpZHMpIHtcbiAgICBjb25zdCB7IGdsb2JhbCwgdmlzaW9uIH0gPSBncmlkcztcblxuICAgIHJldHVybiB2aXNpb24ucmVkdWNlKChhY2MsIHBvaW50KSA9PiB7XG4gICAgICAgIGNvbnN0IHJhZCA9IGFyYy5jbG9ja3dpc2VcbiAgICAgICAgICAgID8gcG9pbnQuYWxwaGEgLSBhcmMudGhldGFcbiAgICAgICAgICAgIDogcG9pbnQuYWxwaGEgLSBhcmMudGhldGEgKyBSQUQudDE4MDtcblxuICAgICAgICBwb2ludC54ID0gcG9pbnQuciAqIE1hdGguY29zKHJhZCk7XG4gICAgICAgIHBvaW50LnkgPSBwb2ludC5yICogTWF0aC5zaW4ocmFkKTtcblxuICAgICAgICByZXR1cm4gYWNjLmNvbmNhdChwb2ludCk7XG4gICAgfSwgW10pO1xufVxuXG4vLyA9PT09PSBET00gUkVOREVSSU5HID09PT09XG5mdW5jdGlvbiByZXBhaW50Q29udGFpbmVyKG5vZGUsIGFyYykge1xuICAgIG5vZGUuc3R5bGUubGVmdCA9IGAke2FyYy5lbmRYfXB4YDtcbiAgICBub2RlLnN0eWxlLnRvcCA9IGAke2FyYy5lbmRZfXB4YDtcbn1cblxuZnVuY3Rpb24gcmVwYWludEJvZHkobm9kZSwgYXJjLCBpc0xlYWRlcikge1xuICAgIGNvbnN0IHJhZCA9IGFyYy5jbG9ja3dpc2VcbiAgICAgICAgPyBSQUQudDE4MCAtIGFyYy50aGV0YVxuICAgICAgICA6IFJBRC50MzYwIC0gYXJjLnRoZXRhO1xuXG4gICAgbm9kZS5zdHlsZS50cmFuc2Zvcm0gPSBgcm90YXRlKCR7cmFkICsgUkFELnQ0NX1yYWQpYDtcblxuICAgIGlzTGVhZGVyID8gbm9kZS5zdHlsZS5vdXRsaW5lID0gJzFweCBzb2xpZCByZWQnIDogbm9kZS5zdHlsZS5vdXRsaW5lID0gJyc7XG59XG5cbmZ1bmN0aW9uIHJlcGFpbnRDaXJjbGUobm9kZSwgYXJjKSB7XG4gICAgaWYgKG5vZGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbm9kZS5zdHlsZS53aWR0aCA9IGAkezIgKiBhcmMucmFkaXVzfXB4YDtcbiAgICBub2RlLnN0eWxlLmhlaWdodCA9IGAkezIgKiBhcmMucmFkaXVzfXB4YDtcblxuICAgIG5vZGUuc3R5bGUubGVmdCA9IGAtJHthcmMucmFkaXVzICsgYXJjLnJhZGl1cyAqIE1hdGguY29zKGFyYy50aGV0YSl9cHhgOyAgLy8gVE9ETyBwZXJmIGhlcmVcbiAgICBub2RlLnN0eWxlLnRvcCA9IGAtJHthcmMucmFkaXVzIC0gYXJjLnJhZGl1cyAqIE1hdGguc2luKGFyYy50aGV0YSl9cHhgOyAgIC8vIFRPRE8gcGVyZiBoZXJlXG5cbiAgICBub2RlLnN0eWxlLmJvcmRlclJhZGl1cyA9IGAke2FyYy5yYWRpdXN9cHhgO1xufVxuXG5mdW5jdGlvbiByZXBhaW50VmlzaW9uR3JpZChub2RlcywgYXJjLCBncmlkcykge1xuICAgIGlmIChub2RlcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBncmlkcy52aXNpb24uZm9yRWFjaCgoeyB4LCB5LCB0b3VjaCB9LCBpKSA9PiB7XG4gICAgICAgIG5vZGVzW2ldLnN0eWxlLmxlZnQgPSBgJHt4fXB4YDtcbiAgICAgICAgbm9kZXNbaV0uc3R5bGUudG9wID0gYCR7eX1weGA7XG5cbiAgICAgICAgbm9kZXNbaV0uc3R5bGUuYm9yZGVyID0gKHRvdWNoID8gJzJweCBzb2xpZCByZWQnIDogJzAnKTtcbiAgICB9KTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgUGFydGljbGU7XG5cblxuXG4vLyBXRUJQQUNLIEZPT1RFUiAvL1xuLy8ganMvcGFydGljbGUuanMiXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBO0FBQ0E7OztBQUFBO0FBQ0E7QUFBQTtBQUNBOzs7QUFBQTtBQUNBOzs7OztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFUQTtBQURBO0FBQ0E7QUFhQTtBQUNBO0FBQ0E7QUFDQTtBQUZBO0FBREE7QUFDQTtBQU1BO0FBQ0E7QUFEQTtBQUNBO0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFMQTtBQURBO0FBQ0E7QUFTQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFkQTtBQUFBO0FBQUE7QUFDQTtBQWdCQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUZBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwic291cmNlUm9vdCI6IiJ9"); /***/ }), /* 20 */ @@ -954,7 +943,7 @@ eval("var g;\r\n\r\n// This works in non-strict mode\r\ng = (function() {\r\n\tr /***/ (function(module, exports, __webpack_require__) { "use strict"; -eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _rxjs = __webpack_require__(/*! rxjs */ 13);\n\nvar _rxjs2 = _interopRequireDefault(_rxjs);\n\nvar _grid = __webpack_require__(/*! ./grid */ 359);\n\nvar _grid2 = _interopRequireDefault(_grid);\n\nvar _particle = __webpack_require__(/*! ./particle */ 19);\n\nvar _particle2 = _interopRequireDefault(_particle);\n\nvar _store = __webpack_require__(/*! ./store */ 17);\n\nvar _store2 = _interopRequireDefault(_store);\n\nvar _controls = __webpack_require__(/*! ./controls */ 16);\n\nvar _controls2 = _interopRequireDefault(_controls);\n\nvar _enums = __webpack_require__(/*! ./enums */ 15);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction Animation3a() {\n this.options = {\n cohesion: true,\n count: 10,\n maxCount: 1000,\n showVisionGrid: true,\n speed: 4\n };\n\n this.container = document.getElementById('animation3a');\n this.bounds = this.container.getBoundingClientRect();\n\n this.particles = [];\n this.globalGrid = new _grid2.default();\n\n var controls = new _controls2.default(document.getElementById('controls3a'), this.options);\n\n controls.mount().subscribe(this.subscriber.bind(this));\n\n this.updateAnimating(this.options.animating);\n this.updateCount(this.options.count);\n\n // TODO extract Arc\n // TODO get \"top\" leader, once...don't update each time?\n // TODO if leader sees follower, assign to this leader?\n // TODO X dimension modified by core UI, maybe recalc grid in animation start?\n // TODO remove bottom padding from Disqus\n // TODO ANIM2ab randomize hazards\n // TODO fix \"hangup\" small radius evade bug\n\n // TODO ANIM3a perf Scale vision grid to 1000 particles\n // TODO ANIM3a circular leadership\n // TODO hazard grid, particles grid\n // TODO completely seal Particle\n\n // TODO ANIM3a cohesion\n // TODO ANIM3b separation\n // TODO ANIM3c alignment\n};\n\nAnimation3a.prototype.subscriber = function (_ref) {\n var key = _ref.key,\n value = _ref.value;\n\n switch (key) {\n case _enums.CONTROLS.ANIMATING:\n this.updateAnimating(value);break;\n case _enums.CONTROLS.COUNT:\n this.updateCount(value);break;\n case _enums.CONTROLS.SPEED:\n this.updateSpeed(value);break;\n }\n};\n\nAnimation3a.prototype.nextFrame = function () {\n var _this = this;\n\n this.particles.forEach(function (p) {\n var prevX = p.arc.endX;\n var prevY = p.arc.endY;\n\n p.nextFrame(_this.globalGrid);\n\n _this.globalGrid.deletePoint({ x: prevX, y: prevY, type: _enums.ENTITIES.PARTICLE });\n _this.globalGrid.setPoint({ x: p.arc.endX, y: p.arc.endY, type: _enums.ENTITIES.PARTICLE }, p);\n });\n};\n\nAnimation3a.prototype.updateAnimating = function (isAnimating) {\n var _this2 = this;\n\n this.options.animating = isAnimating;\n\n if (isAnimating) {\n var fps$ = _rxjs2.default.Observable.interval(1000 / 32).takeWhile(function (_) {\n return _this2.options.animating;\n });\n\n fps$.subscribe(this.nextFrame.bind(this));\n }\n};\n\nAnimation3a.prototype.updateCount = function (count) {\n while (this.particles.length > count) {\n delete this.particles.pop().remove();\n }\n\n while (this.particles.length < count) {\n var p = new _particle2.default(this.container, this.bounds, this.options, this.globalGrid);\n this.particles.push(p);\n }\n};\n\nAnimation3a.prototype.updateSpeed = function (value) {\n this.options.speed = value;\n this.particles.forEach(function (p) {\n return p.updateConfig({ speed: value });\n });\n};\n\nexports.default = Animation3a;//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNzcuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vanMvYW5pbWF0aW9uM2EuanM/YzA5NyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUngsIHsgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IEdyaWQgZnJvbSAnLi9ncmlkJztcbmltcG9ydCBQYXJ0aWNsZSBmcm9tICcuL3BhcnRpY2xlJztcbmltcG9ydCBTdG9yZSBmcm9tICcuL3N0b3JlJztcbmltcG9ydCBDb250cm9scyBmcm9tICcuL2NvbnRyb2xzJztcbmltcG9ydCB7IENPTlRST0xTLCBFTlRJVElFUyB9IGZyb20gJy4vZW51bXMnO1xuXG5mdW5jdGlvbiBBbmltYXRpb24zYSgpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSB7XG4gICAgICAgIGNvaGVzaW9uOiB0cnVlLFxuICAgICAgICBjb3VudDogMTAsXG4gICAgICAgIG1heENvdW50OiAxMDAwLFxuICAgICAgICBzaG93VmlzaW9uR3JpZDogdHJ1ZSxcbiAgICAgICAgc3BlZWQ6IDRcbiAgICB9O1xuXG4gICAgdGhpcy5jb250YWluZXIgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYW5pbWF0aW9uM2EnKTtcbiAgICB0aGlzLmJvdW5kcyA9IHRoaXMuY29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXG4gICAgdGhpcy5wYXJ0aWNsZXMgPSBbXTtcbiAgICB0aGlzLmdsb2JhbEdyaWQgPSBuZXcgR3JpZCgpO1xuXG4gICAgY29uc3QgY29udHJvbHMgPSBuZXcgQ29udHJvbHMoXG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdjb250cm9sczNhJyksXG4gICAgICAgIHRoaXMub3B0aW9uc1xuICAgICk7XG5cbiAgICBjb250cm9scy5tb3VudCgpLnN1YnNjcmliZSh0aGlzLnN1YnNjcmliZXIuYmluZCh0aGlzKSk7XG5cbiAgICB0aGlzLnVwZGF0ZUFuaW1hdGluZyh0aGlzLm9wdGlvbnMuYW5pbWF0aW5nKTtcbiAgICB0aGlzLnVwZGF0ZUNvdW50KHRoaXMub3B0aW9ucy5jb3VudCk7XG5cbiAgICAvLyBUT0RPIGV4dHJhY3QgQXJjXG4gICAgLy8gVE9ETyBnZXQgXCJ0b3BcIiBsZWFkZXIsIG9uY2UuLi5kb24ndCB1cGRhdGUgZWFjaCB0aW1lP1xuICAgIC8vIFRPRE8gaWYgbGVhZGVyIHNlZXMgZm9sbG93ZXIsIGFzc2lnbiB0byB0aGlzIGxlYWRlcj9cbiAgICAvLyBUT0RPIFggZGltZW5zaW9uIG1vZGlmaWVkIGJ5IGNvcmUgVUksIG1heWJlIHJlY2FsYyBncmlkIGluIGFuaW1hdGlvbiBzdGFydD9cbiAgICAvLyBUT0RPIHJlbW92ZSBib3R0b20gcGFkZGluZyBmcm9tIERpc3F1c1xuICAgIC8vIFRPRE8gQU5JTTJhYiByYW5kb21pemUgaGF6YXJkc1xuICAgIC8vIFRPRE8gZml4IFwiaGFuZ3VwXCIgc21hbGwgcmFkaXVzIGV2YWRlIGJ1Z1xuXG4gICAgLy8gVE9ETyBBTklNM2EgcGVyZiBTY2FsZSB2aXNpb24gZ3JpZCB0byAxMDAwIHBhcnRpY2xlc1xuICAgIC8vIFRPRE8gQU5JTTNhIGNpcmN1bGFyIGxlYWRlcnNoaXBcbiAgICAvLyBUT0RPIGhhemFyZCBncmlkLCBwYXJ0aWNsZXMgZ3JpZFxuICAgIC8vIFRPRE8gY29tcGxldGVseSBzZWFsIFBhcnRpY2xlXG5cbiAgICAvLyBUT0RPIEFOSU0zYSBjb2hlc2lvblxuICAgIC8vIFRPRE8gQU5JTTNiIHNlcGFyYXRpb25cbiAgICAvLyBUT0RPIEFOSU0zYyBhbGlnbm1lbnRcbn07XG5cbkFuaW1hdGlvbjNhLnByb3RvdHlwZS5zdWJzY3JpYmVyID0gZnVuY3Rpb24oeyBrZXksIHZhbHVlIH0pIHtcbiAgICBzd2l0Y2goa2V5KSB7XG4gICAgICAgIGNhc2UgQ09OVFJPTFMuQU5JTUFUSU5HOiB0aGlzLnVwZGF0ZUFuaW1hdGluZyh2YWx1ZSk7IGJyZWFrO1xuICAgICAgICBjYXNlIENPTlRST0xTLkNPVU5UOiB0aGlzLnVwZGF0ZUNvdW50KHZhbHVlKTsgYnJlYWs7XG4gICAgICAgIGNhc2UgQ09OVFJPTFMuU1BFRUQ6IHRoaXMudXBkYXRlU3BlZWQodmFsdWUpOyBicmVhaztcbiAgICB9XG59XG5cbkFuaW1hdGlvbjNhLnByb3RvdHlwZS5uZXh0RnJhbWUgPSBmdW5jdGlvbigpIHtcbiAgICB0aGlzLnBhcnRpY2xlcy5mb3JFYWNoKHAgPT4ge1xuICAgICAgICBjb25zdCBwcmV2WCA9IHAuYXJjLmVuZFg7XG4gICAgICAgIGNvbnN0IHByZXZZID0gcC5hcmMuZW5kWTtcblxuICAgICAgICBwLm5leHRGcmFtZSh0aGlzLmdsb2JhbEdyaWQpO1xuXG4gICAgICAgIHRoaXMuZ2xvYmFsR3JpZC5kZWxldGVQb2ludCh7IHg6IHByZXZYLCB5OiBwcmV2WSwgdHlwZTogRU5USVRJRVMuUEFSVElDTEUgfSk7XG4gICAgICAgIHRoaXMuZ2xvYmFsR3JpZC5zZXRQb2ludCh7IHg6IHAuYXJjLmVuZFgsIHk6IHAuYXJjLmVuZFksIHR5cGU6IEVOVElUSUVTLlBBUlRJQ0xFIH0sIHApO1xuICAgIH0pO1xufVxuXG5BbmltYXRpb24zYS5wcm90b3R5cGUudXBkYXRlQW5pbWF0aW5nID0gZnVuY3Rpb24oaXNBbmltYXRpbmcpIHtcbiAgICB0aGlzLm9wdGlvbnMuYW5pbWF0aW5nID0gaXNBbmltYXRpbmc7XG5cbiAgICBpZiAoaXNBbmltYXRpbmcpIHtcbiAgICAgICAgY29uc3QgZnBzJCA9IFJ4Lk9ic2VydmFibGUuaW50ZXJ2YWwoMTAwMCAvIDMyKVxuICAgICAgICAgICAgLnRha2VXaGlsZShfID0+IHRoaXMub3B0aW9ucy5hbmltYXRpbmcpO1xuXG4gICAgICAgIGZwcyQuc3Vic2NyaWJlKHRoaXMubmV4dEZyYW1lLmJpbmQodGhpcykpO1xuICAgIH1cbn1cblxuQW5pbWF0aW9uM2EucHJvdG90eXBlLnVwZGF0ZUNvdW50ID0gZnVuY3Rpb24oY291bnQpIHtcbiAgICB3aGlsZSAodGhpcy5wYXJ0aWNsZXMubGVuZ3RoID4gY291bnQpIHtcbiAgICAgICAgZGVsZXRlIHRoaXMucGFydGljbGVzLnBvcCgpLnJlbW92ZSgpO1xuICAgIH1cblxuICAgIHdoaWxlICh0aGlzLnBhcnRpY2xlcy5sZW5ndGggPCBjb3VudCkge1xuICAgICAgICBjb25zdCBwID0gbmV3IFBhcnRpY2xlKHRoaXMuY29udGFpbmVyLCB0aGlzLmJvdW5kcywgdGhpcy5vcHRpb25zLCB0aGlzLmdsb2JhbEdyaWQpO1xuICAgICAgICB0aGlzLnBhcnRpY2xlcy5wdXNoKHApO1xuICAgIH1cbn1cblxuQW5pbWF0aW9uM2EucHJvdG90eXBlLnVwZGF0ZVNwZWVkID0gZnVuY3Rpb24odmFsdWUpIHtcbiAgICB0aGlzLm9wdGlvbnMuc3BlZWQgPSB2YWx1ZTtcbiAgICB0aGlzLnBhcnRpY2xlcy5mb3JFYWNoKHAgPT4gcC51cGRhdGVDb25maWcoeyBzcGVlZDogdmFsdWUgfSkpO1xufVxuXG5leHBvcnQgZGVmYXVsdCBBbmltYXRpb24zYTtcblxuXG5cbi8vIFdFQlBBQ0sgRk9PVEVSIC8vXG4vLyBqcy9hbmltYXRpb24zYS5qcyJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUE7QUFDQTs7O0FBQUE7QUFDQTs7O0FBQUE7QUFDQTs7O0FBQUE7QUFDQTs7O0FBQUE7QUFDQTs7O0FBQUE7QUFDQTs7O0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFMQTtBQUNBO0FBT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQUE7QUFDQTtBQUFBO0FBSEE7QUFLQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQSIsInNvdXJjZVJvb3QiOiIifQ=="); +eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _rxjs = __webpack_require__(/*! rxjs */ 13);\n\nvar _rxjs2 = _interopRequireDefault(_rxjs);\n\nvar _grid = __webpack_require__(/*! ./grid */ 359);\n\nvar _grid2 = _interopRequireDefault(_grid);\n\nvar _particle = __webpack_require__(/*! ./particle */ 19);\n\nvar _particle2 = _interopRequireDefault(_particle);\n\nvar _controls = __webpack_require__(/*! ./controls */ 16);\n\nvar _controls2 = _interopRequireDefault(_controls);\n\nvar _enums = __webpack_require__(/*! ./enums */ 15);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nfunction Animation3a() {\n this.options = {\n cohesion: true,\n count: 10,\n maxCount: 1000,\n showVisionGrid: true,\n speed: 4\n };\n\n this.container = document.getElementById('animation3a');\n this.bounds = this.container.getBoundingClientRect();\n\n this.particles = [];\n this.globalGrid = new _grid2.default();\n\n var controls = new _controls2.default(document.getElementById('controls3a'), this.options);\n\n controls.mount().subscribe(this.subscriber.bind(this));\n\n this.updateAnimating(this.options.animating);\n this.updateCount(this.options.count);\n\n // TODO get \"top\" leader, once...don't update each time?\n // TODO if leader sees follower, assign to this leader?\n // TODO X dimension modified by core UI, maybe recalc grid in animation start?\n // TODO remove bottom padding from Disqus\n // TODO ANIM2ab randomize hazards\n // TODO fix \"hangup\" small radius evade bug\n\n // TODO ANIM3a perf Scale vision grid to 1000 particles\n // TODO ANIM3a circular leadership\n // TODO hazard grid, particles grid\n // TODO completely seal Particle\n\n // TODO ANIM3a cohesion\n // TODO ANIM3b separation\n // TODO ANIM3c alignment\n};\n\nAnimation3a.prototype.subscriber = function (_ref) {\n var key = _ref.key,\n value = _ref.value;\n\n switch (key) {\n case _enums.CONTROLS.ANIMATING:\n this.updateAnimating(value);break;\n case _enums.CONTROLS.COUNT:\n this.updateCount(value);break;\n case _enums.CONTROLS.SPEED:\n this.updateSpeed(value);break;\n }\n};\n\nAnimation3a.prototype.nextFrame = function () {\n var _this = this;\n\n this.particles.forEach(function (p) {\n var prevX = p.arc.endX;\n var prevY = p.arc.endY;\n\n p.nextFrame(_this.globalGrid);\n\n _this.globalGrid.deletePoint({ x: prevX, y: prevY, type: _enums.ENTITIES.PARTICLE });\n _this.globalGrid.setPoint({ x: p.arc.endX, y: p.arc.endY, type: _enums.ENTITIES.PARTICLE }, p);\n });\n};\n\nAnimation3a.prototype.updateAnimating = function (isAnimating) {\n var _this2 = this;\n\n this.options.animating = isAnimating;\n\n if (isAnimating) {\n var fps$ = _rxjs2.default.Observable.interval(1000 / 32).takeWhile(function (_) {\n return _this2.options.animating;\n });\n\n fps$.subscribe(this.nextFrame.bind(this));\n }\n};\n\nAnimation3a.prototype.updateCount = function (count) {\n while (this.particles.length > count) {\n delete this.particles.pop().remove();\n }\n\n while (this.particles.length < count) {\n var p = new _particle2.default(this.container, this.bounds, this.options, this.globalGrid);\n this.particles.push(p);\n }\n};\n\nAnimation3a.prototype.updateSpeed = function (value) {\n this.options.speed = value;\n this.particles.forEach(function (p) {\n return p.updateConfig({ speed: value });\n });\n};\n\nexports.default = Animation3a;//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNzcuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vanMvYW5pbWF0aW9uM2EuanM/YzA5NyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUngsIHsgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IEdyaWQgZnJvbSAnLi9ncmlkJztcbmltcG9ydCBQYXJ0aWNsZSBmcm9tICcuL3BhcnRpY2xlJztcbmltcG9ydCBDb250cm9scyBmcm9tICcuL2NvbnRyb2xzJztcbmltcG9ydCB7IENPTlRST0xTLCBFTlRJVElFUyB9IGZyb20gJy4vZW51bXMnO1xuXG5mdW5jdGlvbiBBbmltYXRpb24zYSgpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSB7XG4gICAgICAgIGNvaGVzaW9uOiB0cnVlLFxuICAgICAgICBjb3VudDogMTAsXG4gICAgICAgIG1heENvdW50OiAxMDAwLFxuICAgICAgICBzaG93VmlzaW9uR3JpZDogdHJ1ZSxcbiAgICAgICAgc3BlZWQ6IDRcbiAgICB9O1xuXG4gICAgdGhpcy5jb250YWluZXIgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYW5pbWF0aW9uM2EnKTtcbiAgICB0aGlzLmJvdW5kcyA9IHRoaXMuY29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXG4gICAgdGhpcy5wYXJ0aWNsZXMgPSBbXTtcbiAgICB0aGlzLmdsb2JhbEdyaWQgPSBuZXcgR3JpZCgpO1xuXG4gICAgY29uc3QgY29udHJvbHMgPSBuZXcgQ29udHJvbHMoXG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdjb250cm9sczNhJyksXG4gICAgICAgIHRoaXMub3B0aW9uc1xuICAgICk7XG5cbiAgICBjb250cm9scy5tb3VudCgpLnN1YnNjcmliZSh0aGlzLnN1YnNjcmliZXIuYmluZCh0aGlzKSk7XG5cbiAgICB0aGlzLnVwZGF0ZUFuaW1hdGluZyh0aGlzLm9wdGlvbnMuYW5pbWF0aW5nKTtcbiAgICB0aGlzLnVwZGF0ZUNvdW50KHRoaXMub3B0aW9ucy5jb3VudCk7XG5cbiAgICAvLyBUT0RPIGdldCBcInRvcFwiIGxlYWRlciwgb25jZS4uLmRvbid0IHVwZGF0ZSBlYWNoIHRpbWU/XG4gICAgLy8gVE9ETyBpZiBsZWFkZXIgc2VlcyBmb2xsb3dlciwgYXNzaWduIHRvIHRoaXMgbGVhZGVyP1xuICAgIC8vIFRPRE8gWCBkaW1lbnNpb24gbW9kaWZpZWQgYnkgY29yZSBVSSwgbWF5YmUgcmVjYWxjIGdyaWQgaW4gYW5pbWF0aW9uIHN0YXJ0P1xuICAgIC8vIFRPRE8gcmVtb3ZlIGJvdHRvbSBwYWRkaW5nIGZyb20gRGlzcXVzXG4gICAgLy8gVE9ETyBBTklNMmFiIHJhbmRvbWl6ZSBoYXphcmRzXG4gICAgLy8gVE9ETyBmaXggXCJoYW5ndXBcIiBzbWFsbCByYWRpdXMgZXZhZGUgYnVnXG5cbiAgICAvLyBUT0RPIEFOSU0zYSBwZXJmIFNjYWxlIHZpc2lvbiBncmlkIHRvIDEwMDAgcGFydGljbGVzXG4gICAgLy8gVE9ETyBBTklNM2EgY2lyY3VsYXIgbGVhZGVyc2hpcFxuICAgIC8vIFRPRE8gaGF6YXJkIGdyaWQsIHBhcnRpY2xlcyBncmlkXG4gICAgLy8gVE9ETyBjb21wbGV0ZWx5IHNlYWwgUGFydGljbGVcblxuICAgIC8vIFRPRE8gQU5JTTNhIGNvaGVzaW9uXG4gICAgLy8gVE9ETyBBTklNM2Igc2VwYXJhdGlvblxuICAgIC8vIFRPRE8gQU5JTTNjIGFsaWdubWVudFxufTtcblxuQW5pbWF0aW9uM2EucHJvdG90eXBlLnN1YnNjcmliZXIgPSBmdW5jdGlvbih7IGtleSwgdmFsdWUgfSkge1xuICAgIHN3aXRjaChrZXkpIHtcbiAgICAgICAgY2FzZSBDT05UUk9MUy5BTklNQVRJTkc6IHRoaXMudXBkYXRlQW5pbWF0aW5nKHZhbHVlKTsgYnJlYWs7XG4gICAgICAgIGNhc2UgQ09OVFJPTFMuQ09VTlQ6IHRoaXMudXBkYXRlQ291bnQodmFsdWUpOyBicmVhaztcbiAgICAgICAgY2FzZSBDT05UUk9MUy5TUEVFRDogdGhpcy51cGRhdGVTcGVlZCh2YWx1ZSk7IGJyZWFrO1xuICAgIH1cbn1cblxuQW5pbWF0aW9uM2EucHJvdG90eXBlLm5leHRGcmFtZSA9IGZ1bmN0aW9uKCkge1xuICAgIHRoaXMucGFydGljbGVzLmZvckVhY2gocCA9PiB7XG4gICAgICAgIGNvbnN0IHByZXZYID0gcC5hcmMuZW5kWDtcbiAgICAgICAgY29uc3QgcHJldlkgPSBwLmFyYy5lbmRZO1xuXG4gICAgICAgIHAubmV4dEZyYW1lKHRoaXMuZ2xvYmFsR3JpZCk7XG5cbiAgICAgICAgdGhpcy5nbG9iYWxHcmlkLmRlbGV0ZVBvaW50KHsgeDogcHJldlgsIHk6IHByZXZZLCB0eXBlOiBFTlRJVElFUy5QQVJUSUNMRSB9KTtcbiAgICAgICAgdGhpcy5nbG9iYWxHcmlkLnNldFBvaW50KHsgeDogcC5hcmMuZW5kWCwgeTogcC5hcmMuZW5kWSwgdHlwZTogRU5USVRJRVMuUEFSVElDTEUgfSwgcCk7XG4gICAgfSk7XG59XG5cbkFuaW1hdGlvbjNhLnByb3RvdHlwZS51cGRhdGVBbmltYXRpbmcgPSBmdW5jdGlvbihpc0FuaW1hdGluZykge1xuICAgIHRoaXMub3B0aW9ucy5hbmltYXRpbmcgPSBpc0FuaW1hdGluZztcblxuICAgIGlmIChpc0FuaW1hdGluZykge1xuICAgICAgICBjb25zdCBmcHMkID0gUnguT2JzZXJ2YWJsZS5pbnRlcnZhbCgxMDAwIC8gMzIpXG4gICAgICAgICAgICAudGFrZVdoaWxlKF8gPT4gdGhpcy5vcHRpb25zLmFuaW1hdGluZyk7XG5cbiAgICAgICAgZnBzJC5zdWJzY3JpYmUodGhpcy5uZXh0RnJhbWUuYmluZCh0aGlzKSk7XG4gICAgfVxufVxuXG5BbmltYXRpb24zYS5wcm90b3R5cGUudXBkYXRlQ291bnQgPSBmdW5jdGlvbihjb3VudCkge1xuICAgIHdoaWxlICh0aGlzLnBhcnRpY2xlcy5sZW5ndGggPiBjb3VudCkge1xuICAgICAgICBkZWxldGUgdGhpcy5wYXJ0aWNsZXMucG9wKCkucmVtb3ZlKCk7XG4gICAgfVxuXG4gICAgd2hpbGUgKHRoaXMucGFydGljbGVzLmxlbmd0aCA8IGNvdW50KSB7XG4gICAgICAgIGNvbnN0IHAgPSBuZXcgUGFydGljbGUodGhpcy5jb250YWluZXIsIHRoaXMuYm91bmRzLCB0aGlzLm9wdGlvbnMsIHRoaXMuZ2xvYmFsR3JpZCk7XG4gICAgICAgIHRoaXMucGFydGljbGVzLnB1c2gocCk7XG4gICAgfVxufVxuXG5BbmltYXRpb24zYS5wcm90b3R5cGUudXBkYXRlU3BlZWQgPSBmdW5jdGlvbih2YWx1ZSkge1xuICAgIHRoaXMub3B0aW9ucy5zcGVlZCA9IHZhbHVlO1xuICAgIHRoaXMucGFydGljbGVzLmZvckVhY2gocCA9PiBwLnVwZGF0ZUNvbmZpZyh7IHNwZWVkOiB2YWx1ZSB9KSk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IEFuaW1hdGlvbjNhO1xuXG5cblxuLy8gV0VCUEFDSyBGT09URVIgLy9cbi8vIGpzL2FuaW1hdGlvbjNhLmpzIl0sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQTtBQUNBOzs7QUFBQTtBQUNBOzs7QUFBQTtBQUNBOzs7QUFBQTtBQUNBOzs7QUFBQTtBQUNBOzs7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUxBO0FBQ0E7QUFPQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQUE7QUFDQTtBQUFBO0FBSEE7QUFLQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFDQSIsInNvdXJjZVJvb3QiOiIifQ=="); /***/ }), /* 78 */ @@ -4332,7 +4321,31 @@ eval("/* WEBPACK VAR INJECTION */(function(global, process) {(function (global, /***/ (function(module, exports, __webpack_require__) { "use strict"; -eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = Grid;\nfunction getKey(_ref) {\n var x = _ref.x,\n y = _ref.y,\n type = _ref.type;\n\n var gridX = x - x % 5;\n var gridY = y - y % 5;\n\n return gridX + \"-\" + gridY;\n}\n\nfunction Grid() {\n this.points = {};\n this.gridSize = 5;\n};\n\nGrid.prototype.setPoint = function (_ref2, detail) {\n var x = _ref2.x,\n y = _ref2.y,\n type = _ref2.type;\n\n this.points[getKey({ x: x, y: y, type: type })] = detail;\n};\n\nGrid.prototype.getPoint = function (_ref3) {\n var x = _ref3.x,\n y = _ref3.y,\n type = _ref3.type;\n\n return this.points[getKey({ x: x, y: y, type: type })];\n};\n\nGrid.prototype.deletePoint = function (_ref4) {\n var x = _ref4.x,\n y = _ref4.y,\n type = _ref4.type;\n\n delete this.points[getKey({ x: x, y: y, type: type })];\n};\n\n// Grid.prototype.setArea = function({ x, y, w, h, type }) {\n// for (let i = x; i <= (x + w); i += this.gridSize) {\n// for (let j = y; j <= (y + h); j += this.gridSize) {\n// this.setPoint({ x: i, y: j, type });\n// }\n// }\n// };//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMzU5LmpzIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vL2pzL2dyaWQuanM/ZTI2YyJdLCJzb3VyY2VzQ29udGVudCI6WyJmdW5jdGlvbiBnZXRLZXkoeyB4LCB5LCB0eXBlIH0pIHtcbiAgICBjb25zdCBncmlkWCA9IHggLSB4ICUgNTtcbiAgICBjb25zdCBncmlkWSA9IHkgLSB5ICUgNTtcblxuICAgIHJldHVybiBgJHtncmlkWH0tJHtncmlkWX1gO1xufVxuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBHcmlkKCkge1xuICAgIHRoaXMucG9pbnRzID0ge307XG4gICAgdGhpcy5ncmlkU2l6ZSA9IDU7XG59O1xuXG5HcmlkLnByb3RvdHlwZS5zZXRQb2ludCA9IGZ1bmN0aW9uKHsgeCwgeSwgdHlwZSB9LCBkZXRhaWwpIHtcbiAgICB0aGlzLnBvaW50c1tnZXRLZXkoeyB4LCB5LCB0eXBlIH0pXSA9IGRldGFpbDtcbn07XG5cbkdyaWQucHJvdG90eXBlLmdldFBvaW50ID0gZnVuY3Rpb24oeyB4LCB5LCB0eXBlIH0pIHtcbiAgICByZXR1cm4gdGhpcy5wb2ludHNbZ2V0S2V5KHsgeCwgeSwgdHlwZSB9KV07XG59XG5cbkdyaWQucHJvdG90eXBlLmRlbGV0ZVBvaW50ID0gZnVuY3Rpb24oeyB4LCB5LCB0eXBlIH0pIHtcbiAgICBkZWxldGUgdGhpcy5wb2ludHNbZ2V0S2V5KHsgeCwgeSwgdHlwZSB9KV07XG59O1xuXG4vLyBHcmlkLnByb3RvdHlwZS5zZXRBcmVhID0gZnVuY3Rpb24oeyB4LCB5LCB3LCBoLCB0eXBlIH0pIHtcbi8vICAgICBmb3IgKGxldCBpID0geDsgaSA8PSAoeCArIHcpOyBpICs9IHRoaXMuZ3JpZFNpemUpIHtcbi8vICAgICAgICAgZm9yIChsZXQgaiA9IHk7IGogPD0gKHkgKyBoKTsgaiArPSB0aGlzLmdyaWRTaXplKSB7XG4vLyAgICAgICAgICAgICB0aGlzLnNldFBvaW50KHsgeDogaSwgeTogaiwgdHlwZSB9KTtcbi8vICAgICAgICAgfVxuLy8gICAgIH1cbi8vIH07XG5cblxuXG4vLyBXRUJQQUNLIEZPT1RFUiAvL1xuLy8ganMvZ3JpZC5qcyJdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFPQTtBQVBBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VSb290IjoiIn0="); +eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = Grid;\nfunction getKey(_ref) {\n var x = _ref.x,\n y = _ref.y,\n type = _ref.type;\n\n var gridX = x - x % 5;\n var gridY = y - y % 5;\n\n return gridX + \"-\" + gridY;\n}\n\nfunction Grid() {\n this.points = {};\n this.gridSize = 5;\n};\n\nGrid.prototype.setPoint = function (_ref2, detail) {\n var x = _ref2.x,\n y = _ref2.y,\n type = _ref2.type;\n\n this.points[getKey({ x: x, y: y, type: type })] = detail;\n};\n\nGrid.prototype.getPoint = function (_ref3) {\n var x = _ref3.x,\n y = _ref3.y,\n type = _ref3.type;\n\n return this.points[getKey({ x: x, y: y, type: type })];\n};\n\nGrid.prototype.deletePoint = function (_ref4) {\n var x = _ref4.x,\n y = _ref4.y,\n type = _ref4.type;\n\n delete this.points[getKey({ x: x, y: y, type: type })];\n};\n\n// Grid.prototype.setArea = function({ x, y, w, h, type }) {\n// for (let i = x; i <= (x + w); i += this.gridSize) {\n// for (let j = y; j <= (y + h); j += this.gridSize) {\n// this.setPoint({ x: i, y: j, type });\n// }\n// }\n// };\n\n// const Store = function(initialProps) {\n// this.state = Object.freeze(initialProps);\n// }\n//\n// Store.prototype.set = function(props) {\n// this.state = Object.freeze(Object.assign({}, this.state, props));\n// return this.state;\n// };\n//\n// Store.prototype.get = function() {\n// return this.state;\n// }\n//\n// export default Store;//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMzU5LmpzIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vL2pzL2dyaWQuanM/ZTI2YyJdLCJzb3VyY2VzQ29udGVudCI6WyJmdW5jdGlvbiBnZXRLZXkoeyB4LCB5LCB0eXBlIH0pIHtcbiAgICBjb25zdCBncmlkWCA9IHggLSB4ICUgNTtcbiAgICBjb25zdCBncmlkWSA9IHkgLSB5ICUgNTtcblxuICAgIHJldHVybiBgJHtncmlkWH0tJHtncmlkWX1gO1xufVxuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBHcmlkKCkge1xuICAgIHRoaXMucG9pbnRzID0ge307XG4gICAgdGhpcy5ncmlkU2l6ZSA9IDU7XG59O1xuXG5HcmlkLnByb3RvdHlwZS5zZXRQb2ludCA9IGZ1bmN0aW9uKHsgeCwgeSwgdHlwZSB9LCBkZXRhaWwpIHtcbiAgICB0aGlzLnBvaW50c1tnZXRLZXkoeyB4LCB5LCB0eXBlIH0pXSA9IGRldGFpbDtcbn07XG5cbkdyaWQucHJvdG90eXBlLmdldFBvaW50ID0gZnVuY3Rpb24oeyB4LCB5LCB0eXBlIH0pIHtcbiAgICByZXR1cm4gdGhpcy5wb2ludHNbZ2V0S2V5KHsgeCwgeSwgdHlwZSB9KV07XG59XG5cbkdyaWQucHJvdG90eXBlLmRlbGV0ZVBvaW50ID0gZnVuY3Rpb24oeyB4LCB5LCB0eXBlIH0pIHtcbiAgICBkZWxldGUgdGhpcy5wb2ludHNbZ2V0S2V5KHsgeCwgeSwgdHlwZSB9KV07XG59O1xuXG4vLyBHcmlkLnByb3RvdHlwZS5zZXRBcmVhID0gZnVuY3Rpb24oeyB4LCB5LCB3LCBoLCB0eXBlIH0pIHtcbi8vICAgICBmb3IgKGxldCBpID0geDsgaSA8PSAoeCArIHcpOyBpICs9IHRoaXMuZ3JpZFNpemUpIHtcbi8vICAgICAgICAgZm9yIChsZXQgaiA9IHk7IGogPD0gKHkgKyBoKTsgaiArPSB0aGlzLmdyaWRTaXplKSB7XG4vLyAgICAgICAgICAgICB0aGlzLnNldFBvaW50KHsgeDogaSwgeTogaiwgdHlwZSB9KTtcbi8vICAgICAgICAgfVxuLy8gICAgIH1cbi8vIH07XG5cbi8vIGNvbnN0IFN0b3JlID0gZnVuY3Rpb24oaW5pdGlhbFByb3BzKSB7XG4vLyAgICAgdGhpcy5zdGF0ZSA9IE9iamVjdC5mcmVlemUoaW5pdGlhbFByb3BzKTtcbi8vIH1cbi8vXG4vLyBTdG9yZS5wcm90b3R5cGUuc2V0ID0gZnVuY3Rpb24ocHJvcHMpIHtcbi8vICAgICB0aGlzLnN0YXRlID0gT2JqZWN0LmZyZWV6ZShPYmplY3QuYXNzaWduKHt9LCB0aGlzLnN0YXRlLCBwcm9wcykpO1xuLy8gICAgIHJldHVybiB0aGlzLnN0YXRlO1xuLy8gfTtcbi8vXG4vLyBTdG9yZS5wcm90b3R5cGUuZ2V0ID0gZnVuY3Rpb24oKSB7XG4vLyAgICAgcmV0dXJuIHRoaXMuc3RhdGU7XG4vLyB9XG4vL1xuLy8gZXhwb3J0IGRlZmF1bHQgU3RvcmU7XG5cblxuXG4vLyBXRUJQQUNLIEZPT1RFUiAvL1xuLy8ganMvZ3JpZC5qcyJdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFPQTtBQVBBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFBQTtBQUFBO0FBQUE7QUFDQTtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUFBO0FBQ0E7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VSb290IjoiIn0="); + +/***/ }), +/* 360 */ +/* unknown exports provided */ +/* all exports used */ +/*!*******************!*\ + !*** ./js/arc.js ***! + \*******************/ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _enums = __webpack_require__(/*! ./enums */ 15);\n\nvar _random = __webpack_require__(/*! ./random */ 361);\n\nvar _random2 = _interopRequireDefault(_random);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar Arc = {\n create: function create(bounds, grids) {\n var arc = {\n centerX: _random2.default.num(0, bounds.width),\n centerY: _random2.default.num(0, bounds.height),\n clockwise: _random2.default.bool(),\n endX: 0,\n endY: 0,\n length: _random2.default.num(_enums.RAD.t90, _enums.RAD.t360),\n radius: _random2.default.num(100, 200),\n theta: _random2.default.num(_enums.RAD.t90, _enums.RAD.t360)\n };\n\n arc.endX = arc.centerX + arc.radius * Math.cos(arc.theta);\n arc.endY = arc.centerY - arc.radius * Math.sin(arc.theta);\n\n arc = Arc.overflow(arc, bounds);\n\n var x = arc.endX - arc.endX % 5;\n var y = arc.endY - arc.endY % 5;\n\n // If starting in a hazard, recurse.\n // if (grids.global[x] !== undefined && grids.global[x][y] !== undefined) {\n // arc = createArc(bounds, grids);\n // }\n\n return arc;\n },\n\n step: function step(arc, _ref) {\n var bounds = _ref.bounds,\n speed = _ref.speed;\n\n // Ensure constant velocity and theta between 0 and 2π.\n var delta = speed / arc.radius;\n arc.length -= delta;\n\n arc.theta += arc.clockwise ? -delta : +delta;\n arc.theta = arc.theta > 0 ? arc.theta % _enums.RAD.t360 : _enums.RAD.t360 + arc.theta;\n\n arc.endX = arc.centerX + arc.radius * Math.cos(arc.theta); // TODO perf here\n arc.endY = arc.centerY - arc.radius * Math.sin(arc.theta); // TODO perf here\n\n // Overflow.\n arc = Arc.overflow(arc, bounds);\n\n return arc;\n },\n\n randomize: function randomize(arc) {\n arc.length = _random2.default.num(_enums.RAD.t90, _enums.RAD.t360);\n\n arc = Arc.changeRadius(arc, _random2.default.num(100, 200));\n\n if (_random2.default.bool(0.8)) {\n arc = Arc.reverse(arc);\n }\n\n return arc;\n },\n\n overflow: function overflow(arc, bounds) {\n if (arc.endX < 0) {\n arc.endX += bounds.width;\n arc.centerX += bounds.width;\n } else if (arc.endX > bounds.width) {\n arc.endX -= bounds.width;\n arc.centerX -= bounds.width;\n }\n\n if (arc.endY < 0) {\n arc.endY += bounds.height;\n arc.centerY += bounds.height;\n } else if (arc.endY > bounds.height) {\n arc.endY -= bounds.height;\n arc.centerY -= bounds.height;\n }\n\n return arc;\n },\n\n changeRadius: function changeRadius(arc, newRadius) {\n var r0 = arc.radius;\n var r1 = newRadius;\n\n // Moves arc center to new radius while keeping theta constant.\n arc.centerX -= (r1 - r0) * Math.cos(arc.theta); // TODO perf here\n arc.centerY += (r1 - r0) * Math.sin(arc.theta); // TODO perf here\n arc.radius = r1;\n\n return arc;\n },\n\n reverse: function reverse(arc) {\n arc.clockwise = !arc.clockwise;\n\n arc.theta = (arc.theta + _enums.RAD.t180) % _enums.RAD.t360;\n\n arc.centerX -= 2 * arc.radius * Math.cos(arc.theta); // TODO perf here\n arc.centerY += 2 * arc.radius * Math.sin(arc.theta); // TODO perf here\n\n return arc;\n },\n\n follow: function follow(arc, arcToFollow) {\n if (arc.clockwise !== arcToFollow.clockwise) {\n arc = Arc.reverse(arc);\n }\n\n if (Math.abs(arc.theta - arcToFollow.theta) > 0.1) {\n arc = Arc.changeRadius(arc, 20);\n } else {\n arc = Arc.changeRadius(arc, arcToFollow.radius);\n }\n\n return arc;\n },\n\n evade: function evade(arc, visionGrid) {\n // const danger = visionGrid.reduce((acc, v) => acc || v.touch, false);\n //\n // if (danger === false) {\n // return arc;\n // }\n //\n // const evasionArc = moveArc(arc, 20);\n // evasionArc.length = 1;\n //\n // return evasionArc;\n }\n};\n\nexports.default = Arc;//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMzYwLmpzIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vL2pzL2FyYy5qcz85YjVmIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFJBRCB9IGZyb20gJy4vZW51bXMnO1xuaW1wb3J0IFJhbmRvbSBmcm9tICcuL3JhbmRvbSc7XG5cbmNvbnN0IEFyYyA9IHtcbiAgICBjcmVhdGU6IGZ1bmN0aW9uKGJvdW5kcywgZ3JpZHMpIHtcbiAgICAgICAgbGV0IGFyYyA9IHtcbiAgICAgICAgICAgIGNlbnRlclg6IFJhbmRvbS5udW0oMCwgYm91bmRzLndpZHRoKSxcbiAgICAgICAgICAgIGNlbnRlclk6IFJhbmRvbS5udW0oMCwgYm91bmRzLmhlaWdodCksXG4gICAgICAgICAgICBjbG9ja3dpc2U6IFJhbmRvbS5ib29sKCksXG4gICAgICAgICAgICBlbmRYOiAwLFxuICAgICAgICAgICAgZW5kWTogMCxcbiAgICAgICAgICAgIGxlbmd0aDogUmFuZG9tLm51bShSQUQudDkwLCBSQUQudDM2MCksXG4gICAgICAgICAgICByYWRpdXM6IFJhbmRvbS5udW0oMTAwLCAyMDApLFxuICAgICAgICAgICAgdGhldGE6IFJhbmRvbS5udW0oUkFELnQ5MCwgUkFELnQzNjApXG4gICAgICAgIH07XG5cbiAgICAgICAgYXJjLmVuZFggPSBhcmMuY2VudGVyWCArIGFyYy5yYWRpdXMgKiBNYXRoLmNvcyhhcmMudGhldGEpO1xuICAgICAgICBhcmMuZW5kWSA9IGFyYy5jZW50ZXJZIC0gYXJjLnJhZGl1cyAqIE1hdGguc2luKGFyYy50aGV0YSk7XG5cbiAgICAgICAgYXJjID0gQXJjLm92ZXJmbG93KGFyYywgYm91bmRzKTtcblxuICAgICAgICBjb25zdCB4ID0gYXJjLmVuZFggLSBhcmMuZW5kWCAlIDU7XG4gICAgICAgIGNvbnN0IHkgPSBhcmMuZW5kWSAtIGFyYy5lbmRZICUgNTtcblxuICAgICAgICAvLyBJZiBzdGFydGluZyBpbiBhIGhhemFyZCwgcmVjdXJzZS5cbiAgICAgICAgLy8gaWYgKGdyaWRzLmdsb2JhbFt4XSAhPT0gdW5kZWZpbmVkICYmIGdyaWRzLmdsb2JhbFt4XVt5XSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIC8vICAgICBhcmMgPSBjcmVhdGVBcmMoYm91bmRzLCBncmlkcyk7XG4gICAgICAgIC8vIH1cblxuICAgICAgICByZXR1cm4gYXJjO1xuICAgIH0sXG5cbiAgICBzdGVwOiBmdW5jdGlvbihhcmMsIHsgYm91bmRzLCBzcGVlZCB9KSB7XG4gICAgICAgIC8vIEVuc3VyZSBjb25zdGFudCB2ZWxvY2l0eSBhbmQgdGhldGEgYmV0d2VlbiAwIGFuZCAyz4AuXG4gICAgICAgIGNvbnN0IGRlbHRhID0gc3BlZWQgLyBhcmMucmFkaXVzO1xuICAgICAgICBhcmMubGVuZ3RoIC09IGRlbHRhO1xuXG4gICAgICAgIGFyYy50aGV0YSArPSAoYXJjLmNsb2Nrd2lzZSA/IC1kZWx0YSA6ICtkZWx0YSk7XG4gICAgICAgIGFyYy50aGV0YSA9IChhcmMudGhldGEgPiAwID8gYXJjLnRoZXRhICUgUkFELnQzNjAgOiBSQUQudDM2MCArIGFyYy50aGV0YSk7XG5cbiAgICAgICAgYXJjLmVuZFggPSBhcmMuY2VudGVyWCArIGFyYy5yYWRpdXMgKiBNYXRoLmNvcyhhcmMudGhldGEpOyAvLyBUT0RPIHBlcmYgaGVyZVxuICAgICAgICBhcmMuZW5kWSA9IGFyYy5jZW50ZXJZIC0gYXJjLnJhZGl1cyAqIE1hdGguc2luKGFyYy50aGV0YSk7IC8vIFRPRE8gcGVyZiBoZXJlXG5cbiAgICAgICAgLy8gT3ZlcmZsb3cuXG4gICAgICAgIGFyYyA9IEFyYy5vdmVyZmxvdyhhcmMsIGJvdW5kcyk7XG5cbiAgICAgICAgcmV0dXJuIGFyYztcbiAgICB9LFxuXG4gICAgcmFuZG9taXplOiBmdW5jdGlvbihhcmMpIHtcbiAgICAgICAgYXJjLmxlbmd0aCA9IFJhbmRvbS5udW0oUkFELnQ5MCwgUkFELnQzNjApO1xuXG4gICAgICAgIGFyYyA9IEFyYy5jaGFuZ2VSYWRpdXMoYXJjLCBSYW5kb20ubnVtKDEwMCwgMjAwKSk7XG5cbiAgICAgICAgaWYgKFJhbmRvbS5ib29sKDAuOCkpIHtcbiAgICAgICAgICAgIGFyYyA9IEFyYy5yZXZlcnNlKGFyYyk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYXJjO1xuICAgIH0sXG5cbiAgICBvdmVyZmxvdzogZnVuY3Rpb24oYXJjLCBib3VuZHMpIHtcbiAgICAgICAgaWYgKGFyYy5lbmRYIDwgMCkge1xuICAgICAgICAgICAgYXJjLmVuZFggKz0gYm91bmRzLndpZHRoO1xuICAgICAgICAgICAgYXJjLmNlbnRlclggKz0gYm91bmRzLndpZHRoXG4gICAgICAgIH0gZWxzZSBpZiAoYXJjLmVuZFggPiBib3VuZHMud2lkdGgpIHtcbiAgICAgICAgICAgIGFyYy5lbmRYIC09IGJvdW5kcy53aWR0aDtcbiAgICAgICAgICAgIGFyYy5jZW50ZXJYIC09IGJvdW5kcy53aWR0aFxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGFyYy5lbmRZIDwgMCkge1xuICAgICAgICAgICAgYXJjLmVuZFkgKz0gYm91bmRzLmhlaWdodDtcbiAgICAgICAgICAgIGFyYy5jZW50ZXJZICs9IGJvdW5kcy5oZWlnaHRcbiAgICAgICAgfSBlbHNlIGlmIChhcmMuZW5kWSA+IGJvdW5kcy5oZWlnaHQpIHtcbiAgICAgICAgICAgIGFyYy5lbmRZIC09IGJvdW5kcy5oZWlnaHQ7XG4gICAgICAgICAgICBhcmMuY2VudGVyWSAtPSBib3VuZHMuaGVpZ2h0XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYXJjO1xuICAgIH0sXG5cbiAgICBjaGFuZ2VSYWRpdXM6IGZ1bmN0aW9uKGFyYywgbmV3UmFkaXVzKSB7XG4gICAgICAgIGNvbnN0IHIwID0gYXJjLnJhZGl1cztcbiAgICAgICAgY29uc3QgcjEgPSBuZXdSYWRpdXM7XG5cbiAgICAgICAgLy8gTW92ZXMgYXJjIGNlbnRlciB0byBuZXcgcmFkaXVzIHdoaWxlIGtlZXBpbmcgdGhldGEgY29uc3RhbnQuXG4gICAgICAgIGFyYy5jZW50ZXJYIC09IChyMSAtIHIwKSAqIE1hdGguY29zKGFyYy50aGV0YSk7IC8vIFRPRE8gcGVyZiBoZXJlXG4gICAgICAgIGFyYy5jZW50ZXJZICs9IChyMSAtIHIwKSAqIE1hdGguc2luKGFyYy50aGV0YSk7IC8vIFRPRE8gcGVyZiBoZXJlXG4gICAgICAgIGFyYy5yYWRpdXMgPSByMTtcblxuICAgICAgICByZXR1cm4gYXJjO1xuICAgIH0sXG5cbiAgICByZXZlcnNlOiBmdW5jdGlvbihhcmMpIHtcbiAgICAgICAgYXJjLmNsb2Nrd2lzZSA9ICFhcmMuY2xvY2t3aXNlO1xuXG4gICAgICAgIGFyYy50aGV0YSA9IChhcmMudGhldGEgKyBSQUQudDE4MCkgJSBSQUQudDM2MDtcblxuICAgICAgICBhcmMuY2VudGVyWCAtPSAoMiAqIGFyYy5yYWRpdXMpICogTWF0aC5jb3MoYXJjLnRoZXRhKTsgLy8gVE9ETyBwZXJmIGhlcmVcbiAgICAgICAgYXJjLmNlbnRlclkgKz0gKDIgKiBhcmMucmFkaXVzKSAqIE1hdGguc2luKGFyYy50aGV0YSk7IC8vIFRPRE8gcGVyZiBoZXJlXG5cbiAgICAgICAgcmV0dXJuIGFyYztcbiAgICB9LFxuXG4gICAgZm9sbG93OiBmdW5jdGlvbihhcmMsIGFyY1RvRm9sbG93KSB7XG4gICAgICAgIGlmIChhcmMuY2xvY2t3aXNlICE9PSBhcmNUb0ZvbGxvdy5jbG9ja3dpc2UpIHtcbiAgICAgICAgICAgIGFyYyA9IEFyYy5yZXZlcnNlKGFyYyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoTWF0aC5hYnMoYXJjLnRoZXRhIC0gYXJjVG9Gb2xsb3cudGhldGEpID4gMC4xKSB7XG4gICAgICAgICAgICBhcmMgPSBBcmMuY2hhbmdlUmFkaXVzKGFyYywgMjApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYXJjID0gQXJjLmNoYW5nZVJhZGl1cyhhcmMsIGFyY1RvRm9sbG93LnJhZGl1cyk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYXJjO1xuICAgIH0sXG5cbiAgICBldmFkZTogZnVuY3Rpb24oYXJjLCB2aXNpb25HcmlkKSB7XG4gICAgICAgIC8vIGNvbnN0IGRhbmdlciA9IHZpc2lvbkdyaWQucmVkdWNlKChhY2MsIHYpID0+IGFjYyB8fCB2LnRvdWNoLCBmYWxzZSk7XG4gICAgICAgIC8vXG4gICAgICAgIC8vIGlmIChkYW5nZXIgPT09IGZhbHNlKSB7XG4gICAgICAgIC8vICAgICByZXR1cm4gYXJjO1xuICAgICAgICAvLyB9XG4gICAgICAgIC8vXG4gICAgICAgIC8vIGNvbnN0IGV2YXNpb25BcmMgPSBtb3ZlQXJjKGFyYywgMjApO1xuICAgICAgICAvLyBldmFzaW9uQXJjLmxlbmd0aCA9IDE7XG4gICAgICAgIC8vXG4gICAgICAgIC8vIHJldHVybiBldmFzaW9uQXJjO1xuICAgIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgQXJjO1xuXG5cblxuLy8gV0VCUEFDSyBGT09URVIgLy9cbi8vIGpzL2FyYy5qcyJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUE7QUFDQTtBQUFBO0FBQ0E7Ozs7O0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQVJBO0FBQ0E7QUFVQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQUE7QUFBQTtBQUNBO0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUE5SEE7QUFDQTtBQWdJQSIsInNvdXJjZVJvb3QiOiIifQ=="); + +/***/ }), +/* 361 */ +/* unknown exports provided */ +/* all exports used */ +/*!**********************!*\ + !*** ./js/random.js ***! + \**********************/ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nvar random = {\n bool: function bool(weight) {\n return Math.random() < (weight || 0.5);\n },\n color: function color() {\n return \"rgb(\\n \" + Math.floor(Math.random() * 230) + \",\\n \" + Math.floor(Math.random() * 230) + \",\\n \" + Math.floor(Math.random() * 230) + \"\\n )\";\n },\n id: function id() {\n return String.fromCharCode(random.num(65, 90), random.num(97, 122), random.num(97, 122)\n // random.num(97, 122), random.num(97, 122), random.num(97, 122)\n );\n },\n num: function num(min, max) {\n return min + Math.round(Math.random() * (max - min));\n }\n};\n\nexports.default = random;//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMzYxLmpzIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vL2pzL3JhbmRvbS5qcz83MTBjIl0sInNvdXJjZXNDb250ZW50IjpbImNvbnN0IHJhbmRvbSA9IHtcbiAgICBib29sOiAod2VpZ2h0KSA9PiBNYXRoLnJhbmRvbSgpIDwgKHdlaWdodCB8fCAwLjUpLFxuICAgIGNvbG9yOiAoKSA9PiBgcmdiKFxuICAgICAgICAke01hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDIzMCl9LFxuICAgICAgICAke01hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDIzMCl9LFxuICAgICAgICAke01hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIDIzMCl9XG4gICAgKWAsXG4gICAgaWQ6ICgpID0+IFN0cmluZy5mcm9tQ2hhckNvZGUoXG4gICAgICAgIHJhbmRvbS5udW0oNjUsIDkwKSwgcmFuZG9tLm51bSg5NywgMTIyKSwgcmFuZG9tLm51bSg5NywgMTIyKVxuICAgICAgICAvLyByYW5kb20ubnVtKDk3LCAxMjIpLCByYW5kb20ubnVtKDk3LCAxMjIpLCByYW5kb20ubnVtKDk3LCAxMjIpXG4gICAgKSxcbiAgICBudW06IChtaW4sIG1heCkgPT4gbWluICsgTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKG1heCAtIG1pbikpLFxufTtcblxuZXhwb3J0IGRlZmF1bHQgcmFuZG9tO1xuXG5cblxuLy8gV0VCUEFDSyBGT09URVIgLy9cbi8vIGpzL3JhbmRvbS5qcyJdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQTtBQUNBO0FBQUE7QUFBQTtBQUNBO0FBQUE7QUFBQTtBQUtBO0FBQUE7QUFFQTtBQUZBO0FBQUE7QUFJQTtBQUFBO0FBQUE7QUFYQTtBQUNBO0FBYUEiLCJzb3VyY2VSb290IjoiIn0="); /***/ }) /******/ ]); \ No newline at end of file diff --git a/js/grid.js b/js/grid.js index 7ae7e3b..e3adc95 100644 --- a/js/grid.js +++ b/js/grid.js @@ -29,3 +29,18 @@ Grid.prototype.deletePoint = function({ x, y, type }) { // } // } // }; + +// const Store = function(initialProps) { +// this.state = Object.freeze(initialProps); +// } +// +// Store.prototype.set = function(props) { +// this.state = Object.freeze(Object.assign({}, this.state, props)); +// return this.state; +// }; +// +// Store.prototype.get = function() { +// return this.state; +// } +// +// export default Store; diff --git a/js/particle.js b/js/particle.js index 353a2bd..24dfd2f 100644 --- a/js/particle.js +++ b/js/particle.js @@ -1,20 +1,7 @@ import Rx, { Observable } from 'rxjs'; import { BEHAVIOR, ENTITIES, RAD } from './enums'; -import Store from './store'; - -const random = { - bool: (weight) => Math.random() < (weight || 0.5), - color: () => `rgb( - ${Math.floor(Math.random() * 230)}, - ${Math.floor(Math.random() * 230)}, - ${Math.floor(Math.random() * 230)} - )`, - id: () => String.fromCharCode( - random.num(65, 90), random.num(97, 122), random.num(97, 122) - // random.num(97, 122), random.num(97, 122), random.num(97, 122) - ), - num: (min, max) => min + Math.round(Math.random() * (max - min)), -} +import Arc from './arc'; +import Random from './random'; // ===== Constructor ===== @@ -23,7 +10,7 @@ function Particle(parent, bounds, config, globalGrid) { value: Object.assign({}, { behavior: BEHAVIOR.COHESION, bounds, - color: random.color(), + color: Random.color(), gridSize: 5, randomize: true, showMovementCircle: false, @@ -41,7 +28,7 @@ function Particle(parent, bounds, config, globalGrid) { }); Object.defineProperty(this, 'id', { - value: random.id(6) + value: Random.id(6) }); Object.defineProperty(this, 'nodes', { @@ -61,7 +48,7 @@ function Particle(parent, bounds, config, globalGrid) { this.nodes.container.appendChild(this.nodes.body); parent.appendChild(this.nodes.container); - this.arc = createArc(bounds, this.grids); + this.arc = Arc.create(bounds, this.grids); this.updateConfig(this.config); this.nextFrame(globalGrid); }; @@ -76,13 +63,13 @@ Particle.prototype.remove = function() { Particle.prototype.nextFrame = function(globalGrid) { // Randomly change radius and rotation direction. if (this.arc.length <= 0 && this.config.randomize) { - this.arc = randomizeArc(this.arc); + this.arc = Arc.randomize(this.arc); } - this.arc = step(this.arc, this.config); + this.arc = Arc.step(this.arc, this.config); if (this.leader !== null) { - this.arc = followArc(this.arc, this.leader.arc); + this.arc = Arc.follow(this.arc, this.leader.arc); } this.grids.global = globalGrid; @@ -159,36 +146,28 @@ Particle.prototype.updateLeader = function() { } } -// ===== CREATION ===== - -function createArc(bounds, grids) { - let arc = { - centerX: random.num(0, bounds.width), - centerY: random.num(0, bounds.height), - clockwise: random.bool(), - endX: 0, - endY: 0, - length: random.num(RAD.t90, RAD.t360), - radius: random.num(100, 200), - theta: random.num(RAD.t90, RAD.t360), - }; - - arc.endX = arc.centerX + arc.radius * Math.cos(arc.theta); - arc.endY = arc.centerY - arc.radius * Math.sin(arc.theta); +function look(arc, grids) { + const { global, vision } = grids; - arc = overflowArc(arc, bounds); + return vision.reduce((acc, point) => { + const x = arc.endX + point.x; + const y = arc.endY + point.y; + const p = global.getPoint({ x, y, type: ENTITIES.PARTICLE }); - const x = arc.endX - arc.endX % 5; - const y = arc.endY - arc.endY % 5; + if (p) { + acc.particles.push(p); + } - // If starting in a hazard, recurse. - if (grids.global[x] !== undefined && grids.global[x][y] !== undefined) { - arc = createArc(bounds, grids); - } + // if (global.getPoint({ x, y, type: ENTITIES.HAZARD })) { + // acc.hazards.push({ x, y }); + // } - return arc; + return acc; + }, { hazards: [], particles: [] }); } +// ===== DOM CREATION ===== + function createBodyNode(config) { const node = document.createElement('div'); node.className = 'particle-body'; @@ -263,93 +242,6 @@ function createVisionGridNodes(config, grids, nodes) { }, []); } -// ===== CALCULATIONS ===== - -function step(arc, { bounds, speed }) { - // Ensure constant velocity and theta between 0 and 2π. - const delta = speed / arc.radius; - arc.length -= delta; - - arc.theta += (arc.clockwise ? -delta : +delta); - arc.theta = (arc.theta > 0 ? arc.theta % RAD.t360 : RAD.t360 + arc.theta); - - arc.endX = arc.centerX + arc.radius * Math.cos(arc.theta); // TODO perf here - arc.endY = arc.centerY - arc.radius * Math.sin(arc.theta); // TODO perf here - - // Overflow. - arc = overflowArc(arc, bounds); - - return arc; -} - -function randomizeArc(arc) { - arc.length = random.num(RAD.t90, RAD.t360); - - arc = moveArc(arc, random.num(100, 200)); - - if (random.bool(0.8)) { - arc = reverseArc(arc); - } - - return arc; -} - -function overflowArc(arc, bounds) { - if (arc.endX < 0) { - arc.endX += bounds.width; - arc.centerX += bounds.width - } else if (arc.endX > bounds.width) { - arc.endX -= bounds.width; - arc.centerX -= bounds.width - } - - if (arc.endY < 0) { - arc.endY += bounds.height; - arc.centerY += bounds.height - } else if (arc.endY > bounds.height) { - arc.endY -= bounds.height; - arc.centerY -= bounds.height - } - - return arc; -} - -function moveArc(arc, newRadius) { - const r0 = arc.radius; - const r1 = newRadius; - - // Moves arc center to new radius while keeping theta constant. - arc.centerX -= (r1 - r0) * Math.cos(arc.theta); // TODO perf here - arc.centerY += (r1 - r0) * Math.sin(arc.theta); // TODO perf here - arc.radius = r1; - - return arc; -} - -function reverseArc(arc) { - arc.clockwise = !arc.clockwise; - - arc.theta = (arc.theta + RAD.t180) % RAD.t360; - - arc.centerX -= (2 * arc.radius) * Math.cos(arc.theta); // TODO perf here - arc.centerY += (2 * arc.radius) * Math.sin(arc.theta); // TODO perf here - - return arc; -} - -function followArc(arc, arcToFollow) { - if (arc.clockwise !== arcToFollow.clockwise) { - arc = reverseArc(arc); - } - - if (Math.abs(arc.theta - arcToFollow.theta) > 0.1) { - arc = moveArc(arc, 20); - } else { - arc = moveArc(arc, arcToFollow.radius); - } - - return arc; -} function updateVisionGrid(arc, config, grids) { const { global, vision } = grids; @@ -366,41 +258,7 @@ function updateVisionGrid(arc, config, grids) { }, []); } -// ===== ACTIONS ===== -function look(arc, grids) { - const { global, vision } = grids; - - return vision.reduce((acc, point) => { - const x = arc.endX + point.x; - const y = arc.endY + point.y; - const p = global.getPoint({ x, y, type: ENTITIES.PARTICLE }); - - if (p) { - acc.particles.push(p); - } - - // if (global.getPoint({ x, y, type: ENTITIES.HAZARD })) { - // acc.hazards.push({ x, y }); - // } - - return acc; - }, { hazards: [], particles: [] }); -} - -function evade(arc, visionGrid) { - // const danger = visionGrid.reduce((acc, v) => acc || v.touch, false); - // - // if (danger === false) { - // return arc; - // } - // - // const evasionArc = moveArc(arc, 20); - // evasionArc.length = 1; - // - // return evasionArc; -} - -// ===== RENDERING ===== +// ===== DOM RENDERING ===== function repaintContainer(node, arc) { node.style.left = `${arc.endX}px`; node.style.top = `${arc.endY}px`; diff --git a/js/random.js b/js/random.js new file mode 100644 index 0000000..4a49816 --- /dev/null +++ b/js/random.js @@ -0,0 +1,15 @@ +const random = { + bool: (weight) => Math.random() < (weight || 0.5), + color: () => `rgb( + ${Math.floor(Math.random() * 230)}, + ${Math.floor(Math.random() * 230)}, + ${Math.floor(Math.random() * 230)} + )`, + id: () => String.fromCharCode( + random.num(65, 90), random.num(97, 122), random.num(97, 122) + // random.num(97, 122), random.num(97, 122), random.num(97, 122) + ), + num: (min, max) => min + Math.round(Math.random() * (max - min)), +}; + +export default random; diff --git a/js/store.js b/js/store.js deleted file mode 100644 index 5d1834f..0000000 --- a/js/store.js +++ /dev/null @@ -1,14 +0,0 @@ -const Store = function(initialProps) { - this.state = Object.freeze(initialProps); -} - -Store.prototype.set = function(props) { - this.state = Object.freeze(Object.assign({}, this.state, props)); - return this.state; -}; - -Store.prototype.get = function() { - return this.state; -} - -export default Store;