├── .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 | [](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 | [](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/ICdzY2FsYXInIDogdmVjQ29tcG9uZW50cyArICctY29tcG9uZW50IHZlY3Rvcid9YClcbiAgICB9XG4gICAgaWYgKE51bWJlci5pc0Zpbml0ZSh2KSkge1xuICAgICAgb3V0WzBdID0gdlxuICAgICAgb3V0WzFdID0gb3V0WzJdID0gb3V0WzNdID0gMFxuICAgICAgcmV0dXJuIG91dFxuICAgIH1cbiAgICB2ZWM0LmNvcHkob3V0LCB2KVxuICAgIHdoaWxlIChvdXQubGVuZ3RoIDwgNCkgb3V0LnB1c2goMClcbiAgICByZXR1cm4gb3V0XG4gIH1cblxuICB2YWx1ZSA9IG1ha2VWYWx1ZVZlYzQoW10sIHZhbHVlKVxuICBsZXQgbGFzdFZhbHVlID0gdmVjNC5jb3B5KFtdLCB2YWx1ZSlcbiAgbGV0IGRlc3RpbmF0aW9uVmFsdWUgPSB2ZWM0LmNvcHkoW10sIHZhbHVlKVxuXG4gIC8vIHNldCB1cCBzb21lIHJldXNhYmxlIGFycmF5cyB0byB1c2UgaW4gdGljaygpXG4gIGxldCBuZXh0VmFsdWUgPSBbXVxuICBsZXQgdmVsb2NpdHkgPSBbXVxuICBsZXQgZGVsdGEgPSBbXVxuICBsZXQgc3ByaW5nID0gW11cbiAgbGV0IGRhbXBlciA9IFtdXG4gIGxldCBhY2NlbGVyYXRpb24gPSBbXVxuXG4gIHJldHVybiB7XG4gICAgc2V0RGVzdGluYXRpb24sXG4gICAgZ2V0Q3VycmVudFZhbHVlLFxuICAgIGlzQXREZXN0aW5hdGlvbixcbiAgICB0aWNrXG4gIH1cblxuICBmdW5jdGlvbiBzZXREZXN0aW5hdGlvbiAobmV3VmFsdWUsIHNob3VsZEFuaW1hdGUgPSB0cnVlKSB7XG4gICAgbWFrZVZhbHVlVmVjNChkZXN0aW5hdGlvblZhbHVlLCBuZXdWYWx1ZSlcbiAgICBpZiAoIXNob3VsZEFuaW1hdGUpIHtcbiAgICAgIHZlYzQuY29weSh2YWx1ZSwgZGVzdGluYXRpb25WYWx1ZSlcbiAgICAgIHZlYzQuY29weShsYXN0VmFsdWUsIGRlc3RpbmF0aW9uVmFsdWUpXG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gaXNBdERlc3RpbmF0aW9uICh0aHJlc2hvbGQpIHtcbiAgICAvLyBzcXVhcmUgdGhpcyBzbyB3ZSBkb24ndCBuZWVkIHRvIHVzZSBNYXRoLnNxcnRcbiAgICB0aHJlc2hvbGQgPSB0aHJlc2hvbGQgPyB0aHJlc2hvbGQgKiB0aHJlc2hvbGQgOiBwcmVjaXNpb25cbiAgICByZXR1cm4gKFxuICAgICAgdmVjNC5zcXVhcmVkRGlzdGFuY2UodmFsdWUsIGRlc3RpbmF0aW9uVmFsdWUpIDw9IHRocmVzaG9sZCAmJlxuICAgICAgdmVjNC5zcXVhcmVkRGlzdGFuY2UodmFsdWUsIGxhc3RWYWx1ZSkgPD0gdGhyZXNob2xkXG4gICAgKVxuICB9XG5cbiAgZnVuY3Rpb24gZ2V0Q3VycmVudFZhbHVlIChvdXQgPSBbXSkge1xuICAgIGlmICghaXNJbnB1dEFycmF5KSByZXR1cm4gdmFsdWVbMF1cbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHZlY0NvbXBvbmVudHM7IGkrKykge1xuICAgICAgb3V0W2ldID0gdmFsdWVbaV1cbiAgICB9XG4gICAgcmV0dXJuIG91dFxuICB9XG5cbiAgZnVuY3Rpb24gdGljayAocyA9IHN0aWZmbmVzcywgZCA9IGRhbXBlbmluZykge1xuICAgIHZlYzQuc3VidHJhY3QodmVsb2NpdHksIHZhbHVlLCBsYXN0VmFsdWUpXG4gICAgdmVjNC5zdWJ0cmFjdChkZWx0YSwgZGVzdGluYXRpb25WYWx1ZSwgdmFsdWUpXG4gICAgdmVjNC5zY2FsZShzcHJpbmcsIGRlbHRhLCBzKVxuICAgIHZlYzQuc2NhbGUoZGFtcGVyLCB2ZWxvY2l0eSwgLWQpXG4gICAgdmVjNC5hZGQoYWNjZWxlcmF0aW9uLCBzcHJpbmcsIGRhbXBlcilcbiAgICB2ZWM0LmFkZCh2ZWxvY2l0eSwgdmVsb2NpdHksIGFjY2VsZXJhdGlvbilcbiAgICB2ZWM0LmFkZChuZXh0VmFsdWUsIHZlbG9jaXR5LCB2YWx1ZSlcbiAgICB2ZWM0LmNvcHkobGFzdFZhbHVlLCB2YWx1ZSlcbiAgICB2ZWM0LmNvcHkodmFsdWUsIG5leHRWYWx1ZSlcbiAgICBpZiAoaXNBdERlc3RpbmF0aW9uKCkpIHtcbiAgICAgIHZlYzQuY29weSh2YWx1ZSwgZGVzdGluYXRpb25WYWx1ZSlcbiAgICAgIHZlYzQuY29weShsYXN0VmFsdWUsIGRlc3RpbmF0aW9uVmFsdWUpXG4gICAgfVxuICB9XG59XG4iXSwibmFtZXMiOlsidmVjTm9ybWFsaXplIiwidmVjU2NhbGUiLCJyZXF1aXJlJCQwIiwicmVxdWlyZSQkMSIsInJlcXVpcmUkJDIiLCJyZXF1aXJlJCQzIiwicmVxdWlyZSQkNCIsInJlcXVpcmUkJDUiLCJyZXF1aXJlJCQ2IiwicmVxdWlyZSQkNyIsInJlcXVpcmUkJDgiLCJyZXF1aXJlJCQ5IiwicmVxdWlyZSQkMTAiLCJyZXF1aXJlJCQxMSIsInJlcXVpcmUkJDEyIiwicmVxdWlyZSQkMTMiLCJyZXF1aXJlJCQxNCIsInJlcXVpcmUkJDE1IiwicmVxdWlyZSQkMTYiLCJyZXF1aXJlJCQxNyIsInJlcXVpcmUkJDE4IiwicmVxdWlyZSQkMTkiLCJyZXF1aXJlJCQyMCIsInJlcXVpcmUkJDIxIiwicmVxdWlyZSQkMjIiLCJyZXF1aXJlJCQyMyIsInJlcXVpcmUkJDI0IiwidmVjNCJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0VBQUEsWUFBYyxHQUFHLE9BQU07Ozs7Ozs7RUFPdkIsU0FBUyxNQUFNLElBQUk7SUFDakIsSUFBSSxHQUFHLEdBQUcsSUFBSSxZQUFZLENBQUMsQ0FBQyxFQUFDO0lBQzdCLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFDO0lBQ1YsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUM7SUFDVixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBQztJQUNWLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFDO0lBQ1YsT0FBTyxHQUFHO0dBQ1g7O0VDZEQsV0FBYyxHQUFHLE1BQUs7Ozs7Ozs7O0VBUXRCLFNBQVMsS0FBSyxFQUFFLENBQUMsRUFBRTtJQUNqQixJQUFJLEdBQUcsR0FBRyxJQUFJLFlBQVksQ0FBQyxDQUFDLEVBQUM7SUFDN0IsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDYixHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBQztJQUNiLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFDO0lBQ2IsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUM7SUFDYixPQUFPLEdBQUc7R0FDWDs7RUNmRCxnQkFBYyxHQUFHLFdBQVU7Ozs7Ozs7Ozs7O0VBVzNCLFNBQVMsVUFBVSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRTtJQUMvQixJQUFJLEdBQUcsR0FBRyxJQUFJLFlBQVksQ0FBQyxDQUFDLEVBQUM7SUFDN0IsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUM7SUFDVixHQUFHLENBQUMsQ0FBQyxDQUFDLEdB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RSxRQUFRLEVBQUUsQ0FBQyxDQUFDLEVBQUM7RUFDcEMsSUFBSUEsTUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBQztFQUMxQyxJQUFJQSxNQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxRQUFRLEVBQUUsWUFBWSxFQUFDO0VBQzlDLElBQUlBLE1BQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUM7RUFDeEMsSUFBSUEsTUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsS0FBSyxFQUFDO0VBQy9CLElBQUlBLE1BQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxFQUFFLFNBQVMsRUFBQztFQUMvQixJQUFJLElBQUksZUFBZSxFQUFFLEVBQUU7RUFDM0IsTUFBTUEsTUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsZ0JBQWdCLEVBQUM7RUFDeEMsTUFBTUEsTUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsZ0JBQWdCLEVBQUM7RUFDNUMsS0FBSztFQUNMLEdBQUc7RUFDSCxDQUFDOzs7Ozs7Ozs7Ozs7In0=
594 |
--------------------------------------------------------------------------------