├── .eslintrc ├── .gitignore ├── .npmignore ├── test.js ├── rollup.config.js ├── example.rollup.config.js ├── docs └── index.html ├── example ├── index.html └── index.js ├── TODO.md ├── LICENSE.md ├── README.md ├── package.json ├── src └── index.js └── lib └── umd.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["standard"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | .DS_Store 4 | example/bundle.js 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | .DS_Store 4 | bundle.js 5 | test.js 6 | docs/ 7 | example/ 8 | .npmignore 9 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | const { createSpring } = require('./lib') 2 | const test = require('tape') 3 | 4 | test('createSpring should be a function', function (t) { 5 | t.equal(typeof createSpring, 'function') 6 | t.end() 7 | }) 8 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from 'rollup-plugin-node-resolve' 2 | import commonjs from 'rollup-plugin-commonjs' 3 | 4 | export default { 5 | input: 'src/index.js', 6 | output: { 7 | file: 'lib/umd.js', 8 | format: 'umd', 9 | name: 'SpringAnimator', 10 | sourcemap: 'inline' 11 | }, 12 | plugins: [ 13 | resolve(), 14 | commonjs() 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /example.rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from 'rollup-plugin-node-resolve' 2 | import commonjs from 'rollup-plugin-commonjs' 3 | 4 | export default { 5 | input: 'example/index.js', 6 | output: { 7 | file: 'example/bundle.js', 8 | format: 'iife', 9 | sourcemap: 'inline' 10 | }, 11 | plugins: [ 12 | resolve(), 13 | commonjs({ 14 | namedExports: { 'dat.gui': ['GUI'] } 15 | }) 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Spring Animator Example 5 | 21 | 22 | 23 |
24 |

Spring Animator Example

25 |

(Click around!)

26 | 27 |
28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Spring Animator Example 5 | 21 | 22 | 23 |
24 |

Spring Animator Example

25 |

(Click around!)

26 | 27 |
28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # TODO 2 | 3 | - [X] pull out a getCurrentValue() method from tick() 4 | - [x] allow users to pass in different stiffness and dampening to tick() 5 | - [X] use isAtDestination in tick() to set at destination and make velocity 0 6 | - [X] support scalars _and_ up to vec4 7 | - [X] remove `step` arg from tick() 8 | - [X] fix example (`stiffness`, _then_ `dampening`) 9 | - [X] rename `updateValue` to `setDestination` 10 | - [X] update demo to choose better ranges for `stiffness` and `dampening` 11 | - [X] optimize so no arrays are created beyond initialization 12 | - [X] add console.log suggesting spring/dampen vals when none are provided? link to example? 13 | - [X] rewrite docs & README 14 | - [X] merge package.jsons from example and root 15 | - [X] bump package version and publish 16 | 17 | # not gonna do: 18 | 19 | - [-] add other types of physics based animators? 20 | - [-] what if dampening increased as you got closer to target? 21 | - [meh] write some tests 22 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2017, 2019 Taylor Baldwin 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 20 | OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spring-animator 2 | 3 | [![stable](http://badges.github.io/stability-badges/dist/stable.svg)](http://github.com/badges/stability-badges) 4 | 5 | A little tool for easing values with spring forces for animations. 6 | 7 | Here's [an example](https://rolyatmax.github.io/spring-animator/). 8 | 9 | ## Install 10 | 11 | Use [npm](https://npmjs.com/) to install. 12 | 13 | ```sh 14 | npm install spring-animator --save 15 | ``` 16 | 17 | ## Usage 18 | 19 | ```js 20 | import { createSpring } from 'spring-animator' 21 | 22 | const stiffness = 0.003 23 | const dampening = 0.1 24 | const startingValue = 10 25 | 26 | const spring = createSpring(stiffness, dampening, startingValue) 27 | 28 | // must first set a new destination value to animate towards 29 | spring.setDestination(15) 30 | 31 | spring.tick() // takes one step towards destination value 32 | 33 | // pass custom stiffness and dampening values for just this tick 34 | spring.tick(0.003, 0.1) 35 | 36 | const value = spring.getCurrentValue() // returns the current value 37 | ``` 38 | 39 | I personally like these values: 40 | 41 | ```js 42 | { 43 | stiffness: 0.003, 44 | dampening: 0.1 45 | } 46 | ``` 47 | 48 | ## To run the example: 49 | 50 | ```sh 51 | npm install 52 | npm start 53 | ``` 54 | 55 | And then make sure to open example/index.html in a browser! 56 | 57 | Or you can just try it out [here](https://rolyatmax.github.io/spring-animator/). 58 | 59 | [![NPM](https://nodei.co/npm/spring-animator.png)](https://www.npmjs.com/package/spring-animator) 60 | 61 | ## License 62 | 63 | MIT, see [LICENSE.md](http://github.com/rolyatmax/spring-animator/blob/master/LICENSE.md) for details. 64 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spring-animator", 3 | "version": "2.0.0", 4 | "description": "a little tool for animating scalar and vector values with spring forces", 5 | "main": "lib/umd.js", 6 | "module": "src/index.js", 7 | "license": "MIT", 8 | "author": { 9 | "name": "Taylor Baldwin", 10 | "email": "taylorbaldwin@gmail.com", 11 | "url": "https://tbaldw.in/" 12 | }, 13 | "dependencies": { 14 | "gl-vec4": "^1.0.1" 15 | }, 16 | "devDependencies": { 17 | "dat.gui": "0.7.6", 18 | "rollup": "^1.11.3", 19 | "rollup-plugin-commonjs": "^9.3.4", 20 | "rollup-plugin-node-resolve": "^4.2.3", 21 | "rollup-watch": "^4.3.1", 22 | "standard": "^12.0.1", 23 | "tape": "^4.10.1" 24 | }, 25 | "scripts": { 26 | "build": "rollup -c rollup.config.js", 27 | "build-example": "mkdir -p docs && rollup --config=example.rollup.config.js && cp example/index.html docs/ && cp example/bundle.js docs/", 28 | "start": "rollup --watch --config=example.rollup.config.js", 29 | "test": "node test.js", 30 | "lint": "standard", 31 | "prepublish": "npm run build && npm run lint" 32 | }, 33 | "files": [ 34 | "lib", 35 | "src" 36 | ], 37 | "keywords": [ 38 | "animate", 39 | "animation", 40 | "spring", 41 | "physics" 42 | ], 43 | "standard": { 44 | "ignore": [ 45 | "lib" 46 | ] 47 | }, 48 | "repository": { 49 | "type": "git", 50 | "url": "git://github.com/rolyatmax/spring-animator.git" 51 | }, 52 | "homepage": "https://github.com/rolyatmax/spring-animator", 53 | "bugs": { 54 | "url": "https://github.com/rolyatmax/spring-animator/issues" 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /example/index.js: -------------------------------------------------------------------------------- 1 | /* global requestAnimationFrame */ 2 | 3 | import { createSpring } from '../src' 4 | import { GUI } from 'dat.gui' 5 | 6 | const MAX_RADIUS = 100 7 | const MIN_RADIUS = 5 8 | const LAST_VALUES_TRAIL_LENGTH = 500 9 | 10 | const settings = { 11 | stiffness: 0.003, 12 | dampening: 0.1 13 | } 14 | 15 | const gui = new GUI() 16 | gui.add(settings, 'stiffness', 0.001, 0.08).step(0.001) 17 | gui.add(settings, 'dampening', 0.01, 0.5).step(0.01) 18 | gui.add({ clear: setupSprings }, 'clear') 19 | 20 | const canvas = document.querySelector('canvas') 21 | const ctx = setupCanvasAndGetContext(canvas) 22 | 23 | canvas.addEventListener('click', (e) => { 24 | if ( 25 | circle.positionSpring.isAtDestination(0.2) && 26 | circle.radiusSpring.isAtDestination(0.2) 27 | ) { 28 | lastValues = [] 29 | } 30 | setPositionAndRadius([e.offsetX, e.offsetY]) 31 | }) 32 | 33 | const center = [canvas.width / 2, canvas.height / 2] 34 | let lastValues = [] 35 | 36 | let circle 37 | setupSprings() 38 | setPositionAndRadius(center) 39 | requestAnimationFrame(loop) 40 | 41 | function setupSprings () { 42 | const dampening = settings.dampening 43 | const stiffness = settings.stiffness 44 | lastValues = [] 45 | circle = { 46 | radiusSpring: createSpring(stiffness, dampening, 10), 47 | positionSpring: createSpring(stiffness, dampening, center) 48 | } 49 | } 50 | 51 | function setPositionAndRadius (position) { 52 | const newRadius = (MAX_RADIUS - MIN_RADIUS) * Math.random() + MIN_RADIUS 53 | circle.radiusSpring.setDestination(newRadius) 54 | circle.positionSpring.setDestination(position) 55 | } 56 | 57 | function setupCanvasAndGetContext (canvas) { 58 | let { width, height } = canvas.parentElement.getBoundingClientRect() 59 | height *= 2 60 | canvas.width = width 61 | canvas.height = height 62 | canvas.style.width = `${width}px` 63 | canvas.style.height = `${height}px` 64 | return canvas.getContext('2d') 65 | } 66 | 67 | function loop () { 68 | requestAnimationFrame(loop) 69 | clearRect(ctx, 'rgb(248, 245, 250)') 70 | circle.positionSpring.tick(settings.stiffness, settings.dampening) 71 | circle.radiusSpring.tick(settings.stiffness, settings.dampening) 72 | const position = circle.positionSpring.getCurrentValue() 73 | const radius = circle.radiusSpring.getCurrentValue() 74 | lastValues = lastValues.slice(Math.max(0, lastValues.length - LAST_VALUES_TRAIL_LENGTH)) 75 | lastValues.forEach(([pos, rad]) => drawCircle(ctx, pos, rad, 'transparent', 'rgba(94, 126, 178, 0.4)')) 76 | drawCircle(ctx, position, radius, 'rgb(94, 126, 178)', 'rgba(255, 255, 255, 0.8)') 77 | lastValues.push([position, radius]) 78 | } 79 | 80 | function drawCircle (ctx, position, radius, fillColor = 'transparent', strokeColor = 'transparent') { 81 | if (radius < 0) return 82 | ctx.beginPath() 83 | ctx.strokeStyle = strokeColor 84 | ctx.fillStyle = fillColor 85 | ctx.arc(position[0], position[1], radius, 0, Math.PI * 2) 86 | ctx.fill() 87 | ctx.stroke() 88 | } 89 | 90 | function clearRect (ctx, color) { 91 | ctx.beginPath() 92 | ctx.fillStyle = color 93 | ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height) 94 | ctx.fill() 95 | } 96 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import vec4 from 'gl-vec4' 2 | 3 | export function createSpring (stiffness, dampening, value, precision) { 4 | precision = precision ? precision * precision : Number.EPSILON 5 | const isInputArray = Array.isArray(value) 6 | const vecComponents = isInputArray ? value.length : Number.isFinite(value) ? 1 : null 7 | 8 | if (!Number.isFinite(stiffness) || !Number.isFinite(dampening)) { 9 | throw new Error(`spring-animator: expected numbers for stiffness and dampening. (e.g. createSpring(0.003, 0.1, startingValue))`) 10 | } 11 | 12 | if (!vecComponents || vecComponents > 4) { 13 | throw new Error(`spring-animator: expected value \`${value}\` to be a scalar, vec2, vec3, or vec4`) 14 | } 15 | 16 | function makeValueVec4 (out = [], v) { 17 | if (isInputArray !== Array.isArray(v) || (isInputArray && vecComponents !== v.length)) { 18 | throw new Error(`spring-animator: destination value type must match initial value type: ${!isInputArray ? 'scalar' : vecComponents + '-component vector'}`) 19 | } 20 | 21 | if (Number.isFinite(v)) { 22 | out[0] = v 23 | out[1] = out[2] = out[3] = 0 24 | return out 25 | } 26 | 27 | let i = 0 28 | while (i < 4) { 29 | out[i] = i < v.length ? v[i] : 0 30 | i += 1 31 | } 32 | return out 33 | } 34 | 35 | value = makeValueVec4([], value) 36 | let lastValue = vec4.copy([], value) 37 | let destinationValue = vec4.copy([], value) 38 | 39 | // set up some reusable arrays to use in tick() 40 | let nextValue = [] 41 | let velocity = [] 42 | let delta = [] 43 | let spring = [] 44 | let damper = [] 45 | let acceleration = [] 46 | 47 | return { 48 | setDestination, 49 | getCurrentValue, 50 | isAtDestination, 51 | tick 52 | } 53 | 54 | function setDestination (newValue, shouldAnimate = true) { 55 | makeValueVec4(destinationValue, newValue) 56 | if (!shouldAnimate) { 57 | vec4.copy(value, destinationValue) 58 | vec4.copy(lastValue, destinationValue) 59 | } 60 | } 61 | 62 | function isAtDestination (threshold) { 63 | // square this so we don't need to use Math.sqrt 64 | threshold = threshold ? threshold * threshold : precision 65 | return ( 66 | vec4.squaredDistance(value, destinationValue) <= threshold && 67 | vec4.squaredDistance(value, lastValue) <= threshold 68 | ) 69 | } 70 | 71 | function getCurrentValue (out = []) { 72 | if (!isInputArray) return value[0] 73 | for (let i = 0; i < vecComponents; i++) { 74 | out[i] = value[i] 75 | } 76 | return out 77 | } 78 | 79 | function tick (s = stiffness, d = dampening) { 80 | vec4.subtract(velocity, value, lastValue) 81 | vec4.subtract(delta, destinationValue, value) 82 | vec4.scale(spring, delta, s) 83 | vec4.scale(damper, velocity, -d) 84 | vec4.add(acceleration, spring, damper) 85 | vec4.add(velocity, velocity, acceleration) 86 | vec4.add(nextValue, velocity, value) 87 | vec4.copy(lastValue, value) 88 | vec4.copy(value, nextValue) 89 | if (isAtDestination()) { 90 | vec4.copy(value, destinationValue) 91 | vec4.copy(lastValue, destinationValue) 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /lib/umd.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : 3 | typeof define === 'function' && define.amd ? define(['exports'], factory) : 4 | (global = global || self, factory(global.SpringAnimator = {})); 5 | }(this, function (exports) { 'use strict'; 6 | 7 | var create_1 = create; 8 | 9 | /** 10 | * Creates a new, empty vec4 11 | * 12 | * @returns {vec4} a new 4D vector 13 | */ 14 | function create () { 15 | var out = new Float32Array(4); 16 | out[0] = 0; 17 | out[1] = 0; 18 | out[2] = 0; 19 | out[3] = 0; 20 | return out 21 | } 22 | 23 | var clone_1 = clone; 24 | 25 | /** 26 | * Creates a new vec4 initialized with values from an existing vector 27 | * 28 | * @param {vec4} a vector to clone 29 | * @returns {vec4} a new 4D vector 30 | */ 31 | function clone (a) { 32 | var out = new Float32Array(4); 33 | out[0] = a[0]; 34 | out[1] = a[1]; 35 | out[2] = a[2]; 36 | out[3] = a[3]; 37 | return out 38 | } 39 | 40 | var fromValues_1 = fromValues; 41 | 42 | /** 43 | * Creates a new vec4 initialized with the given values 44 | * 45 | * @param {Number} x X component 46 | * @param {Number} y Y component 47 | * @param {Number} z Z component 48 | * @param {Number} w W component 49 | * @returns {vec4} a new 4D vector 50 | */ 51 | function fromValues (x, y, z, w) { 52 | var out = new Float32Array(4); 53 | out[0] = x; 54 | out[1] = y; 55 | out[2] = z; 56 | out[3] = w; 57 | return out 58 | } 59 | 60 | var copy_1 = copy; 61 | 62 | /** 63 | * Copy the values from one vec4 to another 64 | * 65 | * @param {vec4} out the receiving vector 66 | * @param {vec4} a the source vector 67 | * @returns {vec4} out 68 | */ 69 | function copy (out, a) { 70 | out[0] = a[0]; 71 | out[1] = a[1]; 72 | out[2] = a[2]; 73 | out[3] = a[3]; 74 | return out 75 | } 76 | 77 | var set_1 = set; 78 | 79 | /** 80 | * Set the components of a vec4 to the given values 81 | * 82 | * @param {vec4} out the receiving vector 83 | * @param {Number} x X component 84 | * @param {Number} y Y component 85 | * @param {Number} z Z component 86 | * @param {Number} w W component 87 | * @returns {vec4} out 88 | */ 89 | function set (out, x, y, z, w) { 90 | out[0] = x; 91 | out[1] = y; 92 | out[2] = z; 93 | out[3] = w; 94 | return out 95 | } 96 | 97 | var add_1 = add; 98 | 99 | /** 100 | * Adds two vec4's 101 | * 102 | * @param {vec4} out the receiving vector 103 | * @param {vec4} a the first operand 104 | * @param {vec4} b the second operand 105 | * @returns {vec4} out 106 | */ 107 | function add (out, a, b) { 108 | out[0] = a[0] + b[0]; 109 | out[1] = a[1] + b[1]; 110 | out[2] = a[2] + b[2]; 111 | out[3] = a[3] + b[3]; 112 | return out 113 | } 114 | 115 | var subtract_1 = subtract; 116 | 117 | /** 118 | * Subtracts vector b from vector a 119 | * 120 | * @param {vec4} out the receiving vector 121 | * @param {vec4} a the first operand 122 | * @param {vec4} b the second operand 123 | * @returns {vec4} out 124 | */ 125 | function subtract (out, a, b) { 126 | out[0] = a[0] - b[0]; 127 | out[1] = a[1] - b[1]; 128 | out[2] = a[2] - b[2]; 129 | out[3] = a[3] - b[3]; 130 | return out 131 | } 132 | 133 | var multiply_1 = multiply; 134 | 135 | /** 136 | * Multiplies two vec4's 137 | * 138 | * @param {vec4} out the receiving vector 139 | * @param {vec4} a the first operand 140 | * @param {vec4} b the second operand 141 | * @returns {vec4} out 142 | */ 143 | function multiply (out, a, b) { 144 | out[0] = a[0] * b[0]; 145 | out[1] = a[1] * b[1]; 146 | out[2] = a[2] * b[2]; 147 | out[3] = a[3] * b[3]; 148 | return out 149 | } 150 | 151 | var divide_1 = divide; 152 | 153 | /** 154 | * Divides two vec4's 155 | * 156 | * @param {vec4} out the receiving vector 157 | * @param {vec4} a the first operand 158 | * @param {vec4} b the second operand 159 | * @returns {vec4} out 160 | */ 161 | function divide (out, a, b) { 162 | out[0] = a[0] / b[0]; 163 | out[1] = a[1] / b[1]; 164 | out[2] = a[2] / b[2]; 165 | out[3] = a[3] / b[3]; 166 | return out 167 | } 168 | 169 | var min_1 = min; 170 | 171 | /** 172 | * Returns the minimum of two vec4's 173 | * 174 | * @param {vec4} out the receiving vector 175 | * @param {vec4} a the first operand 176 | * @param {vec4} b the second operand 177 | * @returns {vec4} out 178 | */ 179 | function min (out, a, b) { 180 | out[0] = Math.min(a[0], b[0]); 181 | out[1] = Math.min(a[1], b[1]); 182 | out[2] = Math.min(a[2], b[2]); 183 | out[3] = Math.min(a[3], b[3]); 184 | return out 185 | } 186 | 187 | var max_1 = max; 188 | 189 | /** 190 | * Returns the maximum of two vec4's 191 | * 192 | * @param {vec4} out the receiving vector 193 | * @param {vec4} a the first operand 194 | * @param {vec4} b the second operand 195 | * @returns {vec4} out 196 | */ 197 | function max (out, a, b) { 198 | out[0] = Math.max(a[0], b[0]); 199 | out[1] = Math.max(a[1], b[1]); 200 | out[2] = Math.max(a[2], b[2]); 201 | out[3] = Math.max(a[3], b[3]); 202 | return out 203 | } 204 | 205 | var scale_1 = scale; 206 | 207 | /** 208 | * Scales a vec4 by a scalar number 209 | * 210 | * @param {vec4} out the receiving vector 211 | * @param {vec4} a the vector to scale 212 | * @param {Number} b amount to scale the vector by 213 | * @returns {vec4} out 214 | */ 215 | function scale (out, a, b) { 216 | out[0] = a[0] * b; 217 | out[1] = a[1] * b; 218 | out[2] = a[2] * b; 219 | out[3] = a[3] * b; 220 | return out 221 | } 222 | 223 | var scaleAndAdd_1 = scaleAndAdd; 224 | 225 | /** 226 | * Adds two vec4's after scaling the second operand by a scalar value 227 | * 228 | * @param {vec4} out the receiving vector 229 | * @param {vec4} a the first operand 230 | * @param {vec4} b the second operand 231 | * @param {Number} scale the amount to scale b by before adding 232 | * @returns {vec4} out 233 | */ 234 | function scaleAndAdd (out, a, b, scale) { 235 | out[0] = a[0] + (b[0] * scale); 236 | out[1] = a[1] + (b[1] * scale); 237 | out[2] = a[2] + (b[2] * scale); 238 | out[3] = a[3] + (b[3] * scale); 239 | return out 240 | } 241 | 242 | var distance_1 = distance; 243 | 244 | /** 245 | * Calculates the euclidian distance between two vec4's 246 | * 247 | * @param {vec4} a the first operand 248 | * @param {vec4} b the second operand 249 | * @returns {Number} distance between a and b 250 | */ 251 | function distance (a, b) { 252 | var x = b[0] - a[0], 253 | y = b[1] - a[1], 254 | z = b[2] - a[2], 255 | w = b[3] - a[3]; 256 | return Math.sqrt(x * x + y * y + z * z + w * w) 257 | } 258 | 259 | var squaredDistance_1 = squaredDistance; 260 | 261 | /** 262 | * Calculates the squared euclidian distance between two vec4's 263 | * 264 | * @param {vec4} a the first operand 265 | * @param {vec4} b the second operand 266 | * @returns {Number} squared distance between a and b 267 | */ 268 | function squaredDistance (a, b) { 269 | var x = b[0] - a[0], 270 | y = b[1] - a[1], 271 | z = b[2] - a[2], 272 | w = b[3] - a[3]; 273 | return x * x + y * y + z * z + w * w 274 | } 275 | 276 | var length_1 = length; 277 | 278 | /** 279 | * Calculates the length of a vec4 280 | * 281 | * @param {vec4} a vector to calculate length of 282 | * @returns {Number} length of a 283 | */ 284 | function length (a) { 285 | var x = a[0], 286 | y = a[1], 287 | z = a[2], 288 | w = a[3]; 289 | return Math.sqrt(x * x + y * y + z * z + w * w) 290 | } 291 | 292 | var squaredLength_1 = squaredLength; 293 | 294 | /** 295 | * Calculates the squared length of a vec4 296 | * 297 | * @param {vec4} a vector to calculate squared length of 298 | * @returns {Number} squared length of a 299 | */ 300 | function squaredLength (a) { 301 | var x = a[0], 302 | y = a[1], 303 | z = a[2], 304 | w = a[3]; 305 | return x * x + y * y + z * z + w * w 306 | } 307 | 308 | var negate_1 = negate; 309 | 310 | /** 311 | * Negates the components of a vec4 312 | * 313 | * @param {vec4} out the receiving vector 314 | * @param {vec4} a vector to negate 315 | * @returns {vec4} out 316 | */ 317 | function negate (out, a) { 318 | out[0] = -a[0]; 319 | out[1] = -a[1]; 320 | out[2] = -a[2]; 321 | out[3] = -a[3]; 322 | return out 323 | } 324 | 325 | var inverse_1 = inverse; 326 | 327 | /** 328 | * Returns the inverse of the components of a vec4 329 | * 330 | * @param {vec4} out the receiving vector 331 | * @param {vec4} a vector to invert 332 | * @returns {vec4} out 333 | */ 334 | function inverse (out, a) { 335 | out[0] = 1.0 / a[0]; 336 | out[1] = 1.0 / a[1]; 337 | out[2] = 1.0 / a[2]; 338 | out[3] = 1.0 / a[3]; 339 | return out 340 | } 341 | 342 | var normalize_1 = normalize; 343 | 344 | /** 345 | * Normalize a vec4 346 | * 347 | * @param {vec4} out the receiving vector 348 | * @param {vec4} a vector to normalize 349 | * @returns {vec4} out 350 | */ 351 | function normalize (out, a) { 352 | var x = a[0], 353 | y = a[1], 354 | z = a[2], 355 | w = a[3]; 356 | var len = x * x + y * y + z * z + w * w; 357 | if (len > 0) { 358 | len = 1 / Math.sqrt(len); 359 | out[0] = x * len; 360 | out[1] = y * len; 361 | out[2] = z * len; 362 | out[3] = w * len; 363 | } 364 | return out 365 | } 366 | 367 | var dot_1 = dot; 368 | 369 | /** 370 | * Calculates the dot product of two vec4's 371 | * 372 | * @param {vec4} a the first operand 373 | * @param {vec4} b the second operand 374 | * @returns {Number} dot product of a and b 375 | */ 376 | function dot (a, b) { 377 | return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3] 378 | } 379 | 380 | var lerp_1 = lerp; 381 | 382 | /** 383 | * Performs a linear interpolation between two vec4's 384 | * 385 | * @param {vec4} out the receiving vector 386 | * @param {vec4} a the first operand 387 | * @param {vec4} b the second operand 388 | * @param {Number} t interpolation amount between the two inputs 389 | * @returns {vec4} out 390 | */ 391 | function lerp (out, a, b, t) { 392 | var ax = a[0], 393 | ay = a[1], 394 | az = a[2], 395 | aw = a[3]; 396 | out[0] = ax + t * (b[0] - ax); 397 | out[1] = ay + t * (b[1] - ay); 398 | out[2] = az + t * (b[2] - az); 399 | out[3] = aw + t * (b[3] - aw); 400 | return out 401 | } 402 | 403 | var random_1 = random; 404 | 405 | /** 406 | * Generates a random vector with the given scale 407 | * 408 | * @param {vec4} out the receiving vector 409 | * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned 410 | * @returns {vec4} out 411 | */ 412 | function random (out, scale) { 413 | scale = scale || 1.0; 414 | 415 | // TODO: This is a pretty awful way of doing this. Find something better. 416 | out[0] = Math.random(); 417 | out[1] = Math.random(); 418 | out[2] = Math.random(); 419 | out[3] = Math.random(); 420 | normalize_1(out, out); 421 | scale_1(out, out, scale); 422 | return out 423 | } 424 | 425 | var transformMat4_1 = transformMat4; 426 | 427 | /** 428 | * Transforms the vec4 with a mat4. 429 | * 430 | * @param {vec4} out the receiving vector 431 | * @param {vec4} a the vector to transform 432 | * @param {mat4} m matrix to transform with 433 | * @returns {vec4} out 434 | */ 435 | function transformMat4 (out, a, m) { 436 | var x = a[0], y = a[1], z = a[2], w = a[3]; 437 | out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w; 438 | out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w; 439 | out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w; 440 | out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w; 441 | return out 442 | } 443 | 444 | var transformQuat_1 = transformQuat; 445 | 446 | /** 447 | * Transforms the vec4 with a quat 448 | * 449 | * @param {vec4} out the receiving vector 450 | * @param {vec4} a the vector to transform 451 | * @param {quat} q quaternion to transform with 452 | * @returns {vec4} out 453 | */ 454 | function transformQuat (out, a, q) { 455 | var x = a[0], y = a[1], z = a[2], 456 | qx = q[0], qy = q[1], qz = q[2], qw = q[3], 457 | 458 | // calculate quat * vec 459 | ix = qw * x + qy * z - qz * y, 460 | iy = qw * y + qz * x - qx * z, 461 | iz = qw * z + qx * y - qy * x, 462 | iw = -qx * x - qy * y - qz * z; 463 | 464 | // calculate result * inverse quat 465 | out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; 466 | out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; 467 | out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; 468 | out[3] = a[3]; 469 | return out 470 | } 471 | 472 | var glVec4 = { 473 | create: create_1, 474 | clone: clone_1, 475 | fromValues: fromValues_1, 476 | copy: copy_1, 477 | set: set_1, 478 | add: add_1, 479 | subtract: subtract_1, 480 | multiply: multiply_1, 481 | divide: divide_1, 482 | min: min_1, 483 | max: max_1, 484 | scale: scale_1, 485 | scaleAndAdd: scaleAndAdd_1, 486 | distance: distance_1, 487 | squaredDistance: squaredDistance_1, 488 | length: length_1, 489 | squaredLength: squaredLength_1, 490 | negate: negate_1, 491 | inverse: inverse_1, 492 | normalize: normalize_1, 493 | dot: dot_1, 494 | lerp: lerp_1, 495 | random: random_1, 496 | transformMat4: transformMat4_1, 497 | transformQuat: transformQuat_1 498 | }; 499 | 500 | function createSpring (stiffness, dampening, value, precision) { 501 | precision = precision ? precision * precision : Number.EPSILON; 502 | const isInputArray = Array.isArray(value); 503 | const vecComponents = isInputArray ? value.length : Number.isFinite(value) ? 1 : null; 504 | 505 | if (!Number.isFinite(stiffness) || !Number.isFinite(dampening)) { 506 | throw new Error(`spring-animator: expected numbers for stiffness and dampening. (e.g. createSpring(0.003, 0.1, startingValue))`) 507 | } 508 | 509 | if (!vecComponents || vecComponents > 4) { 510 | throw new Error(`spring-animator: expected value \`${value}\` to be a scalar, vec2, vec3, or vec4`) 511 | } 512 | 513 | function makeValueVec4 (out = [], v) { 514 | if (isInputArray !== Array.isArray(v) || (isInputArray && vecComponents !== v.length)) { 515 | throw new Error(`spring-animator: destination value type must match initial value type: ${!isInputArray ? 'scalar' : vecComponents + '-component vector'}`) 516 | } 517 | if (Number.isFinite(v)) { 518 | out[0] = v; 519 | out[1] = out[2] = out[3] = 0; 520 | return out 521 | } 522 | glVec4.copy(out, v); 523 | while (out.length < 4) out.push(0); 524 | return out 525 | } 526 | 527 | value = makeValueVec4([], value); 528 | let lastValue = glVec4.copy([], value); 529 | let destinationValue = glVec4.copy([], value); 530 | 531 | // set up some reusable arrays to use in tick() 532 | let nextValue = []; 533 | let velocity = []; 534 | let delta = []; 535 | let spring = []; 536 | let damper = []; 537 | let acceleration = []; 538 | 539 | return { 540 | setDestination, 541 | getCurrentValue, 542 | isAtDestination, 543 | tick 544 | } 545 | 546 | function setDestination (newValue, shouldAnimate = true) { 547 | makeValueVec4(destinationValue, newValue); 548 | if (!shouldAnimate) { 549 | glVec4.copy(value, destinationValue); 550 | glVec4.copy(lastValue, destinationValue); 551 | } 552 | } 553 | 554 | function isAtDestination (threshold) { 555 | // square this so we don't need to use Math.sqrt 556 | threshold = threshold ? threshold * threshold : precision; 557 | return ( 558 | glVec4.squaredDistance(value, destinationValue) <= threshold && 559 | glVec4.squaredDistance(value, lastValue) <= threshold 560 | ) 561 | } 562 | 563 | function getCurrentValue (out = []) { 564 | if (!isInputArray) return value[0] 565 | for (let i = 0; i < vecComponents; i++) { 566 | out[i] = value[i]; 567 | } 568 | return out 569 | } 570 | 571 | function tick (s = stiffness, d = dampening) { 572 | glVec4.subtract(velocity, value, lastValue); 573 | glVec4.subtract(delta, destinationValue, value); 574 | glVec4.scale(spring, delta, s); 575 | glVec4.scale(damper, velocity, -d); 576 | glVec4.add(acceleration, spring, damper); 577 | glVec4.add(velocity, velocity, acceleration); 578 | glVec4.add(nextValue, velocity, value); 579 | glVec4.copy(lastValue, value); 580 | glVec4.copy(value, nextValue); 581 | if (isAtDestination()) { 582 | glVec4.copy(value, destinationValue); 583 | glVec4.copy(lastValue, destinationValue); 584 | } 585 | } 586 | } 587 | 588 | exports.createSpring = createSpring; 589 | 590 | Object.defineProperty(exports, '__esModule', { value: true }); 591 | 592 | })); 593 | //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidW1kLmpzIiwic291cmNlcyI6WyIuLi9ub2RlX21vZHVsZXMvZ2wtdmVjNC9jcmVhdGUuanMiLCIuLi9ub2RlX21vZHVsZXMvZ2wtdmVjNC9jbG9uZS5qcyIsIi4uL25vZGVfbW9kdWxlcy9nbC12ZWM0L2Zyb21WYWx1ZXMuanMiLCIuLi9ub2RlX21vZHVsZXMvZ2wtdmVjNC9jb3B5LmpzIiwiLi4vbm9kZV9tb2R1bGVzL2dsLXZlYzQvc2V0LmpzIiwiLi4vbm9kZV9tb2R1bGVzL2dsLXZlYzQvYWRkLmpzIiwiLi4vbm9kZV9tb2R1bGVzL2dsLXZlYzQvc3VidHJhY3QuanMiLCIuLi9ub2RlX21vZHVsZXMvZ2wtdmVjNC9tdWx0aXBseS5qcyIsIi4uL25vZGVfbW9kdWxlcy9nbC12ZWM0L2RpdmlkZS5qcyIsIi4uL25vZGVfbW9kdWxlcy9nbC12ZWM0L21pbi5qcyIsIi4uL25vZGVfbW9kdWxlcy9nbC12ZWM0L21heC5qcyIsIi4uL25vZGVfbW9kdWxlcy9nbC12ZWM0L3NjYWxlLmpzIiwiLi4vbm9kZV9tb2R1bGVzL2dsLXZlYzQvc2NhbGVBbmRBZGQuanMiLCIuLi9ub2RlX21vZHVsZXMvZ2wtdmVjNC9kaXN0YW5jZS5qcyIsIi4uL25vZGVfbW9kdWxlcy9nbC12ZWM0L3NxdWFyZWREaXN0YW5jZS5qcyIsIi4uL25vZGVfbW9kdWxlcy9nbC12ZWM0L2xlbmd0aC5qcyIsIi4uL25vZGVfbW9kdWxlcy9nbC12ZWM0L3NxdWFyZWRMZW5ndGguanMiLCIuLi9ub2RlX21vZHVsZXMvZ2wtdmVjNC9uZWdhdGUuanMiLCIuLi9ub2RlX21vZHVsZXMvZ2wtdmVjNC9pbnZlcnNlLmpzIiwiLi4vbm9kZV9tb2R1bGVzL2dsLXZlYzQvbm9ybWFsaXplLmpzIiwiLi4vbm9kZV9tb2R1bGVzL2dsLXZlYzQvZG90LmpzIiwiLi4vbm9kZV9tb2R1bGVzL2dsLXZlYzQvbGVycC5qcyIsIi4uL25vZGVfbW9kdWxlcy9nbC12ZWM0L3JhbmRvbS5qcyIsIi4uL25vZGVfbW9kdWxlcy9nbC12ZWM0L3RyYW5zZm9ybU1hdDQuanMiLCIuLi9ub2RlX21vZHVsZXMvZ2wtdmVjNC90cmFuc2Zvcm1RdWF0LmpzIiwiLi4vbm9kZV9tb2R1bGVzL2dsLXZlYzQvaW5kZXguanMiLCIuLi9zcmMvaW5kZXguanMiXSwic291cmNlc0NvbnRlbnQiOlsibW9kdWxlLmV4cG9ydHMgPSBjcmVhdGVcblxuLyoqXG4gKiBDcmVhdGVzIGEgbmV3LCBlbXB0eSB2ZWM0XG4gKlxuICogQHJldHVybnMge3ZlYzR9IGEgbmV3IDREIHZlY3RvclxuICovXG5mdW5jdGlvbiBjcmVhdGUgKCkge1xuICB2YXIgb3V0ID0gbmV3IEZsb2F0MzJBcnJheSg0KVxuICBvdXRbMF0gPSAwXG4gIG91dFsxXSA9IDBcbiAgb3V0WzJdID0gMFxuICBvdXRbM10gPSAwXG4gIHJldHVybiBvdXRcbn1cbiIsIm1vZHVsZS5leHBvcnRzID0gY2xvbmVcblxuLyoqXG4gKiBDcmVhdGVzIGEgbmV3IHZlYzQgaW5pdGlhbGl6ZWQgd2l0aCB2YWx1ZXMgZnJvbSBhbiBleGlzdGluZyB2ZWN0b3JcbiAqXG4gKiBAcGFyYW0ge3ZlYzR9IGEgdmVjdG9yIHRvIGNsb25lXG4gKiBAcmV0dXJucyB7dmVjNH0gYSBuZXcgNEQgdmVjdG9yXG4gKi9cbmZ1bmN0aW9uIGNsb25lIChhKSB7XG4gIHZhciBvdXQgPSBuZXcgRmxvYXQzMkFycmF5KDQpXG4gIG91dFswXSA9IGFbMF1cbiAgb3V0WzFdID0gYVsxXVxuICBvdXRbMl0gPSBhWzJdXG4gIG91dFszXSA9IGFbM11cbiAgcmV0dXJuIG91dFxufVxuIiwibW9kdWxlLmV4cG9ydHMgPSBmcm9tVmFsdWVzXG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldyB2ZWM0IGluaXRpYWxpemVkIHdpdGggdGhlIGdpdmVuIHZhbHVlc1xuICpcbiAqIEBwYXJhbSB7TnVtYmVyfSB4IFggY29tcG9uZW50XG4gKiBAcGFyYW0ge051bWJlcn0geSBZIGNvbXBvbmVudFxuICogQHBhcmFtIHtOdW1iZXJ9IHogWiBjb21wb25lbnRcbiAqIEBwYXJhbSB7TnVtYmVyfSB3IFcgY29tcG9uZW50XG4gKiBAcmV0dXJucyB7dmVjNH0gYSBuZXcgNEQgdmVjdG9yXG4gKi9cbmZ1bmN0aW9uIGZyb21WYWx1ZXMgKHgsIHksIHosIHcpIHtcbiAgdmFyIG91dCA9IG5ldyBGbG9hdDMyQXJyYXkoNClcbiAgb3V0WzBdID0geFxuICBvdXRbMV0gPSB5XG4gIG91dFsyXSA9IHpcbiAgb3V0WzNdID0gd1xuICByZXR1cm4gb3V0XG59XG4iLCJtb2R1bGUuZXhwb3J0cyA9IGNvcHlcblxuLyoqXG4gKiBDb3B5IHRoZSB2YWx1ZXMgZnJvbSBvbmUgdmVjNCB0byBhbm90aGVyXG4gKlxuICogQHBhcmFtIHt2ZWM0fSBvdXQgdGhlIHJlY2VpdmluZyB2ZWN0b3JcbiAqIEBwYXJhbSB7dmVjNH0gYSB0aGUgc291cmNlIHZlY3RvclxuICogQHJldHVybnMge3ZlYzR9IG91dFxuICovXG5mdW5jdGlvbiBjb3B5IChvdXQsIGEpIHtcbiAgb3V0WzBdID0gYVswXVxuICBvdXRbMV0gPSBhWzFdXG4gIG91dFsyXSA9IGFbMl1cbiAgb3V0WzNdID0gYVszXVxuICByZXR1cm4gb3V0XG59XG4iLCJtb2R1bGUuZXhwb3J0cyA9IHNldFxuXG4vKipcbiAqIFNldCB0aGUgY29tcG9uZW50cyBvZiBhIHZlYzQgdG8gdGhlIGdpdmVuIHZhbHVlc1xuICpcbiAqIEBwYXJhbSB7dmVjNH0gb3V0IHRoZSByZWNlaXZpbmcgdmVjdG9yXG4gKiBAcGFyYW0ge051bWJlcn0geCBYIGNvbXBvbmVudFxuICogQHBhcmFtIHtOdW1iZXJ9IHkgWSBjb21wb25lbnRcbiAqIEBwYXJhbSB7TnVtYmVyfSB6IFogY29tcG9uZW50XG4gKiBAcGFyYW0ge051bWJlcn0gdyBXIGNvbXBvbmVudFxuICogQHJldHVybnMge3ZlYzR9IG91dFxuICovXG5mdW5jdGlvbiBzZXQgKG91dCwgeCwgeSwgeiwgdykge1xuICBvdXRbMF0gPSB4XG4gIG91dFsxXSA9IHlcbiAgb3V0WzJdID0gelxuICBvdXRbM10gPSB3XG4gIHJldHVybiBvdXRcbn1cbiIsIm1vZHVsZS5leHBvcnRzID0gYWRkXG5cbi8qKlxuICogQWRkcyB0d28gdmVjNCdzXG4gKlxuICogQHBhcmFtIHt2ZWM0fSBvdXQgdGhlIHJlY2VpdmluZyB2ZWN0b3JcbiAqIEBwYXJhbSB7dmVjNH0gYSB0aGUgZmlyc3Qgb3BlcmFuZFxuICogQHBhcmFtIHt2ZWM0fSBiIHRoZSBzZWNvbmQgb3BlcmFuZFxuICogQHJldHVybnMge3ZlYzR9IG91dFxuICovXG5mdW5jdGlvbiBhZGQgKG91dCwgYSwgYikge1xuICBvdXRbMF0gPSBhWzBdICsgYlswXVxuICBvdXRbMV0gPSBhWzFdICsgYlsxXVxuICBvdXRbMl0gPSBhWzJdICsgYlsyXVxuICBvdXRbM10gPSBhWzNdICsgYlszXVxuICByZXR1cm4gb3V0XG59XG4iLCJtb2R1bGUuZXhwb3J0cyA9IHN1YnRyYWN0XG5cbi8qKlxuICogU3VidHJhY3RzIHZlY3RvciBiIGZyb20gdmVjdG9yIGFcbiAqXG4gKiBAcGFyYW0ge3ZlYzR9IG91dCB0aGUgcmVjZWl2aW5nIHZlY3RvclxuICogQHBhcmFtIHt2ZWM0fSBhIHRoZSBmaXJzdCBvcGVyYW5kXG4gKiBAcGFyYW0ge3ZlYzR9IGIgdGhlIHNlY29uZCBvcGVyYW5kXG4gKiBAcmV0dXJucyB7dmVjNH0gb3V0XG4gKi9cbmZ1bmN0aW9uIHN1YnRyYWN0IChvdXQsIGEsIGIpIHtcbiAgb3V0WzBdID0gYVswXSAtIGJbMF1cbiAgb3V0WzFdID0gYVsxXSAtIGJbMV1cbiAgb3V0WzJdID0gYVsyXSAtIGJbMl1cbiAgb3V0WzNdID0gYVszXSAtIGJbM11cbiAgcmV0dXJuIG91dFxufVxuIiwibW9kdWxlLmV4cG9ydHMgPSBtdWx0aXBseVxuXG4vKipcbiAqIE11bHRpcGxpZXMgdHdvIHZlYzQnc1xuICpcbiAqIEBwYXJhbSB7dmVjNH0gb3V0IHRoZSByZWNlaXZpbmcgdmVjdG9yXG4gKiBAcGFyYW0ge3ZlYzR9IGEgdGhlIGZpcnN0IG9wZXJhbmRcbiAqIEBwYXJhbSB7dmVjNH0gYiB0aGUgc2Vjb25kIG9wZXJhbmRcbiAqIEByZXR1cm5zIHt2ZWM0fSBvdXRcbiAqL1xuZnVuY3Rpb24gbXVsdGlwbHkgKG91dCwgYSwgYikge1xuICBvdXRbMF0gPSBhWzBdICogYlswXVxuICBvdXRbMV0gPSBhWzFdICogYlsxXVxuICBvdXRbMl0gPSBhWzJdICogYlsyXVxuICBvdXRbM10gPSBhWzNdICogYlszXVxuICByZXR1cm4gb3V0XG59XG4iLCJtb2R1bGUuZXhwb3J0cyA9IGRpdmlkZVxuXG4vKipcbiAqIERpdmlkZXMgdHdvIHZlYzQnc1xuICpcbiAqIEBwYXJhbSB7dmVjNH0gb3V0IHRoZSByZWNlaXZpbmcgdmVjdG9yXG4gKiBAcGFyYW0ge3ZlYzR9IGEgdGhlIGZpcnN0IG9wZXJhbmRcbiAqIEBwYXJhbSB7dmVjNH0gYiB0aGUgc2Vjb25kIG9wZXJhbmRcbiAqIEByZXR1cm5zIHt2ZWM0fSBvdXRcbiAqL1xuZnVuY3Rpb24gZGl2aWRlIChvdXQsIGEsIGIpIHtcbiAgb3V0WzBdID0gYVswXSAvIGJbMF1cbiAgb3V0WzFdID0gYVsxXSAvIGJbMV1cbiAgb3V0WzJdID0gYVsyXSAvIGJbMl1cbiAgb3V0WzNdID0gYVszXSAvIGJbM11cbiAgcmV0dXJuIG91dFxufVxuIiwibW9kdWxlLmV4cG9ydHMgPSBtaW5cblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBtaW5pbXVtIG9mIHR3byB2ZWM0J3NcbiAqXG4gKiBAcGFyYW0ge3ZlYzR9IG91dCB0aGUgcmVjZWl2aW5nIHZlY3RvclxuICogQHBhcmFtIHt2ZWM0fSBhIHRoZSBmaXJzdCBvcGVyYW5kXG4gKiBAcGFyYW0ge3ZlYzR9IGIgdGhlIHNlY29uZCBvcGVyYW5kXG4gKiBAcmV0dXJucyB7dmVjNH0gb3V0XG4gKi9cbmZ1bmN0aW9uIG1pbiAob3V0LCBhLCBiKSB7XG4gIG91dFswXSA9IE1hdGgubWluKGFbMF0sIGJbMF0pXG4gIG91dFsxXSA9IE1hdGgubWluKGFbMV0sIGJbMV0pXG4gIG91dFsyXSA9IE1hdGgubWluKGFbMl0sIGJbMl0pXG4gIG91dFszXSA9IE1hdGgubWluKGFbM10sIGJbM10pXG4gIHJldHVybiBvdXRcbn1cbiIsIm1vZHVsZS5leHBvcnRzID0gbWF4XG5cbi8qKlxuICogUmV0dXJucyB0aGUgbWF4aW11bSBvZiB0d28gdmVjNCdzXG4gKlxuICogQHBhcmFtIHt2ZWM0fSBvdXQgdGhlIHJlY2VpdmluZyB2ZWN0b3JcbiAqIEBwYXJhbSB7dmVjNH0gYSB0aGUgZmlyc3Qgb3BlcmFuZFxuICogQHBhcmFtIHt2ZWM0fSBiIHRoZSBzZWNvbmQgb3BlcmFuZFxuICogQHJldHVybnMge3ZlYzR9IG91dFxuICovXG5mdW5jdGlvbiBtYXggKG91dCwgYSwgYikge1xuICBvdXRbMF0gPSBNYXRoLm1heChhWzBdLCBiWzBdKVxuICBvdXRbMV0gPSBNYXRoLm1heChhWzFdLCBiWzFdKVxuICBvdXRbMl0gPSBNYXRoLm1heChhWzJdLCBiWzJdKVxuICBvdXRbM10gPSBNYXRoLm1heChhWzNdLCBiWzNdKVxuICByZXR1cm4gb3V0XG59XG4iLCJtb2R1bGUuZXhwb3J0cyA9IHNjYWxlXG5cbi8qKlxuICogU2NhbGVzIGEgdmVjNCBieSBhIHNjYWxhciBudW1iZXJcbiAqXG4gKiBAcGFyYW0ge3ZlYzR9IG91dCB0aGUgcmVjZWl2aW5nIHZlY3RvclxuICogQHBhcmFtIHt2ZWM0fSBhIHRoZSB2ZWN0b3IgdG8gc2NhbGVcbiAqIEBwYXJhbSB7TnVtYmVyfSBiIGFtb3VudCB0byBzY2FsZSB0aGUgdmVjdG9yIGJ5XG4gKiBAcmV0dXJucyB7dmVjNH0gb3V0XG4gKi9cbmZ1bmN0aW9uIHNjYWxlIChvdXQsIGEsIGIpIHtcbiAgb3V0WzBdID0gYVswXSAqIGJcbiAgb3V0WzFdID0gYVsxXSAqIGJcbiAgb3V0WzJdID0gYVsyXSAqIGJcbiAgb3V0WzNdID0gYVszXSAqIGJcbiAgcmV0dXJuIG91dFxufVxuIiwibW9kdWxlLmV4cG9ydHMgPSBzY2FsZUFuZEFkZFxuXG4vKipcbiAqIEFkZHMgdHdvIHZlYzQncyBhZnRlciBzY2FsaW5nIHRoZSBzZWNvbmQgb3BlcmFuZCBieSBhIHNjYWxhciB2YWx1ZVxuICpcbiAqIEBwYXJhbSB7dmVjNH0gb3V0IHRoZSByZWNlaXZpbmcgdmVjdG9yXG4gKiBAcGFyYW0ge3ZlYzR9IGEgdGhlIGZpcnN0IG9wZXJhbmRcbiAqIEBwYXJhbSB7dmVjNH0gYiB0aGUgc2Vjb25kIG9wZXJhbmRcbiAqIEBwYXJhbSB7TnVtYmVyfSBzY2FsZSB0aGUgYW1vdW50IHRvIHNjYWxlIGIgYnkgYmVmb3JlIGFkZGluZ1xuICogQHJldHVybnMge3ZlYzR9IG91dFxuICovXG5mdW5jdGlvbiBzY2FsZUFuZEFkZCAob3V0LCBhLCBiLCBzY2FsZSkge1xuICBvdXRbMF0gPSBhWzBdICsgKGJbMF0gKiBzY2FsZSlcbiAgb3V0WzFdID0gYVsxXSArIChiWzFdICogc2NhbGUpXG4gIG91dFsyXSA9IGFbMl0gKyAoYlsyXSAqIHNjYWxlKVxuICBvdXRbM10gPSBhWzNdICsgKGJbM10gKiBzY2FsZSlcbiAgcmV0dXJuIG91dFxufVxuIiwibW9kdWxlLmV4cG9ydHMgPSBkaXN0YW5jZVxuXG4vKipcbiAqIENhbGN1bGF0ZXMgdGhlIGV1Y2xpZGlhbiBkaXN0YW5jZSBiZXR3ZWVuIHR3byB2ZWM0J3NcbiAqXG4gKiBAcGFyYW0ge3ZlYzR9IGEgdGhlIGZpcnN0IG9wZXJhbmRcbiAqIEBwYXJhbSB7dmVjNH0gYiB0aGUgc2Vjb25kIG9wZXJhbmRcbiAqIEByZXR1cm5zIHtOdW1iZXJ9IGRpc3RhbmNlIGJldHdlZW4gYSBhbmQgYlxuICovXG5mdW5jdGlvbiBkaXN0YW5jZSAoYSwgYikge1xuICB2YXIgeCA9IGJbMF0gLSBhWzBdLFxuICAgIHkgPSBiWzFdIC0gYVsxXSxcbiAgICB6ID0gYlsyXSAtIGFbMl0sXG4gICAgdyA9IGJbM10gLSBhWzNdXG4gIHJldHVybiBNYXRoLnNxcnQoeCAqIHggKyB5ICogeSArIHogKiB6ICsgdyAqIHcpXG59XG4iLCJtb2R1bGUuZXhwb3J0cyA9IHNxdWFyZWREaXN0YW5jZVxuXG4vKipcbiAqIENhbGN1bGF0ZXMgdGhlIHNxdWFyZWQgZXVjbGlkaWFuIGRpc3RhbmNlIGJldHdlZW4gdHdvIHZlYzQnc1xuICpcbiAqIEBwYXJhbSB7dmVjNH0gYSB0aGUgZmlyc3Qgb3BlcmFuZFxuICogQHBhcmFtIHt2ZWM0fSBiIHRoZSBzZWNvbmQgb3BlcmFuZFxuICogQHJldHVybnMge051bWJlcn0gc3F1YXJlZCBkaXN0YW5jZSBiZXR3ZWVuIGEgYW5kIGJcbiAqL1xuZnVuY3Rpb24gc3F1YXJlZERpc3RhbmNlIChhLCBiKSB7XG4gIHZhciB4ID0gYlswXSAtIGFbMF0sXG4gICAgeSA9IGJbMV0gLSBhWzFdLFxuICAgIHogPSBiWzJdIC0gYVsyXSxcbiAgICB3ID0gYlszXSAtIGFbM11cbiAgcmV0dXJuIHggKiB4ICsgeSAqIHkgKyB6ICogeiArIHcgKiB3XG59XG4iLCJtb2R1bGUuZXhwb3J0cyA9IGxlbmd0aFxuXG4vKipcbiAqIENhbGN1bGF0ZXMgdGhlIGxlbmd0aCBvZiBhIHZlYzRcbiAqXG4gKiBAcGFyYW0ge3ZlYzR9IGEgdmVjdG9yIHRvIGNhbGN1bGF0ZSBsZW5ndGggb2ZcbiAqIEByZXR1cm5zIHtOdW1iZXJ9IGxlbmd0aCBvZiBhXG4gKi9cbmZ1bmN0aW9uIGxlbmd0aCAoYSkge1xuICB2YXIgeCA9IGFbMF0sXG4gICAgeSA9IGFbMV0sXG4gICAgeiA9IGFbMl0sXG4gICAgdyA9IGFbM11cbiAgcmV0dXJuIE1hdGguc3FydCh4ICogeCArIHkgKiB5ICsgeiAqIHogKyB3ICogdylcbn1cbiIsIm1vZHVsZS5leHBvcnRzID0gc3F1YXJlZExlbmd0aFxuXG4vKipcbiAqIENhbGN1bGF0ZXMgdGhlIHNxdWFyZWQgbGVuZ3RoIG9mIGEgdmVjNFxuICpcbiAqIEBwYXJhbSB7dmVjNH0gYSB2ZWN0b3IgdG8gY2FsY3VsYXRlIHNxdWFyZWQgbGVuZ3RoIG9mXG4gKiBAcmV0dXJucyB7TnVtYmVyfSBzcXVhcmVkIGxlbmd0aCBvZiBhXG4gKi9cbmZ1bmN0aW9uIHNxdWFyZWRMZW5ndGggKGEpIHtcbiAgdmFyIHggPSBhWzBdLFxuICAgIHkgPSBhWzFdLFxuICAgIHogPSBhWzJdLFxuICAgIHcgPSBhWzNdXG4gIHJldHVybiB4ICogeCArIHkgKiB5ICsgeiAqIHogKyB3ICogd1xufVxuIiwibW9kdWxlLmV4cG9ydHMgPSBuZWdhdGVcblxuLyoqXG4gKiBOZWdhdGVzIHRoZSBjb21wb25lbnRzIG9mIGEgdmVjNFxuICpcbiAqIEBwYXJhbSB7dmVjNH0gb3V0IHRoZSByZWNlaXZpbmcgdmVjdG9yXG4gKiBAcGFyYW0ge3ZlYzR9IGEgdmVjdG9yIHRvIG5lZ2F0ZVxuICogQHJldHVybnMge3ZlYzR9IG91dFxuICovXG5mdW5jdGlvbiBuZWdhdGUgKG91dCwgYSkge1xuICBvdXRbMF0gPSAtYVswXVxuICBvdXRbMV0gPSAtYVsxXVxuICBvdXRbMl0gPSAtYVsyXVxuICBvdXRbM10gPSAtYVszXVxuICByZXR1cm4gb3V0XG59XG4iLCJtb2R1bGUuZXhwb3J0cyA9IGludmVyc2VcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBpbnZlcnNlIG9mIHRoZSBjb21wb25lbnRzIG9mIGEgdmVjNFxuICpcbiAqIEBwYXJhbSB7dmVjNH0gb3V0IHRoZSByZWNlaXZpbmcgdmVjdG9yXG4gKiBAcGFyYW0ge3ZlYzR9IGEgdmVjdG9yIHRvIGludmVydFxuICogQHJldHVybnMge3ZlYzR9IG91dFxuICovXG5mdW5jdGlvbiBpbnZlcnNlIChvdXQsIGEpIHtcbiAgb3V0WzBdID0gMS4wIC8gYVswXVxuICBvdXRbMV0gPSAxLjAgLyBhWzFdXG4gIG91dFsyXSA9IDEuMCAvIGFbMl1cbiAgb3V0WzNdID0gMS4wIC8gYVszXVxuICByZXR1cm4gb3V0XG59XG4iLCJtb2R1bGUuZXhwb3J0cyA9IG5vcm1hbGl6ZVxuXG4vKipcbiAqIE5vcm1hbGl6ZSBhIHZlYzRcbiAqXG4gKiBAcGFyYW0ge3ZlYzR9IG91dCB0aGUgcmVjZWl2aW5nIHZlY3RvclxuICogQHBhcmFtIHt2ZWM0fSBhIHZlY3RvciB0byBub3JtYWxpemVcbiAqIEByZXR1cm5zIHt2ZWM0fSBvdXRcbiAqL1xuZnVuY3Rpb24gbm9ybWFsaXplIChvdXQsIGEpIHtcbiAgdmFyIHggPSBhWzBdLFxuICAgIHkgPSBhWzFdLFxuICAgIHogPSBhWzJdLFxuICAgIHcgPSBhWzNdXG4gIHZhciBsZW4gPSB4ICogeCArIHkgKiB5ICsgeiAqIHogKyB3ICogd1xuICBpZiAobGVuID4gMCkge1xuICAgIGxlbiA9IDEgLyBNYXRoLnNxcnQobGVuKVxuICAgIG91dFswXSA9IHggKiBsZW5cbiAgICBvdXRbMV0gPSB5ICogbGVuXG4gICAgb3V0WzJdID0geiAqIGxlblxuICAgIG91dFszXSA9IHcgKiBsZW5cbiAgfVxuICByZXR1cm4gb3V0XG59XG4iLCJtb2R1bGUuZXhwb3J0cyA9IGRvdFxuXG4vKipcbiAqIENhbGN1bGF0ZXMgdGhlIGRvdCBwcm9kdWN0IG9mIHR3byB2ZWM0J3NcbiAqXG4gKiBAcGFyYW0ge3ZlYzR9IGEgdGhlIGZpcnN0IG9wZXJhbmRcbiAqIEBwYXJhbSB7dmVjNH0gYiB0aGUgc2Vjb25kIG9wZXJhbmRcbiAqIEByZXR1cm5zIHtOdW1iZXJ9IGRvdCBwcm9kdWN0IG9mIGEgYW5kIGJcbiAqL1xuZnVuY3Rpb24gZG90IChhLCBiKSB7XG4gIHJldHVybiBhWzBdICogYlswXSArIGFbMV0gKiBiWzFdICsgYVsyXSAqIGJbMl0gKyBhWzNdICogYlszXVxufVxuIiwibW9kdWxlLmV4cG9ydHMgPSBsZXJwXG5cbi8qKlxuICogUGVyZm9ybXMgYSBsaW5lYXIgaW50ZXJwb2xhdGlvbiBiZXR3ZWVuIHR3byB2ZWM0J3NcbiAqXG4gKiBAcGFyYW0ge3ZlYzR9IG91dCB0aGUgcmVjZWl2aW5nIHZlY3RvclxuICogQHBhcmFtIHt2ZWM0fSBhIHRoZSBmaXJzdCBvcGVyYW5kXG4gKiBAcGFyYW0ge3ZlYzR9IGIgdGhlIHNlY29uZCBvcGVyYW5kXG4gKiBAcGFyYW0ge051bWJlcn0gdCBpbnRlcnBvbGF0aW9uIGFtb3VudCBiZXR3ZWVuIHRoZSB0d28gaW5wdXRzXG4gKiBAcmV0dXJucyB7dmVjNH0gb3V0XG4gKi9cbmZ1bmN0aW9uIGxlcnAgKG91dCwgYSwgYiwgdCkge1xuICB2YXIgYXggPSBhWzBdLFxuICAgIGF5ID0gYVsxXSxcbiAgICBheiA9IGFbMl0sXG4gICAgYXcgPSBhWzNdXG4gIG91dFswXSA9IGF4ICsgdCAqIChiWzBdIC0gYXgpXG4gIG91dFsxXSA9IGF5ICsgdCAqIChiWzFdIC0gYXkpXG4gIG91dFsyXSA9IGF6ICsgdCAqIChiWzJdIC0gYXopXG4gIG91dFszXSA9IGF3ICsgdCAqIChiWzNdIC0gYXcpXG4gIHJldHVybiBvdXRcbn1cbiIsInZhciB2ZWNOb3JtYWxpemUgPSByZXF1aXJlKCcuL25vcm1hbGl6ZScpXG52YXIgdmVjU2NhbGUgPSByZXF1aXJlKCcuL3NjYWxlJylcblxubW9kdWxlLmV4cG9ydHMgPSByYW5kb21cblxuLyoqXG4gKiBHZW5lcmF0ZXMgYSByYW5kb20gdmVjdG9yIHdpdGggdGhlIGdpdmVuIHNjYWxlXG4gKlxuICogQHBhcmFtIHt2ZWM0fSBvdXQgdGhlIHJlY2VpdmluZyB2ZWN0b3JcbiAqIEBwYXJhbSB7TnVtYmVyfSBbc2NhbGVdIExlbmd0aCBvZiB0aGUgcmVzdWx0aW5nIHZlY3Rvci4gSWYgb21taXR0ZWQsIGEgdW5pdCB2ZWN0b3Igd2lsbCBiZSByZXR1cm5lZFxuICogQHJldHVybnMge3ZlYzR9IG91dFxuICovXG5mdW5jdGlvbiByYW5kb20gKG91dCwgc2NhbGUpIHtcbiAgc2NhbGUgPSBzY2FsZSB8fCAxLjBcblxuICAvLyBUT0RPOiBUaGlzIGlzIGEgcHJldHR5IGF3ZnVsIHdheSBvZiBkb2luZyB0aGlzLiBGaW5kIHNvbWV0aGluZyBiZXR0ZXIuXG4gIG91dFswXSA9IE1hdGgucmFuZG9tKClcbiAgb3V0WzFdID0gTWF0aC5yYW5kb20oKVxuICBvdXRbMl0gPSBNYXRoLnJhbmRvbSgpXG4gIG91dFszXSA9IE1hdGgucmFuZG9tKClcbiAgdmVjTm9ybWFsaXplKG91dCwgb3V0KVxuICB2ZWNTY2FsZShvdXQsIG91dCwgc2NhbGUpXG4gIHJldHVybiBvdXRcbn1cbiIsIm1vZHVsZS5leHBvcnRzID0gdHJhbnNmb3JtTWF0NFxuXG4vKipcbiAqIFRyYW5zZm9ybXMgdGhlIHZlYzQgd2l0aCBhIG1hdDQuXG4gKlxuICogQHBhcmFtIHt2ZWM0fSBvdXQgdGhlIHJlY2VpdmluZyB2ZWN0b3JcbiAqIEBwYXJhbSB7dmVjNH0gYSB0aGUgdmVjdG9yIHRvIHRyYW5zZm9ybVxuICogQHBhcmFtIHttYXQ0fSBtIG1hdHJpeCB0byB0cmFuc2Zvcm0gd2l0aFxuICogQHJldHVybnMge3ZlYzR9IG91dFxuICovXG5mdW5jdGlvbiB0cmFuc2Zvcm1NYXQ0IChvdXQsIGEsIG0pIHtcbiAgdmFyIHggPSBhWzBdLCB5ID0gYVsxXSwgeiA9IGFbMl0sIHcgPSBhWzNdXG4gIG91dFswXSA9IG1bMF0gKiB4ICsgbVs0XSAqIHkgKyBtWzhdICogeiArIG1bMTJdICogd1xuICBvdXRbMV0gPSBtWzFdICogeCArIG1bNV0gKiB5ICsgbVs5XSAqIHogKyBtWzEzXSAqIHdcbiAgb3V0WzJdID0gbVsyXSAqIHggKyBtWzZdICogeSArIG1bMTBdICogeiArIG1bMTRdICogd1xuICBvdXRbM10gPSBtWzNdICogeCArIG1bN10gKiB5ICsgbVsxMV0gKiB6ICsgbVsxNV0gKiB3XG4gIHJldHVybiBvdXRcbn1cbiIsIm1vZHVsZS5leHBvcnRzID0gdHJhbnNmb3JtUXVhdFxuXG4vKipcbiAqIFRyYW5zZm9ybXMgdGhlIHZlYzQgd2l0aCBhIHF1YXRcbiAqXG4gKiBAcGFyYW0ge3ZlYzR9IG91dCB0aGUgcmVjZWl2aW5nIHZlY3RvclxuICogQHBhcmFtIHt2ZWM0fSBhIHRoZSB2ZWN0b3IgdG8gdHJhbnNmb3JtXG4gKiBAcGFyYW0ge3F1YXR9IHEgcXVhdGVybmlvbiB0byB0cmFuc2Zvcm0gd2l0aFxuICogQHJldHVybnMge3ZlYzR9IG91dFxuICovXG5mdW5jdGlvbiB0cmFuc2Zvcm1RdWF0IChvdXQsIGEsIHEpIHtcbiAgdmFyIHggPSBhWzBdLCB5ID0gYVsxXSwgeiA9IGFbMl0sXG4gICAgcXggPSBxWzBdLCBxeSA9IHFbMV0sIHF6ID0gcVsyXSwgcXcgPSBxWzNdLFxuXG4gICAgLy8gY2FsY3VsYXRlIHF1YXQgKiB2ZWNcbiAgICBpeCA9IHF3ICogeCArIHF5ICogeiAtIHF6ICogeSxcbiAgICBpeSA9IHF3ICogeSArIHF6ICogeCAtIHF4ICogeixcbiAgICBpeiA9IHF3ICogeiArIHF4ICogeSAtIHF5ICogeCxcbiAgICBpdyA9IC1xeCAqIHggLSBxeSAqIHkgLSBxeiAqIHpcblxuICAvLyBjYWxjdWxhdGUgcmVzdWx0ICogaW52ZXJzZSBxdWF0XG4gIG91dFswXSA9IGl4ICogcXcgKyBpdyAqIC1xeCArIGl5ICogLXF6IC0gaXogKiAtcXlcbiAgb3V0WzFdID0gaXkgKiBxdyArIGl3ICogLXF5ICsgaXogKiAtcXggLSBpeCAqIC1xelxuICBvdXRbMl0gPSBpeiAqIHF3ICsgaXcgKiAtcXogKyBpeCAqIC1xeSAtIGl5ICogLXF4XG4gIG91dFszXSA9IGFbM11cbiAgcmV0dXJuIG91dFxufVxuIiwibW9kdWxlLmV4cG9ydHMgPSB7XG4gIGNyZWF0ZTogcmVxdWlyZSgnLi9jcmVhdGUnKSxcbiAgY2xvbmU6IHJlcXVpcmUoJy4vY2xvbmUnKSxcbiAgZnJvbVZhbHVlczogcmVxdWlyZSgnLi9mcm9tVmFsdWVzJyksXG4gIGNvcHk6IHJlcXVpcmUoJy4vY29weScpLFxuICBzZXQ6IHJlcXVpcmUoJy4vc2V0JyksXG4gIGFkZDogcmVxdWlyZSgnLi9hZGQnKSxcbiAgc3VidHJhY3Q6IHJlcXVpcmUoJy4vc3VidHJhY3QnKSxcbiAgbXVsdGlwbHk6IHJlcXVpcmUoJy4vbXVsdGlwbHknKSxcbiAgZGl2aWRlOiByZXF1aXJlKCcuL2RpdmlkZScpLFxuICBtaW46IHJlcXVpcmUoJy4vbWluJyksXG4gIG1heDogcmVxdWlyZSgnLi9tYXgnKSxcbiAgc2NhbGU6IHJlcXVpcmUoJy4vc2NhbGUnKSxcbiAgc2NhbGVBbmRBZGQ6IHJlcXVpcmUoJy4vc2NhbGVBbmRBZGQnKSxcbiAgZGlzdGFuY2U6IHJlcXVpcmUoJy4vZGlzdGFuY2UnKSxcbiAgc3F1YXJlZERpc3RhbmNlOiByZXF1aXJlKCcuL3NxdWFyZWREaXN0YW5jZScpLFxuICBsZW5ndGg6IHJlcXVpcmUoJy4vbGVuZ3RoJyksXG4gIHNxdWFyZWRMZW5ndGg6IHJlcXVpcmUoJy4vc3F1YXJlZExlbmd0aCcpLFxuICBuZWdhdGU6IHJlcXVpcmUoJy4vbmVnYXRlJyksXG4gIGludmVyc2U6IHJlcXVpcmUoJy4vaW52ZXJzZScpLFxuICBub3JtYWxpemU6IHJlcXVpcmUoJy4vbm9ybWFsaXplJyksXG4gIGRvdDogcmVxdWlyZSgnLi9kb3QnKSxcbiAgbGVycDogcmVxdWlyZSgnLi9sZXJwJyksXG4gIHJhbmRvbTogcmVxdWlyZSgnLi9yYW5kb20nKSxcbiAgdHJhbnNmb3JtTWF0NDogcmVxdWlyZSgnLi90cmFuc2Zvcm1NYXQ0JyksXG4gIHRyYW5zZm9ybVF1YXQ6IHJlcXVpcmUoJy4vdHJhbnNmb3JtUXVhdCcpXG59XG4iLCJpbXBvcnQgdmVjNCBmcm9tICdnbC12ZWM0J1xuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlU3ByaW5nIChzdGlmZm5lc3MsIGRhbXBlbmluZywgdmFsdWUsIHByZWNpc2lvbikge1xuICBwcmVjaXNpb24gPSBwcmVjaXNpb24gPyBwcmVjaXNpb24gKiBwcmVjaXNpb24gOiBOdW1iZXIuRVBTSUxPTlxuICBjb25zdCBpc0lucHV0QXJyYXkgPSBBcnJheS5pc0FycmF5KHZhbHVlKVxuICBjb25zdCB2ZWNDb21wb25lbnRzID0gaXNJbnB1dEFycmF5ID8gdmFsdWUubGVuZ3RoIDogTnVtYmVyLmlzRmluaXRlKHZhbHVlKSA/IDEgOiBudWxsXG5cbiAgaWYgKCFOdW1iZXIuaXNGaW5pdGUoc3RpZmZuZXNzKSB8fCAhTnVtYmVyLmlzRmluaXRlKGRhbXBlbmluZykpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYHNwcmluZy1hbmltYXRvcjogZXhwZWN0ZWQgbnVtYmVycyBmb3Igc3RpZmZuZXNzIGFuZCBkYW1wZW5pbmcuIChlLmcuIGNyZWF0ZVNwcmluZygwLjAwMywgMC4xLCBzdGFydGluZ1ZhbHVlKSlgKVxuICB9XG5cbiAgaWYgKCF2ZWNDb21wb25lbnRzIHx8IHZlY0NvbXBvbmVudHMgPiA0KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBzcHJpbmctYW5pbWF0b3I6IGV4cGVjdGVkIHZhbHVlIFxcYCR7dmFsdWV9XFxgIHRvIGJlIGEgc2NhbGFyLCB2ZWMyLCB2ZWMzLCBvciB2ZWM0YClcbiAgfVxuXG4gIGZ1bmN0aW9uIG1ha2VWYWx1ZVZlYzQgKG91dCA9IFtdLCB2KSB7XG4gICAgaWYgKGlzSW5wdXRBcnJheSAhPT0gQXJyYXkuaXNBcnJheSh2KSB8fCAoaXNJbnB1dEFycmF5ICYmIHZlY0NvbXBvbmVudHMgIT09IHYubGVuZ3RoKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBzcHJpbmctYW5pbWF0b3I6IGRlc3RpbmF0aW9uIHZhbHVlIHR5cGUgbXVzdCBtYXRjaCBpbml0aWFsIHZhbHVlIHR5cGU6ICR7IWlzSW5wdXRBcnJheSA/ICdzY2FsYXInIDogdmVjQ29tcG9uZW50cyArICctY29tcG9uZW50IHZlY3Rvcid9YClcbiAgICB9XG4gICAgaWYgKE51bWJlci5pc0Zpbml0ZSh2KSkge1xuICAgICAgb3V0WzBdID0gdlxuICAgICAgb3V0WzFdID0gb3V0WzJdID0gb3V0WzNdID0gMFxuICAgICAgcmV0dXJuIG91dFxuICAgIH1cbiAgICB2ZWM0LmNvcHkob3V0LCB2KVxuICAgIHdoaWxlIChvdXQubGVuZ3RoIDwgNCkgb3V0LnB1c2goMClcbiAgICByZXR1cm4gb3V0XG4gIH1cblxuICB2YWx1ZSA9IG1ha2VWYWx1ZVZlYzQoW10sIHZhbHVlKVxuICBsZXQgbGFzdFZhbHVlID0gdmVjNC5jb3B5KFtdLCB2YWx1ZSlcbiAgbGV0IGRlc3RpbmF0aW9uVmFsdWUgPSB2ZWM0LmNvcHkoW10sIHZhbHVlKVxuXG4gIC8vIHNldCB1cCBzb21lIHJldXNhYmxlIGFycmF5cyB0byB1c2UgaW4gdGljaygpXG4gIGxldCBuZXh0VmFsdWUgPSBbXVxuICBsZXQgdmVsb2NpdHkgPSBbXVxuICBsZXQgZGVsdGEgPSBbXVxuICBsZXQgc3ByaW5nID0gW11cbiAgbGV0IGRhbXBlciA9IFtdXG4gIGxldCBhY2NlbGVyYXRpb24gPSBbXVxuXG4gIHJldHVybiB7XG4gICAgc2V0RGVzdGluYXRpb24sXG4gICAgZ2V0Q3VycmVudFZhbHVlLFxuICAgIGlzQXREZXN0aW5hdGlvbixcbiAgICB0aWNrXG4gIH1cblxuICBmdW5jdGlvbiBzZXREZXN0aW5hdGlvbiAobmV3VmFsdWUsIHNob3VsZEFuaW1hdGUgPSB0cnVlKSB7XG4gICAgbWFrZVZhbHVlVmVjNChkZXN0aW5hdGlvblZhbHVlLCBuZXdWYWx1ZSlcbiAgICBpZiAoIXNob3VsZEFuaW1hdGUpIHtcbiAgICAgIHZlYzQuY29weSh2YWx1ZSwgZGVzdGluYXRpb25WYWx1ZSlcbiAgICAgIHZlYzQuY29weShsYXN0VmFsdWUsIGRlc3RpbmF0aW9uVmFsdWUpXG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gaXNBdERlc3RpbmF0aW9uICh0aHJlc2hvbGQpIHtcbiAgICAvLyBzcXVhcmUgdGhpcyBzbyB3ZSBkb24ndCBuZWVkIHRvIHVzZSBNYXRoLnNxcnRcbiAgICB0aHJlc2hvbGQgPSB0aHJlc2hvbGQgPyB0aHJlc2hvbGQgKiB0aHJlc2hvbGQgOiBwcmVjaXNpb25cbiAgICByZXR1cm4gKFxuICAgICAgdmVjNC5zcXVhcmVkRGlzdGFuY2UodmFsdWUsIGRlc3RpbmF0aW9uVmFsdWUpIDw9IHRocmVzaG9sZCAmJlxuICAgICAgdmVjNC5zcXVhcmVkRGlzdGFuY2UodmFsdWUsIGxhc3RWYWx1ZSkgPD0gdGhyZXNob2xkXG4gICAgKVxuICB9XG5cbiAgZnVuY3Rpb24gZ2V0Q3VycmVudFZhbHVlIChvdXQgPSBbXSkge1xuICAgIGlmICghaXNJbnB1dEFycmF5KSByZXR1cm4gdmFsdWVbMF1cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHZlY0NvbXBvbmVudHM7IGkrKykge1xuICAgICAgb3V0W2ldID0gdmFsdWVbaV1cbiAgICB9XG4gICAgcmV0dXJuIG91dFxuICB9XG5cbiAgZnVuY3Rpb24gdGljayAocyA9IHN0aWZmbmVzcywgZCA9IGRhbXBlbmluZykge1xuICAgIHZlYzQuc3VidHJhY3QodmVsb2NpdHksIHZhbHVlLCBsYXN0VmFsdWUpXG4gICAgdmVjNC5zdWJ0cmFjdChkZWx0YSwgZGVzdGluYXRpb25WYWx1ZSwgdmFsdWUpXG4gICAgdmVjNC5zY2FsZShzcHJpbmcsIGRlbHRhLCBzKVxuICAgIHZlYzQuc2NhbGUoZGFtcGVyLCB2ZWxvY2l0eSwgLWQpXG4gICAgdmVjNC5hZGQoYWNjZWxlcmF0aW9uLCBzcHJpbmcsIGRhbXBlcilcbiAgICB2ZWM0LmFkZCh2ZWxvY2l0eSwgdmVsb2NpdHksIGFjY2VsZXJhdGlvbilcbiAgICB2ZWM0LmFkZChuZXh0VmFsdWUsIHZlbG9jaXR5LCB2YWx1ZSlcbiAgICB2ZWM0LmNvcHkobGFzdFZhbHVlLCB2YWx1ZSlcbiAgICB2ZWM0LmNvcHkodmFsdWUsIG5leHRWYWx1ZSlcbiAgICBpZiAoaXNBdERlc3RpbmF0aW9uKCkpIHtcbiAgICAgIHZlYzQuY29weSh2YWx1ZSwgZGVzdGluYXRpb25WYWx1ZSlcbiAgICAgIHZlYzQuY29weShsYXN0VmFsdWUsIGRlc3RpbmF0aW9uVmFsdWUpXG4gICAgfVxuICB9XG59XG4iXSwibmFtZXMiOlsidmVjTm9ybWFsaXplIiwidmVjU2NhbGUiLCJyZXF1aXJlJCQwIiwicmVxdWlyZSQkMSIsInJlcXVpcmUkJDIiLCJyZXF1aXJlJCQzIiwicmVxdWlyZSQkNCIsInJlcXVpcmUkJDUiLCJyZXF1aXJlJCQ2IiwicmVxdWlyZSQkNyIsInJlcXVpcmUkJDgiLCJyZXF1aXJlJCQ5IiwicmVxdWlyZSQkMTAiLCJyZXF1aXJlJCQxMSIsInJlcXVpcmUkJDEyIiwicmVxdWlyZSQkMTMiLCJyZXF1aXJlJCQxNCIsInJlcXVpcmUkJDE1IiwicmVxdWlyZSQkMTYiLCJyZXF1aXJlJCQxNyIsInJlcXVpcmUkJDE4IiwicmVxdWlyZSQkMTkiLCJyZXF1aXJlJCQyMCIsInJlcXVpcmUkJDIxIiwicmVxdWlyZSQkMjIiLCJyZXF1aXJlJCQyMyIsInJlcXVpcmUkJDI0IiwidmVjNCJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0VBQUEsWUFBYyxHQUFHLE9BQU07Ozs7Ozs7RUFPdkIsU0FBUyxNQUFNLElBQUk7SUFDakIsSUFBSSxHQUFHLEdBQUcsSUFBSSxZQUFZLENBQUMsQ0FBQyxFQUFDO0lBQzdCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFDO0lBQ1YsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUM7SUFDVixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBQztJQUNWLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFDO0lBQ1YsT0FBTyxHQUFHO0dBQ1g7O0VDZEQsV0FBYyxHQUFHLE1BQUs7Ozs7Ozs7O0VBUXRCLFNBQVMsS0FBSyxFQUFFLENBQUMsRUFBRTtJQUNqQixJQUFJLEdBQUcsR0FBRyxJQUFJLFlBQVksQ0FBQyxDQUFDLEVBQUM7SUFDN0IsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDYixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUNiLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ2IsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDYixPQUFPLEdBQUc7R0FDWDs7RUNmRCxnQkFBYyxHQUFHLFdBQVU7Ozs7Ozs7Ozs7O0VBVzNCLFNBQVMsVUFBVSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUMvQixJQUFJLEdBQUcsR0FBRyxJQUFJLFlBQVksQ0FBQyxDQUFDLEVBQUM7SUFDN0IsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUM7SUFDVixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBQztJQUNWLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFDO0lBQ1YsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUM7SUFDVixPQUFPLEdBQUc7R0FDWDs7RUNsQkQsVUFBYyxHQUFHLEtBQUk7Ozs7Ozs7OztFQVNyQixTQUFTLElBQUksRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFO0lBQ3JCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ2IsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDYixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUNiLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ2IsT0FBTyxHQUFHO0dBQ1g7O0VDZkQsU0FBYyxHQUFHLElBQUc7Ozs7Ozs7Ozs7OztFQVlwQixTQUFTLEdBQUcsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFO0lBQzdCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFDO0lBQ1YsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUM7SUFDVixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBQztJQUNWLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFDO0lBQ1YsT0FBTyxHQUFHO0dBQ1g7O0VDbEJELFNBQWMsR0FBRyxJQUFHOzs7Ozs7Ozs7O0VBVXBCLFNBQVMsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFO0lBQ3ZCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUNwQixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDcEIsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ3BCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUNwQixPQUFPLEdBQUc7R0FDWDs7RUNoQkQsY0FBYyxHQUFHLFNBQVE7Ozs7Ozs7Ozs7RUFVekIsU0FBUyxRQUFRLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUU7SUFDNUIsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ3BCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUNwQixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDcEIsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ3BCLE9BQU8sR0FBRztHQUNYOztFQ2hCRCxjQUFjLEdBQUcsU0FBUTs7Ozs7Ozs7OztFQVV6QixTQUFTLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUM1QixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDcEIsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ3BCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUNwQixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDcEIsT0FBTyxHQUFHO0dBQ1g7O0VDaEJELFlBQWMsR0FBRyxPQUFNOzs7Ozs7Ozs7O0VBVXZCLFNBQVMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFO0lBQzFCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUNwQixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDcEIsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ3BCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUNwQixPQUFPLEdBQUc7R0FDWDs7RUNoQkQsU0FBYyxHQUFHLElBQUc7Ozs7Ozs7Ozs7RUFVcEIsU0FBUyxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUU7SUFDdkIsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUM3QixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQzdCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDN0IsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUM3QixPQUFPLEdBQUc7R0FDWDs7RUNoQkQsU0FBYyxHQUFHLElBQUc7Ozs7Ozs7Ozs7RUFVcEIsU0FBUyxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUU7SUFDdkIsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUM3QixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQzdCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDN0IsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUM3QixPQUFPLEdBQUc7R0FDWDs7RUNoQkQsV0FBYyxHQUFHLE1BQUs7Ozs7Ozs7Ozs7RUFVdEIsU0FBUyxLQUFLLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUU7SUFDekIsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFDO0lBQ2pCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBQztJQUNqQixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUM7SUFDakIsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFDO0lBQ2pCLE9BQU8sR0FBRztHQUNYOztFQ2hCRCxpQkFBYyxHQUFHLFlBQVc7Ozs7Ozs7Ozs7O0VBVzVCLFNBQVMsV0FBVyxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRTtJQUN0QyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLEVBQUM7SUFDOUIsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxFQUFDO0lBQzlCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssRUFBQztJQUM5QixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLEVBQUM7SUFDOUIsT0FBTyxHQUFHO0dBQ1g7O0VDakJELGNBQWMsR0FBRyxTQUFROzs7Ozs7Ozs7RUFTekIsU0FBUyxRQUFRLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUN2QixJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUNqQixDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7TUFDZixDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7TUFDZixDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDakIsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7R0FDaEQ7O0VDZkQscUJBQWMsR0FBRyxnQkFBZTs7Ozs7Ozs7O0VBU2hDLFNBQVMsZUFBZSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUU7SUFDOUIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7TUFDakIsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQ2YsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQ2YsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ2pCLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUM7R0FDckM7O0VDZkQsWUFBYyxHQUFHLE9BQU07Ozs7Ozs7O0VBUXZCLFNBQVMsTUFBTSxFQUFFLENBQUMsRUFBRTtJQUNsQixJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQ1YsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7TUFDUixDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUNSLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ1YsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7R0FDaEQ7O0VDZEQsbUJBQWMsR0FBRyxjQUFhOzs7Ozs7OztFQVE5QixTQUFTLGFBQWEsRUFBRSxDQUFDLEVBQUU7SUFDekIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUNWLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQ1IsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7TUFDUixDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUNWLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUM7R0FDckM7O0VDZEQsWUFBYyxHQUFHLE9BQU07Ozs7Ozs7OztFQVN2QixTQUFTLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFO0lBQ3ZCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDZCxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ2QsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUNkLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDZCxPQUFPLEdBQUc7R0FDWDs7RUNmRCxhQUFjLEdBQUcsUUFBTzs7Ozs7Ozs7O0VBU3hCLFNBQVMsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUU7SUFDeEIsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ25CLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUNuQixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDbkIsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ25CLE9BQU8sR0FBRztHQUNYOztFQ2ZELGVBQWMsR0FBRyxVQUFTOzs7Ozs7Ozs7RUFTMUIsU0FBUyxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRTtJQUMxQixJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQ1YsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7TUFDUixDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUNSLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ1YsSUFBSSxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUM7SUFDdkMsSUFBSSxHQUFHLEdBQUcsQ0FBQyxFQUFFO01BQ1gsR0FBRyxHQUFHLENBQUMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBQztNQUN4QixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUc7TUFDaEIsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFHO01BQ2hCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsSUFBRztNQUNoQixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUc7S0FDakI7SUFDRCxPQUFPLEdBQUc7R0FDWDs7RUN2QkQsU0FBYyxHQUFHLElBQUc7Ozs7Ozs7OztFQVNwQixTQUFTLEdBQUcsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFO0lBQ2xCLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7R0FDN0Q7O0VDWEQsVUFBYyxHQUFHLEtBQUk7Ozs7Ozs7Ozs7O0VBV3JCLFNBQVMsSUFBSSxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUMzQixJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO01BQ1gsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7TUFDVCxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUNULEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ1gsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBQztJQUM3QixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFDO0lBQzdCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUM7SUFDN0IsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBQztJQUM3QixPQUFPLEdBQUc7R0FDWDs7RUNsQkQsWUFBYyxHQUFHLE9BQU07Ozs7Ozs7OztFQVN2QixTQUFTLE1BQU0sRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFO0lBQzNCLEtBQUssR0FBRyxLQUFLLElBQUksSUFBRzs7O0lBR3BCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxHQUFFO0lBQ3RCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxHQUFFO0lBQ3RCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxHQUFFO0lBQ3RCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsTUFBTSxHQUFFO0lBQ3RCQSxXQUFZLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBQztJQUN0QkMsT0FBUSxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFDO0lBQ3pCLE9BQU8sR0FBRztHQUNYOztFQ3ZCRCxtQkFBYyxHQUFHLGNBQWE7Ozs7Ozs7Ozs7RUFVOUIsU0FBUyxhQUFhLEVBQUUsR0FBRyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUU7SUFDakMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUMxQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUM7SUFDbkQsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFDO0lBQ25ELEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBQztJQUNwRCxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUM7SUFDcEQsT0FBTyxHQUFHO0dBQ1g7O0VDakJELG1CQUFjLEdBQUcsY0FBYTs7Ozs7Ozs7OztFQVU5QixTQUFTLGFBQWEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUNqQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztNQUM5QixFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQzs7O01BRzFDLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUM7TUFDN0IsRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQztNQUM3QixFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDO01BQzdCLEVBQUUsR0FBRyxDQUFDLEVBQUUsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBQzs7O0lBR2hDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsR0FBRTtJQUNqRCxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDLEdBQUU7SUFDakQsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxHQUFFO0lBQ2pELEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ2IsT0FBTyxHQUFHO0dBQ1g7O0VDMUJELFVBQWMsR0FBRztJQUNmLE1BQU0sRUFBRUMsUUFBbUI7SUFDM0IsS0FBSyxFQUFFQyxPQUFrQjtJQUN6QixVQUFVLEVBQUVDLFlBQXVCO0lBQ25DLElBQUksRUFBRUMsTUFBaUI7SUFDdkIsR0FBRyxFQUFFQyxLQUFnQjtJQUNyQixHQUFHLEVBQUVDLEtBQWdCO0lBQ3JCLFFBQVEsRUFBRUMsVUFBcUI7SUFDL0IsUUFBUSxFQUFFQyxVQUFxQjtJQUMvQixNQUFNLEVBQUVDLFFBQW1CO0lBQzNCLEdBQUcsRUFBRUMsS0FBZ0I7SUFDckIsR0FBRyxFQUFFQyxLQUFnQjtJQUNyQixLQUFLLEVBQUVDLE9BQWtCO0lBQ3pCLFdBQVcsRUFBRUMsYUFBd0I7SUFDckMsUUFBUSxFQUFFQyxVQUFxQjtJQUMvQixlQUFlLEVBQUVDLGlCQUE0QjtJQUM3QyxNQUFNLEVBQUVDLFFBQW1CO0lBQzNCLGFBQWEsRUFBRUMsZUFBMEI7SUFDekMsTUFBTSxFQUFFQyxRQUFtQjtJQUMzQixPQUFPLEVBQUVDLFNBQW9CO0lBQzdCLFNBQVMsRUFBRUMsV0FBc0I7SUFDakMsR0FBRyxFQUFFQyxLQUFnQjtJQUNyQixJQUFJLEVBQUVDLE1BQWlCO0lBQ3ZCLE1BQU0sRUFBRUMsUUFBbUI7SUFDM0IsYUFBYSxFQUFFQyxlQUEwQjtJQUN6QyxhQUFhLEVBQUVDLGVBQTBCO0dBQzFDOztFQ3hCTSxTQUFTLFlBQVksRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUU7RUFDdEUsRUFBRSxTQUFTLEdBQUcsU0FBUyxHQUFHLFNBQVMsR0FBRyxTQUFTLEdBQUcsTUFBTSxDQUFDLFFBQU87RUFDaEUsRUFBRSxNQUFNLFlBQVksR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBQztFQUMzQyxFQUFFLE1BQU0sYUFBYSxHQUFHLFlBQVksR0FBRyxLQUFLLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLEtBQUk7O0VBRXZGLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxFQUFFO0VBQ2xFLElBQUksTUFBTSxJQUFJLEtBQUssQ0FBQyxDQUFDLDZHQUE2RyxDQUFDLENBQUM7RUFDcEksR0FBRzs7RUFFSCxFQUFFLElBQUksQ0FBQyxhQUFhLElBQUksYUFBYSxHQUFHLENBQUMsRUFBRTtFQUMzQyxJQUFJLE1BQU0sSUFBSSxLQUFLLENBQUMsQ0FBQyxrQ0FBa0MsRUFBRSxLQUFLLENBQUMsc0NBQXNDLENBQUMsQ0FBQztFQUN2RyxHQUFHOztFQUVILEVBQUUsU0FBUyxhQUFhLEVBQUUsR0FBRyxHQUFHLEVBQUUsRUFBRSxDQUFDLEVBQUU7RUFDdkMsSUFBSSxJQUFJLFlBQVksS0FBSyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLFlBQVksSUFBSSxhQUFhLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxFQUFFO0VBQzNGLE1BQU0sTUFBTSxJQUFJLEtBQUssQ0FBQyxDQUFDLHVFQUF1RSxFQUFFLENBQUMsWUFBWSxHQUFHLFFBQVEsR0FBRyxhQUFhLEdBQUcsbUJBQW1CLENBQUMsQ0FBQyxDQUFDO0VBQ2pLLEtBQUs7RUFDTCxJQUFJLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBRTtFQUM1QixNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFDO0VBQ2hCLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBQztFQUNsQyxNQUFNLE9BQU8sR0FBRztFQUNoQixLQUFLO0VBQ0wsSUFBSUMsTUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFDO0VBQ3JCLElBQUksT0FBTyxHQUFHLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBQztFQUN0QyxJQUFJLE9BQU8sR0FBRztFQUNkLEdBQUc7O0VBRUgsRUFBRSxLQUFLLEdBQUcsYUFBYSxDQUFDLEVBQUUsRUFBRSxLQUFLLEVBQUM7RUFDbEMsRUFBRSxJQUFJLFNBQVMsR0FBR0EsTUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFDO0VBQ3RDLEVBQUUsSUFBSSxnQkFBZ0IsR0FBR0EsTUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQUUsS0FBSyxFQUFDOztFQUU3QztFQUNBLEVBQUUsSUFBSSxTQUFTLEdBQUcsR0FBRTtFQUNwQixFQUFFLElBQUksUUFBUSxHQUFHLEdBQUU7RUFDbkIsRUFBRSxJQUFJLEtBQUssR0FBRyxHQUFFO0VBQ2hCLEVBQUUsSUFBSSxNQUFNLEdBQUcsR0FBRTtFQUNqQixFQUFFLElBQUksTUFBTSxHQUFHLEdBQUU7RUFDakIsRUFBRSxJQUFJLFlBQVksR0FBRyxHQUFFOztFQUV2QixFQUFFLE9BQU87RUFDVCxJQUFJLGNBQWM7RUFDbEIsSUFBSSxlQUFlO0VBQ25CLElBQUksZUFBZTtFQUNuQixJQUFJLElBQUk7RUFDUixHQUFHOztFQUVILEVBQUUsU0FBUyxjQUFjLEVBQUUsUUFBUSxFQUFFLGFBQWEsR0FBRyxJQUFJLEVBQUU7RUFDM0QsSUFBSSxhQUFhLENBQUMsZ0JBQWdCLEVBQUUsUUFBUSxFQUFDO0VBQzdDLElBQUksSUFBSSxDQUFDLGFBQWEsRUFBRTtFQUN4QixNQUFNQSxNQUFJLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxnQkFBZ0IsRUFBQztFQUN4QyxNQUFNQSxNQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxnQkFBZ0IsRUFBQztFQUM1QyxLQUFLO0VBQ0wsR0FBRzs7RUFFSCxFQUFFLFNBQVMsZUFBZSxFQUFFLFNBQVMsRUFBRTtFQUN2QztFQUNBLElBQUksU0FBUyxHQUFHLFNBQVMsR0FBRyxTQUFTLEdBQUcsU0FBUyxHQUFHLFVBQVM7RUFDN0QsSUFBSTtFQUNKLE1BQU1BLE1BQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxFQUFFLGdCQUFnQixDQUFDLElBQUksU0FBUztFQUNoRSxNQUFNQSxNQUFJLENBQUMsZUFBZSxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsSUFBSSxTQUFTO0VBQ3pELEtBQUs7RUFDTCxHQUFHOztFQUVILEVBQUUsU0FBUyxlQUFlLEVBQUUsR0FBRyxHQUFHLEVBQUUsRUFBRTtFQUN0QyxJQUFJLElBQUksQ0FBQyxZQUFZLEVBQUUsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDO0VBQ3RDLElBQUksS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLGFBQWEsRUFBRSxDQUFDLEVBQUUsRUFBRTtFQUM1QyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsQ0FBQyxFQUFDO0VBQ3ZCLEtBQUs7RUFDTCxJQUFJLE9BQU8sR0FBRztFQUNkLEdBQUc7O0VBRUgsRUFBRSxTQUFTLElBQUksRUFBRSxDQUFDLEdBQUcsU0FBUyxFQUFFLENBQUMsR0FBRyxTQUFTLEVBQUU7RUFDL0MsSUFBSUEsTUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBQztFQUM3QyxJQUFJQSxNQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxnQkFBZ0IsRUFBRSxLQUFLLEVBQUM7RUFDakQsSUFBSUEsTUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBQztFQUNoQyxJQUFJQSxNQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDLEVBQUM7RUFDcEMsSUFBSUEsTUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBQztFQUMxQyxJQUFJQSxNQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxRQUFRLEVBQUUsWUFBWSxFQUFDO0VBQzlDLElBQUlBLE1BQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUM7RUFDeEMsSUFBSUEsTUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsS0FBSyxFQUFDO0VBQy9CLElBQUlBLE1BQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLFNBQVMsRUFBQztFQUMvQixJQUFJLElBQUksZUFBZSxFQUFFLEVBQUU7RUFDM0IsTUFBTUEsTUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsZ0JBQWdCLEVBQUM7RUFDeEMsTUFBTUEsTUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsZ0JBQWdCLEVBQUM7RUFDNUMsS0FBSztFQUNMLEdBQUc7RUFDSCxDQUFDOzs7Ozs7Ozs7Ozs7In0= 594 | --------------------------------------------------------------------------------