made with requirebin
Last active
October 28, 2017 21:59
-
-
Save jcblw/8ff90d2fe506cea2870a8ea239d8381e to your computer and use it in GitHub Desktop.
requirebin sketch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| var Simplex = require('perlin-simplex') | |
| var TWEEN = require('@tweenjs/tween.js') | |
| const canvas = document.getElementsByTagName('canvas')[0]; | |
| const context = canvas.getContext('2d') | |
| class WanderingCircle { | |
| constructor({ | |
| anchorAmount = 180, | |
| radius = 5, | |
| basePathRadius = 10, | |
| startVariant = 0, | |
| pathCenter = [0, 0], | |
| transitionTime = 1000, | |
| iteration = 0, | |
| color = 'tomato', | |
| debug = false, | |
| startStep = 0, | |
| variationAmount = 10 | |
| }) { | |
| Object.assign(this, { | |
| anchorAmount, | |
| radius, | |
| basePathRadius, | |
| pathCenter, | |
| variant: startVariant, | |
| transitionTime, | |
| simplex: new Simplex(), | |
| iteration, | |
| debug, | |
| color, | |
| step: startStep, | |
| variationAmount | |
| }); | |
| this.createAnimation( | |
| this.nextVariation(this.iteration) | |
| ) | |
| } | |
| nextVariation(iteration) { | |
| // TODO make this more configurable | |
| return this.simplex.noise(1, iteration) * 0.8 | |
| } | |
| createAnimation(current = 0) { | |
| this.iteration = ++this.iteration; | |
| const next = this.nextVariation(this.iteration); | |
| const tween = new TWEEN.Tween({ offset: current }) | |
| .to({ offset: next }, this.transitionTime) | |
| .onUpdate(({ offset }) => { | |
| this.variant = offset; | |
| }) | |
| .onComplete(() => this.createAnimation(next)) | |
| .start() | |
| return tween | |
| } | |
| toPath([x, y], radius = 5) { | |
| const path = new Path2D() | |
| path.arc(x, y, radius, 0, 2 * Math.PI) | |
| return path; | |
| } | |
| render(ctx) { | |
| const segments = new Array(this.anchorAmount) | |
| .join('.') | |
| .split('.') | |
| .map(mapSegment(this.pathCenter, this.basePathRadius + this.variant * this.variationAmount)) | |
| // create the circle | |
| const coordinate = segments[this.step] | |
| if (!this.debug) { | |
| ctx.fillStyle = this.color | |
| ctx.fill( | |
| this.toPath(coordinate, this.radius) | |
| ) | |
| } else { | |
| ctx.strokeStyle = '#222' | |
| ctx.strokeWidth = 1 | |
| ctx.stroke( | |
| this.toPath(coordinate, this.radius) | |
| ) | |
| // segments.forEach((segment) => { | |
| // ctx.fillStyle = '#222' | |
| // ctx.fill( | |
| // this.toPath(segment, 1) | |
| // ) | |
| // }) | |
| } | |
| this.step = this.step + 1; | |
| if (this.step === this.anchorAmount) { | |
| if (this.anchorAmount > 720) { | |
| this.anchorAmount = this.anchorAmount + 10 | |
| } | |
| this.step = 0 | |
| } | |
| return { | |
| coordinate, | |
| size: this.radius | |
| } | |
| } | |
| } | |
| /** | |
| * Based on Metaball script by Hiroyuki Sato | |
| * http://shspage.com/aijs/en/#metaball | |
| */ | |
| function dist([x1, y1], [x2, y2]) { | |
| return Math.pow(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2), 0.5) | |
| } | |
| function getVector([cx, cy], a, r) { | |
| return [cx + r * Math.cos(a), cy + r * Math.sin(a)]; | |
| } | |
| function angle([x1, y1], [x2, y2]) { | |
| return Math.atan2(y1 - y2, x1 - x2); | |
| } | |
| /** | |
| * Based on Metaball script by SATO Hiroyuki | |
| * http://park12.wakwak.com/~shp/lc/et/en_aics_script.html | |
| */ | |
| function metaball( | |
| radius1, | |
| radius2, | |
| center1, | |
| center2, | |
| onMitosis = () => {}, | |
| handleLenRate = 2.4, | |
| v = 0.5 | |
| ) { | |
| const HALF_PI = Math.PI / 2; | |
| const d = dist(center1, center2); | |
| const maxDist = radius1 + radius2 * 2.5; | |
| let u1, u2; | |
| if (radius1 === 0 || radius2 === 0) { | |
| return onMitosis(); | |
| } | |
| if (d > maxDist) { | |
| return onMitosis(); | |
| } | |
| if (d <= Math.abs(radius1 - radius2)) { | |
| return onMitosis(); | |
| } else if (d < radius1 + radius2) { | |
| u1 = Math.acos( | |
| (radius1 * radius1 + d * d - radius2 * radius2) / (2 * radius1 * d) | |
| ); | |
| u2 = Math.acos( | |
| (radius2 * radius2 + d * d - radius1 * radius1) / (2 * radius2 * d) | |
| ); | |
| } else { | |
| u1 = 0; | |
| u2 = 0; | |
| } | |
| // All the angles | |
| const angle1 = angle(center2, center1); | |
| const angle2 = Math.acos((radius1 - radius2) / d); | |
| const angle1a = angle1 + u1 + (angle2 - u1) * v; | |
| const angle1b = angle1 - u1 - (angle2 - u1) * v; | |
| const angle2a = angle1 + Math.PI - u2 - (Math.PI - u2 - angle2) * v; | |
| const angle2b = angle1 - Math.PI + u2 + (Math.PI - u2 - angle2) * v; | |
| // Points | |
| const p1a = getVector(center1, angle1a, radius1); | |
| const p1b = getVector(center1, angle1b, radius1); | |
| const p2a = getVector(center2, angle2a, radius2); | |
| const p2b = getVector(center2, angle2b, radius2); | |
| // Define handle length by the | |
| // distance between both ends of the curve | |
| const totalRadius = radius1 + radius2; | |
| const d2Base = Math.min(v * handleLenRate, dist(p1a, p2a) / totalRadius); | |
| // Take into account when circles are overlapping | |
| const d2 = d2Base * Math.min(1, d * 2 / (radius1 + radius2)); | |
| const r1 = radius1 * d2; | |
| const r2 = radius2 * d2; | |
| const h1 = getVector(p1a, angle1a - HALF_PI, r1); | |
| const h2 = getVector(p2a, angle2a + HALF_PI, r2); | |
| const h3 = getVector(p2b, angle2b - HALF_PI, r2); | |
| const h4 = getVector(p1b, angle1b + HALF_PI, r1); | |
| return metaballToPath( | |
| p1a, | |
| p2a, | |
| p1b, | |
| p2b, | |
| h1, | |
| h2, | |
| h3, | |
| h4, | |
| d > radius1, | |
| radius2 | |
| ); | |
| } | |
| function metaballToPath(p1a, p2a, p1b, p2b, h1, h2, h3, h4, escaped, r) { | |
| return new Path2D([ | |
| 'M', p1a, | |
| 'C', h1, h2, p2a, | |
| 'A', r, r, 0, escaped ? 1 : 0, 0, p2b, | |
| 'C', h3, h4, p1b, | |
| ].join(' ')) | |
| } | |
| let position = [50, 50] | |
| canvas.addEventListener('mousemove', (e) => { | |
| position = [e.x, e.y] | |
| }) | |
| function circle(x, y, radius) { | |
| const path = new Path2D() | |
| path.arc(x, y, radius, 0, 2 * Math.PI) | |
| return path; | |
| } | |
| const SIZE = 75 | |
| const MAIN_SIZE = 100 | |
| const STEPS = 320 | |
| const COLOR = '#F47D31' | |
| function mapSegment (center, radius) { | |
| return (offset, i, arr) => { | |
| const radian = Math.PI * 2 | |
| const a = radian / arr.length * i - radian / 4 // << needs to be total radians / amount | |
| const coordinates = [ | |
| center[0] + (radius + offset) * Math.cos(a), | |
| center[1] + (radius + offset) * Math.sin(a), | |
| ] | |
| return [...coordinates]; | |
| } | |
| } | |
| // const circles = [ | |
| // new WanderingCircle({ | |
| // anchorAmount: 180, | |
| // radius: 60, | |
| // basePathRadius: 40, | |
| // transitionTime: 1000, | |
| // color: COLOR, | |
| // variationAmount: 20, | |
| // }), | |
| // new WanderingCircle({ | |
| // anchorAmount: 360, | |
| // radius: 80, | |
| // basePathRadius: 30, | |
| // transitionTime: 1000, | |
| // color: COLOR | |
| // }), | |
| // new WanderingCircle({ | |
| // anchorAmount: 640, | |
| // radius: 60, | |
| // basePathRadius: 40, | |
| // transitionTime: 3000, | |
| // variationAmount: 25, | |
| // step: 320, | |
| // color: COLOR | |
| // }) | |
| // ] | |
| function randomNumber ( upperlimit, min ) { | |
| return Math.max(Math.abs(Math.floor(Math.random() * upperlimit)), min) | |
| } | |
| const circles = new Array(50).join('.').split('.').map((_, i) => { | |
| const anchorAmount = randomNumber(720, 180); | |
| return new WanderingCircle({ | |
| anchorAmount, | |
| radius: randomNumber(80, 60), | |
| basePathRadius: 40, | |
| transitionTime: randomNumber(3000, 1000), | |
| variationAmount: randomNumber(15, 10), | |
| startStep: randomNumber(anchorAmount, 0), | |
| color: COLOR, | |
| //debug: true | |
| }) | |
| }) | |
| function onUpdate() { | |
| // increment(); | |
| try { | |
| canvas.width = window.innerWidth | |
| canvas.height = window.innerHeight | |
| const center = [window.innerWidth/2, window.innerHeight/2] | |
| const circleFactory = () => circle(...center, MAIN_SIZE) | |
| context.save() | |
| context.clearRect(0, 0, canvas.width, canvas.height) | |
| context.fillStyle = COLOR | |
| context.fill(circle(...position, 25)) | |
| context.fill(circle(...center, MAIN_SIZE)) | |
| circles.forEach(wcircle => { | |
| wcircle.pathCenter = center | |
| const meta = wcircle.render(context) | |
| context.fill(metaball(meta.size, MAIN_SIZE, meta.coordinate, center, circleFactory)) | |
| }) | |
| // meta bubble stuff | |
| // context.fill(metaball(25, MAIN_SIZE, position, center, circleFactory)) | |
| // context.fill(metaball(SIZE, MAIN_SIZE, cs1, center, circleFactory)) | |
| context.restore() | |
| } catch(e) { | |
| console.log(e) | |
| } | |
| } | |
| function draw() { | |
| TWEEN.update() | |
| onUpdate() | |
| requestAnimationFrame(draw) | |
| } | |
| draw() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| setTimeout(function(){ | |
| ;require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({"perlin-simplex":[function(require,module,exports){ | |
| // https://gist.github.com/banksean/304522 | |
| // | |
| // Ported from Stefan Gustavson's java implementation | |
| // http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf | |
| // Read Stefan's excellent paper for details on how this code works. | |
| // | |
| // Sean McCullough [email protected] | |
| /** | |
| * You can pass in a random number generator object if you like. | |
| * It is assumed to have a random() method. | |
| */ | |
| module.exports = SimplexNoise = function(r) { | |
| if (r == undefined) r = Math; | |
| this.grad3 = [[1,1,0],[-1,1,0],[1,-1,0],[-1,-1,0], | |
| [1,0,1],[-1,0,1],[1,0,-1],[-1,0,-1], | |
| [0,1,1],[0,-1,1],[0,1,-1],[0,-1,-1]]; | |
| this.p = []; | |
| for (var i=0; i<256; i++) { | |
| this.p[i] = Math.floor(r.random()*256); | |
| } | |
| // To remove the need for index wrapping, double the permutation table length | |
| this.perm = []; | |
| for(var i=0; i<512; i++) { | |
| this.perm[i]=this.p[i & 255]; | |
| } | |
| // A lookup table to traverse the simplex around a given point in 4D. | |
| // Details can be found where this table is used, in the 4D noise method. | |
| this.simplex = [ | |
| [0,1,2,3],[0,1,3,2],[0,0,0,0],[0,2,3,1],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,2,3,0], | |
| [0,2,1,3],[0,0,0,0],[0,3,1,2],[0,3,2,1],[0,0,0,0],[0,0,0,0],[0,0,0,0],[1,3,2,0], | |
| [0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0], | |
| [1,2,0,3],[0,0,0,0],[1,3,0,2],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,3,0,1],[2,3,1,0], | |
| [1,0,2,3],[1,0,3,2],[0,0,0,0],[0,0,0,0],[0,0,0,0],[2,0,3,1],[0,0,0,0],[2,1,3,0], | |
| [0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0], | |
| [2,0,1,3],[0,0,0,0],[0,0,0,0],[0,0,0,0],[3,0,1,2],[3,0,2,1],[0,0,0,0],[3,1,2,0], | |
| [2,1,0,3],[0,0,0,0],[0,0,0,0],[0,0,0,0],[3,1,0,2],[0,0,0,0],[3,2,0,1],[3,2,1,0]]; | |
| }; | |
| SimplexNoise.prototype.dot = function(g, x, y) { | |
| return g[0]*x + g[1]*y; | |
| }; | |
| SimplexNoise.prototype.noise = function(xin, yin) { | |
| var n0, n1, n2; // Noise contributions from the three corners | |
| // Skew the input space to determine which simplex cell we're in | |
| var F2 = 0.5*(Math.sqrt(3.0)-1.0); | |
| var s = (xin+yin)*F2; // Hairy factor for 2D | |
| var i = Math.floor(xin+s); | |
| var j = Math.floor(yin+s); | |
| var G2 = (3.0-Math.sqrt(3.0))/6.0; | |
| var t = (i+j)*G2; | |
| var X0 = i-t; // Unskew the cell origin back to (x,y) space | |
| var Y0 = j-t; | |
| var x0 = xin-X0; // The x,y distances from the cell origin | |
| var y0 = yin-Y0; | |
| // For the 2D case, the simplex shape is an equilateral triangle. | |
| // Determine which simplex we are in. | |
| var i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords | |
| if(x0>y0) {i1=1; j1=0;} // lower triangle, XY order: (0,0)->(1,0)->(1,1) | |
| else {i1=0; j1=1;} // upper triangle, YX order: (0,0)->(0,1)->(1,1) | |
| // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and | |
| // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where | |
| // c = (3-sqrt(3))/6 | |
| var x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords | |
| var y1 = y0 - j1 + G2; | |
| var x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords | |
| var y2 = y0 - 1.0 + 2.0 * G2; | |
| // Work out the hashed gradient indices of the three simplex corners | |
| var ii = i & 255; | |
| var jj = j & 255; | |
| var gi0 = this.perm[ii+this.perm[jj]] % 12; | |
| var gi1 = this.perm[ii+i1+this.perm[jj+j1]] % 12; | |
| var gi2 = this.perm[ii+1+this.perm[jj+1]] % 12; | |
| // Calculate the contribution from the three corners | |
| var t0 = 0.5 - x0*x0-y0*y0; | |
| if(t0<0) n0 = 0.0; | |
| else { | |
| t0 *= t0; | |
| n0 = t0 * t0 * this.dot(this.grad3[gi0], x0, y0); // (x,y) of grad3 used for 2D gradient | |
| } | |
| var t1 = 0.5 - x1*x1-y1*y1; | |
| if(t1<0) n1 = 0.0; | |
| else { | |
| t1 *= t1; | |
| n1 = t1 * t1 * this.dot(this.grad3[gi1], x1, y1); | |
| } | |
| var t2 = 0.5 - x2*x2-y2*y2; | |
| if(t2<0) n2 = 0.0; | |
| else { | |
| t2 *= t2; | |
| n2 = t2 * t2 * this.dot(this.grad3[gi2], x2, y2); | |
| } | |
| // Add contributions from each corner to get the final noise value. | |
| // The result is scaled to return values in the interval [-1,1]. | |
| return 70.0 * (n0 + n1 + n2); | |
| }; | |
| // 3D simplex noise | |
| SimplexNoise.prototype.noise3d = function(xin, yin, zin) { | |
| var n0, n1, n2, n3; // Noise contributions from the four corners | |
| // Skew the input space to determine which simplex cell we're in | |
| var F3 = 1.0/3.0; | |
| var s = (xin+yin+zin)*F3; // Very nice and simple skew factor for 3D | |
| var i = Math.floor(xin+s); | |
| var j = Math.floor(yin+s); | |
| var k = Math.floor(zin+s); | |
| var G3 = 1.0/6.0; // Very nice and simple unskew factor, too | |
| var t = (i+j+k)*G3; | |
| var X0 = i-t; // Unskew the cell origin back to (x,y,z) space | |
| var Y0 = j-t; | |
| var Z0 = k-t; | |
| var x0 = xin-X0; // The x,y,z distances from the cell origin | |
| var y0 = yin-Y0; | |
| var z0 = zin-Z0; | |
| // For the 3D case, the simplex shape is a slightly irregular tetrahedron. | |
| // Determine which simplex we are in. | |
| var i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords | |
| var i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords | |
| if(x0>=y0) { | |
| if(y0>=z0) | |
| { i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } // X Y Z order | |
| else if(x0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } // X Z Y order | |
| else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } // Z X Y order | |
| } | |
| else { // x0<y0 | |
| if(y0<z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } // Z Y X order | |
| else if(x0<z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } // Y Z X order | |
| else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } // Y X Z order | |
| } | |
| // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z), | |
| // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and | |
| // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where | |
| // c = 1/6. | |
| var x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords | |
| var y1 = y0 - j1 + G3; | |
| var z1 = z0 - k1 + G3; | |
| var x2 = x0 - i2 + 2.0*G3; // Offsets for third corner in (x,y,z) coords | |
| var y2 = y0 - j2 + 2.0*G3; | |
| var z2 = z0 - k2 + 2.0*G3; | |
| var x3 = x0 - 1.0 + 3.0*G3; // Offsets for last corner in (x,y,z) coords | |
| var y3 = y0 - 1.0 + 3.0*G3; | |
| var z3 = z0 - 1.0 + 3.0*G3; | |
| // Work out the hashed gradient indices of the four simplex corners | |
| var ii = i & 255; | |
| var jj = j & 255; | |
| var kk = k & 255; | |
| var gi0 = this.perm[ii+this.perm[jj+this.perm[kk]]] % 12; | |
| var gi1 = this.perm[ii+i1+this.perm[jj+j1+this.perm[kk+k1]]] % 12; | |
| var gi2 = this.perm[ii+i2+this.perm[jj+j2+this.perm[kk+k2]]] % 12; | |
| var gi3 = this.perm[ii+1+this.perm[jj+1+this.perm[kk+1]]] % 12; | |
| // Calculate the contribution from the four corners | |
| var t0 = 0.6 - x0*x0 - y0*y0 - z0*z0; | |
| if(t0<0) n0 = 0.0; | |
| else { | |
| t0 *= t0; | |
| n0 = t0 * t0 * this.dot(this.grad3[gi0], x0, y0, z0); | |
| } | |
| var t1 = 0.6 - x1*x1 - y1*y1 - z1*z1; | |
| if(t1<0) n1 = 0.0; | |
| else { | |
| t1 *= t1; | |
| n1 = t1 * t1 * this.dot(this.grad3[gi1], x1, y1, z1); | |
| } | |
| var t2 = 0.6 - x2*x2 - y2*y2 - z2*z2; | |
| if(t2<0) n2 = 0.0; | |
| else { | |
| t2 *= t2; | |
| n2 = t2 * t2 * this.dot(this.grad3[gi2], x2, y2, z2); | |
| } | |
| var t3 = 0.6 - x3*x3 - y3*y3 - z3*z3; | |
| if(t3<0) n3 = 0.0; | |
| else { | |
| t3 *= t3; | |
| n3 = t3 * t3 * this.dot(this.grad3[gi3], x3, y3, z3); | |
| } | |
| // Add contributions from each corner to get the final noise value. | |
| // The result is scaled to stay just inside [-1,1] | |
| return 32.0*(n0 + n1 + n2 + n3); | |
| }; | |
| },{}]},{},[]) | |
| //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsInBlcmxpbi1zaW1wbGV4Il0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLy8gaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vYmFua3NlYW4vMzA0NTIyXG4vL1xuLy8gUG9ydGVkIGZyb20gU3RlZmFuIEd1c3RhdnNvbidzIGphdmEgaW1wbGVtZW50YXRpb25cbi8vIGh0dHA6Ly9zdGFmZnd3dy5pdG4ubGl1LnNlL35zdGVndS9zaW1wbGV4bm9pc2Uvc2ltcGxleG5vaXNlLnBkZlxuLy8gUmVhZCBTdGVmYW4ncyBleGNlbGxlbnQgcGFwZXIgZm9yIGRldGFpbHMgb24gaG93IHRoaXMgY29kZSB3b3Jrcy5cbi8vXG4vLyBTZWFuIE1jQ3VsbG91Z2ggYmFua3NlYW5AZ21haWwuY29tXG5cbi8qKlxuICogWW91IGNhbiBwYXNzIGluIGEgcmFuZG9tIG51bWJlciBnZW5lcmF0b3Igb2JqZWN0IGlmIHlvdSBsaWtlLlxuICogSXQgaXMgYXNzdW1lZCB0byBoYXZlIGEgcmFuZG9tKCkgbWV0aG9kLlxuICovXG5tb2R1bGUuZXhwb3J0cyA9IFNpbXBsZXhOb2lzZSA9IGZ1bmN0aW9uKHIpIHtcbiAgaWYgKHIgPT0gdW5kZWZpbmVkKSByID0gTWF0aDtcbiAgdGhpcy5ncmFkMyA9IFtbMSwxLDBdLFstMSwxLDBdLFsxLC0xLDBdLFstMSwtMSwwXSwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbMSwwLDFdLFstMSwwLDFdLFsxLDAsLTFdLFstMSwwLC0xXSwgXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbMCwxLDFdLFswLC0xLDFdLFswLDEsLTFdLFswLC0xLC0xXV07IFxuICB0aGlzLnAgPSBbXTtcbiAgZm9yICh2YXIgaT0wOyBpPDI1NjsgaSsrKSB7XG4gICAgdGhpcy5wW2ldID0gTWF0aC5mbG9vcihyLnJhbmRvbSgpKjI1Nik7XG4gIH1cbiAgLy8gVG8gcmVtb3ZlIHRoZSBuZWVkIGZvciBpbmRleCB3cmFwcGluZywgZG91YmxlIHRoZSBwZXJtdXRhdGlvbiB0YWJsZSBsZW5ndGggXG4gIHRoaXMucGVybSA9IFtdOyBcbiAgZm9yKHZhciBpPTA7IGk8NTEyOyBpKyspIHtcbiAgICB0aGlzLnBlcm1baV09dGhpcy5wW2kgJiAyNTVdO1xuICB9IFxuXG4gIC8vIEEgbG9va3VwIHRhYmxlIHRvIHRyYXZlcnNlIHRoZSBzaW1wbGV4IGFyb3VuZCBhIGdpdmVuIHBvaW50IGluIDRELiBcbiAgLy8gRGV0YWlscyBjYW4gYmUgZm91bmQgd2hlcmUgdGhpcyB0YWJsZSBpcyB1c2VkLCBpbiB0aGUgNEQgbm9pc2UgbWV0aG9kLiBcbiAgdGhpcy5zaW1wbGV4ID0gWyBcbiAgICBbMCwxLDIsM10sWzAsMSwzLDJdLFswLDAsMCwwXSxbMCwyLDMsMV0sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzEsMiwzLDBdLCBcbiAgICBbMCwyLDEsM10sWzAsMCwwLDBdLFswLDMsMSwyXSxbMCwzLDIsMV0sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzEsMywyLDBdLCBcbiAgICBbMCwwLDAsMF0sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzAsMCwwLDBdLCBcbiAgICBbMSwyLDAsM10sWzAsMCwwLDBdLFsxLDMsMCwyXSxbMCwwLDAsMF0sWzAsMCwwLDBdLFswLDAsMCwwXSxbMiwzLDAsMV0sWzIsMywxLDBdLCBcbiAgICBbMSwwLDIsM10sWzEsMCwzLDJdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzAsMCwwLDBdLFsyLDAsMywxXSxbMCwwLDAsMF0sWzIsMSwzLDBdLCBcbiAgICBbMCwwLDAsMF0sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzAsMCwwLDBdLCBcbiAgICBbMiwwLDEsM10sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzMsMCwxLDJdLFszLDAsMiwxXSxbMCwwLDAsMF0sWzMsMSwyLDBdLCBcbiAgICBbMiwxLDAsM10sWzAsMCwwLDBdLFswLDAsMCwwXSxbMCwwLDAsMF0sWzMsMSwwLDJdLFswLDAsMCwwXSxbMywyLDAsMV0sWzMsMiwxLDBdXTsgXG59O1xuXG5TaW1wbGV4Tm9pc2UucHJvdG90eXBlLmRvdCA9IGZ1bmN0aW9uKGcsIHgsIHkpIHsgXG4gIHJldHVybiBnWzBdKnggKyBnWzFdKnk7XG59O1xuXG5TaW1wbGV4Tm9pc2UucHJvdG90eXBlLm5vaXNlID0gZnVuY3Rpb24oeGluLCB5aW4pIHsgXG4gIHZhciBuMCwgbjEsIG4yOyAvLyBOb2lzZSBjb250cmlidXRpb25zIGZyb20gdGhlIHRocmVlIGNvcm5lcnMgXG4gIC8vIFNrZXcgdGhlIGlucHV0IHNwYWNlIHRvIGRldGVybWluZSB3aGljaCBzaW1wbGV4IGNlbGwgd2UncmUgaW4gXG4gIHZhciBGMiA9IDAuNSooTWF0aC5zcXJ0KDMuMCktMS4wKTsgXG4gIHZhciBzID0gKHhpbit5aW4pKkYyOyAvLyBIYWlyeSBmYWN0b3IgZm9yIDJEIFxuICB2YXIgaSA9IE1hdGguZmxvb3IoeGluK3MpOyBcbiAgdmFyIGogPSBNYXRoLmZsb29yKHlpbitzKTsgXG4gIHZhciBHMiA9ICgzLjAtTWF0aC5zcXJ0KDMuMCkpLzYuMDsgXG4gIHZhciB0ID0gKGkraikqRzI7IFxuICB2YXIgWDAgPSBpLXQ7IC8vIFVuc2tldyB0aGUgY2VsbCBvcmlnaW4gYmFjayB0byAoeCx5KSBzcGFjZSBcbiAgdmFyIFkwID0gai10OyBcbiAgdmFyIHgwID0geGluLVgwOyAvLyBUaGUgeCx5IGRpc3RhbmNlcyBmcm9tIHRoZSBjZWxsIG9yaWdpbiBcbiAgdmFyIHkwID0geWluLVkwOyBcbiAgLy8gRm9yIHRoZSAyRCBjYXNlLCB0aGUgc2ltcGxleCBzaGFwZSBpcyBhbiBlcXVpbGF0ZXJhbCB0cmlhbmdsZS4gXG4gIC8vIERldGVybWluZSB3aGljaCBzaW1wbGV4IHdlIGFyZSBpbi4gXG4gIHZhciBpMSwgajE7IC8vIE9mZnNldHMgZm9yIHNlY29uZCAobWlkZGxlKSBjb3JuZXIgb2Ygc2ltcGxleCBpbiAoaSxqKSBjb29yZHMgXG4gIGlmKHgwPnkwKSB7aTE9MTsgajE9MDt9IC8vIGxvd2VyIHRyaWFuZ2xlLCBYWSBvcmRlcjogKDAsMCktPigxLDApLT4oMSwxKSBcbiAgZWxzZSB7aTE9MDsgajE9MTt9ICAgICAgLy8gdXBwZXIgdHJpYW5nbGUsIFlYIG9yZGVyOiAoMCwwKS0+KDAsMSktPigxLDEpIFxuICAvLyBBIHN0ZXAgb2YgKDEsMCkgaW4gKGksaikgbWVhbnMgYSBzdGVwIG9mICgxLWMsLWMpIGluICh4LHkpLCBhbmQgXG4gIC8vIGEgc3RlcCBvZiAoMCwxKSBpbiAoaSxqKSBtZWFucyBhIHN0ZXAgb2YgKC1jLDEtYykgaW4gKHgseSksIHdoZXJlIFxuICAvLyBjID0gKDMtc3FydCgzKSkvNiBcbiAgdmFyIHgxID0geDAgLSBpMSArIEcyOyAvLyBPZmZzZXRzIGZvciBtaWRkbGUgY29ybmVyIGluICh4LHkpIHVuc2tld2VkIGNvb3JkcyBcbiAgdmFyIHkxID0geTAgLSBqMSArIEcyOyBcbiAgdmFyIHgyID0geDAgLSAxLjAgKyAyLjAgKiBHMjsgLy8gT2Zmc2V0cyBmb3IgbGFzdCBjb3JuZXIgaW4gKHgseSkgdW5za2V3ZWQgY29vcmRzIFxuICB2YXIgeTIgPSB5MCAtIDEuMCArIDIuMCAqIEcyOyBcbiAgLy8gV29yayBvdXQgdGhlIGhhc2hlZCBncmFkaWVudCBpbmRpY2VzIG9mIHRoZSB0aHJlZSBzaW1wbGV4IGNvcm5lcnMgXG4gIHZhciBpaSA9IGkgJiAyNTU7IFxuICB2YXIgamogPSBqICYgMjU1OyBcbiAgdmFyIGdpMCA9IHRoaXMucGVybVtpaSt0aGlzLnBlcm1bampdXSAlIDEyOyBcbiAgdmFyIGdpMSA9IHRoaXMucGVybVtpaStpMSt0aGlzLnBlcm1bamorajFdXSAlIDEyOyBcbiAgdmFyIGdpMiA9IHRoaXMucGVybVtpaSsxK3RoaXMucGVybVtqaisxXV0gJSAxMjsgXG4gIC8vIENhbGN1bGF0ZSB0aGUgY29udHJpYnV0aW9uIGZyb20gdGhlIHRocmVlIGNvcm5lcnMgXG4gIHZhciB0MCA9IDAuNSAtIHgwKngwLXkwKnkwOyBcbiAgaWYodDA8MCkgbjAgPSAwLjA7IFxuICBlbHNlIHsgXG4gICAgdDAgKj0gdDA7IFxuICAgIG4wID0gdDAgKiB0MCAqIHRoaXMuZG90KHRoaXMuZ3JhZDNbZ2kwXSwgeDAsIHkwKTsgIC8vICh4LHkpIG9mIGdyYWQzIHVzZWQgZm9yIDJEIGdyYWRpZW50IFxuICB9IFxuICB2YXIgdDEgPSAwLjUgLSB4MSp4MS15MSp5MTsgXG4gIGlmKHQxPDApIG4xID0gMC4wOyBcbiAgZWxzZSB7IFxuICAgIHQxICo9IHQxOyBcbiAgICBuMSA9IHQxICogdDEgKiB0aGlzLmRvdCh0aGlzLmdyYWQzW2dpMV0sIHgxLCB5MSk7IFxuICB9XG4gIHZhciB0MiA9IDAuNSAtIHgyKngyLXkyKnkyOyBcbiAgaWYodDI8MCkgbjIgPSAwLjA7IFxuICBlbHNlIHsgXG4gICAgdDIgKj0gdDI7IFxuICAgIG4yID0gdDIgKiB0MiAqIHRoaXMuZG90KHRoaXMuZ3JhZDNbZ2kyXSwgeDIsIHkyKTsgXG4gIH0gXG4gIC8vIEFkZCBjb250cmlidXRpb25zIGZyb20gZWFjaCBjb3JuZXIgdG8gZ2V0IHRoZSBmaW5hbCBub2lzZSB2YWx1ZS4gXG4gIC8vIFRoZSByZXN1bHQgaXMgc2NhbGVkIHRvIHJldHVybiB2YWx1ZXMgaW4gdGhlIGludGVydmFsIFstMSwxXS4gXG4gIHJldHVybiA3MC4wICogKG4wICsgbjEgKyBuMik7IFxufTtcblxuLy8gM0Qgc2ltcGxleCBub2lzZSBcblNpbXBsZXhOb2lzZS5wcm90b3R5cGUubm9pc2UzZCA9IGZ1bmN0aW9uKHhpbiwgeWluLCB6aW4pIHsgXG4gIHZhciBuMCwgbjEsIG4yLCBuMzsgLy8gTm9pc2UgY29udHJpYnV0aW9ucyBmcm9tIHRoZSBmb3VyIGNvcm5lcnMgXG4gIC8vIFNrZXcgdGhlIGlucHV0IHNwYWNlIHRvIGRldGVybWluZSB3aGljaCBzaW1wbGV4IGNlbGwgd2UncmUgaW4gXG4gIHZhciBGMyA9IDEuMC8zLjA7IFxuICB2YXIgcyA9ICh4aW4reWluK3ppbikqRjM7IC8vIFZlcnkgbmljZSBhbmQgc2ltcGxlIHNrZXcgZmFjdG9yIGZvciAzRCBcbiAgdmFyIGkgPSBNYXRoLmZsb29yKHhpbitzKTsgXG4gIHZhciBqID0gTWF0aC5mbG9vcih5aW4rcyk7IFxuICB2YXIgayA9IE1hdGguZmxvb3IoemluK3MpOyBcbiAgdmFyIEczID0gMS4wLzYuMDsgLy8gVmVyeSBuaWNlIGFuZCBzaW1wbGUgdW5za2V3IGZhY3RvciwgdG9vIFxuICB2YXIgdCA9IChpK2oraykqRzM7IFxuICB2YXIgWDAgPSBpLXQ7IC8vIFVuc2tldyB0aGUgY2VsbCBvcmlnaW4gYmFjayB0byAoeCx5LHopIHNwYWNlIFxuICB2YXIgWTAgPSBqLXQ7IFxuICB2YXIgWjAgPSBrLXQ7IFxuICB2YXIgeDAgPSB4aW4tWDA7IC8vIFRoZSB4LHkseiBkaXN0YW5jZXMgZnJvbSB0aGUgY2VsbCBvcmlnaW4gXG4gIHZhciB5MCA9IHlpbi1ZMDsgXG4gIHZhciB6MCA9IHppbi1aMDsgXG4gIC8vIEZvciB0aGUgM0QgY2FzZSwgdGhlIHNpbXBsZXggc2hhcGUgaXMgYSBzbGlnaHRseSBpcnJlZ3VsYXIgdGV0cmFoZWRyb24uIFxuICAvLyBEZXRlcm1pbmUgd2hpY2ggc2ltcGxleCB3ZSBhcmUgaW4uIFxuICB2YXIgaTEsIGoxLCBrMTsgLy8gT2Zmc2V0cyBmb3Igc2Vjb25kIGNvcm5lciBvZiBzaW1wbGV4IGluIChpLGosaykgY29vcmRzIFxuICB2YXIgaTIsIGoyLCBrMjsgLy8gT2Zmc2V0cyBmb3IgdGhpcmQgY29ybmVyIG9mIHNpbXBsZXggaW4gKGksaixrKSBjb29yZHMgXG4gIGlmKHgwPj15MCkgeyBcbiAgICBpZih5MD49ejApIFxuICAgICAgeyBpMT0xOyBqMT0wOyBrMT0wOyBpMj0xOyBqMj0xOyBrMj0wOyB9IC8vIFggWSBaIG9yZGVyIFxuICAgICAgZWxzZSBpZih4MD49ejApIHsgaTE9MTsgajE9MDsgazE9MDsgaTI9MTsgajI9MDsgazI9MTsgfSAvLyBYIFogWSBvcmRlciBcbiAgICAgIGVsc2UgeyBpMT0wOyBqMT0wOyBrMT0xOyBpMj0xOyBqMj0wOyBrMj0xOyB9IC8vIFogWCBZIG9yZGVyIFxuICAgIH0gXG4gIGVsc2UgeyAvLyB4MDx5MCBcbiAgICBpZih5MDx6MCkgeyBpMT0wOyBqMT0wOyBrMT0xOyBpMj0wOyBqMj0xOyBrMj0xOyB9IC8vIFogWSBYIG9yZGVyIFxuICAgIGVsc2UgaWYoeDA8ejApIHsgaTE9MDsgajE9MTsgazE9MDsgaTI9MDsgajI9MTsgazI9MTsgfSAvLyBZIFogWCBvcmRlciBcbiAgICBlbHNlIHsgaTE9MDsgajE9MTsgazE9MDsgaTI9MTsgajI9MTsgazI9MDsgfSAvLyBZIFggWiBvcmRlciBcbiAgfSBcbiAgLy8gQSBzdGVwIG9mICgxLDAsMCkgaW4gKGksaixrKSBtZWFucyBhIHN0ZXAgb2YgKDEtYywtYywtYykgaW4gKHgseSx6KSwgXG4gIC8vIGEgc3RlcCBvZiAoMCwxLDApIGluIChpLGosaykgbWVhbnMgYSBzdGVwIG9mICgtYywxLWMsLWMpIGluICh4LHkseiksIGFuZCBcbiAgLy8gYSBzdGVwIG9mICgwLDAsMSkgaW4gKGksaixrKSBtZWFucyBhIHN0ZXAgb2YgKC1jLC1jLDEtYykgaW4gKHgseSx6KSwgd2hlcmUgXG4gIC8vIGMgPSAxLzYuXG4gIHZhciB4MSA9IHgwIC0gaTEgKyBHMzsgLy8gT2Zmc2V0cyBmb3Igc2Vjb25kIGNvcm5lciBpbiAoeCx5LHopIGNvb3JkcyBcbiAgdmFyIHkxID0geTAgLSBqMSArIEczOyBcbiAgdmFyIHoxID0gejAgLSBrMSArIEczOyBcbiAgdmFyIHgyID0geDAgLSBpMiArIDIuMCpHMzsgLy8gT2Zmc2V0cyBmb3IgdGhpcmQgY29ybmVyIGluICh4LHkseikgY29vcmRzIFxuICB2YXIgeTIgPSB5MCAtIGoyICsgMi4wKkczOyBcbiAgdmFyIHoyID0gejAgLSBrMiArIDIuMCpHMzsgXG4gIHZhciB4MyA9IHgwIC0gMS4wICsgMy4wKkczOyAvLyBPZmZzZXRzIGZvciBsYXN0IGNvcm5lciBpbiAoeCx5LHopIGNvb3JkcyBcbiAgdmFyIHkzID0geTAgLSAxLjAgKyAzLjAqRzM7IFxuICB2YXIgejMgPSB6MCAtIDEuMCArIDMuMCpHMzsgXG4gIC8vIFdvcmsgb3V0IHRoZSBoYXNoZWQgZ3JhZGllbnQgaW5kaWNlcyBvZiB0aGUgZm91ciBzaW1wbGV4IGNvcm5lcnMgXG4gIHZhciBpaSA9IGkgJiAyNTU7IFxuICB2YXIgamogPSBqICYgMjU1OyBcbiAgdmFyIGtrID0gayAmIDI1NTsgXG4gIHZhciBnaTAgPSB0aGlzLnBlcm1baWkrdGhpcy5wZXJtW2pqK3RoaXMucGVybVtra11dXSAlIDEyOyBcbiAgdmFyIGdpMSA9IHRoaXMucGVybVtpaStpMSt0aGlzLnBlcm1bamorajErdGhpcy5wZXJtW2trK2sxXV1dICUgMTI7IFxuICB2YXIgZ2kyID0gdGhpcy5wZXJtW2lpK2kyK3RoaXMucGVybVtqaitqMit0aGlzLnBlcm1ba2srazJdXV0gJSAxMjsgXG4gIHZhciBnaTMgPSB0aGlzLnBlcm1baWkrMSt0aGlzLnBlcm1bamorMSt0aGlzLnBlcm1ba2srMV1dXSAlIDEyOyBcbiAgLy8gQ2FsY3VsYXRlIHRoZSBjb250cmlidXRpb24gZnJvbSB0aGUgZm91ciBjb3JuZXJzIFxuICB2YXIgdDAgPSAwLjYgLSB4MCp4MCAtIHkwKnkwIC0gejAqejA7IFxuICBpZih0MDwwKSBuMCA9IDAuMDsgXG4gIGVsc2UgeyBcbiAgICB0MCAqPSB0MDsgXG4gICAgbjAgPSB0MCAqIHQwICogdGhpcy5kb3QodGhpcy5ncmFkM1tnaTBdLCB4MCwgeTAsIHowKTsgXG4gIH1cbiAgdmFyIHQxID0gMC42IC0geDEqeDEgLSB5MSp5MSAtIHoxKnoxOyBcbiAgaWYodDE8MCkgbjEgPSAwLjA7IFxuICBlbHNlIHsgXG4gICAgdDEgKj0gdDE7IFxuICAgIG4xID0gdDEgKiB0MSAqIHRoaXMuZG90KHRoaXMuZ3JhZDNbZ2kxXSwgeDEsIHkxLCB6MSk7IFxuICB9IFxuICB2YXIgdDIgPSAwLjYgLSB4Mip4MiAtIHkyKnkyIC0gejIqejI7IFxuICBpZih0MjwwKSBuMiA9IDAuMDsgXG4gIGVsc2UgeyBcbiAgICB0MiAqPSB0MjsgXG4gICAgbjIgPSB0MiAqIHQyICogdGhpcy5kb3QodGhpcy5ncmFkM1tnaTJdLCB4MiwgeTIsIHoyKTsgXG4gIH0gXG4gIHZhciB0MyA9IDAuNiAtIHgzKngzIC0geTMqeTMgLSB6Myp6MzsgXG4gIGlmKHQzPDApIG4zID0gMC4wOyBcbiAgZWxzZSB7IFxuICAgIHQzICo9IHQzOyBcbiAgICBuMyA9IHQzICogdDMgKiB0aGlzLmRvdCh0aGlzLmdyYWQzW2dpM10sIHgzLCB5MywgejMpOyBcbiAgfSBcbiAgLy8gQWRkIGNvbnRyaWJ1dGlvbnMgZnJvbSBlYWNoIGNvcm5lciB0byBnZXQgdGhlIGZpbmFsIG5vaXNlIHZhbHVlLiBcbiAgLy8gVGhlIHJlc3VsdCBpcyBzY2FsZWQgdG8gc3RheSBqdXN0IGluc2lkZSBbLTEsMV0gXG4gIHJldHVybiAzMi4wKihuMCArIG4xICsgbjIgKyBuMyk7IFxufTsiXX0= | |
| require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | |
| // shim for using process in browser | |
| var process = module.exports = {}; | |
| // cached from whatever global is present so that test runners that stub it | |
| // don't break things. But we need to wrap it in a try catch in case it is | |
| // wrapped in strict mode code which doesn't define any globals. It's inside a | |
| // function because try/catches deoptimize in certain engines. | |
| var cachedSetTimeout; | |
| var cachedClearTimeout; | |
| function defaultSetTimout() { | |
| throw new Error('setTimeout has not been defined'); | |
| } | |
| function defaultClearTimeout () { | |
| throw new Error('clearTimeout has not been defined'); | |
| } | |
| (function () { | |
| try { | |
| if (typeof setTimeout === 'function') { | |
| cachedSetTimeout = setTimeout; | |
| } else { | |
| cachedSetTimeout = defaultSetTimout; | |
| } | |
| } catch (e) { | |
| cachedSetTimeout = defaultSetTimout; | |
| } | |
| try { | |
| if (typeof clearTimeout === 'function') { | |
| cachedClearTimeout = clearTimeout; | |
| } else { | |
| cachedClearTimeout = defaultClearTimeout; | |
| } | |
| } catch (e) { | |
| cachedClearTimeout = defaultClearTimeout; | |
| } | |
| } ()) | |
| function runTimeout(fun) { | |
| if (cachedSetTimeout === setTimeout) { | |
| //normal enviroments in sane situations | |
| return setTimeout(fun, 0); | |
| } | |
| // if setTimeout wasn't available but was latter defined | |
| if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { | |
| cachedSetTimeout = setTimeout; | |
| return setTimeout(fun, 0); | |
| } | |
| try { | |
| // when when somebody has screwed with setTimeout but no I.E. maddness | |
| return cachedSetTimeout(fun, 0); | |
| } catch(e){ | |
| try { | |
| // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally | |
| return cachedSetTimeout.call(null, fun, 0); | |
| } catch(e){ | |
| // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error | |
| return cachedSetTimeout.call(this, fun, 0); | |
| } | |
| } | |
| } | |
| function runClearTimeout(marker) { | |
| if (cachedClearTimeout === clearTimeout) { | |
| //normal enviroments in sane situations | |
| return clearTimeout(marker); | |
| } | |
| // if clearTimeout wasn't available but was latter defined | |
| if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { | |
| cachedClearTimeout = clearTimeout; | |
| return clearTimeout(marker); | |
| } | |
| try { | |
| // when when somebody has screwed with setTimeout but no I.E. maddness | |
| return cachedClearTimeout(marker); | |
| } catch (e){ | |
| try { | |
| // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally | |
| return cachedClearTimeout.call(null, marker); | |
| } catch (e){ | |
| // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. | |
| // Some versions of I.E. have different rules for clearTimeout vs setTimeout | |
| return cachedClearTimeout.call(this, marker); | |
| } | |
| } | |
| } | |
| var queue = []; | |
| var draining = false; | |
| var currentQueue; | |
| var queueIndex = -1; | |
| function cleanUpNextTick() { | |
| if (!draining || !currentQueue) { | |
| return; | |
| } | |
| draining = false; | |
| if (currentQueue.length) { | |
| queue = currentQueue.concat(queue); | |
| } else { | |
| queueIndex = -1; | |
| } | |
| if (queue.length) { | |
| drainQueue(); | |
| } | |
| } | |
| function drainQueue() { | |
| if (draining) { | |
| return; | |
| } | |
| var timeout = runTimeout(cleanUpNextTick); | |
| draining = true; | |
| var len = queue.length; | |
| while(len) { | |
| currentQueue = queue; | |
| queue = []; | |
| while (++queueIndex < len) { | |
| if (currentQueue) { | |
| currentQueue[queueIndex].run(); | |
| } | |
| } | |
| queueIndex = -1; | |
| len = queue.length; | |
| } | |
| currentQueue = null; | |
| draining = false; | |
| runClearTimeout(timeout); | |
| } | |
| process.nextTick = function (fun) { | |
| var args = new Array(arguments.length - 1); | |
| if (arguments.length > 1) { | |
| for (var i = 1; i < arguments.length; i++) { | |
| args[i - 1] = arguments[i]; | |
| } | |
| } | |
| queue.push(new Item(fun, args)); | |
| if (queue.length === 1 && !draining) { | |
| runTimeout(drainQueue); | |
| } | |
| }; | |
| // v8 likes predictible objects | |
| function Item(fun, array) { | |
| this.fun = fun; | |
| this.array = array; | |
| } | |
| Item.prototype.run = function () { | |
| this.fun.apply(null, this.array); | |
| }; | |
| process.title = 'browser'; | |
| process.browser = true; | |
| process.env = {}; | |
| process.argv = []; | |
| process.version = ''; // empty string to avoid regexp issues | |
| process.versions = {}; | |
| function noop() {} | |
| process.on = noop; | |
| process.addListener = noop; | |
| process.once = noop; | |
| process.off = noop; | |
| process.removeListener = noop; | |
| process.removeAllListeners = noop; | |
| process.emit = noop; | |
| process.binding = function (name) { | |
| throw new Error('process.binding is not supported'); | |
| }; | |
| process.cwd = function () { return '/' }; | |
| process.chdir = function (dir) { | |
| throw new Error('process.chdir is not supported'); | |
| }; | |
| process.umask = function() { return 0; }; | |
| },{}],"@tweenjs/tween.js":[function(require,module,exports){ | |
| (function (process){ | |
| /** | |
| * Tween.js - Licensed under the MIT license | |
| * https://github.com/tweenjs/tween.js | |
| * ---------------------------------------------- | |
| * | |
| * See https://github.com/tweenjs/tween.js/graphs/contributors for the full list of contributors. | |
| * Thank you all, you're awesome! | |
| */ | |
| var _Group = function () { | |
| this._tweens = {}; | |
| this._tweensAddedDuringUpdate = {}; | |
| }; | |
| _Group.prototype = { | |
| getAll: function () { | |
| return Object.keys(this._tweens).map(function (tweenId) { | |
| return this._tweens[tweenId]; | |
| }.bind(this)); | |
| }, | |
| removeAll: function () { | |
| this._tweens = {}; | |
| }, | |
| add: function (tween) { | |
| this._tweens[tween.getId()] = tween; | |
| this._tweensAddedDuringUpdate[tween.getId()] = tween; | |
| }, | |
| remove: function (tween) { | |
| delete this._tweens[tween.getId()]; | |
| delete this._tweensAddedDuringUpdate[tween.getId()]; | |
| }, | |
| update: function (time, preserve) { | |
| var tweenIds = Object.keys(this._tweens); | |
| if (tweenIds.length === 0) { | |
| return false; | |
| } | |
| time = time !== undefined ? time : TWEEN.now(); | |
| // Tweens are updated in "batches". If you add a new tween during an update, then the | |
| // new tween will be updated in the next batch. | |
| // If you remove a tween during an update, it may or may not be updated. However, | |
| // if the removed tween was added during the current batch, then it will not be updated. | |
| while (tweenIds.length > 0) { | |
| this._tweensAddedDuringUpdate = {}; | |
| for (var i = 0; i < tweenIds.length; i++) { | |
| var tween = this._tweens[tweenIds[i]]; | |
| if (tween && tween.update(time) === false) { | |
| tween._isPlaying = false; | |
| if (!preserve) { | |
| delete this._tweens[tweenIds[i]]; | |
| } | |
| } | |
| } | |
| tweenIds = Object.keys(this._tweensAddedDuringUpdate); | |
| } | |
| return true; | |
| } | |
| }; | |
| var TWEEN = new _Group(); | |
| TWEEN.Group = _Group; | |
| TWEEN._nextId = 0; | |
| TWEEN.nextId = function () { | |
| return TWEEN._nextId++; | |
| }; | |
| // Include a performance.now polyfill. | |
| // In node.js, use process.hrtime. | |
| if (typeof (window) === 'undefined' && typeof (process) !== 'undefined') { | |
| TWEEN.now = function () { | |
| var time = process.hrtime(); | |
| // Convert [seconds, nanoseconds] to milliseconds. | |
| return time[0] * 1000 + time[1] / 1000000; | |
| }; | |
| } | |
| // In a browser, use window.performance.now if it is available. | |
| else if (typeof (window) !== 'undefined' && | |
| window.performance !== undefined && | |
| window.performance.now !== undefined) { | |
| // This must be bound, because directly assigning this function | |
| // leads to an invocation exception in Chrome. | |
| TWEEN.now = window.performance.now.bind(window.performance); | |
| } | |
| // Use Date.now if it is available. | |
| else if (Date.now !== undefined) { | |
| TWEEN.now = Date.now; | |
| } | |
| // Otherwise, use 'new Date().getTime()'. | |
| else { | |
| TWEEN.now = function () { | |
| return new Date().getTime(); | |
| }; | |
| } | |
| TWEEN.Tween = function (object, group) { | |
| this._object = object; | |
| this._valuesStart = {}; | |
| this._valuesEnd = {}; | |
| this._valuesStartRepeat = {}; | |
| this._duration = 1000; | |
| this._repeat = 0; | |
| this._repeatDelayTime = undefined; | |
| this._yoyo = false; | |
| this._isPlaying = false; | |
| this._reversed = false; | |
| this._delayTime = 0; | |
| this._startTime = null; | |
| this._easingFunction = TWEEN.Easing.Linear.None; | |
| this._interpolationFunction = TWEEN.Interpolation.Linear; | |
| this._chainedTweens = []; | |
| this._onStartCallback = null; | |
| this._onStartCallbackFired = false; | |
| this._onUpdateCallback = null; | |
| this._onCompleteCallback = null; | |
| this._onStopCallback = null; | |
| this._group = group || TWEEN; | |
| this._id = TWEEN.nextId(); | |
| }; | |
| TWEEN.Tween.prototype = { | |
| getId: function getId() { | |
| return this._id; | |
| }, | |
| isPlaying: function isPlaying() { | |
| return this._isPlaying; | |
| }, | |
| to: function to(properties, duration) { | |
| this._valuesEnd = properties; | |
| if (duration !== undefined) { | |
| this._duration = duration; | |
| } | |
| return this; | |
| }, | |
| start: function start(time) { | |
| this._group.add(this); | |
| this._isPlaying = true; | |
| this._onStartCallbackFired = false; | |
| this._startTime = time !== undefined ? typeof time === 'string' ? TWEEN.now() + parseFloat(time) : time : TWEEN.now(); | |
| this._startTime += this._delayTime; | |
| for (var property in this._valuesEnd) { | |
| // Check if an Array was provided as property value | |
| if (this._valuesEnd[property] instanceof Array) { | |
| if (this._valuesEnd[property].length === 0) { | |
| continue; | |
| } | |
| // Create a local copy of the Array with the start value at the front | |
| this._valuesEnd[property] = [this._object[property]].concat(this._valuesEnd[property]); | |
| } | |
| // If `to()` specifies a property that doesn't exist in the source object, | |
| // we should not set that property in the object | |
| if (this._object[property] === undefined) { | |
| continue; | |
| } | |
| // Save the starting value. | |
| this._valuesStart[property] = this._object[property]; | |
| if ((this._valuesStart[property] instanceof Array) === false) { | |
| this._valuesStart[property] *= 1.0; // Ensures we're using numbers, not strings | |
| } | |
| this._valuesStartRepeat[property] = this._valuesStart[property] || 0; | |
| } | |
| return this; | |
| }, | |
| stop: function stop() { | |
| if (!this._isPlaying) { | |
| return this; | |
| } | |
| this._group.remove(this); | |
| this._isPlaying = false; | |
| if (this._onStopCallback !== null) { | |
| this._onStopCallback(this._object); | |
| } | |
| this.stopChainedTweens(); | |
| return this; | |
| }, | |
| end: function end() { | |
| this.update(this._startTime + this._duration); | |
| return this; | |
| }, | |
| stopChainedTweens: function stopChainedTweens() { | |
| for (var i = 0, numChainedTweens = this._chainedTweens.length; i < numChainedTweens; i++) { | |
| this._chainedTweens[i].stop(); | |
| } | |
| }, | |
| delay: function delay(amount) { | |
| this._delayTime = amount; | |
| return this; | |
| }, | |
| repeat: function repeat(times) { | |
| this._repeat = times; | |
| return this; | |
| }, | |
| repeatDelay: function repeatDelay(amount) { | |
| this._repeatDelayTime = amount; | |
| return this; | |
| }, | |
| yoyo: function yoyo(yoyo) { | |
| this._yoyo = yoyo; | |
| return this; | |
| }, | |
| easing: function easing(easing) { | |
| this._easingFunction = easing; | |
| return this; | |
| }, | |
| interpolation: function interpolation(interpolation) { | |
| this._interpolationFunction = interpolation; | |
| return this; | |
| }, | |
| chain: function chain() { | |
| this._chainedTweens = arguments; | |
| return this; | |
| }, | |
| onStart: function onStart(callback) { | |
| this._onStartCallback = callback; | |
| return this; | |
| }, | |
| onUpdate: function onUpdate(callback) { | |
| this._onUpdateCallback = callback; | |
| return this; | |
| }, | |
| onComplete: function onComplete(callback) { | |
| this._onCompleteCallback = callback; | |
| return this; | |
| }, | |
| onStop: function onStop(callback) { | |
| this._onStopCallback = callback; | |
| return this; | |
| }, | |
| update: function update(time) { | |
| var property; | |
| var elapsed; | |
| var value; | |
| if (time < this._startTime) { | |
| return true; | |
| } | |
| if (this._onStartCallbackFired === false) { | |
| if (this._onStartCallback !== null) { | |
| this._onStartCallback(this._object); | |
| } | |
| this._onStartCallbackFired = true; | |
| } | |
| elapsed = (time - this._startTime) / this._duration; | |
| elapsed = elapsed > 1 ? 1 : elapsed; | |
| value = this._easingFunction(elapsed); | |
| for (property in this._valuesEnd) { | |
| // Don't update properties that do not exist in the source object | |
| if (this._valuesStart[property] === undefined) { | |
| continue; | |
| } | |
| var start = this._valuesStart[property] || 0; | |
| var end = this._valuesEnd[property]; | |
| if (end instanceof Array) { | |
| this._object[property] = this._interpolationFunction(end, value); | |
| } else { | |
| // Parses relative end values with start as base (e.g.: +10, -3) | |
| if (typeof (end) === 'string') { | |
| if (end.charAt(0) === '+' || end.charAt(0) === '-') { | |
| end = start + parseFloat(end); | |
| } else { | |
| end = parseFloat(end); | |
| } | |
| } | |
| // Protect against non numeric properties. | |
| if (typeof (end) === 'number') { | |
| this._object[property] = start + (end - start) * value; | |
| } | |
| } | |
| } | |
| if (this._onUpdateCallback !== null) { | |
| this._onUpdateCallback(this._object); | |
| } | |
| if (elapsed === 1) { | |
| if (this._repeat > 0) { | |
| if (isFinite(this._repeat)) { | |
| this._repeat--; | |
| } | |
| // Reassign starting values, restart by making startTime = now | |
| for (property in this._valuesStartRepeat) { | |
| if (typeof (this._valuesEnd[property]) === 'string') { | |
| this._valuesStartRepeat[property] = this._valuesStartRepeat[property] + parseFloat(this._valuesEnd[property]); | |
| } | |
| if (this._yoyo) { | |
| var tmp = this._valuesStartRepeat[property]; | |
| this._valuesStartRepeat[property] = this._valuesEnd[property]; | |
| this._valuesEnd[property] = tmp; | |
| } | |
| this._valuesStart[property] = this._valuesStartRepeat[property]; | |
| } | |
| if (this._yoyo) { | |
| this._reversed = !this._reversed; | |
| } | |
| if (this._repeatDelayTime !== undefined) { | |
| this._startTime = time + this._repeatDelayTime; | |
| } else { | |
| this._startTime = time + this._delayTime; | |
| } | |
| return true; | |
| } else { | |
| if (this._onCompleteCallback !== null) { | |
| this._onCompleteCallback(this._object); | |
| } | |
| for (var i = 0, numChainedTweens = this._chainedTweens.length; i < numChainedTweens; i++) { | |
| // Make the chained tweens start exactly at the time they should, | |
| // even if the `update()` method was called way past the duration of the tween | |
| this._chainedTweens[i].start(this._startTime + this._duration); | |
| } | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| }; | |
| TWEEN.Easing = { | |
| Linear: { | |
| None: function (k) { | |
| return k; | |
| } | |
| }, | |
| Quadratic: { | |
| In: function (k) { | |
| return k * k; | |
| }, | |
| Out: function (k) { | |
| return k * (2 - k); | |
| }, | |
| InOut: function (k) { | |
| if ((k *= 2) < 1) { | |
| return 0.5 * k * k; | |
| } | |
| return - 0.5 * (--k * (k - 2) - 1); | |
| } | |
| }, | |
| Cubic: { | |
| In: function (k) { | |
| return k * k * k; | |
| }, | |
| Out: function (k) { | |
| return --k * k * k + 1; | |
| }, | |
| InOut: function (k) { | |
| if ((k *= 2) < 1) { | |
| return 0.5 * k * k * k; | |
| } | |
| return 0.5 * ((k -= 2) * k * k + 2); | |
| } | |
| }, | |
| Quartic: { | |
| In: function (k) { | |
| return k * k * k * k; | |
| }, | |
| Out: function (k) { | |
| return 1 - (--k * k * k * k); | |
| }, | |
| InOut: function (k) { | |
| if ((k *= 2) < 1) { | |
| return 0.5 * k * k * k * k; | |
| } | |
| return - 0.5 * ((k -= 2) * k * k * k - 2); | |
| } | |
| }, | |
| Quintic: { | |
| In: function (k) { | |
| return k * k * k * k * k; | |
| }, | |
| Out: function (k) { | |
| return --k * k * k * k * k + 1; | |
| }, | |
| InOut: function (k) { | |
| if ((k *= 2) < 1) { | |
| return 0.5 * k * k * k * k * k; | |
| } | |
| return 0.5 * ((k -= 2) * k * k * k * k + 2); | |
| } | |
| }, | |
| Sinusoidal: { | |
| In: function (k) { | |
| return 1 - Math.cos(k * Math.PI / 2); | |
| }, | |
| Out: function (k) { | |
| return Math.sin(k * Math.PI / 2); | |
| }, | |
| InOut: function (k) { | |
| return 0.5 * (1 - Math.cos(Math.PI * k)); | |
| } | |
| }, | |
| Exponential: { | |
| In: function (k) { | |
| return k === 0 ? 0 : Math.pow(1024, k - 1); | |
| }, | |
| Out: function (k) { | |
| return k === 1 ? 1 : 1 - Math.pow(2, - 10 * k); | |
| }, | |
| InOut: function (k) { | |
| if (k === 0) { | |
| return 0; | |
| } | |
| if (k === 1) { | |
| return 1; | |
| } | |
| if ((k *= 2) < 1) { | |
| return 0.5 * Math.pow(1024, k - 1); | |
| } | |
| return 0.5 * (- Math.pow(2, - 10 * (k - 1)) + 2); | |
| } | |
| }, | |
| Circular: { | |
| In: function (k) { | |
| return 1 - Math.sqrt(1 - k * k); | |
| }, | |
| Out: function (k) { | |
| return Math.sqrt(1 - (--k * k)); | |
| }, | |
| InOut: function (k) { | |
| if ((k *= 2) < 1) { | |
| return - 0.5 * (Math.sqrt(1 - k * k) - 1); | |
| } | |
| return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1); | |
| } | |
| }, | |
| Elastic: { | |
| In: function (k) { | |
| if (k === 0) { | |
| return 0; | |
| } | |
| if (k === 1) { | |
| return 1; | |
| } | |
| return -Math.pow(2, 10 * (k - 1)) * Math.sin((k - 1.1) * 5 * Math.PI); | |
| }, | |
| Out: function (k) { | |
| if (k === 0) { | |
| return 0; | |
| } | |
| if (k === 1) { | |
| return 1; | |
| } | |
| return Math.pow(2, -10 * k) * Math.sin((k - 0.1) * 5 * Math.PI) + 1; | |
| }, | |
| InOut: function (k) { | |
| if (k === 0) { | |
| return 0; | |
| } | |
| if (k === 1) { | |
| return 1; | |
| } | |
| k *= 2; | |
| if (k < 1) { | |
| return -0.5 * Math.pow(2, 10 * (k - 1)) * Math.sin((k - 1.1) * 5 * Math.PI); | |
| } | |
| return 0.5 * Math.pow(2, -10 * (k - 1)) * Math.sin((k - 1.1) * 5 * Math.PI) + 1; | |
| } | |
| }, | |
| Back: { | |
| In: function (k) { | |
| var s = 1.70158; | |
| return k * k * ((s + 1) * k - s); | |
| }, | |
| Out: function (k) { | |
| var s = 1.70158; | |
| return --k * k * ((s + 1) * k + s) + 1; | |
| }, | |
| InOut: function (k) { | |
| var s = 1.70158 * 1.525; | |
| if ((k *= 2) < 1) { | |
| return 0.5 * (k * k * ((s + 1) * k - s)); | |
| } | |
| return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2); | |
| } | |
| }, | |
| Bounce: { | |
| In: function (k) { | |
| return 1 - TWEEN.Easing.Bounce.Out(1 - k); | |
| }, | |
| Out: function (k) { | |
| if (k < (1 / 2.75)) { | |
| return 7.5625 * k * k; | |
| } else if (k < (2 / 2.75)) { | |
| return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; | |
| } else if (k < (2.5 / 2.75)) { | |
| return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; | |
| } else { | |
| return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; | |
| } | |
| }, | |
| InOut: function (k) { | |
| if (k < 0.5) { | |
| return TWEEN.Easing.Bounce.In(k * 2) * 0.5; | |
| } | |
| return TWEEN.Easing.Bounce.Out(k * 2 - 1) * 0.5 + 0.5; | |
| } | |
| } | |
| }; | |
| TWEEN.Interpolation = { | |
| Linear: function (v, k) { | |
| var m = v.length - 1; | |
| var f = m * k; | |
| var i = Math.floor(f); | |
| var fn = TWEEN.Interpolation.Utils.Linear; | |
| if (k < 0) { | |
| return fn(v[0], v[1], f); | |
| } | |
| if (k > 1) { | |
| return fn(v[m], v[m - 1], m - f); | |
| } | |
| return fn(v[i], v[i + 1 > m ? m : i + 1], f - i); | |
| }, | |
| Bezier: function (v, k) { | |
| var b = 0; | |
| var n = v.length - 1; | |
| var pw = Math.pow; | |
| var bn = TWEEN.Interpolation.Utils.Bernstein; | |
| for (var i = 0; i <= n; i++) { | |
| b += pw(1 - k, n - i) * pw(k, i) * v[i] * bn(n, i); | |
| } | |
| return b; | |
| }, | |
| CatmullRom: function (v, k) { | |
| var m = v.length - 1; | |
| var f = m * k; | |
| var i = Math.floor(f); | |
| var fn = TWEEN.Interpolation.Utils.CatmullRom; | |
| if (v[0] === v[m]) { | |
| if (k < 0) { | |
| i = Math.floor(f = m * (1 + k)); | |
| } | |
| return fn(v[(i - 1 + m) % m], v[i], v[(i + 1) % m], v[(i + 2) % m], f - i); | |
| } else { | |
| if (k < 0) { | |
| return v[0] - (fn(v[0], v[0], v[1], v[1], -f) - v[0]); | |
| } | |
| if (k > 1) { | |
| return v[m] - (fn(v[m], v[m], v[m - 1], v[m - 1], f - m) - v[m]); | |
| } | |
| return fn(v[i ? i - 1 : 0], v[i], v[m < i + 1 ? m : i + 1], v[m < i + 2 ? m : i + 2], f - i); | |
| } | |
| }, | |
| Utils: { | |
| Linear: function (p0, p1, t) { | |
| return (p1 - p0) * t + p0; | |
| }, | |
| Bernstein: function (n, i) { | |
| var fc = TWEEN.Interpolation.Utils.Factorial; | |
| return fc(n) / fc(i) / fc(n - i); | |
| }, | |
| Factorial: (function () { | |
| var a = [1]; | |
| return function (n) { | |
| var s = 1; | |
| if (a[n]) { | |
| return a[n]; | |
| } | |
| for (var i = n; i > 1; i--) { | |
| s *= i; | |
| } | |
| a[n] = s; | |
| return s; | |
| }; | |
| })(), | |
| CatmullRom: function (p0, p1, p2, p3, t) { | |
| var v0 = (p2 - p0) * 0.5; | |
| var v1 = (p3 - p1) * 0.5; | |
| var t2 = t * t; | |
| var t3 = t * t2; | |
| return (2 * p1 - 2 * p2 + v0 + v1) * t3 + (- 3 * p1 + 3 * p2 - 2 * v0 - v1) * t2 + v0 * t + p1; | |
| } | |
| } | |
| }; | |
| // UMD (Universal Module Definition) | |
| (function (root) { | |
| if (typeof define === 'function' && define.amd) { | |
| // AMD | |
| define([], function () { | |
| return TWEEN; | |
| }); | |
| } else if (typeof module !== 'undefined' && typeof exports === 'object') { | |
| // Node.js | |
| module.exports = TWEEN; | |
| } else if (root !== undefined) { | |
| // Global variable | |
| root.TWEEN = TWEEN; | |
| } | |
| })(this); | |
| }).call(this,require('_process')) | |
| },{"_process":1}]},{},[]) | |
| //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL3Byb2Nlc3MvYnJvd3Nlci5qcyIsInNyYy9Ud2Vlbi5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUNwTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLy8gc2hpbSBmb3IgdXNpbmcgcHJvY2VzcyBpbiBicm93c2VyXG52YXIgcHJvY2VzcyA9IG1vZHVsZS5leHBvcnRzID0ge307XG5cbi8vIGNhY2hlZCBmcm9tIHdoYXRldmVyIGdsb2JhbCBpcyBwcmVzZW50IHNvIHRoYXQgdGVzdCBydW5uZXJzIHRoYXQgc3R1YiBpdFxuLy8gZG9uJ3QgYnJlYWsgdGhpbmdzLiAgQnV0IHdlIG5lZWQgdG8gd3JhcCBpdCBpbiBhIHRyeSBjYXRjaCBpbiBjYXNlIGl0IGlzXG4vLyB3cmFwcGVkIGluIHN0cmljdCBtb2RlIGNvZGUgd2hpY2ggZG9lc24ndCBkZWZpbmUgYW55IGdsb2JhbHMuICBJdCdzIGluc2lkZSBhXG4vLyBmdW5jdGlvbiBiZWNhdXNlIHRyeS9jYXRjaGVzIGRlb3B0aW1pemUgaW4gY2VydGFpbiBlbmdpbmVzLlxuXG52YXIgY2FjaGVkU2V0VGltZW91dDtcbnZhciBjYWNoZWRDbGVhclRpbWVvdXQ7XG5cbmZ1bmN0aW9uIGRlZmF1bHRTZXRUaW1vdXQoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdzZXRUaW1lb3V0IGhhcyBub3QgYmVlbiBkZWZpbmVkJyk7XG59XG5mdW5jdGlvbiBkZWZhdWx0Q2xlYXJUaW1lb3V0ICgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2NsZWFyVGltZW91dCBoYXMgbm90IGJlZW4gZGVmaW5lZCcpO1xufVxuKGZ1bmN0aW9uICgpIHtcbiAgICB0cnkge1xuICAgICAgICBpZiAodHlwZW9mIHNldFRpbWVvdXQgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIGNhY2hlZFNldFRpbWVvdXQgPSBzZXRUaW1lb3V0O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY2FjaGVkU2V0VGltZW91dCA9IGRlZmF1bHRTZXRUaW1vdXQ7XG4gICAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNhY2hlZFNldFRpbWVvdXQgPSBkZWZhdWx0U2V0VGltb3V0O1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgICBpZiAodHlwZW9mIGNsZWFyVGltZW91dCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgY2FjaGVkQ2xlYXJUaW1lb3V0ID0gY2xlYXJUaW1lb3V0O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY2FjaGVkQ2xlYXJUaW1lb3V0ID0gZGVmYXVsdENsZWFyVGltZW91dDtcbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY2FjaGVkQ2xlYXJUaW1lb3V0ID0gZGVmYXVsdENsZWFyVGltZW91dDtcbiAgICB9XG59ICgpKVxuZnVuY3Rpb24gcnVuVGltZW91dChmdW4pIHtcbiAgICBpZiAoY2FjaGVkU2V0VGltZW91dCA9PT0gc2V0VGltZW91dCkge1xuICAgICAgICAvL25vcm1hbCBlbnZpcm9tZW50cyBpbiBzYW5lIHNpdHVhdGlvbnNcbiAgICAgICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuLCAwKTtcbiAgICB9XG4gICAgLy8gaWYgc2V0VGltZW91dCB3YXNuJ3QgYXZhaWxhYmxlIGJ1dCB3YXMgbGF0dGVyIGRlZmluZWRcbiAgICBpZiAoKGNhY2hlZFNldFRpbWVvdXQgPT09IGRlZmF1bHRTZXRUaW1vdXQgfHwgIWNhY2hlZFNldFRpbWVvdXQpICYmIHNldFRpbWVvdXQpIHtcbiAgICAgICAgY2FjaGVkU2V0VGltZW91dCA9IHNldFRpbWVvdXQ7XG4gICAgICAgIHJldHVybiBzZXRUaW1lb3V0KGZ1biwgMCk7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICAgIC8vIHdoZW4gd2hlbiBzb21lYm9keSBoYXMgc2NyZXdlZCB3aXRoIHNldFRpbWVvdXQgYnV0IG5vIEkuRS4gbWFkZG5lc3NcbiAgICAgICAgcmV0dXJuIGNhY2hlZFNldFRpbWVvdXQoZnVuLCAwKTtcbiAgICB9IGNhdGNoKGUpe1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gV2hlbiB3ZSBhcmUgaW4gSS5FLiBidXQgdGhlIHNjcmlwdCBoYXMgYmVlbiBldmFsZWQgc28gSS5FLiBkb2Vzbid0IHRydXN0IHRoZSBnbG9iYWwgb2JqZWN0IHdoZW4gY2FsbGVkIG5vcm1hbGx5XG4gICAgICAgICAgICByZXR1cm4gY2FjaGVkU2V0VGltZW91dC5jYWxsKG51bGwsIGZ1biwgMCk7XG4gICAgICAgIH0gY2F0Y2goZSl7XG4gICAgICAgICAgICAvLyBzYW1lIGFzIGFib3ZlIGJ1dCB3aGVuIGl0J3MgYSB2ZXJzaW9uIG9mIEkuRS4gdGhhdCBtdXN0IGhhdmUgdGhlIGdsb2JhbCBvYmplY3QgZm9yICd0aGlzJywgaG9wZnVsbHkgb3VyIGNvbnRleHQgY29ycmVjdCBvdGhlcndpc2UgaXQgd2lsbCB0aHJvdyBhIGdsb2JhbCBlcnJvclxuICAgICAgICAgICAgcmV0dXJuIGNhY2hlZFNldFRpbWVvdXQuY2FsbCh0aGlzLCBmdW4sIDApO1xuICAgICAgICB9XG4gICAgfVxuXG5cbn1cbmZ1bmN0aW9uIHJ1bkNsZWFyVGltZW91dChtYXJrZXIpIHtcbiAgICBpZiAoY2FjaGVkQ2xlYXJUaW1lb3V0ID09PSBjbGVhclRpbWVvdXQpIHtcbiAgICAgICAgLy9ub3JtYWwgZW52aXJvbWVudHMgaW4gc2FuZSBzaXR1YXRpb25zXG4gICAgICAgIHJldHVybiBjbGVhclRpbWVvdXQobWFya2VyKTtcbiAgICB9XG4gICAgLy8gaWYgY2xlYXJUaW1lb3V0IHdhc24ndCBhdmFpbGFibGUgYnV0IHdhcyBsYXR0ZXIgZGVmaW5lZFxuICAgIGlmICgoY2FjaGVkQ2xlYXJUaW1lb3V0ID09PSBkZWZhdWx0Q2xlYXJUaW1lb3V0IHx8ICFjYWNoZWRDbGVhclRpbWVvdXQpICYmIGNsZWFyVGltZW91dCkge1xuICAgICAgICBjYWNoZWRDbGVhclRpbWVvdXQgPSBjbGVhclRpbWVvdXQ7XG4gICAgICAgIHJldHVybiBjbGVhclRpbWVvdXQobWFya2VyKTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgICAgLy8gd2hlbiB3aGVuIHNvbWVib2R5IGhhcyBzY3Jld2VkIHdpdGggc2V0VGltZW91dCBidXQgbm8gSS5FLiBtYWRkbmVzc1xuICAgICAgICByZXR1cm4gY2FjaGVkQ2xlYXJUaW1lb3V0KG1hcmtlcik7XG4gICAgfSBjYXRjaCAoZSl7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICAvLyBXaGVuIHdlIGFyZSBpbiBJLkUuIGJ1dCB0aGUgc2NyaXB0IGhhcyBiZWVuIGV2YWxlZCBzbyBJLkUuIGRvZXNuJ3QgIHRydXN0IHRoZSBnbG9iYWwgb2JqZWN0IHdoZW4gY2FsbGVkIG5vcm1hbGx5XG4gICAgICAgICAgICByZXR1cm4gY2FjaGVkQ2xlYXJUaW1lb3V0LmNhbGwobnVsbCwgbWFya2VyKTtcbiAgICAgICAgfSBjYXRjaCAoZSl7XG4gICAgICAgICAgICAvLyBzYW1lIGFzIGFib3ZlIGJ1dCB3aGVuIGl0J3MgYSB2ZXJzaW9uIG9mIEkuRS4gdGhhdCBtdXN0IGhhdmUgdGhlIGdsb2JhbCBvYmplY3QgZm9yICd0aGlzJywgaG9wZnVsbHkgb3VyIGNvbnRleHQgY29ycmVjdCBvdGhlcndpc2UgaXQgd2lsbCB0aHJvdyBhIGdsb2JhbCBlcnJvci5cbiAgICAgICAgICAgIC8vIFNvbWUgdmVyc2lvbnMgb2YgSS5FLiBoYXZlIGRpZmZlcmVudCBydWxlcyBmb3IgY2xlYXJUaW1lb3V0IHZzIHNldFRpbWVvdXRcbiAgICAgICAgICAgIHJldHVybiBjYWNoZWRDbGVhclRpbWVvdXQuY2FsbCh0aGlzLCBtYXJrZXIpO1xuICAgICAgICB9XG4gICAgfVxuXG5cblxufVxudmFyIHF1ZXVlID0gW107XG52YXIgZHJhaW5pbmcgPSBmYWxzZTtcbnZhciBjdXJyZW50UXVldWU7XG52YXIgcXVldWVJbmRleCA9IC0xO1xuXG5mdW5jdGlvbiBjbGVhblVwTmV4dFRpY2soKSB7XG4gICAgaWYgKCFkcmFpbmluZyB8fCAhY3VycmVudFF1ZXVlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZHJhaW5pbmcgPSBmYWxzZTtcbiAgICBpZiAoY3VycmVudFF1ZXVlLmxlbmd0aCkge1xuICAgICAgICBxdWV1ZSA9IGN1cnJlbnRRdWV1ZS5jb25jYXQocXVldWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHF1ZXVlSW5kZXggPSAtMTtcbiAgICB9XG4gICAgaWYgKHF1ZXVlLmxlbmd0aCkge1xuICAgICAgICBkcmFpblF1ZXVlKCk7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBkcmFpblF1ZXVlKCkge1xuICAgIGlmIChkcmFpbmluZykge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIHZhciB0aW1lb3V0ID0gcnVuVGltZW91dChjbGVhblVwTmV4dFRpY2spO1xuICAgIGRyYWluaW5nID0gdHJ1ZTtcblxuICAgIHZhciBsZW4gPSBxdWV1ZS5sZW5ndGg7XG4gICAgd2hpbGUobGVuKSB7XG4gICAgICAgIGN1cnJlbnRRdWV1ZSA9IHF1ZXVlO1xuICAgICAgICBxdWV1ZSA9IFtdO1xuICAgICAgICB3aGlsZSAoKytxdWV1ZUluZGV4IDwgbGVuKSB7XG4gICAgICAgICAgICBpZiAoY3VycmVudFF1ZXVlKSB7XG4gICAgICAgICAgICAgICAgY3VycmVudFF1ZXVlW3F1ZXVlSW5kZXhdLnJ1bigpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHF1ZXVlSW5kZXggPSAtMTtcbiAgICAgICAgbGVuID0gcXVldWUubGVuZ3RoO1xuICAgIH1cbiAgICBjdXJyZW50UXVldWUgPSBudWxsO1xuICAgIGRyYWluaW5nID0gZmFsc2U7XG4gICAgcnVuQ2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xufVxuXG5wcm9jZXNzLm5leHRUaWNrID0gZnVuY3Rpb24gKGZ1bikge1xuICAgIHZhciBhcmdzID0gbmV3IEFycmF5KGFyZ3VtZW50cy5sZW5ndGggLSAxKTtcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDE7IGkgPCBhcmd1bWVudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGFyZ3NbaSAtIDFdID0gYXJndW1lbnRzW2ldO1xuICAgICAgICB9XG4gICAgfVxuICAgIHF1ZXVlLnB1c2gobmV3IEl0ZW0oZnVuLCBhcmdzKSk7XG4gICAgaWYgKHF1ZXVlLmxlbmd0aCA9PT0gMSAmJiAhZHJhaW5pbmcpIHtcbiAgICAgICAgcnVuVGltZW91dChkcmFpblF1ZXVlKTtcbiAgICB9XG59O1xuXG4vLyB2OCBsaWtlcyBwcmVkaWN0aWJsZSBvYmplY3RzXG5mdW5jdGlvbiBJdGVtKGZ1biwgYXJyYXkpIHtcbiAgICB0aGlzLmZ1biA9IGZ1bjtcbiAgICB0aGlzLmFycmF5ID0gYXJyYXk7XG59XG5JdGVtLnByb3RvdHlwZS5ydW4gPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5mdW4uYXBwbHkobnVsbCwgdGhpcy5hcnJheSk7XG59O1xucHJvY2Vzcy50aXRsZSA9ICdicm93c2VyJztcbnByb2Nlc3MuYnJvd3NlciA9IHRydWU7XG5wcm9jZXNzLmVudiA9IHt9O1xucHJvY2Vzcy5hcmd2ID0gW107XG5wcm9jZXNzLnZlcnNpb24gPSAnJzsgLy8gZW1wdHkgc3RyaW5nIHRvIGF2b2lkIHJlZ2V4cCBpc3N1ZXNcbnByb2Nlc3MudmVyc2lvbnMgPSB7fTtcblxuZnVuY3Rpb24gbm9vcCgpIHt9XG5cbnByb2Nlc3Mub24gPSBub29wO1xucHJvY2Vzcy5hZGRMaXN0ZW5lciA9IG5vb3A7XG5wcm9jZXNzLm9uY2UgPSBub29wO1xucHJvY2Vzcy5vZmYgPSBub29wO1xucHJvY2Vzcy5yZW1vdmVMaXN0ZW5lciA9IG5vb3A7XG5wcm9jZXNzLnJlbW92ZUFsbExpc3RlbmVycyA9IG5vb3A7XG5wcm9jZXNzLmVtaXQgPSBub29wO1xuXG5wcm9jZXNzLmJpbmRpbmcgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgIHRocm93IG5ldyBFcnJvcigncHJvY2Vzcy5iaW5kaW5nIGlzIG5vdCBzdXBwb3J0ZWQnKTtcbn07XG5cbnByb2Nlc3MuY3dkID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gJy8nIH07XG5wcm9jZXNzLmNoZGlyID0gZnVuY3Rpb24gKGRpcikge1xuICAgIHRocm93IG5ldyBFcnJvcigncHJvY2Vzcy5jaGRpciBpcyBub3Qgc3VwcG9ydGVkJyk7XG59O1xucHJvY2Vzcy51bWFzayA9IGZ1bmN0aW9uKCkgeyByZXR1cm4gMDsgfTtcbiIsIi8qKlxuICogVHdlZW4uanMgLSBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2VcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS90d2VlbmpzL3R3ZWVuLmpzXG4gKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gKlxuICogU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS90d2VlbmpzL3R3ZWVuLmpzL2dyYXBocy9jb250cmlidXRvcnMgZm9yIHRoZSBmdWxsIGxpc3Qgb2YgY29udHJpYnV0b3JzLlxuICogVGhhbmsgeW91IGFsbCwgeW91J3JlIGF3ZXNvbWUhXG4gKi9cblxuXG52YXIgX0dyb3VwID0gZnVuY3Rpb24gKCkge1xuXHR0aGlzLl90d2VlbnMgPSB7fTtcblx0dGhpcy5fdHdlZW5zQWRkZWREdXJpbmdVcGRhdGUgPSB7fTtcbn07XG5cbl9Hcm91cC5wcm90b3R5cGUgPSB7XG5cdGdldEFsbDogZnVuY3Rpb24gKCkge1xuXG5cdFx0cmV0dXJuIE9iamVjdC5rZXlzKHRoaXMuX3R3ZWVucykubWFwKGZ1bmN0aW9uICh0d2VlbklkKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5fdHdlZW5zW3R3ZWVuSWRdO1xuXHRcdH0uYmluZCh0aGlzKSk7XG5cblx0fSxcblxuXHRyZW1vdmVBbGw6IGZ1bmN0aW9uICgpIHtcblxuXHRcdHRoaXMuX3R3ZWVucyA9IHt9O1xuXG5cdH0sXG5cblx0YWRkOiBmdW5jdGlvbiAodHdlZW4pIHtcblxuXHRcdHRoaXMuX3R3ZWVuc1t0d2Vlbi5nZXRJZCgpXSA9IHR3ZWVuO1xuXHRcdHRoaXMuX3R3ZWVuc0FkZGVkRHVyaW5nVXBkYXRlW3R3ZWVuLmdldElkKCldID0gdHdlZW47XG5cblx0fSxcblxuXHRyZW1vdmU6IGZ1bmN0aW9uICh0d2Vlbikge1xuXG5cdFx0ZGVsZXRlIHRoaXMuX3R3ZWVuc1t0d2Vlbi5nZXRJZCgpXTtcblx0XHRkZWxldGUgdGhpcy5fdHdlZW5zQWRkZWREdXJpbmdVcGRhdGVbdHdlZW4uZ2V0SWQoKV07XG5cblx0fSxcblxuXHR1cGRhdGU6IGZ1bmN0aW9uICh0aW1lLCBwcmVzZXJ2ZSkge1xuXG5cdFx0dmFyIHR3ZWVuSWRzID0gT2JqZWN0LmtleXModGhpcy5fdHdlZW5zKTtcblxuXHRcdGlmICh0d2Vlbklkcy5sZW5ndGggPT09IDApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHR0aW1lID0gdGltZSAhPT0gdW5kZWZpbmVkID8gdGltZSA6IFRXRUVOLm5vdygpO1xuXG5cdFx0Ly8gVHdlZW5zIGFyZSB1cGRhdGVkIGluIFwiYmF0Y2hlc1wiLiBJZiB5b3UgYWRkIGEgbmV3IHR3ZWVuIGR1cmluZyBhbiB1cGRhdGUsIHRoZW4gdGhlXG5cdFx0Ly8gbmV3IHR3ZWVuIHdpbGwgYmUgdXBkYXRlZCBpbiB0aGUgbmV4dCBiYXRjaC5cblx0XHQvLyBJZiB5b3UgcmVtb3ZlIGEgdHdlZW4gZHVyaW5nIGFuIHVwZGF0ZSwgaXQgbWF5IG9yIG1heSBub3QgYmUgdXBkYXRlZC4gSG93ZXZlcixcblx0XHQvLyBpZiB0aGUgcmVtb3ZlZCB0d2VlbiB3YXMgYWRkZWQgZHVyaW5nIHRoZSBjdXJyZW50IGJhdGNoLCB0aGVuIGl0IHdpbGwgbm90IGJlIHVwZGF0ZWQuXG5cdFx0d2hpbGUgKHR3ZWVuSWRzLmxlbmd0aCA+IDApIHtcblx0XHRcdHRoaXMuX3R3ZWVuc0FkZGVkRHVyaW5nVXBkYXRlID0ge307XG5cblx0XHRcdGZvciAodmFyIGkgPSAwOyBpIDwgdHdlZW5JZHMubGVuZ3RoOyBpKyspIHtcblxuXHRcdFx0XHR2YXIgdHdlZW4gPSB0aGlzLl90d2VlbnNbdHdlZW5JZHNbaV1dO1xuXG5cdFx0XHRcdGlmICh0d2VlbiAmJiB0d2Vlbi51cGRhdGUodGltZSkgPT09IGZhbHNlKSB7XG5cdFx0XHRcdFx0dHdlZW4uX2lzUGxheWluZyA9IGZhbHNlO1xuXG5cdFx0XHRcdFx0aWYgKCFwcmVzZXJ2ZSkge1xuXHRcdFx0XHRcdFx0ZGVsZXRlIHRoaXMuX3R3ZWVuc1t0d2Vlbklkc1tpXV07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdHR3ZWVuSWRzID0gT2JqZWN0LmtleXModGhpcy5fdHdlZW5zQWRkZWREdXJpbmdVcGRhdGUpO1xuXHRcdH1cblxuXHRcdHJldHVybiB0cnVlO1xuXG5cdH1cbn07XG5cbnZhciBUV0VFTiA9IG5ldyBfR3JvdXAoKTtcblxuVFdFRU4uR3JvdXAgPSBfR3JvdXA7XG5UV0VFTi5fbmV4dElkID0gMDtcblRXRUVOLm5leHRJZCA9IGZ1bmN0aW9uICgpIHtcblx0cmV0dXJuIFRXRUVOLl9uZXh0SWQrKztcbn07XG5cblxuLy8gSW5jbHVkZSBhIHBlcmZvcm1hbmNlLm5vdyBwb2x5ZmlsbC5cbi8vIEluIG5vZGUuanMsIHVzZSBwcm9jZXNzLmhydGltZS5cbmlmICh0eXBlb2YgKHdpbmRvdykgPT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiAocHJvY2VzcykgIT09ICd1bmRlZmluZWQnKSB7XG5cdFRXRUVOLm5vdyA9IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgdGltZSA9IHByb2Nlc3MuaHJ0aW1lKCk7XG5cblx0XHQvLyBDb252ZXJ0IFtzZWNvbmRzLCBuYW5vc2Vjb25kc10gdG8gbWlsbGlzZWNvbmRzLlxuXHRcdHJldHVybiB0aW1lWzBdICogMTAwMCArIHRpbWVbMV0gLyAxMDAwMDAwO1xuXHR9O1xufVxuLy8gSW4gYSBicm93c2VyLCB1c2Ugd2luZG93LnBlcmZvcm1hbmNlLm5vdyBpZiBpdCBpcyBhdmFpbGFibGUuXG5lbHNlIGlmICh0eXBlb2YgKHdpbmRvdykgIT09ICd1bmRlZmluZWQnICYmXG4gICAgICAgICB3aW5kb3cucGVyZm9ybWFuY2UgIT09IHVuZGVmaW5lZCAmJlxuXHRcdCB3aW5kb3cucGVyZm9ybWFuY2Uubm93ICE9PSB1bmRlZmluZWQpIHtcblx0Ly8gVGhpcyBtdXN0IGJlIGJvdW5kLCBiZWNhdXNlIGRpcmVjdGx5IGFzc2lnbmluZyB0aGlzIGZ1bmN0aW9uXG5cdC8vIGxlYWRzIHRvIGFuIGludm9jYXRpb24gZXhjZXB0aW9uIGluIENocm9tZS5cblx0VFdFRU4ubm93ID0gd2luZG93LnBlcmZvcm1hbmNlLm5vdy5iaW5kKHdpbmRvdy5wZXJmb3JtYW5jZSk7XG59XG4vLyBVc2UgRGF0ZS5ub3cgaWYgaXQgaXMgYXZhaWxhYmxlLlxuZWxzZSBpZiAoRGF0ZS5ub3cgIT09IHVuZGVmaW5lZCkge1xuXHRUV0VFTi5ub3cgPSBEYXRlLm5vdztcbn1cbi8vIE90aGVyd2lzZSwgdXNlICduZXcgRGF0ZSgpLmdldFRpbWUoKScuXG5lbHNlIHtcblx0VFdFRU4ubm93ID0gZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcblx0fTtcbn1cblxuXG5UV0VFTi5Ud2VlbiA9IGZ1bmN0aW9uIChvYmplY3QsIGdyb3VwKSB7XG5cdHRoaXMuX29iamVjdCA9IG9iamVjdDtcblx0dGhpcy5fdmFsdWVzU3RhcnQgPSB7fTtcblx0dGhpcy5fdmFsdWVzRW5kID0ge307XG5cdHRoaXMuX3ZhbHVlc1N0YXJ0UmVwZWF0ID0ge307XG5cdHRoaXMuX2R1cmF0aW9uID0gMTAwMDtcblx0dGhpcy5fcmVwZWF0ID0gMDtcblx0dGhpcy5fcmVwZWF0RGVsYXlUaW1lID0gdW5kZWZpbmVkO1xuXHR0aGlzLl95b3lvID0gZmFsc2U7XG5cdHRoaXMuX2lzUGxheWluZyA9IGZhbHNlO1xuXHR0aGlzLl9yZXZlcnNlZCA9IGZhbHNlO1xuXHR0aGlzLl9kZWxheVRpbWUgPSAwO1xuXHR0aGlzLl9zdGFydFRpbWUgPSBudWxsO1xuXHR0aGlzLl9lYXNpbmdGdW5jdGlvbiA9IFRXRUVOLkVhc2luZy5MaW5lYXIuTm9uZTtcblx0dGhpcy5faW50ZXJwb2xhdGlvbkZ1bmN0aW9uID0gVFdFRU4uSW50ZXJwb2xhdGlvbi5MaW5lYXI7XG5cdHRoaXMuX2NoYWluZWRUd2VlbnMgPSBbXTtcblx0dGhpcy5fb25TdGFydENhbGxiYWNrID0gbnVsbDtcblx0dGhpcy5fb25TdGFydENhbGxiYWNrRmlyZWQgPSBmYWxzZTtcblx0dGhpcy5fb25VcGRhdGVDYWxsYmFjayA9IG51bGw7XG5cdHRoaXMuX29uQ29tcGxldGVDYWxsYmFjayA9IG51bGw7XG5cdHRoaXMuX29uU3RvcENhbGxiYWNrID0gbnVsbDtcblx0dGhpcy5fZ3JvdXAgPSBncm91cCB8fCBUV0VFTjtcblx0dGhpcy5faWQgPSBUV0VFTi5uZXh0SWQoKTtcblxufTtcblxuVFdFRU4uVHdlZW4ucHJvdG90eXBlID0ge1xuXHRnZXRJZDogZnVuY3Rpb24gZ2V0SWQoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX2lkO1xuXHR9LFxuXG5cdGlzUGxheWluZzogZnVuY3Rpb24gaXNQbGF5aW5nKCkge1xuXHRcdHJldHVybiB0aGlzLl9pc1BsYXlpbmc7XG5cdH0sXG5cblx0dG86IGZ1bmN0aW9uIHRvKHByb3BlcnRpZXMsIGR1cmF0aW9uKSB7XG5cblx0XHR0aGlzLl92YWx1ZXNFbmQgPSBwcm9wZXJ0aWVzO1xuXG5cdFx0aWYgKGR1cmF0aW9uICE9PSB1bmRlZmluZWQpIHtcblx0XHRcdHRoaXMuX2R1cmF0aW9uID0gZHVyYXRpb247XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fSxcblxuXHRzdGFydDogZnVuY3Rpb24gc3RhcnQodGltZSkge1xuXG5cdFx0dGhpcy5fZ3JvdXAuYWRkKHRoaXMpO1xuXG5cdFx0dGhpcy5faXNQbGF5aW5nID0gdHJ1ZTtcblxuXHRcdHRoaXMuX29uU3RhcnRDYWxsYmFja0ZpcmVkID0gZmFsc2U7XG5cblx0XHR0aGlzLl9zdGFydFRpbWUgPSB0aW1lICE9PSB1bmRlZmluZWQgPyB0eXBlb2YgdGltZSA9PT0gJ3N0cmluZycgPyBUV0VFTi5ub3coKSArIHBhcnNlRmxvYXQodGltZSkgOiB0aW1lIDogVFdFRU4ubm93KCk7XG5cdFx0dGhpcy5fc3RhcnRUaW1lICs9IHRoaXMuX2RlbGF5VGltZTtcblxuXHRcdGZvciAodmFyIHByb3BlcnR5IGluIHRoaXMuX3ZhbHVlc0VuZCkge1xuXG5cdFx0XHQvLyBDaGVjayBpZiBhbiBBcnJheSB3YXMgcHJvdmlkZWQgYXMgcHJvcGVydHkgdmFsdWVcblx0XHRcdGlmICh0aGlzLl92YWx1ZXNFbmRbcHJvcGVydHldIGluc3RhbmNlb2YgQXJyYXkpIHtcblxuXHRcdFx0XHRpZiAodGhpcy5fdmFsdWVzRW5kW3Byb3BlcnR5XS5sZW5ndGggPT09IDApIHtcblx0XHRcdFx0XHRjb250aW51ZTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIENyZWF0ZSBhIGxvY2FsIGNvcHkgb2YgdGhlIEFycmF5IHdpdGggdGhlIHN0YXJ0IHZhbHVlIGF0IHRoZSBmcm9udFxuXHRcdFx0XHR0aGlzLl92YWx1ZXNFbmRbcHJvcGVydHldID0gW3RoaXMuX29iamVjdFtwcm9wZXJ0eV1dLmNvbmNhdCh0aGlzLl92YWx1ZXNFbmRbcHJvcGVydHldKTtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBJZiBgdG8oKWAgc3BlY2lmaWVzIGEgcHJvcGVydHkgdGhhdCBkb2Vzbid0IGV4aXN0IGluIHRoZSBzb3VyY2Ugb2JqZWN0LFxuXHRcdFx0Ly8gd2Ugc2hvdWxkIG5vdCBzZXQgdGhhdCBwcm9wZXJ0eSBpbiB0aGUgb2JqZWN0XG5cdFx0XHRpZiAodGhpcy5fb2JqZWN0W3Byb3BlcnR5XSA9PT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTYXZlIHRoZSBzdGFydGluZyB2YWx1ZS5cblx0XHRcdHRoaXMuX3ZhbHVlc1N0YXJ0W3Byb3BlcnR5XSA9IHRoaXMuX29iamVjdFtwcm9wZXJ0eV07XG5cblx0XHRcdGlmICgodGhpcy5fdmFsdWVzU3RhcnRbcHJvcGVydHldIGluc3RhbmNlb2YgQXJyYXkpID09PSBmYWxzZSkge1xuXHRcdFx0XHR0aGlzLl92YWx1ZXNTdGFydFtwcm9wZXJ0eV0gKj0gMS4wOyAvLyBFbnN1cmVzIHdlJ3JlIHVzaW5nIG51bWJlcnMsIG5vdCBzdHJpbmdzXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX3ZhbHVlc1N0YXJ0UmVwZWF0W3Byb3BlcnR5XSA9IHRoaXMuX3ZhbHVlc1N0YXJ0W3Byb3BlcnR5XSB8fCAwO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fSxcblxuXHRzdG9wOiBmdW5jdGlvbiBzdG9wKCkge1xuXG5cdFx0aWYgKCF0aGlzLl9pc1BsYXlpbmcpIHtcblx0XHRcdHJldHVybiB0aGlzO1xuXHRcdH1cblxuXHRcdHRoaXMuX2dyb3VwLnJlbW92ZSh0aGlzKTtcblx0XHR0aGlzLl9pc1BsYXlpbmcgPSBmYWxzZTtcblxuXHRcdGlmICh0aGlzLl9vblN0b3BDYWxsYmFjayAhPT0gbnVsbCkge1xuXHRcdFx0dGhpcy5fb25TdG9wQ2FsbGJhY2sodGhpcy5fb2JqZWN0KTtcblx0XHR9XG5cblx0XHR0aGlzLnN0b3BDaGFpbmVkVHdlZW5zKCk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fSxcblxuXHRlbmQ6IGZ1bmN0aW9uIGVuZCgpIHtcblxuXHRcdHRoaXMudXBkYXRlKHRoaXMuX3N0YXJ0VGltZSArIHRoaXMuX2R1cmF0aW9uKTtcblx0XHRyZXR1cm4gdGhpcztcblxuXHR9LFxuXG5cdHN0b3BDaGFpbmVkVHdlZW5zOiBmdW5jdGlvbiBzdG9wQ2hhaW5lZFR3ZWVucygpIHtcblxuXHRcdGZvciAodmFyIGkgPSAwLCBudW1DaGFpbmVkVHdlZW5zID0gdGhpcy5fY2hhaW5lZFR3ZWVucy5sZW5ndGg7IGkgPCBudW1DaGFpbmVkVHdlZW5zOyBpKyspIHtcblx0XHRcdHRoaXMuX2NoYWluZWRUd2VlbnNbaV0uc3RvcCgpO1xuXHRcdH1cblxuXHR9LFxuXG5cdGRlbGF5OiBmdW5jdGlvbiBkZWxheShhbW91bnQpIHtcblxuXHRcdHRoaXMuX2RlbGF5VGltZSA9IGFtb3VudDtcblx0XHRyZXR1cm4gdGhpcztcblxuXHR9LFxuXG5cdHJlcGVhdDogZnVuY3Rpb24gcmVwZWF0KHRpbWVzKSB7XG5cblx0XHR0aGlzLl9yZXBlYXQgPSB0aW1lcztcblx0XHRyZXR1cm4gdGhpcztcblxuXHR9LFxuXG5cdHJlcGVhdERlbGF5OiBmdW5jdGlvbiByZXBlYXREZWxheShhbW91bnQpIHtcblxuXHRcdHRoaXMuX3JlcGVhdERlbGF5VGltZSA9IGFtb3VudDtcblx0XHRyZXR1cm4gdGhpcztcblxuXHR9LFxuXG5cdHlveW86IGZ1bmN0aW9uIHlveW8oeW95bykge1xuXG5cdFx0dGhpcy5feW95byA9IHlveW87XG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fSxcblxuXHRlYXNpbmc6IGZ1bmN0aW9uIGVhc2luZyhlYXNpbmcpIHtcblxuXHRcdHRoaXMuX2Vhc2luZ0Z1bmN0aW9uID0gZWFzaW5nO1xuXHRcdHJldHVybiB0aGlzO1xuXG5cdH0sXG5cblx0aW50ZXJwb2xhdGlvbjogZnVuY3Rpb24gaW50ZXJwb2xhdGlvbihpbnRlcnBvbGF0aW9uKSB7XG5cblx0XHR0aGlzLl9pbnRlcnBvbGF0aW9uRnVuY3Rpb24gPSBpbnRlcnBvbGF0aW9uO1xuXHRcdHJldHVybiB0aGlzO1xuXG5cdH0sXG5cblx0Y2hhaW46IGZ1bmN0aW9uIGNoYWluKCkge1xuXG5cdFx0dGhpcy5fY2hhaW5lZFR3ZWVucyA9IGFyZ3VtZW50cztcblx0XHRyZXR1cm4gdGhpcztcblxuXHR9LFxuXG5cdG9uU3RhcnQ6IGZ1bmN0aW9uIG9uU3RhcnQoY2FsbGJhY2spIHtcblxuXHRcdHRoaXMuX29uU3RhcnRDYWxsYmFjayA9IGNhbGxiYWNrO1xuXHRcdHJldHVybiB0aGlzO1xuXG5cdH0sXG5cblx0b25VcGRhdGU6IGZ1bmN0aW9uIG9uVXBkYXRlKGNhbGxiYWNrKSB7XG5cblx0XHR0aGlzLl9vblVwZGF0ZUNhbGxiYWNrID0gY2FsbGJhY2s7XG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fSxcblxuXHRvbkNvbXBsZXRlOiBmdW5jdGlvbiBvbkNvbXBsZXRlKGNhbGxiYWNrKSB7XG5cblx0XHR0aGlzLl9vbkNvbXBsZXRlQ2FsbGJhY2sgPSBjYWxsYmFjaztcblx0XHRyZXR1cm4gdGhpcztcblxuXHR9LFxuXG5cdG9uU3RvcDogZnVuY3Rpb24gb25TdG9wKGNhbGxiYWNrKSB7XG5cblx0XHR0aGlzLl9vblN0b3BDYWxsYmFjayA9IGNhbGxiYWNrO1xuXHRcdHJldHVybiB0aGlzO1xuXG5cdH0sXG5cblx0dXBkYXRlOiBmdW5jdGlvbiB1cGRhdGUodGltZSkge1xuXG5cdFx0dmFyIHByb3BlcnR5O1xuXHRcdHZhciBlbGFwc2VkO1xuXHRcdHZhciB2YWx1ZTtcblxuXHRcdGlmICh0aW1lIDwgdGhpcy5fc3RhcnRUaW1lKSB7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9XG5cblx0XHRpZiAodGhpcy5fb25TdGFydENhbGxiYWNrRmlyZWQgPT09IGZhbHNlKSB7XG5cblx0XHRcdGlmICh0aGlzLl9vblN0YXJ0Q2FsbGJhY2sgIT09IG51bGwpIHtcblx0XHRcdFx0dGhpcy5fb25TdGFydENhbGxiYWNrKHRoaXMuX29iamVjdCk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX29uU3RhcnRDYWxsYmFja0ZpcmVkID0gdHJ1ZTtcblx0XHR9XG5cblx0XHRlbGFwc2VkID0gKHRpbWUgLSB0aGlzLl9zdGFydFRpbWUpIC8gdGhpcy5fZHVyYXRpb247XG5cdFx0ZWxhcHNlZCA9IGVsYXBzZWQgPiAxID8gMSA6IGVsYXBzZWQ7XG5cblx0XHR2YWx1ZSA9IHRoaXMuX2Vhc2luZ0Z1bmN0aW9uKGVsYXBzZWQpO1xuXG5cdFx0Zm9yIChwcm9wZXJ0eSBpbiB0aGlzLl92YWx1ZXNFbmQpIHtcblxuXHRcdFx0Ly8gRG9uJ3QgdXBkYXRlIHByb3BlcnRpZXMgdGhhdCBkbyBub3QgZXhpc3QgaW4gdGhlIHNvdXJjZSBvYmplY3Rcblx0XHRcdGlmICh0aGlzLl92YWx1ZXNTdGFydFtwcm9wZXJ0eV0gPT09IHVuZGVmaW5lZCkge1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0dmFyIHN0YXJ0ID0gdGhpcy5fdmFsdWVzU3RhcnRbcHJvcGVydHldIHx8IDA7XG5cdFx0XHR2YXIgZW5kID0gdGhpcy5fdmFsdWVzRW5kW3Byb3BlcnR5XTtcblxuXHRcdFx0aWYgKGVuZCBpbnN0YW5jZW9mIEFycmF5KSB7XG5cblx0XHRcdFx0dGhpcy5fb2JqZWN0W3Byb3BlcnR5XSA9IHRoaXMuX2ludGVycG9sYXRpb25GdW5jdGlvbihlbmQsIHZhbHVlKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBQYXJzZXMgcmVsYXRpdmUgZW5kIHZhbHVlcyB3aXRoIHN0YXJ0IGFzIGJhc2UgKGUuZy46ICsxMCwgLTMpXG5cdFx0XHRcdGlmICh0eXBlb2YgKGVuZCkgPT09ICdzdHJpbmcnKSB7XG5cblx0XHRcdFx0XHRpZiAoZW5kLmNoYXJBdCgwKSA9PT0gJysnIHx8IGVuZC5jaGFyQXQoMCkgPT09ICctJykge1xuXHRcdFx0XHRcdFx0ZW5kID0gc3RhcnQgKyBwYXJzZUZsb2F0KGVuZCk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdGVuZCA9IHBhcnNlRmxvYXQoZW5kKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBQcm90ZWN0IGFnYWluc3Qgbm9uIG51bWVyaWMgcHJvcGVydGllcy5cblx0XHRcdFx0aWYgKHR5cGVvZiAoZW5kKSA9PT0gJ251bWJlcicpIHtcblx0XHRcdFx0XHR0aGlzLl9vYmplY3RbcHJvcGVydHldID0gc3RhcnQgKyAoZW5kIC0gc3RhcnQpICogdmFsdWU7XG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKHRoaXMuX29uVXBkYXRlQ2FsbGJhY2sgIT09IG51bGwpIHtcblx0XHRcdHRoaXMuX29uVXBkYXRlQ2FsbGJhY2sodGhpcy5fb2JqZWN0KTtcblx0XHR9XG5cblx0XHRpZiAoZWxhcHNlZCA9PT0gMSkge1xuXG5cdFx0XHRpZiAodGhpcy5fcmVwZWF0ID4gMCkge1xuXG5cdFx0XHRcdGlmIChpc0Zpbml0ZSh0aGlzLl9yZXBlYXQpKSB7XG5cdFx0XHRcdFx0dGhpcy5fcmVwZWF0LS07XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBSZWFzc2lnbiBzdGFydGluZyB2YWx1ZXMsIHJlc3RhcnQgYnkgbWFraW5nIHN0YXJ0VGltZSA9IG5vd1xuXHRcdFx0XHRmb3IgKHByb3BlcnR5IGluIHRoaXMuX3ZhbHVlc1N0YXJ0UmVwZWF0KSB7XG5cblx0XHRcdFx0XHRpZiAodHlwZW9mICh0aGlzLl92YWx1ZXNFbmRbcHJvcGVydHldKSA9PT0gJ3N0cmluZycpIHtcblx0XHRcdFx0XHRcdHRoaXMuX3ZhbHVlc1N0YXJ0UmVwZWF0W3Byb3BlcnR5XSA9IHRoaXMuX3ZhbHVlc1N0YXJ0UmVwZWF0W3Byb3BlcnR5XSArIHBhcnNlRmxvYXQodGhpcy5fdmFsdWVzRW5kW3Byb3BlcnR5XSk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKHRoaXMuX3lveW8pIHtcblx0XHRcdFx0XHRcdHZhciB0bXAgPSB0aGlzLl92YWx1ZXNTdGFydFJlcGVhdFtwcm9wZXJ0eV07XG5cblx0XHRcdFx0XHRcdHRoaXMuX3ZhbHVlc1N0YXJ0UmVwZWF0W3Byb3BlcnR5XSA9IHRoaXMuX3ZhbHVlc0VuZFtwcm9wZXJ0eV07XG5cdFx0XHRcdFx0XHR0aGlzLl92YWx1ZXNFbmRbcHJvcGVydHldID0gdG1wO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdHRoaXMuX3ZhbHVlc1N0YXJ0W3Byb3BlcnR5XSA9IHRoaXMuX3ZhbHVlc1N0YXJ0UmVwZWF0W3Byb3BlcnR5XTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKHRoaXMuX3lveW8pIHtcblx0XHRcdFx0XHR0aGlzLl9yZXZlcnNlZCA9ICF0aGlzLl9yZXZlcnNlZDtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICh0aGlzLl9yZXBlYXREZWxheVRpbWUgIT09IHVuZGVmaW5lZCkge1xuXHRcdFx0XHRcdHRoaXMuX3N0YXJ0VGltZSA9IHRpbWUgKyB0aGlzLl9yZXBlYXREZWxheVRpbWU7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0dGhpcy5fc3RhcnRUaW1lID0gdGltZSArIHRoaXMuX2RlbGF5VGltZTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGlmICh0aGlzLl9vbkNvbXBsZXRlQ2FsbGJhY2sgIT09IG51bGwpIHtcblxuXHRcdFx0XHRcdHRoaXMuX29uQ29tcGxldGVDYWxsYmFjayh0aGlzLl9vYmplY3QpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Zm9yICh2YXIgaSA9IDAsIG51bUNoYWluZWRUd2VlbnMgPSB0aGlzLl9jaGFpbmVkVHdlZW5zLmxlbmd0aDsgaSA8IG51bUNoYWluZWRUd2VlbnM7IGkrKykge1xuXHRcdFx0XHRcdC8vIE1ha2UgdGhlIGNoYWluZWQgdHdlZW5zIHN0YXJ0IGV4YWN0bHkgYXQgdGhlIHRpbWUgdGhleSBzaG91bGQsXG5cdFx0XHRcdFx0Ly8gZXZlbiBpZiB0aGUgYHVwZGF0ZSgpYCBtZXRob2Qgd2FzIGNhbGxlZCB3YXkgcGFzdCB0aGUgZHVyYXRpb24gb2YgdGhlIHR3ZWVuXG5cdFx0XHRcdFx0dGhpcy5fY2hhaW5lZFR3ZWVuc1tpXS5zdGFydCh0aGlzLl9zdGFydFRpbWUgKyB0aGlzLl9kdXJhdGlvbik7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB0cnVlO1xuXG5cdH1cbn07XG5cblxuVFdFRU4uRWFzaW5nID0ge1xuXG5cdExpbmVhcjoge1xuXG5cdFx0Tm9uZTogZnVuY3Rpb24gKGspIHtcblxuXHRcdFx0cmV0dXJuIGs7XG5cblx0XHR9XG5cblx0fSxcblxuXHRRdWFkcmF0aWM6IHtcblxuXHRcdEluOiBmdW5jdGlvbiAoaykge1xuXG5cdFx0XHRyZXR1cm4gayAqIGs7XG5cblx0XHR9LFxuXG5cdFx0T3V0OiBmdW5jdGlvbiAoaykge1xuXG5cdFx0XHRyZXR1cm4gayAqICgyIC0gayk7XG5cblx0XHR9LFxuXG5cdFx0SW5PdXQ6IGZ1bmN0aW9uIChrKSB7XG5cblx0XHRcdGlmICgoayAqPSAyKSA8IDEpIHtcblx0XHRcdFx0cmV0dXJuIDAuNSAqIGsgKiBrO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gLSAwLjUgKiAoLS1rICogKGsgLSAyKSAtIDEpO1xuXG5cdFx0fVxuXG5cdH0sXG5cblx0Q3ViaWM6IHtcblxuXHRcdEluOiBmdW5jdGlvbiAoaykge1xuXG5cdFx0XHRyZXR1cm4gayAqIGsgKiBrO1xuXG5cdFx0fSxcblxuXHRcdE91dDogZnVuY3Rpb24gKGspIHtcblxuXHRcdFx0cmV0dXJuIC0tayAqIGsgKiBrICsgMTtcblxuXHRcdH0sXG5cblx0XHRJbk91dDogZnVuY3Rpb24gKGspIHtcblxuXHRcdFx0aWYgKChrICo9IDIpIDwgMSkge1xuXHRcdFx0XHRyZXR1cm4gMC41ICogayAqIGsgKiBrO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gMC41ICogKChrIC09IDIpICogayAqIGsgKyAyKTtcblxuXHRcdH1cblxuXHR9LFxuXG5cdFF1YXJ0aWM6IHtcblxuXHRcdEluOiBmdW5jdGlvbiAoaykge1xuXG5cdFx0XHRyZXR1cm4gayAqIGsgKiBrICogaztcblxuXHRcdH0sXG5cblx0XHRPdXQ6IGZ1bmN0aW9uIChrKSB7XG5cblx0XHRcdHJldHVybiAxIC0gKC0tayAqIGsgKiBrICogayk7XG5cblx0XHR9LFxuXG5cdFx0SW5PdXQ6IGZ1bmN0aW9uIChrKSB7XG5cblx0XHRcdGlmICgoayAqPSAyKSA8IDEpIHtcblx0XHRcdFx0cmV0dXJuIDAuNSAqIGsgKiBrICogayAqIGs7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiAtIDAuNSAqICgoayAtPSAyKSAqIGsgKiBrICogayAtIDIpO1xuXG5cdFx0fVxuXG5cdH0sXG5cblx0UXVpbnRpYzoge1xuXG5cdFx0SW46IGZ1bmN0aW9uIChrKSB7XG5cblx0XHRcdHJldHVybiBrICogayAqIGsgKiBrICogaztcblxuXHRcdH0sXG5cblx0XHRPdXQ6IGZ1bmN0aW9uIChrKSB7XG5cblx0XHRcdHJldHVybiAtLWsgKiBrICogayAqIGsgKiBrICsgMTtcblxuXHRcdH0sXG5cblx0XHRJbk91dDogZnVuY3Rpb24gKGspIHtcblxuXHRcdFx0aWYgKChrICo9IDIpIDwgMSkge1xuXHRcdFx0XHRyZXR1cm4gMC41ICogayAqIGsgKiBrICogayAqIGs7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiAwLjUgKiAoKGsgLT0gMikgKiBrICogayAqIGsgKiBrICsgMik7XG5cblx0XHR9XG5cblx0fSxcblxuXHRTaW51c29pZGFsOiB7XG5cblx0XHRJbjogZnVuY3Rpb24gKGspIHtcblxuXHRcdFx0cmV0dXJuIDEgLSBNYXRoLmNvcyhrICogTWF0aC5QSSAvIDIpO1xuXG5cdFx0fSxcblxuXHRcdE91dDogZnVuY3Rpb24gKGspIHtcblxuXHRcdFx0cmV0dXJuIE1hdGguc2luKGsgKiBNYXRoLlBJIC8gMik7XG5cblx0XHR9LFxuXG5cdFx0SW5PdXQ6IGZ1bmN0aW9uIChrKSB7XG5cblx0XHRcdHJldHVybiAwLjUgKiAoMSAtIE1hdGguY29zKE1hdGguUEkgKiBrKSk7XG5cblx0XHR9XG5cblx0fSxcblxuXHRFeHBvbmVudGlhbDoge1xuXG5cdFx0SW46IGZ1bmN0aW9uIChrKSB7XG5cblx0XHRcdHJldHVybiBrID09PSAwID8gMCA6IE1hdGgucG93KDEwMjQsIGsgLSAxKTtcblxuXHRcdH0sXG5cblx0XHRPdXQ6IGZ1bmN0aW9uIChrKSB7XG5cblx0XHRcdHJldHVybiBrID09PSAxID8gMSA6IDEgLSBNYXRoLnBvdygyLCAtIDEwICogayk7XG5cblx0XHR9LFxuXG5cdFx0SW5PdXQ6IGZ1bmN0aW9uIChrKSB7XG5cblx0XHRcdGlmIChrID09PSAwKSB7XG5cdFx0XHRcdHJldHVybiAwO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoayA9PT0gMSkge1xuXHRcdFx0XHRyZXR1cm4gMTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKChrICo9IDIpIDwgMSkge1xuXHRcdFx0XHRyZXR1cm4gMC41ICogTWF0aC5wb3coMTAyNCwgayAtIDEpO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gMC41ICogKC0gTWF0aC5wb3coMiwgLSAxMCAqIChrIC0gMSkpICsgMik7XG5cblx0XHR9XG5cblx0fSxcblxuXHRDaXJjdWxhcjoge1xuXG5cdFx0SW46IGZ1bmN0aW9uIChrKSB7XG5cblx0XHRcdHJldHVybiAxIC0gTWF0aC5zcXJ0KDEgLSBrICogayk7XG5cblx0XHR9LFxuXG5cdFx0T3V0OiBmdW5jdGlvbiAoaykge1xuXG5cdFx0XHRyZXR1cm4gTWF0aC5zcXJ0KDEgLSAoLS1rICogaykpO1xuXG5cdFx0fSxcblxuXHRcdEluT3V0OiBmdW5jdGlvbiAoaykge1xuXG5cdFx0XHRpZiAoKGsgKj0gMikgPCAxKSB7XG5cdFx0XHRcdHJldHVybiAtIDAuNSAqIChNYXRoLnNxcnQoMSAtIGsgKiBrKSAtIDEpO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gMC41ICogKE1hdGguc3FydCgxIC0gKGsgLT0gMikgKiBrKSArIDEpO1xuXG5cdFx0fVxuXG5cdH0sXG5cblx0RWxhc3RpYzoge1xuXG5cdFx0SW46IGZ1bmN0aW9uIChrKSB7XG5cblx0XHRcdGlmIChrID09PSAwKSB7XG5cdFx0XHRcdHJldHVybiAwO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoayA9PT0gMSkge1xuXHRcdFx0XHRyZXR1cm4gMTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIC1NYXRoLnBvdygyLCAxMCAqIChrIC0gMSkpICogTWF0aC5zaW4oKGsgLSAxLjEpICogNSAqIE1hdGguUEkpO1xuXG5cdFx0fSxcblxuXHRcdE91dDogZnVuY3Rpb24gKGspIHtcblxuXHRcdFx0aWYgKGsgPT09IDApIHtcblx0XHRcdFx0cmV0dXJuIDA7XG5cdFx0XHR9XG5cblx0XHRcdGlmIChrID09PSAxKSB7XG5cdFx0XHRcdHJldHVybiAxO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gTWF0aC5wb3coMiwgLTEwICogaykgKiBNYXRoLnNpbigoayAtIDAuMSkgKiA1ICogTWF0aC5QSSkgKyAxO1xuXG5cdFx0fSxcblxuXHRcdEluT3V0OiBmdW5jdGlvbiAoaykge1xuXG5cdFx0XHRpZiAoayA9PT0gMCkge1xuXHRcdFx0XHRyZXR1cm4gMDtcblx0XHRcdH1cblxuXHRcdFx0aWYgKGsgPT09IDEpIHtcblx0XHRcdFx0cmV0dXJuIDE7XG5cdFx0XHR9XG5cblx0XHRcdGsgKj0gMjtcblxuXHRcdFx0aWYgKGsgPCAxKSB7XG5cdFx0XHRcdHJldHVybiAtMC41ICogTWF0aC5wb3coMiwgMTAgKiAoayAtIDEpKSAqIE1hdGguc2luKChrIC0gMS4xKSAqIDUgKiBNYXRoLlBJKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIDAuNSAqIE1hdGgucG93KDIsIC0xMCAqIChrIC0gMSkpICogTWF0aC5zaW4oKGsgLSAxLjEpICogNSAqIE1hdGguUEkpICsgMTtcblxuXHRcdH1cblxuXHR9LFxuXG5cdEJhY2s6IHtcblxuXHRcdEluOiBmdW5jdGlvbiAoaykge1xuXG5cdFx0XHR2YXIgcyA9IDEuNzAxNTg7XG5cblx0XHRcdHJldHVybiBrICogayAqICgocyArIDEpICogayAtIHMpO1xuXG5cdFx0fSxcblxuXHRcdE91dDogZnVuY3Rpb24gKGspIHtcblxuXHRcdFx0dmFyIHMgPSAxLjcwMTU4O1xuXG5cdFx0XHRyZXR1cm4gLS1rICogayAqICgocyArIDEpICogayArIHMpICsgMTtcblxuXHRcdH0sXG5cblx0XHRJbk91dDogZnVuY3Rpb24gKGspIHtcblxuXHRcdFx0dmFyIHMgPSAxLjcwMTU4ICogMS41MjU7XG5cblx0XHRcdGlmICgoayAqPSAyKSA8IDEpIHtcblx0XHRcdFx0cmV0dXJuIDAuNSAqIChrICogayAqICgocyArIDEpICogayAtIHMpKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIDAuNSAqICgoayAtPSAyKSAqIGsgKiAoKHMgKyAxKSAqIGsgKyBzKSArIDIpO1xuXG5cdFx0fVxuXG5cdH0sXG5cblx0Qm91bmNlOiB7XG5cblx0XHRJbjogZnVuY3Rpb24gKGspIHtcblxuXHRcdFx0cmV0dXJuIDEgLSBUV0VFTi5FYXNpbmcuQm91bmNlLk91dCgxIC0gayk7XG5cblx0XHR9LFxuXG5cdFx0T3V0OiBmdW5jdGlvbiAoaykge1xuXG5cdFx0XHRpZiAoayA8ICgxIC8gMi43NSkpIHtcblx0XHRcdFx0cmV0dXJuIDcuNTYyNSAqIGsgKiBrO1xuXHRcdFx0fSBlbHNlIGlmIChrIDwgKDIgLyAyLjc1KSkge1xuXHRcdFx0XHRyZXR1cm4gNy41NjI1ICogKGsgLT0gKDEuNSAvIDIuNzUpKSAqIGsgKyAwLjc1O1xuXHRcdFx0fSBlbHNlIGlmIChrIDwgKDIuNSAvIDIuNzUpKSB7XG5cdFx0XHRcdHJldHVybiA3LjU2MjUgKiAoayAtPSAoMi4yNSAvIDIuNzUpKSAqIGsgKyAwLjkzNzU7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRyZXR1cm4gNy41NjI1ICogKGsgLT0gKDIuNjI1IC8gMi43NSkpICogayArIDAuOTg0Mzc1O1xuXHRcdFx0fVxuXG5cdFx0fSxcblxuXHRcdEluT3V0OiBmdW5jdGlvbiAoaykge1xuXG5cdFx0XHRpZiAoayA8IDAuNSkge1xuXHRcdFx0XHRyZXR1cm4gVFdFRU4uRWFzaW5nLkJvdW5jZS5JbihrICogMikgKiAwLjU7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBUV0VFTi5FYXNpbmcuQm91bmNlLk91dChrICogMiAtIDEpICogMC41ICsgMC41O1xuXG5cdFx0fVxuXG5cdH1cblxufTtcblxuVFdFRU4uSW50ZXJwb2xhdGlvbiA9IHtcblxuXHRMaW5lYXI6IGZ1bmN0aW9uICh2LCBrKSB7XG5cblx0XHR2YXIgbSA9IHYubGVuZ3RoIC0gMTtcblx0XHR2YXIgZiA9IG0gKiBrO1xuXHRcdHZhciBpID0gTWF0aC5mbG9vcihmKTtcblx0XHR2YXIgZm4gPSBUV0VFTi5JbnRlcnBvbGF0aW9uLlV0aWxzLkxpbmVhcjtcblxuXHRcdGlmIChrIDwgMCkge1xuXHRcdFx0cmV0dXJuIGZuKHZbMF0sIHZbMV0sIGYpO1xuXHRcdH1cblxuXHRcdGlmIChrID4gMSkge1xuXHRcdFx0cmV0dXJuIGZuKHZbbV0sIHZbbSAtIDFdLCBtIC0gZik7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZuKHZbaV0sIHZbaSArIDEgPiBtID8gbSA6IGkgKyAxXSwgZiAtIGkpO1xuXG5cdH0sXG5cblx0QmV6aWVyOiBmdW5jdGlvbiAodiwgaykge1xuXG5cdFx0dmFyIGIgPSAwO1xuXHRcdHZhciBuID0gdi5sZW5ndGggLSAxO1xuXHRcdHZhciBwdyA9IE1hdGgucG93O1xuXHRcdHZhciBibiA9IFRXRUVOLkludGVycG9sYXRpb24uVXRpbHMuQmVybnN0ZWluO1xuXG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPD0gbjsgaSsrKSB7XG5cdFx0XHRiICs9IHB3KDEgLSBrLCBuIC0gaSkgKiBwdyhrLCBpKSAqIHZbaV0gKiBibihuLCBpKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gYjtcblxuXHR9LFxuXG5cdENhdG11bGxSb206IGZ1bmN0aW9uICh2LCBrKSB7XG5cblx0XHR2YXIgbSA9IHYubGVuZ3RoIC0gMTtcblx0XHR2YXIgZiA9IG0gKiBrO1xuXHRcdHZhciBpID0gTWF0aC5mbG9vcihmKTtcblx0XHR2YXIgZm4gPSBUV0VFTi5JbnRlcnBvbGF0aW9uLlV0aWxzLkNhdG11bGxSb207XG5cblx0XHRpZiAodlswXSA9PT0gdlttXSkge1xuXG5cdFx0XHRpZiAoayA8IDApIHtcblx0XHRcdFx0aSA9IE1hdGguZmxvb3IoZiA9IG0gKiAoMSArIGspKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGZuKHZbKGkgLSAxICsgbSkgJSBtXSwgdltpXSwgdlsoaSArIDEpICUgbV0sIHZbKGkgKyAyKSAlIG1dLCBmIC0gaSk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoayA8IDApIHtcblx0XHRcdFx0cmV0dXJuIHZbMF0gLSAoZm4odlswXSwgdlswXSwgdlsxXSwgdlsxXSwgLWYpIC0gdlswXSk7XG5cdFx0XHR9XG5cblx0XHRcdGlmIChrID4gMSkge1xuXHRcdFx0XHRyZXR1cm4gdlttXSAtIChmbih2W21dLCB2W21dLCB2W20gLSAxXSwgdlttIC0gMV0sIGYgLSBtKSAtIHZbbV0pO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gZm4odltpID8gaSAtIDEgOiAwXSwgdltpXSwgdlttIDwgaSArIDEgPyBtIDogaSArIDFdLCB2W20gPCBpICsgMiA/IG0gOiBpICsgMl0sIGYgLSBpKTtcblxuXHRcdH1cblxuXHR9LFxuXG5cdFV0aWxzOiB7XG5cblx0XHRMaW5lYXI6IGZ1bmN0aW9uIChwMCwgcDEsIHQpIHtcblxuXHRcdFx0cmV0dXJuIChwMSAtIHAwKSAqIHQgKyBwMDtcblxuXHRcdH0sXG5cblx0XHRCZXJuc3RlaW46IGZ1bmN0aW9uIChuLCBpKSB7XG5cblx0XHRcdHZhciBmYyA9IFRXRUVOLkludGVycG9sYXRpb24uVXRpbHMuRmFjdG9yaWFsO1xuXG5cdFx0XHRyZXR1cm4gZmMobikgLyBmYyhpKSAvIGZjKG4gLSBpKTtcblxuXHRcdH0sXG5cblx0XHRGYWN0b3JpYWw6IChmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHZhciBhID0gWzFdO1xuXG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24gKG4pIHtcblxuXHRcdFx0XHR2YXIgcyA9IDE7XG5cblx0XHRcdFx0aWYgKGFbbl0pIHtcblx0XHRcdFx0XHRyZXR1cm4gYVtuXTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGZvciAodmFyIGkgPSBuOyBpID4gMTsgaS0tKSB7XG5cdFx0XHRcdFx0cyAqPSBpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0YVtuXSA9IHM7XG5cdFx0XHRcdHJldHVybiBzO1xuXG5cdFx0XHR9O1xuXG5cdFx0fSkoKSxcblxuXHRcdENhdG11bGxSb206IGZ1bmN0aW9uIChwMCwgcDEsIHAyLCBwMywgdCkge1xuXG5cdFx0XHR2YXIgdjAgPSAocDIgLSBwMCkgKiAwLjU7XG5cdFx0XHR2YXIgdjEgPSAocDMgLSBwMSkgKiAwLjU7XG5cdFx0XHR2YXIgdDIgPSB0ICogdDtcblx0XHRcdHZhciB0MyA9IHQgKiB0MjtcblxuXHRcdFx0cmV0dXJuICgyICogcDEgLSAyICogcDIgKyB2MCArIHYxKSAqIHQzICsgKC0gMyAqIHAxICsgMyAqIHAyIC0gMiAqIHYwIC0gdjEpICogdDIgKyB2MCAqIHQgKyBwMTtcblxuXHRcdH1cblxuXHR9XG5cbn07XG5cbi8vIFVNRCAoVW5pdmVyc2FsIE1vZHVsZSBEZWZpbml0aW9uKVxuKGZ1bmN0aW9uIChyb290KSB7XG5cblx0aWYgKHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCkge1xuXG5cdFx0Ly8gQU1EXG5cdFx0ZGVmaW5lKFtdLCBmdW5jdGlvbiAoKSB7XG5cdFx0XHRyZXR1cm4gVFdFRU47XG5cdFx0fSk7XG5cblx0fSBlbHNlIGlmICh0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJyAmJiB0eXBlb2YgZXhwb3J0cyA9PT0gJ29iamVjdCcpIHtcblxuXHRcdC8vIE5vZGUuanNcblx0XHRtb2R1bGUuZXhwb3J0cyA9IFRXRUVOO1xuXG5cdH0gZWxzZSBpZiAocm9vdCAhPT0gdW5kZWZpbmVkKSB7XG5cblx0XHQvLyBHbG9iYWwgdmFyaWFibGVcblx0XHRyb290LlRXRUVOID0gVFdFRU47XG5cblx0fVxuXG59KSh0aGlzKTtcbiJdfQ== | |
| var Simplex = require('perlin-simplex') | |
| var TWEEN = require('@tweenjs/tween.js') | |
| const canvas = document.getElementsByTagName('canvas')[0]; | |
| const context = canvas.getContext('2d') | |
| class WanderingCircle { | |
| constructor({ | |
| anchorAmount = 180, | |
| radius = 5, | |
| basePathRadius = 10, | |
| startVariant = 0, | |
| pathCenter = [0, 0], | |
| transitionTime = 1000, | |
| iteration = 0, | |
| color = 'tomato', | |
| debug = false, | |
| startStep = 0, | |
| variationAmount = 10 | |
| }) { | |
| Object.assign(this, { | |
| anchorAmount, | |
| radius, | |
| basePathRadius, | |
| pathCenter, | |
| variant: startVariant, | |
| transitionTime, | |
| simplex: new Simplex(), | |
| iteration, | |
| debug, | |
| color, | |
| step: startStep, | |
| variationAmount | |
| }); | |
| this.createAnimation( | |
| this.nextVariation(this.iteration) | |
| ) | |
| } | |
| nextVariation(iteration) { | |
| // TODO make this more configurable | |
| return this.simplex.noise(1, iteration) * 0.8 | |
| } | |
| createAnimation(current = 0) { | |
| this.iteration = ++this.iteration; | |
| const next = this.nextVariation(this.iteration); | |
| const tween = new TWEEN.Tween({ offset: current }) | |
| .to({ offset: next }, this.transitionTime) | |
| .onUpdate(({ offset }) => { | |
| this.variant = offset; | |
| }) | |
| .onComplete(() => this.createAnimation(next)) | |
| .start() | |
| return tween | |
| } | |
| toPath([x, y], radius = 5) { | |
| const path = new Path2D() | |
| path.arc(x, y, radius, 0, 2 * Math.PI) | |
| return path; | |
| } | |
| render(ctx) { | |
| const segments = new Array(this.anchorAmount) | |
| .join('.') | |
| .split('.') | |
| .map(mapSegment(this.pathCenter, this.basePathRadius + this.variant * this.variationAmount)) | |
| // create the circle | |
| const coordinate = segments[this.step] | |
| if (!this.debug) { | |
| ctx.fillStyle = this.color | |
| ctx.fill( | |
| this.toPath(coordinate, this.radius) | |
| ) | |
| } else { | |
| ctx.strokeStyle = '#222' | |
| ctx.strokeWidth = 1 | |
| ctx.stroke( | |
| this.toPath(coordinate, this.radius) | |
| ) | |
| // segments.forEach((segment) => { | |
| // ctx.fillStyle = '#222' | |
| // ctx.fill( | |
| // this.toPath(segment, 1) | |
| // ) | |
| // }) | |
| } | |
| this.step = this.step + 1; | |
| if (this.step === this.anchorAmount) { | |
| if (this.anchorAmount > 720) { | |
| this.anchorAmount = this.anchorAmount + 10 | |
| } | |
| this.step = 0 | |
| } | |
| return { | |
| coordinate, | |
| size: this.radius | |
| } | |
| } | |
| } | |
| /** | |
| * Based on Metaball script by Hiroyuki Sato | |
| * http://shspage.com/aijs/en/#metaball | |
| */ | |
| function dist([x1, y1], [x2, y2]) { | |
| return Math.pow(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2), 0.5) | |
| } | |
| function getVector([cx, cy], a, r) { | |
| return [cx + r * Math.cos(a), cy + r * Math.sin(a)]; | |
| } | |
| function angle([x1, y1], [x2, y2]) { | |
| return Math.atan2(y1 - y2, x1 - x2); | |
| } | |
| /** | |
| * Based on Metaball script by SATO Hiroyuki | |
| * http://park12.wakwak.com/~shp/lc/et/en_aics_script.html | |
| */ | |
| function metaball( | |
| radius1, | |
| radius2, | |
| center1, | |
| center2, | |
| onMitosis = () => {}, | |
| handleLenRate = 2.4, | |
| v = 0.5 | |
| ) { | |
| const HALF_PI = Math.PI / 2; | |
| const d = dist(center1, center2); | |
| const maxDist = radius1 + radius2 * 2.5; | |
| let u1, u2; | |
| if (radius1 === 0 || radius2 === 0) { | |
| return onMitosis(); | |
| } | |
| if (d > maxDist) { | |
| return onMitosis(); | |
| } | |
| if (d <= Math.abs(radius1 - radius2)) { | |
| return onMitosis(); | |
| } else if (d < radius1 + radius2) { | |
| u1 = Math.acos( | |
| (radius1 * radius1 + d * d - radius2 * radius2) / (2 * radius1 * d) | |
| ); | |
| u2 = Math.acos( | |
| (radius2 * radius2 + d * d - radius1 * radius1) / (2 * radius2 * d) | |
| ); | |
| } else { | |
| u1 = 0; | |
| u2 = 0; | |
| } | |
| // All the angles | |
| const angle1 = angle(center2, center1); | |
| const angle2 = Math.acos((radius1 - radius2) / d); | |
| const angle1a = angle1 + u1 + (angle2 - u1) * v; | |
| const angle1b = angle1 - u1 - (angle2 - u1) * v; | |
| const angle2a = angle1 + Math.PI - u2 - (Math.PI - u2 - angle2) * v; | |
| const angle2b = angle1 - Math.PI + u2 + (Math.PI - u2 - angle2) * v; | |
| // Points | |
| const p1a = getVector(center1, angle1a, radius1); | |
| const p1b = getVector(center1, angle1b, radius1); | |
| const p2a = getVector(center2, angle2a, radius2); | |
| const p2b = getVector(center2, angle2b, radius2); | |
| // Define handle length by the | |
| // distance between both ends of the curve | |
| const totalRadius = radius1 + radius2; | |
| const d2Base = Math.min(v * handleLenRate, dist(p1a, p2a) / totalRadius); | |
| // Take into account when circles are overlapping | |
| const d2 = d2Base * Math.min(1, d * 2 / (radius1 + radius2)); | |
| const r1 = radius1 * d2; | |
| const r2 = radius2 * d2; | |
| const h1 = getVector(p1a, angle1a - HALF_PI, r1); | |
| const h2 = getVector(p2a, angle2a + HALF_PI, r2); | |
| const h3 = getVector(p2b, angle2b - HALF_PI, r2); | |
| const h4 = getVector(p1b, angle1b + HALF_PI, r1); | |
| return metaballToPath( | |
| p1a, | |
| p2a, | |
| p1b, | |
| p2b, | |
| h1, | |
| h2, | |
| h3, | |
| h4, | |
| d > radius1, | |
| radius2 | |
| ); | |
| } | |
| function metaballToPath(p1a, p2a, p1b, p2b, h1, h2, h3, h4, escaped, r) { | |
| return new Path2D([ | |
| 'M', p1a, | |
| 'C', h1, h2, p2a, | |
| 'A', r, r, 0, escaped ? 1 : 0, 0, p2b, | |
| 'C', h3, h4, p1b, | |
| ].join(' ')) | |
| } | |
| let position = [50, 50] | |
| canvas.addEventListener('mousemove', (e) => { | |
| position = [e.x, e.y] | |
| }) | |
| function circle(x, y, radius) { | |
| const path = new Path2D() | |
| path.arc(x, y, radius, 0, 2 * Math.PI) | |
| return path; | |
| } | |
| const SIZE = 75 | |
| const MAIN_SIZE = 100 | |
| const STEPS = 320 | |
| const COLOR = '#F47D31' | |
| function mapSegment (center, radius) { | |
| return (offset, i, arr) => { | |
| const radian = Math.PI * 2 | |
| const a = radian / arr.length * i - radian / 4 // << needs to be total radians / amount | |
| const coordinates = [ | |
| center[0] + (radius + offset) * Math.cos(a), | |
| center[1] + (radius + offset) * Math.sin(a), | |
| ] | |
| return [...coordinates]; | |
| } | |
| } | |
| // const circles = [ | |
| // new WanderingCircle({ | |
| // anchorAmount: 180, | |
| // radius: 60, | |
| // basePathRadius: 40, | |
| // transitionTime: 1000, | |
| // color: COLOR, | |
| // variationAmount: 20, | |
| // }), | |
| // new WanderingCircle({ | |
| // anchorAmount: 360, | |
| // radius: 80, | |
| // basePathRadius: 30, | |
| // transitionTime: 1000, | |
| // color: COLOR | |
| // }), | |
| // new WanderingCircle({ | |
| // anchorAmount: 640, | |
| // radius: 60, | |
| // basePathRadius: 40, | |
| // transitionTime: 3000, | |
| // variationAmount: 25, | |
| // step: 320, | |
| // color: COLOR | |
| // }) | |
| // ] | |
| function randomNumber ( upperlimit, min ) { | |
| return Math.max(Math.abs(Math.floor(Math.random() * upperlimit)), min) | |
| } | |
| const circles = new Array(50).join('.').split('.').map((_, i) => { | |
| const anchorAmount = randomNumber(720, 180); | |
| return new WanderingCircle({ | |
| anchorAmount, | |
| radius: randomNumber(80, 60), | |
| basePathRadius: 40, | |
| transitionTime: randomNumber(3000, 1000), | |
| variationAmount: randomNumber(15, 10), | |
| startStep: randomNumber(anchorAmount, 0), | |
| color: COLOR, | |
| //debug: true | |
| }) | |
| }) | |
| function onUpdate() { | |
| // increment(); | |
| try { | |
| canvas.width = window.innerWidth | |
| canvas.height = window.innerHeight | |
| const center = [window.innerWidth/2, window.innerHeight/2] | |
| const circleFactory = () => circle(...center, MAIN_SIZE) | |
| context.save() | |
| context.clearRect(0, 0, canvas.width, canvas.height) | |
| context.fillStyle = COLOR | |
| context.fill(circle(...position, 25)) | |
| context.fill(circle(...center, MAIN_SIZE)) | |
| circles.forEach(wcircle => { | |
| wcircle.pathCenter = center | |
| const meta = wcircle.render(context) | |
| context.fill(metaball(meta.size, MAIN_SIZE, meta.coordinate, center, circleFactory)) | |
| }) | |
| // meta bubble stuff | |
| // context.fill(metaball(25, MAIN_SIZE, position, center, circleFactory)) | |
| // context.fill(metaball(SIZE, MAIN_SIZE, cs1, center, circleFactory)) | |
| context.restore() | |
| } catch(e) { | |
| console.log(e) | |
| } | |
| } | |
| function draw() { | |
| TWEEN.update() | |
| onUpdate() | |
| requestAnimationFrame(draw) | |
| } | |
| draw() | |
| ;}, 0) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "name": "requirebin-sketch", | |
| "version": "1.0.0", | |
| "dependencies": { | |
| "perlin-simplex": "0.0.2", | |
| "@tweenjs/tween.js": "17.1.1" | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!-- contents of this file will be placed inside the <body> --> | |
| <canvas></canvas> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!-- contents of this file will be placed inside the <head> --> | |
| <style type="text/css"> | |
| body { | |
| margin: 0; | |
| height: 100%; | |
| } | |
| canvas { | |
| height: 100vh; | |
| width: 100vw; | |
| } | |
| </style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment