Skip to content

Instantly share code, notes, and snippets.

@davidguttman davidguttman/index.js
Last active May 22, 2017

Embed
What would you like to do?
requirebin sketch
var Delaunator = require('delaunator')
var Simplex = require('perlin-simplex')
var simplex = new Simplex()
var SPEED = 0.25
var N_POINTS = 150
var width = 0.75 * window.innerWidth
var height = 0.75 * window.innerHeight
document.body.style.background = 'rgb(20, 20, 20)'
var points = createPoints(N_POINTS, width, height)
points.forEach(function (point) {
// document.body.appendChild(point.el)
})
var parent = document.createElement('div')
parent.style.position = 'absolute'
parent.style.top = 0.125 * window.innerHeight + 'px'
parent.style.left = 0.125 * window.innerWidth + 'px'
document.body.appendChild(parent)
var triangles = createTrianges(points)
parent.appendChild(triangles.el)
window.requestAnimationFrame(updateLoop)
function updateLoop () {
window.requestAnimationFrame(updateLoop)
points.forEach(function (point, i) {
// var theta = (0.5 - Math.random()) * (Math.PI / 16)
var x = point.x / 40
var y = point.y / 40
var z = Date.now() / 10000
var s = simplex.noise3d(x, y, z)
// var s = simplex.noise(x, y)
var theta1 = s * (2 * Math.PI)
var theta = (0.01 * theta1) + (0.99 * point.theta)
// if (i === 0) console.log(s, theta)
point.move(theta, SPEED)
})
triangles.update(points)
}
function createPoints (n, w, h) {
var points = []
var x, y
for (var i = 0; i < n; i++) {
x = Math.floor(Math.random() * w)
y = Math.floor(Math.random() * h)
points.push(createPoint([x, y]))
}
return points
}
function createPoint (coords) {
var w = 20
var h = w
var el = document.createElement('div')
el.style.position = 'absolute'
el.style.left = coords[0] + 'px'
el.style.top = coords[1] + 'px'
el.style.width = w + 'px'
el.style.height = h + 'px'
el.style.borderRadius = w / 2 + 'px'
el.style.background = '#aaa'
var point = {
el: el,
x: coords[0],
y: coords[1],
theta: Math.random() * 2 * Math.PI,
move: move
}
return point
}
function mod (a, n) {
return ((a % n) + n) % n
}
function move (theta, r) {
this.theta = theta
this.x += r * Math.cos(this.theta)
this.y += r * Math.sin(this.theta)
this.x = mod(this.x, width)
this.y = mod(this.y, height)
this.el.style.left = this.x + 'px'
this.el.style.top = this.y + 'px'
}
function createTrianges (points) {
var stroke = '#ccc'
var fill = 'rgba(0,0,0,0)'
var viewBox = [0, 0, width, height].join(' ')
var pathData = createPathData(points)
var parent = document.createElement('div')
parent.innerHTML = `
<svg xmlns='http://www.w3.org/svg/2000'
viewBox='${viewBox}'
width=${width}
height=${height}
stroke='none'
fill='none'>
${pathData}
</svg>
`
return {
el: parent,
svg: parent.querySelector('svg'),
update: update
}
}
function createPathData (points) {
var coords = points.map(function (point) {
return [point.x, point.y]
})
var triangles = new Delaunator(coords).triangles
var pathData = []
var maxArea = 2 * (height * width) / (N_POINTS / 3)
var x0, y0, x1, y1, x2, y2, d, fill, b, area
for (var i = 0; i < triangles.length; i += 3) {
x0 = coords[triangles[i]][0]
y0 = coords[triangles[i]][1]
x1 = coords[triangles[i + 1]][0]
y1 = coords[triangles[i + 1]][1]
x2 = coords[triangles[i + 2]][0]
y2 = coords[triangles[i + 2]][1]
d = [
'M', x0, y0,
'L', x1, y1,
'L', x2, y2,
'L', x0, y0
].join(' ')
area = calcArea(x0, y0, x1, y1, x2, y2)
b = Math.floor((area / maxArea) * 255)
fill = `rgb(${b}, ${b}, ${b})`
pathData.push(`<path d='${d}' fill='${fill}' stroke='${fill}' />`)
}
return pathData.join('\n')
}
function update (points) {
this.svg.innerHTML = createPathData(points)
}
function calcArea (x0, y0, x1, y1, x2, y2) {
return Math.abs(((x0 * (y1 - y2)) + (x1 * (y2 - y0)) + (x2 * (y0 - y1))) / 2)
}
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})({"delaunator":[function(require,module,exports){
'use strict';
module.exports = Delaunator;
function Delaunator(points, getX, getY) {
if (!getX) getX = defaultGetX;
if (!getY) getY = defaultGetY;
var minX = Infinity;
var minY = Infinity;
var maxX = -Infinity;
var maxY = -Infinity;
var coords = this.coords = [];
var ids = this.ids = new Uint32Array(points.length);
for (var i = 0; i < points.length; i++) {
var p = points[i];
var x = getX(p);
var y = getY(p);
ids[i] = i;
coords[2 * i] = x;
coords[2 * i + 1] = y;
if (x < minX) minX = x;
if (y < minY) minY = y;
if (x > maxX) maxX = x;
if (y > maxY) maxY = y;
}
var cx = (minX + maxX) / 2;
var cy = (minY + maxY) / 2;
var minDist = Infinity;
var i0, i1, i2;
// pick a seed point close to the centroid
for (i = 0; i < points.length; i++) {
var d = dist(cx, cy, coords[2 * i], coords[2 * i + 1]);
if (d < minDist) {
i0 = i;
minDist = d;
}
}
minDist = Infinity;
// find the point closest to the seed
for (i = 0; i < points.length; i++) {
if (i === i0) continue;
d = dist(coords[2 * i0], coords[2 * i0 + 1], coords[2 * i], coords[2 * i + 1]);
if (d < minDist && d > 0) {
i1 = i;
minDist = d;
}
}
var minRadius = Infinity;
// find the third point which forms the smallest circumcircle with the first two
for (i = 0; i < points.length; i++) {
if (i === i0 || i === i1) continue;
var r = circumradius(
coords[2 * i0], coords[2 * i0 + 1],
coords[2 * i1], coords[2 * i1 + 1],
coords[2 * i], coords[2 * i + 1]);
if (r < minRadius) {
i2 = i;
minRadius = r;
}
}
if (minRadius === Infinity) {
throw new Error('No Delaunay triangulation exists for this input.');
}
// swap the order of the seed points for counter-clockwise orientation
if (area(coords[2 * i0], coords[2 * i0 + 1],
coords[2 * i1], coords[2 * i1 + 1],
coords[2 * i2], coords[2 * i2 + 1]) < 0) {
var tmp = i1;
i1 = i2;
i2 = tmp;
}
var i0x = coords[2 * i0];
var i0y = coords[2 * i0 + 1];
var i1x = coords[2 * i1];
var i1y = coords[2 * i1 + 1];
var i2x = coords[2 * i2];
var i2y = coords[2 * i2 + 1];
var center = circumcenter(i0x, i0y, i1x, i1y, i2x, i2y);
this._cx = center.x;
this._cy = center.y;
// sort the points by distance from the seed triangle circumcenter
quicksort(ids, coords, 0, ids.length - 1, center.x, center.y);
// initialize a hash table for storing edges of the advancing convex hull
this._hashSize = Math.ceil(Math.sqrt(points.length));
this._hash = [];
for (i = 0; i < this._hashSize; i++) this._hash[i] = null;
// initialize a circular doubly-linked list that will hold an advancing convex hull
var e = this.hull = insertNode(coords, i0);
this._hashEdge(e);
e.t = 0;
e = insertNode(coords, i1, e);
this._hashEdge(e);
e.t = 1;
e = insertNode(coords, i2, e);
this._hashEdge(e);
e.t = 2;
var maxTriangles = 2 * points.length - 5;
var triangles = this.triangles = new Uint32Array(maxTriangles * 3);
triangles[0] = i0;
triangles[1] = i1;
triangles[2] = i2;
this.trianglesLen = 3;
var adjacent = this.adjacent = new Int32Array(maxTriangles * 3);
adjacent[0] = -1;
adjacent[1] = -1;
adjacent[2] = -1;
var xp, yp;
for (var k = 0; k < ids.length; k++) {
i = ids[k];
x = coords[2 * i];
y = coords[2 * i + 1];
// skip duplicate points
if (x === xp && y === yp) continue;
xp = x;
yp = y;
// skip seed triangle points
if ((x === i0x && y === i0y) ||
(x === i1x && y === i1y) ||
(x === i2x && y === i2y)) continue;
// find a visible edge on the convex hull using edge hash
var startKey = this._hashKey(x, y);
var key = startKey;
var start;
do {
start = this._hash[key];
key = (key + 1) % this._hashSize;
} while ((!start || start.removed) && key !== startKey);
e = start;
while (area(x, y, e.x, e.y, e.next.x, e.next.y) >= 0) {
e = e.next;
if (e === start) {
throw new Error('Something is wrong with the input points.');
}
}
var walkBack = e === start;
// add the first triangle from the point
var t = this._addTriangle(i, e);
adjacent[t] = -1;
adjacent[t + 1] = -1;
this._link(t + 2, e.t);
e.t = t; // keep track of boundary triangles on the hull
e = insertNode(coords, i, e);
// recursively flip triangles from the point until they satisfy the Delaunay condition
e.t = this._legalize(t + 2);
// walk forward through the hull, adding more triangles and flipping recursively
var q = e.next;
while (area(x, y, q.x, q.y, q.next.x, q.next.y) < 0) {
t = this._addTriangle(i, q);
this._link(t, q.prev.t);
adjacent[t + 1] = -1;
this._link(t + 2, q.t);
q.prev.t = this._legalize(t + 2);
this.hull = removeNode(q);
q = q.next;
}
if (walkBack) {
// walk backward from the other side, adding more triangles and flipping
q = e.prev;
while (area(x, y, q.prev.x, q.prev.y, q.x, q.y) < 0) {
t = this._addTriangle(i, q.prev);
adjacent[t] = -1;
this._link(t + 1, q.t);
this._link(t + 2, q.prev.t);
this._legalize(t + 2);
q.prev.t = t;
this.hull = removeNode(q);
q = q.prev;
}
}
// save the two new edges in the hash table
this._hashEdge(e);
this._hashEdge(e.prev);
}
// trim typed triangle mesh arrays
this.triangles = triangles.subarray(0, this.trianglesLen);
this.adjacent = adjacent.subarray(0, this.trianglesLen);
}
Delaunator.prototype = {
_hashEdge: function (e) {
this._hash[this._hashKey(e.x, e.y)] = e;
},
_hashKey: function (x, y) {
var dx = x - this._cx;
var dy = y - this._cy;
// use pseudo-angle: a measure that monotonically increases
// with real angle, but doesn't require expensive trigonometry
var p = 1 - dx / (Math.abs(dx) + Math.abs(dy));
return Math.floor((2 + (dy < 0 ? -p : p)) * (this._hashSize / 4));
},
_legalize: function (a) {
var triangles = this.triangles;
var coords = this.coords;
var adjacent = this.adjacent;
var b = adjacent[a];
var a0 = a - a % 3;
var b0 = b - b % 3;
var al = a0 + (a + 1) % 3;
var ar = a0 + (a + 2) % 3;
var br = b0 + (b + 1) % 3;
var bl = b0 + (b + 2) % 3;
var p0 = triangles[ar];
var pr = triangles[a];
var pl = triangles[al];
var p1 = triangles[bl];
var illegal = inCircle(
coords[2 * p0], coords[2 * p0 + 1],
coords[2 * pr], coords[2 * pr + 1],
coords[2 * pl], coords[2 * pl + 1],
coords[2 * p1], coords[2 * p1 + 1]);
if (illegal) {
triangles[a] = p1;
triangles[b] = p0;
this._link(a, adjacent[bl]);
this._link(b, adjacent[ar]);
this._link(ar, bl);
this._legalize(a);
return this._legalize(br);
}
return ar;
},
_link: function (a, b) {
this.adjacent[a] = b;
if (b !== -1) this.adjacent[b] = a;
},
_addTriangle(i, e) {
var t = this.trianglesLen;
this.triangles[t] = e.i;
this.triangles[t + 1] = i;
this.triangles[t + 2] = e.next.i;
this.trianglesLen += 3;
return t;
}
};
function dist(ax, ay, bx, by) {
var dx = ax - bx;
var dy = ay - by;
return dx * dx + dy * dy;
}
function area(px, py, qx, qy, rx, ry) {
return (qy - py) * (rx - qx) - (qx - px) * (ry - qy);
}
function inCircle(ax, ay, bx, by, cx, cy, px, py) {
ax -= px;
ay -= py;
bx -= px;
by -= py;
cx -= px;
cy -= py;
var ap = ax * ax + ay * ay;
var bp = bx * bx + by * by;
var cp = cx * cx + cy * cy;
var det = ax * (by * cp - bp * cy) -
ay * (bx * cp - bp * cx) +
ap * (bx * cy - by * cx);
return det < 0;
}
function circumradius(ax, ay, bx, by, cx, cy) {
bx -= ax;
by -= ay;
cx -= ax;
cy -= ay;
var bl = bx * bx + by * by;
var cl = cx * cx + cy * cy;
if (bl === 0 || cl === 0) return Infinity;
var d = bx * cy - by * cx;
if (d === 0) return Infinity;
var x = (cy * bl - by * cl) * 0.5 / d;
var y = (bx * cl - cx * bl) * 0.5 / d;
return x * x + y * y;
}
function circumcenter(ax, ay, bx, by, cx, cy) {
bx -= ax;
by -= ay;
cx -= ax;
cy -= ay;
var bl = bx * bx + by * by;
var cl = cx * cx + cy * cy;
var d = bx * cy - by * cx;
var x = (cy * bl - by * cl) * 0.5 / d;
var y = (bx * cl - cx * bl) * 0.5 / d;
return {
x: ax + x,
y: ay + y
};
}
// create a new node in a doubly linked list
function insertNode(coords, i, prev) {
var node = {
i: i,
x: coords[2 * i],
y: coords[2 * i + 1],
t: 0,
prev: null,
next: null,
removed: false
};
if (!prev) {
node.prev = node;
node.next = node;
} else {
node.next = prev.next;
node.prev = prev;
prev.next.prev = node;
prev.next = node;
}
return node;
}
function removeNode(node) {
node.prev.next = node.next;
node.next.prev = node.prev;
node.removed = true;
return node.prev;
}
function quicksort(ids, coords, left, right, cx, cy) {
var i, j, temp;
if (right - left <= 20) {
for (i = left + 1; i <= right; i++) {
temp = ids[i];
j = i - 1;
while (j >= left && compare(coords, ids[j], temp, cx, cy) > 0) ids[j + 1] = ids[j--];
ids[j + 1] = temp;
}
} else {
var median = (left + right) >> 1;
i = left + 1;
j = right;
swap(ids, median, i);
if (compare(coords, ids[left], ids[right], cx, cy) > 0) swap(ids, left, right);
if (compare(coords, ids[i], ids[right], cx, cy) > 0) swap(ids, i, right);
if (compare(coords, ids[left], ids[i], cx, cy) > 0) swap(ids, left, i);
temp = ids[i];
while (true) {
do i++; while (compare(coords, ids[i], temp, cx, cy) < 0);
do j--; while (compare(coords, ids[j], temp, cx, cy) > 0);
if (j < i) break;
swap(ids, i, j);
}
ids[left + 1] = ids[j];
ids[j] = temp;
if (right - i + 1 >= j - left) {
quicksort(ids, coords, i, right, cx, cy);
quicksort(ids, coords, left, j - 1, cx, cy);
} else {
quicksort(ids, coords, left, j - 1, cx, cy);
quicksort(ids, coords, i, right, cx, cy);
}
}
}
function compare(coords, i, j, cx, cy) {
var d1 = dist(coords[2 * i], coords[2 * i + 1], cx, cy);
var d2 = dist(coords[2 * j], coords[2 * j + 1], cx, cy);
return (d1 - d2) || (coords[2 * i] - coords[2 * j]) || (coords[2 * i + 1] - coords[2 * j + 1]);
}
function swap(arr, i, j) {
var tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
function defaultGetX(p) {
return p[0];
}
function defaultGetY(p) {
return p[1];
}
},{}]},{},[])
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImRlbGF1bmF0b3IiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IERlbGF1bmF0b3I7XG5cbmZ1bmN0aW9uIERlbGF1bmF0b3IocG9pbnRzLCBnZXRYLCBnZXRZKSB7XG5cbiAgICBpZiAoIWdldFgpIGdldFggPSBkZWZhdWx0R2V0WDtcbiAgICBpZiAoIWdldFkpIGdldFkgPSBkZWZhdWx0R2V0WTtcblxuICAgIHZhciBtaW5YID0gSW5maW5pdHk7XG4gICAgdmFyIG1pblkgPSBJbmZpbml0eTtcbiAgICB2YXIgbWF4WCA9IC1JbmZpbml0eTtcbiAgICB2YXIgbWF4WSA9IC1JbmZpbml0eTtcblxuICAgIHZhciBjb29yZHMgPSB0aGlzLmNvb3JkcyA9IFtdO1xuICAgIHZhciBpZHMgPSB0aGlzLmlkcyA9IG5ldyBVaW50MzJBcnJheShwb2ludHMubGVuZ3RoKTtcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBwID0gcG9pbnRzW2ldO1xuICAgICAgICB2YXIgeCA9IGdldFgocCk7XG4gICAgICAgIHZhciB5ID0gZ2V0WShwKTtcbiAgICAgICAgaWRzW2ldID0gaTtcbiAgICAgICAgY29vcmRzWzIgKiBpXSA9IHg7XG4gICAgICAgIGNvb3Jkc1syICogaSArIDFdID0geTtcbiAgICAgICAgaWYgKHggPCBtaW5YKSBtaW5YID0geDtcbiAgICAgICAgaWYgKHkgPCBtaW5ZKSBtaW5ZID0geTtcbiAgICAgICAgaWYgKHggPiBtYXhYKSBtYXhYID0geDtcbiAgICAgICAgaWYgKHkgPiBtYXhZKSBtYXhZID0geTtcbiAgICB9XG5cbiAgICB2YXIgY3ggPSAobWluWCArIG1heFgpIC8gMjtcbiAgICB2YXIgY3kgPSAobWluWSArIG1heFkpIC8gMjtcblxuICAgIHZhciBtaW5EaXN0ID0gSW5maW5pdHk7XG4gICAgdmFyIGkwLCBpMSwgaTI7XG5cbiAgICAvLyBwaWNrIGEgc2VlZCBwb2ludCBjbG9zZSB0byB0aGUgY2VudHJvaWRcbiAgICBmb3IgKGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBkID0gZGlzdChjeCwgY3ksIGNvb3Jkc1syICogaV0sIGNvb3Jkc1syICogaSArIDFdKTtcbiAgICAgICAgaWYgKGQgPCBtaW5EaXN0KSB7XG4gICAgICAgICAgICBpMCA9IGk7XG4gICAgICAgICAgICBtaW5EaXN0ID0gZDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG1pbkRpc3QgPSBJbmZpbml0eTtcblxuICAgIC8vIGZpbmQgdGhlIHBvaW50IGNsb3Nlc3QgdG8gdGhlIHNlZWRcbiAgICBmb3IgKGkgPSAwOyBpIDwgcG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChpID09PSBpMCkgY29udGludWU7XG4gICAgICAgIGQgPSBkaXN0KGNvb3Jkc1syICogaTBdLCBjb29yZHNbMiAqIGkwICsgMV0sIGNvb3Jkc1syICogaV0sIGNvb3Jkc1syICogaSArIDFdKTtcbiAgICAgICAgaWYgKGQgPCBtaW5EaXN0ICYmIGQgPiAwKSB7XG4gICAgICAgICAgICBpMSA9IGk7XG4gICAgICAgICAgICBtaW5EaXN0ID0gZDtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHZhciBtaW5SYWRpdXMgPSBJbmZpbml0eTtcblxuICAgIC8vIGZpbmQgdGhlIHRoaXJkIHBvaW50IHdoaWNoIGZvcm1zIHRoZSBzbWFsbGVzdCBjaXJjdW1jaXJjbGUgd2l0aCB0aGUgZmlyc3QgdHdvXG4gICAgZm9yIChpID0gMDsgaSA8IHBvaW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAoaSA9PT0gaTAgfHwgaSA9PT0gaTEpIGNvbnRpbnVlO1xuXG4gICAgICAgIHZhciByID0gY2lyY3VtcmFkaXVzKFxuICAgICAgICAgICAgY29vcmRzWzIgKiBpMF0sIGNvb3Jkc1syICogaTAgKyAxXSxcbiAgICAgICAgICAgIGNvb3Jkc1syICogaTFdLCBjb29yZHNbMiAqIGkxICsgMV0sXG4gICAgICAgICAgICBjb29yZHNbMiAqIGldLCBjb29yZHNbMiAqIGkgKyAxXSk7XG5cbiAgICAgICAgaWYgKHIgPCBtaW5SYWRpdXMpIHtcbiAgICAgICAgICAgIGkyID0gaTtcbiAgICAgICAgICAgIG1pblJhZGl1cyA9IHI7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAobWluUmFkaXVzID09PSBJbmZpbml0eSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05vIERlbGF1bmF5IHRyaWFuZ3VsYXRpb24gZXhpc3RzIGZvciB0aGlzIGlucHV0LicpO1xuICAgIH1cblxuICAgIC8vIHN3YXAgdGhlIG9yZGVyIG9mIHRoZSBzZWVkIHBvaW50cyBmb3IgY291bnRlci1jbG9ja3dpc2Ugb3JpZW50YXRpb25cbiAgICBpZiAoYXJlYShjb29yZHNbMiAqIGkwXSwgY29vcmRzWzIgKiBpMCArIDFdLFxuICAgICAgICAgICAgIGNvb3Jkc1syICogaTFdLCBjb29yZHNbMiAqIGkxICsgMV0sXG4gICAgICAgICAgICAgY29vcmRzWzIgKiBpMl0sIGNvb3Jkc1syICogaTIgKyAxXSkgPCAwKSB7XG5cbiAgICAgICAgdmFyIHRtcCA9IGkxO1xuICAgICAgICBpMSA9IGkyO1xuICAgICAgICBpMiA9IHRtcDtcbiAgICB9XG5cbiAgICB2YXIgaTB4ID0gY29vcmRzWzIgKiBpMF07XG4gICAgdmFyIGkweSA9IGNvb3Jkc1syICogaTAgKyAxXTtcbiAgICB2YXIgaTF4ID0gY29vcmRzWzIgKiBpMV07XG4gICAgdmFyIGkxeSA9IGNvb3Jkc1syICogaTEgKyAxXTtcbiAgICB2YXIgaTJ4ID0gY29vcmRzWzIgKiBpMl07XG4gICAgdmFyIGkyeSA9IGNvb3Jkc1syICogaTIgKyAxXTtcblxuICAgIHZhciBjZW50ZXIgPSBjaXJjdW1jZW50ZXIoaTB4LCBpMHksIGkxeCwgaTF5LCBpMngsIGkyeSk7XG4gICAgdGhpcy5fY3ggPSBjZW50ZXIueDtcbiAgICB0aGlzLl9jeSA9IGNlbnRlci55O1xuXG4gICAgLy8gc29ydCB0aGUgcG9pbnRzIGJ5IGRpc3RhbmNlIGZyb20gdGhlIHNlZWQgdHJpYW5nbGUgY2lyY3VtY2VudGVyXG4gICAgcXVpY2tzb3J0KGlkcywgY29vcmRzLCAwLCBpZHMubGVuZ3RoIC0gMSwgY2VudGVyLngsIGNlbnRlci55KTtcblxuICAgIC8vIGluaXRpYWxpemUgYSBoYXNoIHRhYmxlIGZvciBzdG9yaW5nIGVkZ2VzIG9mIHRoZSBhZHZhbmNpbmcgY29udmV4IGh1bGxcbiAgICB0aGlzLl9oYXNoU2l6ZSA9IE1hdGguY2VpbChNYXRoLnNxcnQocG9pbnRzLmxlbmd0aCkpO1xuICAgIHRoaXMuX2hhc2ggPSBbXTtcbiAgICBmb3IgKGkgPSAwOyBpIDwgdGhpcy5faGFzaFNpemU7IGkrKykgdGhpcy5faGFzaFtpXSA9IG51bGw7XG5cbiAgICAvLyBpbml0aWFsaXplIGEgY2lyY3VsYXIgZG91Ymx5LWxpbmtlZCBsaXN0IHRoYXQgd2lsbCBob2xkIGFuIGFkdmFuY2luZyBjb252ZXggaHVsbFxuICAgIHZhciBlID0gdGhpcy5odWxsID0gaW5zZXJ0Tm9kZShjb29yZHMsIGkwKTtcbiAgICB0aGlzLl9oYXNoRWRnZShlKTtcbiAgICBlLnQgPSAwO1xuICAgIGUgPSBpbnNlcnROb2RlKGNvb3JkcywgaTEsIGUpO1xuICAgIHRoaXMuX2hhc2hFZGdlKGUpO1xuICAgIGUudCA9IDE7XG4gICAgZSA9IGluc2VydE5vZGUoY29vcmRzLCBpMiwgZSk7XG4gICAgdGhpcy5faGFzaEVkZ2UoZSk7XG4gICAgZS50ID0gMjtcblxuICAgIHZhciBtYXhUcmlhbmdsZXMgPSAyICogcG9pbnRzLmxlbmd0aCAtIDU7XG4gICAgdmFyIHRyaWFuZ2xlcyA9IHRoaXMudHJpYW5nbGVzID0gbmV3IFVpbnQzMkFycmF5KG1heFRyaWFuZ2xlcyAqIDMpO1xuICAgIHRyaWFuZ2xlc1swXSA9IGkwO1xuICAgIHRyaWFuZ2xlc1sxXSA9IGkxO1xuICAgIHRyaWFuZ2xlc1syXSA9IGkyO1xuICAgIHRoaXMudHJpYW5nbGVzTGVuID0gMztcblxuICAgIHZhciBhZGphY2VudCA9IHRoaXMuYWRqYWNlbnQgPSBuZXcgSW50MzJBcnJheShtYXhUcmlhbmdsZXMgKiAzKTtcbiAgICBhZGphY2VudFswXSA9IC0xO1xuICAgIGFkamFjZW50WzFdID0gLTE7XG4gICAgYWRqYWNlbnRbMl0gPSAtMTtcblxuICAgIHZhciB4cCwgeXA7XG4gICAgZm9yICh2YXIgayA9IDA7IGsgPCBpZHMubGVuZ3RoOyBrKyspIHtcbiAgICAgICAgaSA9IGlkc1trXTtcbiAgICAgICAgeCA9IGNvb3Jkc1syICogaV07XG4gICAgICAgIHkgPSBjb29yZHNbMiAqIGkgKyAxXTtcblxuICAgICAgICAvLyBza2lwIGR1cGxpY2F0ZSBwb2ludHNcbiAgICAgICAgaWYgKHggPT09IHhwICYmIHkgPT09IHlwKSBjb250aW51ZTtcbiAgICAgICAgeHAgPSB4O1xuICAgICAgICB5cCA9IHk7XG5cbiAgICAgICAgLy8gc2tpcCBzZWVkIHRyaWFuZ2xlIHBvaW50c1xuICAgICAgICBpZiAoKHggPT09IGkweCAmJiB5ID09PSBpMHkpIHx8XG4gICAgICAgICAgICAoeCA9PT0gaTF4ICYmIHkgPT09IGkxeSkgfHxcbiAgICAgICAgICAgICh4ID09PSBpMnggJiYgeSA9PT0gaTJ5KSkgY29udGludWU7XG5cbiAgICAgICAgLy8gZmluZCBhIHZpc2libGUgZWRnZSBvbiB0aGUgY29udmV4IGh1bGwgdXNpbmcgZWRnZSBoYXNoXG4gICAgICAgIHZhciBzdGFydEtleSA9IHRoaXMuX2hhc2hLZXkoeCwgeSk7XG4gICAgICAgIHZhciBrZXkgPSBzdGFydEtleTtcbiAgICAgICAgdmFyIHN0YXJ0O1xuICAgICAgICBkbyB7XG4gICAgICAgICAgICBzdGFydCA9IHRoaXMuX2hhc2hba2V5XTtcbiAgICAgICAgICAgIGtleSA9IChrZXkgKyAxKSAlIHRoaXMuX2hhc2hTaXplO1xuICAgICAgICB9IHdoaWxlICgoIXN0YXJ0IHx8IHN0YXJ0LnJlbW92ZWQpICYmIGtleSAhPT0gc3RhcnRLZXkpO1xuXG4gICAgICAgIGUgPSBzdGFydDtcbiAgICAgICAgd2hpbGUgKGFyZWEoeCwgeSwgZS54LCBlLnksIGUubmV4dC54LCBlLm5leHQueSkgPj0gMCkge1xuICAgICAgICAgICAgZSA9IGUubmV4dDtcbiAgICAgICAgICAgIGlmIChlID09PSBzdGFydCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignU29tZXRoaW5nIGlzIHdyb25nIHdpdGggdGhlIGlucHV0IHBvaW50cy4nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB3YWxrQmFjayA9IGUgPT09IHN0YXJ0O1xuXG4gICAgICAgIC8vIGFkZCB0aGUgZmlyc3QgdHJpYW5nbGUgZnJvbSB0aGUgcG9pbnRcbiAgICAgICAgdmFyIHQgPSB0aGlzLl9hZGRUcmlhbmdsZShpLCBlKTtcbiAgICAgICAgYWRqYWNlbnRbdF0gPSAtMTtcbiAgICAgICAgYWRqYWNlbnRbdCArIDFdID0gLTE7XG4gICAgICAgIHRoaXMuX2xpbmsodCArIDIsIGUudCk7XG5cbiAgICAgICAgZS50ID0gdDsgLy8ga2VlcCB0cmFjayBvZiBib3VuZGFyeSB0cmlhbmdsZXMgb24gdGhlIGh1bGxcbiAgICAgICAgZSA9IGluc2VydE5vZGUoY29vcmRzLCBpLCBlKTtcblxuICAgICAgICAvLyByZWN1cnNpdmVseSBmbGlwIHRyaWFuZ2xlcyBmcm9tIHRoZSBwb2ludCB1bnRpbCB0aGV5IHNhdGlzZnkgdGhlIERlbGF1bmF5IGNvbmRpdGlvblxuICAgICAgICBlLnQgPSB0aGlzLl9sZWdhbGl6ZSh0ICsgMik7XG5cbiAgICAgICAgLy8gd2FsayBmb3J3YXJkIHRocm91Z2ggdGhlIGh1bGwsIGFkZGluZyBtb3JlIHRyaWFuZ2xlcyBhbmQgZmxpcHBpbmcgcmVjdXJzaXZlbHlcbiAgICAgICAgdmFyIHEgPSBlLm5leHQ7XG4gICAgICAgIHdoaWxlIChhcmVhKHgsIHksIHEueCwgcS55LCBxLm5leHQueCwgcS5uZXh0LnkpIDwgMCkge1xuXG4gICAgICAgICAgICB0ID0gdGhpcy5fYWRkVHJpYW5nbGUoaSwgcSk7XG4gICAgICAgICAgICB0aGlzLl9saW5rKHQsIHEucHJldi50KTtcbiAgICAgICAgICAgIGFkamFjZW50W3QgKyAxXSA9IC0xO1xuICAgICAgICAgICAgdGhpcy5fbGluayh0ICsgMiwgcS50KTtcblxuICAgICAgICAgICAgcS5wcmV2LnQgPSB0aGlzLl9sZWdhbGl6ZSh0ICsgMik7XG5cbiAgICAgICAgICAgIHRoaXMuaHVsbCA9IHJlbW92ZU5vZGUocSk7XG4gICAgICAgICAgICBxID0gcS5uZXh0O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHdhbGtCYWNrKSB7XG4gICAgICAgICAgICAvLyB3YWxrIGJhY2t3YXJkIGZyb20gdGhlIG90aGVyIHNpZGUsIGFkZGluZyBtb3JlIHRyaWFuZ2xlcyBhbmQgZmxpcHBpbmdcbiAgICAgICAgICAgIHEgPSBlLnByZXY7XG4gICAgICAgICAgICB3aGlsZSAoYXJlYSh4LCB5LCBxLnByZXYueCwgcS5wcmV2LnksIHEueCwgcS55KSA8IDApIHtcblxuICAgICAgICAgICAgICAgIHQgPSB0aGlzLl9hZGRUcmlhbmdsZShpLCBxLnByZXYpO1xuICAgICAgICAgICAgICAgIGFkamFjZW50W3RdID0gLTE7XG4gICAgICAgICAgICAgICAgdGhpcy5fbGluayh0ICsgMSwgcS50KTtcbiAgICAgICAgICAgICAgICB0aGlzLl9saW5rKHQgKyAyLCBxLnByZXYudCk7XG5cbiAgICAgICAgICAgICAgICB0aGlzLl9sZWdhbGl6ZSh0ICsgMik7XG5cbiAgICAgICAgICAgICAgICBxLnByZXYudCA9IHQ7XG4gICAgICAgICAgICAgICAgdGhpcy5odWxsID0gcmVtb3ZlTm9kZShxKTtcbiAgICAgICAgICAgICAgICBxID0gcS5wcmV2O1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gc2F2ZSB0aGUgdHdvIG5ldyBlZGdlcyBpbiB0aGUgaGFzaCB0YWJsZVxuICAgICAgICB0aGlzLl9oYXNoRWRnZShlKTtcbiAgICAgICAgdGhpcy5faGFzaEVkZ2UoZS5wcmV2KTtcbiAgICB9XG5cbiAgICAvLyB0cmltIHR5cGVkIHRyaWFuZ2xlIG1lc2ggYXJyYXlzXG4gICAgdGhpcy50cmlhbmdsZXMgPSB0cmlhbmdsZXMuc3ViYXJyYXkoMCwgdGhpcy50cmlhbmdsZXNMZW4pO1xuICAgIHRoaXMuYWRqYWNlbnQgPSBhZGphY2VudC5zdWJhcnJheSgwLCB0aGlzLnRyaWFuZ2xlc0xlbik7XG59XG5cbkRlbGF1bmF0b3IucHJvdG90eXBlID0ge1xuXG4gICAgX2hhc2hFZGdlOiBmdW5jdGlvbiAoZSkge1xuICAgICAgICB0aGlzLl9oYXNoW3RoaXMuX2hhc2hLZXkoZS54LCBlLnkpXSA9IGU7XG4gICAgfSxcblxuICAgIF9oYXNoS2V5OiBmdW5jdGlvbiAoeCwgeSkge1xuICAgICAgICB2YXIgZHggPSB4IC0gdGhpcy5fY3g7XG4gICAgICAgIHZhciBkeSA9IHkgLSB0aGlzLl9jeTtcbiAgICAgICAgLy8gdXNlIHBzZXVkby1hbmdsZTogYSBtZWFzdXJlIHRoYXQgbW9ub3RvbmljYWxseSBpbmNyZWFzZXNcbiAgICAgICAgLy8gd2l0aCByZWFsIGFuZ2xlLCBidXQgZG9lc24ndCByZXF1aXJlIGV4cGVuc2l2ZSB0cmlnb25vbWV0cnlcbiAgICAgICAgdmFyIHAgPSAxIC0gZHggLyAoTWF0aC5hYnMoZHgpICsgTWF0aC5hYnMoZHkpKTtcbiAgICAgICAgcmV0dXJuIE1hdGguZmxvb3IoKDIgKyAoZHkgPCAwID8gLXAgOiBwKSkgKiAodGhpcy5faGFzaFNpemUgLyA0KSk7XG4gICAgfSxcblxuICAgIF9sZWdhbGl6ZTogZnVuY3Rpb24gKGEpIHtcbiAgICAgICAgdmFyIHRyaWFuZ2xlcyA9IHRoaXMudHJpYW5nbGVzO1xuICAgICAgICB2YXIgY29vcmRzID0gdGhpcy5jb29yZHM7XG4gICAgICAgIHZhciBhZGphY2VudCA9IHRoaXMuYWRqYWNlbnQ7XG5cbiAgICAgICAgdmFyIGIgPSBhZGphY2VudFthXTtcblxuICAgICAgICB2YXIgYTAgPSBhIC0gYSAlIDM7XG4gICAgICAgIHZhciBiMCA9IGIgLSBiICUgMztcblxuICAgICAgICB2YXIgYWwgPSBhMCArIChhICsgMSkgJSAzO1xuICAgICAgICB2YXIgYXIgPSBhMCArIChhICsgMikgJSAzO1xuICAgICAgICB2YXIgYnIgPSBiMCArIChiICsgMSkgJSAzO1xuICAgICAgICB2YXIgYmwgPSBiMCArIChiICsgMikgJSAzO1xuXG4gICAgICAgIHZhciBwMCA9IHRyaWFuZ2xlc1thcl07XG4gICAgICAgIHZhciBwciA9IHRyaWFuZ2xlc1thXTtcbiAgICAgICAgdmFyIHBsID0gdHJpYW5nbGVzW2FsXTtcbiAgICAgICAgdmFyIHAxID0gdHJpYW5nbGVzW2JsXTtcblxuICAgICAgICB2YXIgaWxsZWdhbCA9IGluQ2lyY2xlKFxuICAgICAgICAgICAgY29vcmRzWzIgKiBwMF0sIGNvb3Jkc1syICogcDAgKyAxXSxcbiAgICAgICAgICAgIGNvb3Jkc1syICogcHJdLCBjb29yZHNbMiAqIHByICsgMV0sXG4gICAgICAgICAgICBjb29yZHNbMiAqIHBsXSwgY29vcmRzWzIgKiBwbCArIDFdLFxuICAgICAgICAgICAgY29vcmRzWzIgKiBwMV0sIGNvb3Jkc1syICogcDEgKyAxXSk7XG5cbiAgICAgICAgaWYgKGlsbGVnYWwpIHtcbiAgICAgICAgICAgIHRyaWFuZ2xlc1thXSA9IHAxO1xuICAgICAgICAgICAgdHJpYW5nbGVzW2JdID0gcDA7XG5cbiAgICAgICAgICAgIHRoaXMuX2xpbmsoYSwgYWRqYWNlbnRbYmxdKTtcbiAgICAgICAgICAgIHRoaXMuX2xpbmsoYiwgYWRqYWNlbnRbYXJdKTtcbiAgICAgICAgICAgIHRoaXMuX2xpbmsoYXIsIGJsKTtcblxuICAgICAgICAgICAgdGhpcy5fbGVnYWxpemUoYSk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fbGVnYWxpemUoYnIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGFyO1xuICAgIH0sXG5cbiAgICBfbGluazogZnVuY3Rpb24gKGEsIGIpIHtcbiAgICAgICAgdGhpcy5hZGphY2VudFthXSA9IGI7XG4gICAgICAgIGlmIChiICE9PSAtMSkgdGhpcy5hZGphY2VudFtiXSA9IGE7XG4gICAgfSxcblxuICAgIF9hZGRUcmlhbmdsZShpLCBlKSB7XG4gICAgICAgIHZhciB0ID0gdGhpcy50cmlhbmdsZXNMZW47XG4gICAgICAgIHRoaXMudHJpYW5nbGVzW3RdID0gZS5pO1xuICAgICAgICB0aGlzLnRyaWFuZ2xlc1t0ICsgMV0gPSBpO1xuICAgICAgICB0aGlzLnRyaWFuZ2xlc1t0ICsgMl0gPSBlLm5leHQuaTtcbiAgICAgICAgdGhpcy50cmlhbmdsZXNMZW4gKz0gMztcbiAgICAgICAgcmV0dXJuIHQ7XG4gICAgfVxufTtcblxuZnVuY3Rpb24gZGlzdChheCwgYXksIGJ4LCBieSkge1xuICAgIHZhciBkeCA9IGF4IC0gYng7XG4gICAgdmFyIGR5ID0gYXkgLSBieTtcbiAgICByZXR1cm4gZHggKiBkeCArIGR5ICogZHk7XG59XG5cbmZ1bmN0aW9uIGFyZWEocHgsIHB5LCBxeCwgcXksIHJ4LCByeSkge1xuICAgIHJldHVybiAocXkgLSBweSkgKiAocnggLSBxeCkgLSAocXggLSBweCkgKiAocnkgLSBxeSk7XG59XG5cbmZ1bmN0aW9uIGluQ2lyY2xlKGF4LCBheSwgYngsIGJ5LCBjeCwgY3ksIHB4LCBweSkge1xuICAgIGF4IC09IHB4O1xuICAgIGF5IC09IHB5O1xuICAgIGJ4IC09IHB4O1xuICAgIGJ5IC09IHB5O1xuICAgIGN4IC09IHB4O1xuICAgIGN5IC09IHB5O1xuXG4gICAgdmFyIGFwID0gYXggKiBheCArIGF5ICogYXk7XG4gICAgdmFyIGJwID0gYnggKiBieCArIGJ5ICogYnk7XG4gICAgdmFyIGNwID0gY3ggKiBjeCArIGN5ICogY3k7XG5cbiAgICB2YXIgZGV0ID0gYXggKiAoYnkgKiBjcCAtIGJwICogY3kpIC1cbiAgICAgICAgICAgICAgYXkgKiAoYnggKiBjcCAtIGJwICogY3gpICtcbiAgICAgICAgICAgICAgYXAgKiAoYnggKiBjeSAtIGJ5ICogY3gpO1xuXG4gICAgcmV0dXJuIGRldCA8IDA7XG59XG5cbmZ1bmN0aW9uIGNpcmN1bXJhZGl1cyhheCwgYXksIGJ4LCBieSwgY3gsIGN5KSB7XG4gICAgYnggLT0gYXg7XG4gICAgYnkgLT0gYXk7XG4gICAgY3ggLT0gYXg7XG4gICAgY3kgLT0gYXk7XG5cbiAgICB2YXIgYmwgPSBieCAqIGJ4ICsgYnkgKiBieTtcbiAgICB2YXIgY2wgPSBjeCAqIGN4ICsgY3kgKiBjeTtcblxuICAgIGlmIChibCA9PT0gMCB8fCBjbCA9PT0gMCkgcmV0dXJuIEluZmluaXR5O1xuXG4gICAgdmFyIGQgPSBieCAqIGN5IC0gYnkgKiBjeDtcbiAgICBpZiAoZCA9PT0gMCkgcmV0dXJuIEluZmluaXR5O1xuXG4gICAgdmFyIHggPSAoY3kgKiBibCAtIGJ5ICogY2wpICogMC41IC8gZDtcbiAgICB2YXIgeSA9IChieCAqIGNsIC0gY3ggKiBibCkgKiAwLjUgLyBkO1xuXG4gICAgcmV0dXJuIHggKiB4ICsgeSAqIHk7XG59XG5cbmZ1bmN0aW9uIGNpcmN1bWNlbnRlcihheCwgYXksIGJ4LCBieSwgY3gsIGN5KSB7XG4gICAgYnggLT0gYXg7XG4gICAgYnkgLT0gYXk7XG4gICAgY3ggLT0gYXg7XG4gICAgY3kgLT0gYXk7XG5cbiAgICB2YXIgYmwgPSBieCAqIGJ4ICsgYnkgKiBieTtcbiAgICB2YXIgY2wgPSBjeCAqIGN4ICsgY3kgKiBjeTtcblxuICAgIHZhciBkID0gYnggKiBjeSAtIGJ5ICogY3g7XG5cbiAgICB2YXIgeCA9IChjeSAqIGJsIC0gYnkgKiBjbCkgKiAwLjUgLyBkO1xuICAgIHZhciB5ID0gKGJ4ICogY2wgLSBjeCAqIGJsKSAqIDAuNSAvIGQ7XG5cbiAgICByZXR1cm4ge1xuICAgICAgICB4OiBheCArIHgsXG4gICAgICAgIHk6IGF5ICsgeVxuICAgIH07XG59XG5cbi8vIGNyZWF0ZSBhIG5ldyBub2RlIGluIGEgZG91Ymx5IGxpbmtlZCBsaXN0XG5mdW5jdGlvbiBpbnNlcnROb2RlKGNvb3JkcywgaSwgcHJldikge1xuICAgIHZhciBub2RlID0ge1xuICAgICAgICBpOiBpLFxuICAgICAgICB4OiBjb29yZHNbMiAqIGldLFxuICAgICAgICB5OiBjb29yZHNbMiAqIGkgKyAxXSxcbiAgICAgICAgdDogMCxcbiAgICAgICAgcHJldjogbnVsbCxcbiAgICAgICAgbmV4dDogbnVsbCxcbiAgICAgICAgcmVtb3ZlZDogZmFsc2VcbiAgICB9O1xuXG4gICAgaWYgKCFwcmV2KSB7XG4gICAgICAgIG5vZGUucHJldiA9IG5vZGU7XG4gICAgICAgIG5vZGUubmV4dCA9IG5vZGU7XG5cbiAgICB9IGVsc2Uge1xuICAgICAgICBub2RlLm5leHQgPSBwcmV2Lm5leHQ7XG4gICAgICAgIG5vZGUucHJldiA9IHByZXY7XG4gICAgICAgIHByZXYubmV4dC5wcmV2ID0gbm9kZTtcbiAgICAgICAgcHJldi5uZXh0ID0gbm9kZTtcbiAgICB9XG4gICAgcmV0dXJuIG5vZGU7XG59XG5cbmZ1bmN0aW9uIHJlbW92ZU5vZGUobm9kZSkge1xuICAgIG5vZGUucHJldi5uZXh0ID0gbm9kZS5uZXh0O1xuICAgIG5vZGUubmV4dC5wcmV2ID0gbm9kZS5wcmV2O1xuICAgIG5vZGUucmVtb3ZlZCA9IHRydWU7XG4gICAgcmV0dXJuIG5vZGUucHJldjtcbn1cblxuZnVuY3Rpb24gcXVpY2tzb3J0KGlkcywgY29vcmRzLCBsZWZ0LCByaWdodCwgY3gsIGN5KSB7XG4gICAgdmFyIGksIGosIHRlbXA7XG5cbiAgICBpZiAocmlnaHQgLSBsZWZ0IDw9IDIwKSB7XG4gICAgICAgIGZvciAoaSA9IGxlZnQgKyAxOyBpIDw9IHJpZ2h0OyBpKyspIHtcbiAgICAgICAgICAgIHRlbXAgPSBpZHNbaV07XG4gICAgICAgICAgICBqID0gaSAtIDE7XG4gICAgICAgICAgICB3aGlsZSAoaiA+PSBsZWZ0ICYmIGNvbXBhcmUoY29vcmRzLCBpZHNbal0sIHRlbXAsIGN4LCBjeSkgPiAwKSBpZHNbaiArIDFdID0gaWRzW2otLV07XG4gICAgICAgICAgICBpZHNbaiArIDFdID0gdGVtcDtcbiAgICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBtZWRpYW4gPSAobGVmdCArIHJpZ2h0KSA+PiAxO1xuICAgICAgICBpID0gbGVmdCArIDE7XG4gICAgICAgIGogPSByaWdodDtcbiAgICAgICAgc3dhcChpZHMsIG1lZGlhbiwgaSk7XG4gICAgICAgIGlmIChjb21wYXJlKGNvb3JkcywgaWRzW2xlZnRdLCBpZHNbcmlnaHRdLCBjeCwgY3kpID4gMCkgc3dhcChpZHMsIGxlZnQsIHJpZ2h0KTtcbiAgICAgICAgaWYgKGNvbXBhcmUoY29vcmRzLCBpZHNbaV0sIGlkc1tyaWdodF0sIGN4LCBjeSkgPiAwKSBzd2FwKGlkcywgaSwgcmlnaHQpO1xuICAgICAgICBpZiAoY29tcGFyZShjb29yZHMsIGlkc1tsZWZ0XSwgaWRzW2ldLCBjeCwgY3kpID4gMCkgc3dhcChpZHMsIGxlZnQsIGkpO1xuXG4gICAgICAgIHRlbXAgPSBpZHNbaV07XG4gICAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgICAgICBkbyBpKys7IHdoaWxlIChjb21wYXJlKGNvb3JkcywgaWRzW2ldLCB0ZW1wLCBjeCwgY3kpIDwgMCk7XG4gICAgICAgICAgICBkbyBqLS07IHdoaWxlIChjb21wYXJlKGNvb3JkcywgaWRzW2pdLCB0ZW1wLCBjeCwgY3kpID4gMCk7XG4gICAgICAgICAgICBpZiAoaiA8IGkpIGJyZWFrO1xuICAgICAgICAgICAgc3dhcChpZHMsIGksIGopO1xuICAgICAgICB9XG4gICAgICAgIGlkc1tsZWZ0ICsgMV0gPSBpZHNbal07XG4gICAgICAgIGlkc1tqXSA9IHRlbXA7XG5cbiAgICAgICAgaWYgKHJpZ2h0IC0gaSArIDEgPj0gaiAtIGxlZnQpIHtcbiAgICAgICAgICAgIHF1aWNrc29ydChpZHMsIGNvb3JkcywgaSwgcmlnaHQsIGN4LCBjeSk7XG4gICAgICAgICAgICBxdWlja3NvcnQoaWRzLCBjb29yZHMsIGxlZnQsIGogLSAxLCBjeCwgY3kpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcXVpY2tzb3J0KGlkcywgY29vcmRzLCBsZWZ0LCBqIC0gMSwgY3gsIGN5KTtcbiAgICAgICAgICAgIHF1aWNrc29ydChpZHMsIGNvb3JkcywgaSwgcmlnaHQsIGN4LCBjeSk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmZ1bmN0aW9uIGNvbXBhcmUoY29vcmRzLCBpLCBqLCBjeCwgY3kpIHtcbiAgICB2YXIgZDEgPSBkaXN0KGNvb3Jkc1syICogaV0sIGNvb3Jkc1syICogaSArIDFdLCBjeCwgY3kpO1xuICAgIHZhciBkMiA9IGRpc3QoY29vcmRzWzIgKiBqXSwgY29vcmRzWzIgKiBqICsgMV0sIGN4LCBjeSk7XG4gICAgcmV0dXJuIChkMSAtIGQyKSB8fCAoY29vcmRzWzIgKiBpXSAtIGNvb3Jkc1syICogal0pIHx8IChjb29yZHNbMiAqIGkgKyAxXSAtIGNvb3Jkc1syICogaiArIDFdKTtcbn1cblxuZnVuY3Rpb24gc3dhcChhcnIsIGksIGopIHtcbiAgICB2YXIgdG1wID0gYXJyW2ldO1xuICAgIGFycltpXSA9IGFycltqXTtcbiAgICBhcnJbal0gPSB0bXA7XG59XG5cbmZ1bmN0aW9uIGRlZmF1bHRHZXRYKHApIHtcbiAgICByZXR1cm4gcFswXTtcbn1cbmZ1bmN0aW9uIGRlZmF1bHRHZXRZKHApIHtcbiAgICByZXR1cm4gcFsxXTtcbn1cbiJdfQ==
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 banksean@gmail.com
/**
* 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=
var Delaunator = require('delaunator')
var Simplex = require('perlin-simplex')
var simplex = new Simplex()
var SPEED = 0.25
var N_POINTS = 150
var width = 0.75 * window.innerWidth
var height = 0.75 * window.innerHeight
document.body.style.background = 'rgb(20, 20, 20)'
var points = createPoints(N_POINTS, width, height)
points.forEach(function (point) {
// document.body.appendChild(point.el)
})
var parent = document.createElement('div')
parent.style.position = 'absolute'
parent.style.top = 0.125 * window.innerHeight + 'px'
parent.style.left = 0.125 * window.innerWidth + 'px'
document.body.appendChild(parent)
var triangles = createTrianges(points)
parent.appendChild(triangles.el)
window.requestAnimationFrame(updateLoop)
function updateLoop () {
window.requestAnimationFrame(updateLoop)
points.forEach(function (point, i) {
// var theta = (0.5 - Math.random()) * (Math.PI / 16)
var x = point.x / 40
var y = point.y / 40
var z = Date.now() / 10000
var s = simplex.noise3d(x, y, z)
// var s = simplex.noise(x, y)
var theta1 = s * (2 * Math.PI)
var theta = (0.01 * theta1) + (0.99 * point.theta)
// if (i === 0) console.log(s, theta)
point.move(theta, SPEED)
})
triangles.update(points)
}
function createPoints (n, w, h) {
var points = []
var x, y
for (var i = 0; i < n; i++) {
x = Math.floor(Math.random() * w)
y = Math.floor(Math.random() * h)
points.push(createPoint([x, y]))
}
return points
}
function createPoint (coords) {
var w = 20
var h = w
var el = document.createElement('div')
el.style.position = 'absolute'
el.style.left = coords[0] + 'px'
el.style.top = coords[1] + 'px'
el.style.width = w + 'px'
el.style.height = h + 'px'
el.style.borderRadius = w / 2 + 'px'
el.style.background = '#aaa'
var point = {
el: el,
x: coords[0],
y: coords[1],
theta: Math.random() * 2 * Math.PI,
move: move
}
return point
}
function mod (a, n) {
return ((a % n) + n) % n
}
function move (theta, r) {
this.theta = theta
this.x += r * Math.cos(this.theta)
this.y += r * Math.sin(this.theta)
this.x = mod(this.x, width)
this.y = mod(this.y, height)
this.el.style.left = this.x + 'px'
this.el.style.top = this.y + 'px'
}
function createTrianges (points) {
var stroke = '#ccc'
var fill = 'rgba(0,0,0,0)'
var viewBox = [0, 0, width, height].join(' ')
var pathData = createPathData(points)
var parent = document.createElement('div')
parent.innerHTML = `
<svg xmlns='http://www.w3.org/svg/2000'
viewBox='${viewBox}'
width=${width}
height=${height}
stroke='none'
fill='none'>
${pathData}
</svg>
`
return {
el: parent,
svg: parent.querySelector('svg'),
update: update
}
}
function createPathData (points) {
var coords = points.map(function (point) {
return [point.x, point.y]
})
var triangles = new Delaunator(coords).triangles
var pathData = []
var maxArea = 2 * (height * width) / (N_POINTS / 3)
var x0, y0, x1, y1, x2, y2, d, fill, b, area
for (var i = 0; i < triangles.length; i += 3) {
x0 = coords[triangles[i]][0]
y0 = coords[triangles[i]][1]
x1 = coords[triangles[i + 1]][0]
y1 = coords[triangles[i + 1]][1]
x2 = coords[triangles[i + 2]][0]
y2 = coords[triangles[i + 2]][1]
d = [
'M', x0, y0,
'L', x1, y1,
'L', x2, y2,
'L', x0, y0
].join(' ')
area = calcArea(x0, y0, x1, y1, x2, y2)
b = Math.floor((area / maxArea) * 255)
fill = `rgb(${b}, ${b}, ${b})`
pathData.push(`<path d='${d}' fill='${fill}' stroke='${fill}' />`)
}
return pathData.join('\n')
}
function update (points) {
this.svg.innerHTML = createPathData(points)
}
function calcArea (x0, y0, x1, y1, x2, y2) {
return Math.abs(((x0 * (y1 - y2)) + (x1 * (y2 - y0)) + (x2 * (y0 - y1))) / 2)
}
;}, 0)
{
"name": "requirebin-sketch",
"version": "1.0.0",
"dependencies": {
"delaunator": "1.0.2",
"perlin-simplex": "0.0.2"
}
}
<!-- contents of this file will be placed inside the <body> -->
<!-- contents of this file will be placed inside the <head> -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.