Skip to content

Instantly share code, notes, and snippets.

@mikolalysenko
Created August 17, 2016 19:00
Show Gist options
  • Save mikolalysenko/921152d4d15b5d57351a665da6d274a7 to your computer and use it in GitHub Desktop.
Save mikolalysenko/921152d4d15b5d57351a665da6d274a7 to your computer and use it in GitHub Desktop.
requirebin sketch
const polytope = require('conway-hart')('tI')
const vec3 = require('gl-vec3')
const HEIGHT = 6
const bounds = require('bound-points')(polytope.positions)
const radius = Math.max(
bounds[1][0] - bounds[0][0],
bounds[1][1] - bounds[0][1],
bounds[1][2] - bounds[0][2])
const scale = HEIGHT / radius
const edges = []
polytope.cells.forEach((c) => {
for (let i = 0; i < c.length; ++i) {
edges.push([c[i], c[(i + 1) % c.length]])
}
})
const lengths = edges.map(([i, j]) =>
vec3.length(vec3.subtract([], polytope.positions[i], polytope.positions[j])))
lengths.sort(function (a, b) {
return a - b
})
const histogram = {}
let total = 0
lengths.forEach((l) => {
const x = Math.round(scale * l * 1000.0) / 1000.0
histogram[x] = (histogram[x] | 0) + 1
total += x
})
Object.keys(histogram).forEach(function (l) {
histogram[l] /= 2
})
if (typeof document !== 'undefined') {
document.body.appendChild(document.createTextNode(
`dome height: ${HEIGHT} lengths: ${JSON.stringify(histogram)} total: ${total / 2}`))
}
console.log('dome height: ', HEIGHT)
console.log('lengths: ', histogram)
console.log('total: ', total / 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})({1:[function(require,module,exports){
module.exports = add;
/**
* Adds two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
function add(out, a, b) {
out[0] = a[0] + b[0]
out[1] = a[1] + b[1]
out[2] = a[2] + b[2]
return out
}
},{}],2:[function(require,module,exports){
module.exports = angle
var fromValues = require('./fromValues')
var normalize = require('./normalize')
var dot = require('./dot')
/**
* Get the angle between two 3D vectors
* @param {vec3} a The first operand
* @param {vec3} b The second operand
* @returns {Number} The angle in radians
*/
function angle(a, b) {
var tempA = fromValues(a[0], a[1], a[2])
var tempB = fromValues(b[0], b[1], b[2])
normalize(tempA, tempA)
normalize(tempB, tempB)
var cosine = dot(tempA, tempB)
if(cosine > 1.0){
return 0
} else {
return Math.acos(cosine)
}
}
},{"./dot":9,"./fromValues":11,"./normalize":19}],3:[function(require,module,exports){
module.exports = clone;
/**
* Creates a new vec3 initialized with values from an existing vector
*
* @param {vec3} a vector to clone
* @returns {vec3} a new 3D vector
*/
function clone(a) {
var out = new Float32Array(3)
out[0] = a[0]
out[1] = a[1]
out[2] = a[2]
return out
}
},{}],4:[function(require,module,exports){
module.exports = copy;
/**
* Copy the values from one vec3 to another
*
* @param {vec3} out the receiving vector
* @param {vec3} a the source vector
* @returns {vec3} out
*/
function copy(out, a) {
out[0] = a[0]
out[1] = a[1]
out[2] = a[2]
return out
}
},{}],5:[function(require,module,exports){
module.exports = create;
/**
* Creates a new, empty vec3
*
* @returns {vec3} a new 3D vector
*/
function create() {
var out = new Float32Array(3)
out[0] = 0
out[1] = 0
out[2] = 0
return out
}
},{}],6:[function(require,module,exports){
module.exports = cross;
/**
* Computes the cross product of two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
function cross(out, a, b) {
var ax = a[0], ay = a[1], az = a[2],
bx = b[0], by = b[1], bz = b[2]
out[0] = ay * bz - az * by
out[1] = az * bx - ax * bz
out[2] = ax * by - ay * bx
return out
}
},{}],7:[function(require,module,exports){
module.exports = distance;
/**
* Calculates the euclidian distance between two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} distance between a and b
*/
function distance(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1],
z = b[2] - a[2]
return Math.sqrt(x*x + y*y + z*z)
}
},{}],8:[function(require,module,exports){
module.exports = divide;
/**
* Divides two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
function divide(out, a, b) {
out[0] = a[0] / b[0]
out[1] = a[1] / b[1]
out[2] = a[2] / b[2]
return out
}
},{}],9:[function(require,module,exports){
module.exports = dot;
/**
* Calculates the dot product of two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} dot product of a and b
*/
function dot(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]
}
},{}],10:[function(require,module,exports){
module.exports = forEach;
var vec = require('./create')()
/**
* Perform some operation over an array of vec3s.
*
* @param {Array} a the array of vectors to iterate over
* @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
* @param {Number} offset Number of elements to skip at the beginning of the array
* @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
* @param {Function} fn Function to call for each vector in the array
* @param {Object} [arg] additional argument to pass to fn
* @returns {Array} a
* @function
*/
function forEach(a, stride, offset, count, fn, arg) {
var i, l
if(!stride) {
stride = 3
}
if(!offset) {
offset = 0
}
if(count) {
l = Math.min((count * stride) + offset, a.length)
} else {
l = a.length
}
for(i = offset; i < l; i += stride) {
vec[0] = a[i]
vec[1] = a[i+1]
vec[2] = a[i+2]
fn(vec, vec, arg)
a[i] = vec[0]
a[i+1] = vec[1]
a[i+2] = vec[2]
}
return a
}
},{"./create":5}],11:[function(require,module,exports){
module.exports = fromValues;
/**
* Creates a new vec3 initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @returns {vec3} a new 3D vector
*/
function fromValues(x, y, z) {
var out = new Float32Array(3)
out[0] = x
out[1] = y
out[2] = z
return out
}
},{}],12:[function(require,module,exports){
module.exports = inverse;
/**
* Returns the inverse of the components of a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to invert
* @returns {vec3} out
*/
function inverse(out, a) {
out[0] = 1.0 / a[0]
out[1] = 1.0 / a[1]
out[2] = 1.0 / a[2]
return out
}
},{}],13:[function(require,module,exports){
module.exports = length;
/**
* Calculates the length of a vec3
*
* @param {vec3} a vector to calculate length of
* @returns {Number} length of a
*/
function length(a) {
var x = a[0],
y = a[1],
z = a[2]
return Math.sqrt(x*x + y*y + z*z)
}
},{}],14:[function(require,module,exports){
module.exports = lerp;
/**
* Performs a linear interpolation between two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @param {Number} t interpolation amount between the two inputs
* @returns {vec3} out
*/
function lerp(out, a, b, t) {
var ax = a[0],
ay = a[1],
az = a[2]
out[0] = ax + t * (b[0] - ax)
out[1] = ay + t * (b[1] - ay)
out[2] = az + t * (b[2] - az)
return out
}
},{}],15:[function(require,module,exports){
module.exports = max;
/**
* Returns the maximum of two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
function max(out, a, b) {
out[0] = Math.max(a[0], b[0])
out[1] = Math.max(a[1], b[1])
out[2] = Math.max(a[2], b[2])
return out
}
},{}],16:[function(require,module,exports){
module.exports = min;
/**
* Returns the minimum of two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
function min(out, a, b) {
out[0] = Math.min(a[0], b[0])
out[1] = Math.min(a[1], b[1])
out[2] = Math.min(a[2], b[2])
return out
}
},{}],17:[function(require,module,exports){
module.exports = multiply;
/**
* Multiplies two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
function multiply(out, a, b) {
out[0] = a[0] * b[0]
out[1] = a[1] * b[1]
out[2] = a[2] * b[2]
return out
}
},{}],18:[function(require,module,exports){
module.exports = negate;
/**
* Negates the components of a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to negate
* @returns {vec3} out
*/
function negate(out, a) {
out[0] = -a[0]
out[1] = -a[1]
out[2] = -a[2]
return out
}
},{}],19:[function(require,module,exports){
module.exports = normalize;
/**
* Normalize a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to normalize
* @returns {vec3} out
*/
function normalize(out, a) {
var x = a[0],
y = a[1],
z = a[2]
var len = x*x + y*y + z*z
if (len > 0) {
//TODO: evaluate use of glm_invsqrt here?
len = 1 / Math.sqrt(len)
out[0] = a[0] * len
out[1] = a[1] * len
out[2] = a[2] * len
}
return out
}
},{}],20:[function(require,module,exports){
module.exports = random;
/**
* Generates a random vector with the given scale
*
* @param {vec3} out the receiving vector
* @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
* @returns {vec3} out
*/
function random(out, scale) {
scale = scale || 1.0
var r = Math.random() * 2.0 * Math.PI
var z = (Math.random() * 2.0) - 1.0
var zScale = Math.sqrt(1.0-z*z) * scale
out[0] = Math.cos(r) * zScale
out[1] = Math.sin(r) * zScale
out[2] = z * scale
return out
}
},{}],21:[function(require,module,exports){
module.exports = rotateX;
/**
* Rotate a 3D vector around the x-axis
* @param {vec3} out The receiving vec3
* @param {vec3} a The vec3 point to rotate
* @param {vec3} b The origin of the rotation
* @param {Number} c The angle of rotation
* @returns {vec3} out
*/
function rotateX(out, a, b, c){
var p = [], r=[]
//Translate point to the origin
p[0] = a[0] - b[0]
p[1] = a[1] - b[1]
p[2] = a[2] - b[2]
//perform rotation
r[0] = p[0]
r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c)
r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c)
//translate to correct position
out[0] = r[0] + b[0]
out[1] = r[1] + b[1]
out[2] = r[2] + b[2]
return out
}
},{}],22:[function(require,module,exports){
module.exports = rotateY;
/**
* Rotate a 3D vector around the y-axis
* @param {vec3} out The receiving vec3
* @param {vec3} a The vec3 point to rotate
* @param {vec3} b The origin of the rotation
* @param {Number} c The angle of rotation
* @returns {vec3} out
*/
function rotateY(out, a, b, c){
var p = [], r=[]
//Translate point to the origin
p[0] = a[0] - b[0]
p[1] = a[1] - b[1]
p[2] = a[2] - b[2]
//perform rotation
r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c)
r[1] = p[1]
r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c)
//translate to correct position
out[0] = r[0] + b[0]
out[1] = r[1] + b[1]
out[2] = r[2] + b[2]
return out
}
},{}],23:[function(require,module,exports){
module.exports = rotateZ;
/**
* Rotate a 3D vector around the z-axis
* @param {vec3} out The receiving vec3
* @param {vec3} a The vec3 point to rotate
* @param {vec3} b The origin of the rotation
* @param {Number} c The angle of rotation
* @returns {vec3} out
*/
function rotateZ(out, a, b, c){
var p = [], r=[]
//Translate point to the origin
p[0] = a[0] - b[0]
p[1] = a[1] - b[1]
p[2] = a[2] - b[2]
//perform rotation
r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c)
r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c)
r[2] = p[2]
//translate to correct position
out[0] = r[0] + b[0]
out[1] = r[1] + b[1]
out[2] = r[2] + b[2]
return out
}
},{}],24:[function(require,module,exports){
module.exports = scale;
/**
* Scales a vec3 by a scalar number
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {vec3} out
*/
function scale(out, a, b) {
out[0] = a[0] * b
out[1] = a[1] * b
out[2] = a[2] * b
return out
}
},{}],25:[function(require,module,exports){
module.exports = scaleAndAdd;
/**
* Adds two vec3's after scaling the second operand by a scalar value
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @param {Number} scale the amount to scale b by before adding
* @returns {vec3} out
*/
function scaleAndAdd(out, a, b, scale) {
out[0] = a[0] + (b[0] * scale)
out[1] = a[1] + (b[1] * scale)
out[2] = a[2] + (b[2] * scale)
return out
}
},{}],26:[function(require,module,exports){
module.exports = set;
/**
* Set the components of a vec3 to the given values
*
* @param {vec3} out the receiving vector
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @returns {vec3} out
*/
function set(out, x, y, z) {
out[0] = x
out[1] = y
out[2] = z
return out
}
},{}],27:[function(require,module,exports){
module.exports = squaredDistance;
/**
* Calculates the squared euclidian distance between two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} squared distance between a and b
*/
function squaredDistance(a, b) {
var x = b[0] - a[0],
y = b[1] - a[1],
z = b[2] - a[2]
return x*x + y*y + z*z
}
},{}],28:[function(require,module,exports){
module.exports = squaredLength;
/**
* Calculates the squared length of a vec3
*
* @param {vec3} a vector to calculate squared length of
* @returns {Number} squared length of a
*/
function squaredLength(a) {
var x = a[0],
y = a[1],
z = a[2]
return x*x + y*y + z*z
}
},{}],29:[function(require,module,exports){
module.exports = subtract;
/**
* Subtracts vector b from vector a
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
function subtract(out, a, b) {
out[0] = a[0] - b[0]
out[1] = a[1] - b[1]
out[2] = a[2] - b[2]
return out
}
},{}],30:[function(require,module,exports){
module.exports = transformMat3;
/**
* Transforms the vec3 with a mat3.
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {mat4} m the 3x3 matrix to transform with
* @returns {vec3} out
*/
function transformMat3(out, a, m) {
var x = a[0], y = a[1], z = a[2]
out[0] = x * m[0] + y * m[3] + z * m[6]
out[1] = x * m[1] + y * m[4] + z * m[7]
out[2] = x * m[2] + y * m[5] + z * m[8]
return out
}
},{}],31:[function(require,module,exports){
module.exports = transformMat4;
/**
* Transforms the vec3 with a mat4.
* 4th vector component is implicitly '1'
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {mat4} m matrix to transform with
* @returns {vec3} out
*/
function transformMat4(out, a, m) {
var x = a[0], y = a[1], z = a[2],
w = m[3] * x + m[7] * y + m[11] * z + m[15]
w = w || 1.0
out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w
out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w
out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w
return out
}
},{}],32:[function(require,module,exports){
module.exports = transformQuat;
/**
* Transforms the vec3 with a quat
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {quat} q quaternion to transform with
* @returns {vec3} out
*/
function transformQuat(out, a, q) {
// benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
var x = a[0], y = a[1], z = a[2],
qx = q[0], qy = q[1], qz = q[2], qw = q[3],
// calculate quat * vec
ix = qw * x + qy * z - qz * y,
iy = qw * y + qz * x - qx * z,
iz = qw * z + qx * y - qy * x,
iw = -qx * x - qy * y - qz * z
// calculate result * inverse quat
out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy
out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz
out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx
return out
}
},{}],"gl-vec3":[function(require,module,exports){
module.exports = {
create: require('./create')
, clone: require('./clone')
, angle: require('./angle')
, fromValues: require('./fromValues')
, copy: require('./copy')
, set: require('./set')
, add: require('./add')
, subtract: require('./subtract')
, multiply: require('./multiply')
, divide: require('./divide')
, min: require('./min')
, max: require('./max')
, scale: require('./scale')
, scaleAndAdd: require('./scaleAndAdd')
, distance: require('./distance')
, squaredDistance: require('./squaredDistance')
, length: require('./length')
, squaredLength: require('./squaredLength')
, negate: require('./negate')
, inverse: require('./inverse')
, normalize: require('./normalize')
, dot: require('./dot')
, cross: require('./cross')
, lerp: require('./lerp')
, random: require('./random')
, transformMat4: require('./transformMat4')
, transformMat3: require('./transformMat3')
, transformQuat: require('./transformQuat')
, rotateX: require('./rotateX')
, rotateY: require('./rotateY')
, rotateZ: require('./rotateZ')
, forEach: require('./forEach')
}
},{"./add":1,"./angle":2,"./clone":3,"./copy":4,"./create":5,"./cross":6,"./distance":7,"./divide":8,"./dot":9,"./forEach":10,"./fromValues":11,"./inverse":12,"./length":13,"./lerp":14,"./max":15,"./min":16,"./multiply":17,"./negate":18,"./normalize":19,"./random":20,"./rotateX":21,"./rotateY":22,"./rotateZ":23,"./scale":24,"./scaleAndAdd":25,"./set":26,"./squaredDistance":27,"./squaredLength":28,"./subtract":29,"./transformMat3":30,"./transformMat4":31,"./transformQuat":32}]},{},[])
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImFkZC5qcyIsImFuZ2xlLmpzIiwiY2xvbmUuanMiLCJjb3B5LmpzIiwiY3JlYXRlLmpzIiwiY3Jvc3MuanMiLCJkaXN0YW5jZS5qcyIsImRpdmlkZS5qcyIsImRvdC5qcyIsImZvckVhY2guanMiLCJmcm9tVmFsdWVzLmpzIiwiaW52ZXJzZS5qcyIsImxlbmd0aC5qcyIsImxlcnAuanMiLCJtYXguanMiLCJtaW4uanMiLCJtdWx0aXBseS5qcyIsIm5lZ2F0ZS5qcyIsIm5vcm1hbGl6ZS5qcyIsInJhbmRvbS5qcyIsInJvdGF0ZVguanMiLCJyb3RhdGVZLmpzIiwicm90YXRlWi5qcyIsInNjYWxlLmpzIiwic2NhbGVBbmRBZGQuanMiLCJzZXQuanMiLCJzcXVhcmVkRGlzdGFuY2UuanMiLCJzcXVhcmVkTGVuZ3RoLmpzIiwic3VidHJhY3QuanMiLCJ0cmFuc2Zvcm1NYXQzLmpzIiwidHJhbnNmb3JtTWF0NC5qcyIsInRyYW5zZm9ybVF1YXQuanMiLCJpbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2ZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDYkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNkQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNmQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDYkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDYkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDZkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM0JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIm1vZHVsZS5leHBvcnRzID0gYWRkO1xuXG4vKipcbiAqIEFkZHMgdHdvIHZlYzMnc1xuICpcbiAqIEBwYXJhbSB7dmVjM30gb3V0IHRoZSByZWNlaXZpbmcgdmVjdG9yXG4gKiBAcGFyYW0ge3ZlYzN9IGEgdGhlIGZpcnN0IG9wZXJhbmRcbiAqIEBwYXJhbSB7dmVjM30gYiB0aGUgc2Vjb25kIG9wZXJhbmRcbiAqIEByZXR1cm5zIHt2ZWMzfSBvdXRcbiAqL1xuZnVuY3Rpb24gYWRkKG91dCwgYSwgYikge1xuICAgIG91dFswXSA9IGFbMF0gKyBiWzBdXG4gICAgb3V0WzFdID0gYVsxXSArIGJbMV1cbiAgICBvdXRbMl0gPSBhWzJdICsgYlsyXVxuICAgIHJldHVybiBvdXRcbn0iLCJtb2R1bGUuZXhwb3J0cyA9IGFuZ2xlXG5cbnZhciBmcm9tVmFsdWVzID0gcmVxdWlyZSgnLi9mcm9tVmFsdWVzJylcbnZhciBub3JtYWxpemUgPSByZXF1aXJlKCcuL25vcm1hbGl6ZScpXG52YXIgZG90ID0gcmVxdWlyZSgnLi9kb3QnKVxuXG4vKipcbiAqIEdldCB0aGUgYW5nbGUgYmV0d2VlbiB0d28gM0QgdmVjdG9yc1xuICogQHBhcmFtIHt2ZWMzfSBhIFRoZSBmaXJzdCBvcGVyYW5kXG4gKiBAcGFyYW0ge3ZlYzN9IGIgVGhlIHNlY29uZCBvcGVyYW5kXG4gKiBAcmV0dXJucyB7TnVtYmVyfSBUaGUgYW5nbGUgaW4gcmFkaWFuc1xuICovXG5mdW5jdGlvbiBhbmdsZShhLCBiKSB7XG4gICAgdmFyIHRlbXBBID0gZnJvbVZhbHVlcyhhWzBdLCBhWzFdLCBhWzJdKVxuICAgIHZhciB0ZW1wQiA9IGZyb21WYWx1ZXMoYlswXSwgYlsxXSwgYlsyXSlcbiBcbiAgICBub3JtYWxpemUodGVtcEEsIHRlbXBBKVxuICAgIG5vcm1hbGl6ZSh0ZW1wQiwgdGVtcEIpXG4gXG4gICAgdmFyIGNvc2luZSA9IGRvdCh0ZW1wQSwgdGVtcEIpXG5cbiAgICBpZihjb3NpbmUgPiAxLjApe1xuICAgICAgICByZXR1cm4gMFxuICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBNYXRoLmFjb3MoY29zaW5lKVxuICAgIH0gICAgIFxufVxuIiwibW9kdWxlLmV4cG9ydHMgPSBjbG9uZTtcblxuLyoqXG4gKiBDcmVhdGVzIGEgbmV3IHZlYzMgaW5pdGlhbGl6ZWQgd2l0aCB2YWx1ZXMgZnJvbSBhbiBleGlzdGluZyB2ZWN0b3JcbiAqXG4gKiBAcGFyYW0ge3ZlYzN9IGEgdmVjdG9yIHRvIGNsb25lXG4gKiBAcmV0dXJucyB7dmVjM30gYSBuZXcgM0QgdmVjdG9yXG4gKi9cbmZ1bmN0aW9uIGNsb25lKGEpIHtcbiAgICB2YXIgb3V0ID0gbmV3IEZsb2F0MzJBcnJheSgzKVxuICAgIG91dFswXSA9IGFbMF1cbiAgICBvdXRbMV0gPSBhWzFdXG4gICAgb3V0WzJdID0gYVsyXVxuICAgIHJldHVybiBvdXRcbn0iLCJtb2R1bGUuZXhwb3J0cyA9IGNvcHk7XG5cbi8qKlxuICogQ29weSB0aGUgdmFsdWVzIGZyb20gb25lIHZlYzMgdG8gYW5vdGhlclxuICpcbiAqIEBwYXJhbSB7dmVjM30gb3V0IHRoZSByZWNlaXZpbmcgdmVjdG9yXG4gKiBAcGFyYW0ge3ZlYzN9IGEgdGhlIHNvdXJjZSB2ZWN0b3JcbiAqIEByZXR1cm5zIHt2ZWMzfSBvdXRcbiAqL1xuZnVuY3Rpb24gY29weShvdXQsIGEpIHtcbiAgICBvdXRbMF0gPSBhWzBdXG4gICAgb3V0WzFdID0gYVsxXVxuICAgIG91dFsyXSA9IGFbMl1cbiAgICByZXR1cm4gb3V0XG59IiwibW9kdWxlLmV4cG9ydHMgPSBjcmVhdGU7XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldywgZW1wdHkgdmVjM1xuICpcbiAqIEByZXR1cm5zIHt2ZWMzfSBhIG5ldyAzRCB2ZWN0b3JcbiAqL1xuZnVuY3Rpb24gY3JlYXRlKCkge1xuICAgIHZhciBvdXQgPSBuZXcgRmxvYXQzMkFycmF5KDMpXG4gICAgb3V0WzBdID0gMFxuICAgIG91dFsxXSA9IDBcbiAgICBvdXRbMl0gPSAwXG4gICAgcmV0dXJuIG91dFxufSIsIm1vZHVsZS5leHBvcnRzID0gY3Jvc3M7XG5cbi8qKlxuICogQ29tcHV0ZXMgdGhlIGNyb3NzIHByb2R1Y3Qgb2YgdHdvIHZlYzMnc1xuICpcbiAqIEBwYXJhbSB7dmVjM30gb3V0IHRoZSByZWNlaXZpbmcgdmVjdG9yXG4gKiBAcGFyYW0ge3ZlYzN9IGEgdGhlIGZpcnN0IG9wZXJhbmRcbiAqIEBwYXJhbSB7dmVjM30gYiB0aGUgc2Vjb25kIG9wZXJhbmRcbiAqIEByZXR1cm5zIHt2ZWMzfSBvdXRcbiAqL1xuZnVuY3Rpb24gY3Jvc3Mob3V0LCBhLCBiKSB7XG4gICAgdmFyIGF4ID0gYVswXSwgYXkgPSBhWzFdLCBheiA9IGFbMl0sXG4gICAgICAgIGJ4ID0gYlswXSwgYnkgPSBiWzFdLCBieiA9IGJbMl1cblxuICAgIG91dFswXSA9IGF5ICogYnogLSBheiAqIGJ5XG4gICAgb3V0WzFdID0gYXogKiBieCAtIGF4ICogYnpcbiAgICBvdXRbMl0gPSBheCAqIGJ5IC0gYXkgKiBieFxuICAgIHJldHVybiBvdXRcbn0iLCJtb2R1bGUuZXhwb3J0cyA9IGRpc3RhbmNlO1xuXG4vKipcbiAqIENhbGN1bGF0ZXMgdGhlIGV1Y2xpZGlhbiBkaXN0YW5jZSBiZXR3ZWVuIHR3byB2ZWMzJ3NcbiAqXG4gKiBAcGFyYW0ge3ZlYzN9IGEgdGhlIGZpcnN0IG9wZXJhbmRcbiAqIEBwYXJhbSB7dmVjM30gYiB0aGUgc2Vjb25kIG9wZXJhbmRcbiAqIEByZXR1cm5zIHtOdW1iZXJ9IGRpc3RhbmNlIGJldHdlZW4gYSBhbmQgYlxuICovXG5mdW5jdGlvbiBkaXN0YW5jZShhLCBiKSB7XG4gICAgdmFyIHggPSBiWzBdIC0gYVswXSxcbiAgICAgICAgeSA9IGJbMV0gLSBhWzFdLFxuICAgICAgICB6ID0gYlsyXSAtIGFbMl1cbiAgICByZXR1cm4gTWF0aC5zcXJ0KHgqeCArIHkqeSArIHoqeilcbn0iLCJtb2R1bGUuZXhwb3J0cyA9IGRpdmlkZTtcblxuLyoqXG4gKiBEaXZpZGVzIHR3byB2ZWMzJ3NcbiAqXG4gKiBAcGFyYW0ge3ZlYzN9IG91dCB0aGUgcmVjZWl2aW5nIHZlY3RvclxuICogQHBhcmFtIHt2ZWMzfSBhIHRoZSBmaXJzdCBvcGVyYW5kXG4gKiBAcGFyYW0ge3ZlYzN9IGIgdGhlIHNlY29uZCBvcGVyYW5kXG4gKiBAcmV0dXJucyB7dmVjM30gb3V0XG4gKi9cbmZ1bmN0aW9uIGRpdmlkZShvdXQsIGEsIGIpIHtcbiAgICBvdXRbMF0gPSBhWzBdIC8gYlswXVxuICAgIG91dFsxXSA9IGFbMV0gLyBiWzFdXG4gICAgb3V0WzJdID0gYVsyXSAvIGJbMl1cbiAgICByZXR1cm4gb3V0XG59IiwibW9kdWxlLmV4cG9ydHMgPSBkb3Q7XG5cbi8qKlxuICogQ2FsY3VsYXRlcyB0aGUgZG90IHByb2R1Y3Qgb2YgdHdvIHZlYzMnc1xuICpcbiAqIEBwYXJhbSB7dmVjM30gYSB0aGUgZmlyc3Qgb3BlcmFuZFxuICogQHBhcmFtIHt2ZWMzfSBiIHRoZSBzZWNvbmQgb3BlcmFuZFxuICogQHJldHVybnMge051bWJlcn0gZG90IHByb2R1Y3Qgb2YgYSBhbmQgYlxuICovXG5mdW5jdGlvbiBkb3QoYSwgYikge1xuICAgIHJldHVybiBhWzBdICogYlswXSArIGFbMV0gKiBiWzFdICsgYVsyXSAqIGJbMl1cbn0iLCJtb2R1bGUuZXhwb3J0cyA9IGZvckVhY2g7XG5cbnZhciB2ZWMgPSByZXF1aXJlKCcuL2NyZWF0ZScpKClcblxuLyoqXG4gKiBQZXJmb3JtIHNvbWUgb3BlcmF0aW9uIG92ZXIgYW4gYXJyYXkgb2YgdmVjM3MuXG4gKlxuICogQHBhcmFtIHtBcnJheX0gYSB0aGUgYXJyYXkgb2YgdmVjdG9ycyB0byBpdGVyYXRlIG92ZXJcbiAqIEBwYXJhbSB7TnVtYmVyfSBzdHJpZGUgTnVtYmVyIG9mIGVsZW1lbnRzIGJldHdlZW4gdGhlIHN0YXJ0IG9mIGVhY2ggdmVjMy4gSWYgMCBhc3N1bWVzIHRpZ2h0bHkgcGFja2VkXG4gKiBAcGFyYW0ge051bWJlcn0gb2Zmc2V0IE51bWJlciBvZiBlbGVtZW50cyB0byBza2lwIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIGFycmF5XG4gKiBAcGFyYW0ge051bWJlcn0gY291bnQgTnVtYmVyIG9mIHZlYzNzIHRvIGl0ZXJhdGUgb3Zlci4gSWYgMCBpdGVyYXRlcyBvdmVyIGVudGlyZSBhcnJheVxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gRnVuY3Rpb24gdG8gY2FsbCBmb3IgZWFjaCB2ZWN0b3IgaW4gdGhlIGFycmF5XG4gKiBAcGFyYW0ge09iamVjdH0gW2FyZ10gYWRkaXRpb25hbCBhcmd1bWVudCB0byBwYXNzIHRvIGZuXG4gKiBAcmV0dXJucyB7QXJyYXl9IGFcbiAqIEBmdW5jdGlvblxuICovXG5mdW5jdGlvbiBmb3JFYWNoKGEsIHN0cmlkZSwgb2Zmc2V0LCBjb3VudCwgZm4sIGFyZykge1xuICAgICAgICB2YXIgaSwgbFxuICAgICAgICBpZighc3RyaWRlKSB7XG4gICAgICAgICAgICBzdHJpZGUgPSAzXG4gICAgICAgIH1cblxuICAgICAgICBpZighb2Zmc2V0KSB7XG4gICAgICAgICAgICBvZmZzZXQgPSAwXG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIGlmKGNvdW50KSB7XG4gICAgICAgICAgICBsID0gTWF0aC5taW4oKGNvdW50ICogc3RyaWRlKSArIG9mZnNldCwgYS5sZW5ndGgpXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsID0gYS5sZW5ndGhcbiAgICAgICAgfVxuXG4gICAgICAgIGZvcihpID0gb2Zmc2V0OyBpIDwgbDsgaSArPSBzdHJpZGUpIHtcbiAgICAgICAgICAgIHZlY1swXSA9IGFbaV0gXG4gICAgICAgICAgICB2ZWNbMV0gPSBhW2krMV0gXG4gICAgICAgICAgICB2ZWNbMl0gPSBhW2krMl1cbiAgICAgICAgICAgIGZuKHZlYywgdmVjLCBhcmcpXG4gICAgICAgICAgICBhW2ldID0gdmVjWzBdIFxuICAgICAgICAgICAgYVtpKzFdID0gdmVjWzFdIFxuICAgICAgICAgICAgYVtpKzJdID0gdmVjWzJdXG4gICAgICAgIH1cbiAgICAgICAgXG4gICAgICAgIHJldHVybiBhXG59IiwibW9kdWxlLmV4cG9ydHMgPSBmcm9tVmFsdWVzO1xuXG4vKipcbiAqIENyZWF0ZXMgYSBuZXcgdmVjMyBpbml0aWFsaXplZCB3aXRoIHRoZSBnaXZlbiB2YWx1ZXNcbiAqXG4gKiBAcGFyYW0ge051bWJlcn0geCBYIGNvbXBvbmVudFxuICogQHBhcmFtIHtOdW1iZXJ9IHkgWSBjb21wb25lbnRcbiAqIEBwYXJhbSB7TnVtYmVyfSB6IFogY29tcG9uZW50XG4gKiBAcmV0dXJucyB7dmVjM30gYSBuZXcgM0QgdmVjdG9yXG4gKi9cbmZ1bmN0aW9uIGZyb21WYWx1ZXMoeCwgeSwgeikge1xuICAgIHZhciBvdXQgPSBuZXcgRmxvYXQzMkFycmF5KDMpXG4gICAgb3V0WzBdID0geFxuICAgIG91dFsxXSA9IHlcbiAgICBvdXRbMl0gPSB6XG4gICAgcmV0dXJuIG91dFxufSIsIm1vZHVsZS5leHBvcnRzID0gaW52ZXJzZTtcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBpbnZlcnNlIG9mIHRoZSBjb21wb25lbnRzIG9mIGEgdmVjM1xuICpcbiAqIEBwYXJhbSB7dmVjM30gb3V0IHRoZSByZWNlaXZpbmcgdmVjdG9yXG4gKiBAcGFyYW0ge3ZlYzN9IGEgdmVjdG9yIHRvIGludmVydFxuICogQHJldHVybnMge3ZlYzN9IG91dFxuICovXG5mdW5jdGlvbiBpbnZlcnNlKG91dCwgYSkge1xuICBvdXRbMF0gPSAxLjAgLyBhWzBdXG4gIG91dFsxXSA9IDEuMCAvIGFbMV1cbiAgb3V0WzJdID0gMS4wIC8gYVsyXVxuICByZXR1cm4gb3V0XG59IiwibW9kdWxlLmV4cG9ydHMgPSBsZW5ndGg7XG5cbi8qKlxuICogQ2FsY3VsYXRlcyB0aGUgbGVuZ3RoIG9mIGEgdmVjM1xuICpcbiAqIEBwYXJhbSB7dmVjM30gYSB2ZWN0b3IgdG8gY2FsY3VsYXRlIGxlbmd0aCBvZlxuICogQHJldHVybnMge051bWJlcn0gbGVuZ3RoIG9mIGFcbiAqL1xuZnVuY3Rpb24gbGVuZ3RoKGEpIHtcbiAgICB2YXIgeCA9IGFbMF0sXG4gICAgICAgIHkgPSBhWzFdLFxuICAgICAgICB6ID0gYVsyXVxuICAgIHJldHVybiBNYXRoLnNxcnQoeCp4ICsgeSp5ICsgeip6KVxufSIsIm1vZHVsZS5leHBvcnRzID0gbGVycDtcblxuLyoqXG4gKiBQZXJmb3JtcyBhIGxpbmVhciBpbnRlcnBvbGF0aW9uIGJldHdlZW4gdHdvIHZlYzMnc1xuICpcbiAqIEBwYXJhbSB7dmVjM30gb3V0IHRoZSByZWNlaXZpbmcgdmVjdG9yXG4gKiBAcGFyYW0ge3ZlYzN9IGEgdGhlIGZpcnN0IG9wZXJhbmRcbiAqIEBwYXJhbSB7dmVjM30gYiB0aGUgc2Vjb25kIG9wZXJhbmRcbiAqIEBwYXJhbSB7TnVtYmVyfSB0IGludGVycG9sYXRpb24gYW1vdW50IGJldHdlZW4gdGhlIHR3byBpbnB1dHNcbiAqIEByZXR1cm5zIHt2ZWMzfSBvdXRcbiAqL1xuZnVuY3Rpb24gbGVycChvdXQsIGEsIGIsIHQpIHtcbiAgICB2YXIgYXggPSBhWzBdLFxuICAgICAgICBheSA9IGFbMV0sXG4gICAgICAgIGF6ID0gYVsyXVxuICAgIG91dFswXSA9IGF4ICsgdCAqIChiWzBdIC0gYXgpXG4gICAgb3V0WzFdID0gYXkgKyB0ICogKGJbMV0gLSBheSlcbiAgICBvdXRbMl0gPSBheiArIHQgKiAoYlsyXSAtIGF6KVxuICAgIHJldHVybiBvdXRcbn0iLCJtb2R1bGUuZXhwb3J0cyA9IG1heDtcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBtYXhpbXVtIG9mIHR3byB2ZWMzJ3NcbiAqXG4gKiBAcGFyYW0ge3ZlYzN9IG91dCB0aGUgcmVjZWl2aW5nIHZlY3RvclxuICogQHBhcmFtIHt2ZWMzfSBhIHRoZSBmaXJzdCBvcGVyYW5kXG4gKiBAcGFyYW0ge3ZlYzN9IGIgdGhlIHNlY29uZCBvcGVyYW5kXG4gKiBAcmV0dXJucyB7dmVjM30gb3V0XG4gKi9cbmZ1bmN0aW9uIG1heChvdXQsIGEsIGIpIHtcbiAgICBvdXRbMF0gPSBNYXRoLm1heChhWzBdLCBiWzBdKVxuICAgIG91dFsxXSA9IE1hdGgubWF4KGFbMV0sIGJbMV0pXG4gICAgb3V0WzJdID0gTWF0aC5tYXgoYVsyXSwgYlsyXSlcbiAgICByZXR1cm4gb3V0XG59IiwibW9kdWxlLmV4cG9ydHMgPSBtaW47XG5cbi8qKlxuICogUmV0dXJucyB0aGUgbWluaW11bSBvZiB0d28gdmVjMydzXG4gKlxuICogQHBhcmFtIHt2ZWMzfSBvdXQgdGhlIHJlY2VpdmluZyB2ZWN0b3JcbiAqIEBwYXJhbSB7dmVjM30gYSB0aGUgZmlyc3Qgb3BlcmFuZFxuICogQHBhcmFtIHt2ZWMzfSBiIHRoZSBzZWNvbmQgb3BlcmFuZFxuICogQHJldHVybnMge3ZlYzN9IG91dFxuICovXG5mdW5jdGlvbiBtaW4ob3V0LCBhLCBiKSB7XG4gICAgb3V0WzBdID0gTWF0aC5taW4oYVswXSwgYlswXSlcbiAgICBvdXRbMV0gPSBNYXRoLm1pbihhWzFdLCBiWzFdKVxuICAgIG91dFsyXSA9IE1hdGgubWluKGFbMl0sIGJbMl0pXG4gICAgcmV0dXJuIG91dFxufSIsIm1vZHVsZS5leHBvcnRzID0gbXVsdGlwbHk7XG5cbi8qKlxuICogTXVsdGlwbGllcyB0d28gdmVjMydzXG4gKlxuICogQHBhcmFtIHt2ZWMzfSBvdXQgdGhlIHJlY2VpdmluZyB2ZWN0b3JcbiAqIEBwYXJhbSB7dmVjM30gYSB0aGUgZmlyc3Qgb3BlcmFuZFxuICogQHBhcmFtIHt2ZWMzfSBiIHRoZSBzZWNvbmQgb3BlcmFuZFxuICogQHJldHVybnMge3ZlYzN9IG91dFxuICovXG5mdW5jdGlvbiBtdWx0aXBseShvdXQsIGEsIGIpIHtcbiAgICBvdXRbMF0gPSBhWzBdICogYlswXVxuICAgIG91dFsxXSA9IGFbMV0gKiBiWzFdXG4gICAgb3V0WzJdID0gYVsyXSAqIGJbMl1cbiAgICByZXR1cm4gb3V0XG59IiwibW9kdWxlLmV4cG9ydHMgPSBuZWdhdGU7XG5cbi8qKlxuICogTmVnYXRlcyB0aGUgY29tcG9uZW50cyBvZiBhIHZlYzNcbiAqXG4gKiBAcGFyYW0ge3ZlYzN9IG91dCB0aGUgcmVjZWl2aW5nIHZlY3RvclxuICogQHBhcmFtIHt2ZWMzfSBhIHZlY3RvciB0byBuZWdhdGVcbiAqIEByZXR1cm5zIHt2ZWMzfSBvdXRcbiAqL1xuZnVuY3Rpb24gbmVnYXRlKG91dCwgYSkge1xuICAgIG91dFswXSA9IC1hWzBdXG4gICAgb3V0WzFdID0gLWFbMV1cbiAgICBvdXRbMl0gPSAtYVsyXVxuICAgIHJldHVybiBvdXRcbn0iLCJtb2R1bGUuZXhwb3J0cyA9IG5vcm1hbGl6ZTtcblxuLyoqXG4gKiBOb3JtYWxpemUgYSB2ZWMzXG4gKlxuICogQHBhcmFtIHt2ZWMzfSBvdXQgdGhlIHJlY2VpdmluZyB2ZWN0b3JcbiAqIEBwYXJhbSB7dmVjM30gYSB2ZWN0b3IgdG8gbm9ybWFsaXplXG4gKiBAcmV0dXJucyB7dmVjM30gb3V0XG4gKi9cbmZ1bmN0aW9uIG5vcm1hbGl6ZShvdXQsIGEpIHtcbiAgICB2YXIgeCA9IGFbMF0sXG4gICAgICAgIHkgPSBhWzFdLFxuICAgICAgICB6ID0gYVsyXVxuICAgIHZhciBsZW4gPSB4KnggKyB5KnkgKyB6KnpcbiAgICBpZiAobGVuID4gMCkge1xuICAgICAgICAvL1RPRE86IGV2YWx1YXRlIHVzZSBvZiBnbG1faW52c3FydCBoZXJlP1xuICAgICAgICBsZW4gPSAxIC8gTWF0aC5zcXJ0KGxlbilcbiAgICAgICAgb3V0WzBdID0gYVswXSAqIGxlblxuICAgICAgICBvdXRbMV0gPSBhWzFdICogbGVuXG4gICAgICAgIG91dFsyXSA9IGFbMl0gKiBsZW5cbiAgICB9XG4gICAgcmV0dXJuIG91dFxufSIsIm1vZHVsZS5leHBvcnRzID0gcmFuZG9tO1xuXG4vKipcbiAqIEdlbmVyYXRlcyBhIHJhbmRvbSB2ZWN0b3Igd2l0aCB0aGUgZ2l2ZW4gc2NhbGVcbiAqXG4gKiBAcGFyYW0ge3ZlYzN9IG91dCB0aGUgcmVjZWl2aW5nIHZlY3RvclxuICogQHBhcmFtIHtOdW1iZXJ9IFtzY2FsZV0gTGVuZ3RoIG9mIHRoZSByZXN1bHRpbmcgdmVjdG9yLiBJZiBvbW1pdHRlZCwgYSB1bml0IHZlY3RvciB3aWxsIGJlIHJldHVybmVkXG4gKiBAcmV0dXJucyB7dmVjM30gb3V0XG4gKi9cbmZ1bmN0aW9uIHJhbmRvbShvdXQsIHNjYWxlKSB7XG4gICAgc2NhbGUgPSBzY2FsZSB8fCAxLjBcblxuICAgIHZhciByID0gTWF0aC5yYW5kb20oKSAqIDIuMCAqIE1hdGguUElcbiAgICB2YXIgeiA9IChNYXRoLnJhbmRvbSgpICogMi4wKSAtIDEuMFxuICAgIHZhciB6U2NhbGUgPSBNYXRoLnNxcnQoMS4wLXoqeikgKiBzY2FsZVxuXG4gICAgb3V0WzBdID0gTWF0aC5jb3MocikgKiB6U2NhbGVcbiAgICBvdXRbMV0gPSBNYXRoLnNpbihyKSAqIHpTY2FsZVxuICAgIG91dFsyXSA9IHogKiBzY2FsZVxuICAgIHJldHVybiBvdXRcbn0iLCJtb2R1bGUuZXhwb3J0cyA9IHJvdGF0ZVg7XG5cbi8qKlxuICogUm90YXRlIGEgM0QgdmVjdG9yIGFyb3VuZCB0aGUgeC1heGlzXG4gKiBAcGFyYW0ge3ZlYzN9IG91dCBUaGUgcmVjZWl2aW5nIHZlYzNcbiAqIEBwYXJhbSB7dmVjM30gYSBUaGUgdmVjMyBwb2ludCB0byByb3RhdGVcbiAqIEBwYXJhbSB7dmVjM30gYiBUaGUgb3JpZ2luIG9mIHRoZSByb3RhdGlvblxuICogQHBhcmFtIHtOdW1iZXJ9IGMgVGhlIGFuZ2xlIG9mIHJvdGF0aW9uXG4gKiBAcmV0dXJucyB7dmVjM30gb3V0XG4gKi9cbmZ1bmN0aW9uIHJvdGF0ZVgob3V0LCBhLCBiLCBjKXtcbiAgICB2YXIgcCA9IFtdLCByPVtdXG4gICAgLy9UcmFuc2xhdGUgcG9pbnQgdG8gdGhlIG9yaWdpblxuICAgIHBbMF0gPSBhWzBdIC0gYlswXVxuICAgIHBbMV0gPSBhWzFdIC0gYlsxXVxuICAgIHBbMl0gPSBhWzJdIC0gYlsyXVxuXG4gICAgLy9wZXJmb3JtIHJvdGF0aW9uXG4gICAgclswXSA9IHBbMF1cbiAgICByWzFdID0gcFsxXSpNYXRoLmNvcyhjKSAtIHBbMl0qTWF0aC5zaW4oYylcbiAgICByWzJdID0gcFsxXSpNYXRoLnNpbihjKSArIHBbMl0qTWF0aC5jb3MoYylcblxuICAgIC8vdHJhbnNsYXRlIHRvIGNvcnJlY3QgcG9zaXRpb25cbiAgICBvdXRbMF0gPSByWzBdICsgYlswXVxuICAgIG91dFsxXSA9IHJbMV0gKyBiWzFdXG4gICAgb3V0WzJdID0gclsyXSArIGJbMl1cblxuICAgIHJldHVybiBvdXRcbn0iLCJtb2R1bGUuZXhwb3J0cyA9IHJvdGF0ZVk7XG5cbi8qKlxuICogUm90YXRlIGEgM0QgdmVjdG9yIGFyb3VuZCB0aGUgeS1heGlzXG4gKiBAcGFyYW0ge3ZlYzN9IG91dCBUaGUgcmVjZWl2aW5nIHZlYzNcbiAqIEBwYXJhbSB7dmVjM30gYSBUaGUgdmVjMyBwb2ludCB0byByb3RhdGVcbiAqIEBwYXJhbSB7dmVjM30gYiBUaGUgb3JpZ2luIG9mIHRoZSByb3RhdGlvblxuICogQHBhcmFtIHtOdW1iZXJ9IGMgVGhlIGFuZ2xlIG9mIHJvdGF0aW9uXG4gKiBAcmV0dXJucyB7dmVjM30gb3V0XG4gKi9cbmZ1bmN0aW9uIHJvdGF0ZVkob3V0LCBhLCBiLCBjKXtcbiAgICB2YXIgcCA9IFtdLCByPVtdXG4gICAgLy9UcmFuc2xhdGUgcG9pbnQgdG8gdGhlIG9yaWdpblxuICAgIHBbMF0gPSBhWzBdIC0gYlswXVxuICAgIHBbMV0gPSBhWzFdIC0gYlsxXVxuICAgIHBbMl0gPSBhWzJdIC0gYlsyXVxuICBcbiAgICAvL3BlcmZvcm0gcm90YXRpb25cbiAgICByWzBdID0gcFsyXSpNYXRoLnNpbihjKSArIHBbMF0qTWF0aC5jb3MoYylcbiAgICByWzFdID0gcFsxXVxuICAgIHJbMl0gPSBwWzJdKk1hdGguY29zKGMpIC0gcFswXSpNYXRoLnNpbihjKVxuICBcbiAgICAvL3RyYW5zbGF0ZSB0byBjb3JyZWN0IHBvc2l0aW9uXG4gICAgb3V0WzBdID0gclswXSArIGJbMF1cbiAgICBvdXRbMV0gPSByWzFdICsgYlsxXVxuICAgIG91dFsyXSA9IHJbMl0gKyBiWzJdXG4gIFxuICAgIHJldHVybiBvdXRcbn0iLCJtb2R1bGUuZXhwb3J0cyA9IHJvdGF0ZVo7XG5cbi8qKlxuICogUm90YXRlIGEgM0QgdmVjdG9yIGFyb3VuZCB0aGUgei1heGlzXG4gKiBAcGFyYW0ge3ZlYzN9IG91dCBUaGUgcmVjZWl2aW5nIHZlYzNcbiAqIEBwYXJhbSB7dmVjM30gYSBUaGUgdmVjMyBwb2ludCB0byByb3RhdGVcbiAqIEBwYXJhbSB7dmVjM30gYiBUaGUgb3JpZ2luIG9mIHRoZSByb3RhdGlvblxuICogQHBhcmFtIHtOdW1iZXJ9IGMgVGhlIGFuZ2xlIG9mIHJvdGF0aW9uXG4gKiBAcmV0dXJucyB7dmVjM30gb3V0XG4gKi9cbmZ1bmN0aW9uIHJvdGF0ZVoob3V0LCBhLCBiLCBjKXtcbiAgICB2YXIgcCA9IFtdLCByPVtdXG4gICAgLy9UcmFuc2xhdGUgcG9pbnQgdG8gdGhlIG9yaWdpblxuICAgIHBbMF0gPSBhWzBdIC0gYlswXVxuICAgIHBbMV0gPSBhWzFdIC0gYlsxXVxuICAgIHBbMl0gPSBhWzJdIC0gYlsyXVxuICBcbiAgICAvL3BlcmZvcm0gcm90YXRpb25cbiAgICByWzBdID0gcFswXSpNYXRoLmNvcyhjKSAtIHBbMV0qTWF0aC5zaW4oYylcbiAgICByWzFdID0gcFswXSpNYXRoLnNpbihjKSArIHBbMV0qTWF0aC5jb3MoYylcbiAgICByWzJdID0gcFsyXVxuICBcbiAgICAvL3RyYW5zbGF0ZSB0byBjb3JyZWN0IHBvc2l0aW9uXG4gICAgb3V0WzBdID0gclswXSArIGJbMF1cbiAgICBvdXRbMV0gPSByWzFdICsgYlsxXVxuICAgIG91dFsyXSA9IHJbMl0gKyBiWzJdXG4gIFxuICAgIHJldHVybiBvdXRcbn0iLCJtb2R1bGUuZXhwb3J0cyA9IHNjYWxlO1xuXG4vKipcbiAqIFNjYWxlcyBhIHZlYzMgYnkgYSBzY2FsYXIgbnVtYmVyXG4gKlxuICogQHBhcmFtIHt2ZWMzfSBvdXQgdGhlIHJlY2VpdmluZyB2ZWN0b3JcbiAqIEBwYXJhbSB7dmVjM30gYSB0aGUgdmVjdG9yIHRvIHNjYWxlXG4gKiBAcGFyYW0ge051bWJlcn0gYiBhbW91bnQgdG8gc2NhbGUgdGhlIHZlY3RvciBieVxuICogQHJldHVybnMge3ZlYzN9IG91dFxuICovXG5mdW5jdGlvbiBzY2FsZShvdXQsIGEsIGIpIHtcbiAgICBvdXRbMF0gPSBhWzBdICogYlxuICAgIG91dFsxXSA9IGFbMV0gKiBiXG4gICAgb3V0WzJdID0gYVsyXSAqIGJcbiAgICByZXR1cm4gb3V0XG59IiwibW9kdWxlLmV4cG9ydHMgPSBzY2FsZUFuZEFkZDtcblxuLyoqXG4gKiBBZGRzIHR3byB2ZWMzJ3MgYWZ0ZXIgc2NhbGluZyB0aGUgc2Vjb25kIG9wZXJhbmQgYnkgYSBzY2FsYXIgdmFsdWVcbiAqXG4gKiBAcGFyYW0ge3ZlYzN9IG91dCB0aGUgcmVjZWl2aW5nIHZlY3RvclxuICogQHBhcmFtIHt2ZWMzfSBhIHRoZSBmaXJzdCBvcGVyYW5kXG4gKiBAcGFyYW0ge3ZlYzN9IGIgdGhlIHNlY29uZCBvcGVyYW5kXG4gKiBAcGFyYW0ge051bWJlcn0gc2NhbGUgdGhlIGFtb3VudCB0byBzY2FsZSBiIGJ5IGJlZm9yZSBhZGRpbmdcbiAqIEByZXR1cm5zIHt2ZWMzfSBvdXRcbiAqL1xuZnVuY3Rpb24gc2NhbGVBbmRBZGQob3V0LCBhLCBiLCBzY2FsZSkge1xuICAgIG91dFswXSA9IGFbMF0gKyAoYlswXSAqIHNjYWxlKVxuICAgIG91dFsxXSA9IGFbMV0gKyAoYlsxXSAqIHNjYWxlKVxuICAgIG91dFsyXSA9IGFbMl0gKyAoYlsyXSAqIHNjYWxlKVxuICAgIHJldHVybiBvdXRcbn0iLCJtb2R1bGUuZXhwb3J0cyA9IHNldDtcblxuLyoqXG4gKiBTZXQgdGhlIGNvbXBvbmVudHMgb2YgYSB2ZWMzIHRvIHRoZSBnaXZlbiB2YWx1ZXNcbiAqXG4gKiBAcGFyYW0ge3ZlYzN9IG91dCB0aGUgcmVjZWl2aW5nIHZlY3RvclxuICogQHBhcmFtIHtOdW1iZXJ9IHggWCBjb21wb25lbnRcbiAqIEBwYXJhbSB7TnVtYmVyfSB5IFkgY29tcG9uZW50XG4gKiBAcGFyYW0ge051bWJlcn0geiBaIGNvbXBvbmVudFxuICogQHJldHVybnMge3ZlYzN9IG91dFxuICovXG5mdW5jdGlvbiBzZXQob3V0LCB4LCB5LCB6KSB7XG4gICAgb3V0WzBdID0geFxuICAgIG91dFsxXSA9IHlcbiAgICBvdXRbMl0gPSB6XG4gICAgcmV0dXJuIG91dFxufSIsIm1vZHVsZS5leHBvcnRzID0gc3F1YXJlZERpc3RhbmNlO1xuXG4vKipcbiAqIENhbGN1bGF0ZXMgdGhlIHNxdWFyZWQgZXVjbGlkaWFuIGRpc3RhbmNlIGJldHdlZW4gdHdvIHZlYzMnc1xuICpcbiAqIEBwYXJhbSB7dmVjM30gYSB0aGUgZmlyc3Qgb3BlcmFuZFxuICogQHBhcmFtIHt2ZWMzfSBiIHRoZSBzZWNvbmQgb3BlcmFuZFxuICogQHJldHVybnMge051bWJlcn0gc3F1YXJlZCBkaXN0YW5jZSBiZXR3ZWVuIGEgYW5kIGJcbiAqL1xuZnVuY3Rpb24gc3F1YXJlZERpc3RhbmNlKGEsIGIpIHtcbiAgICB2YXIgeCA9IGJbMF0gLSBhWzBdLFxuICAgICAgICB5ID0gYlsxXSAtIGFbMV0sXG4gICAgICAgIHogPSBiWzJdIC0gYVsyXVxuICAgIHJldHVybiB4KnggKyB5KnkgKyB6Knpcbn0iLCJtb2R1bGUuZXhwb3J0cyA9IHNxdWFyZWRMZW5ndGg7XG5cbi8qKlxuICogQ2FsY3VsYXRlcyB0aGUgc3F1YXJlZCBsZW5ndGggb2YgYSB2ZWMzXG4gKlxuICogQHBhcmFtIHt2ZWMzfSBhIHZlY3RvciB0byBjYWxjdWxhdGUgc3F1YXJlZCBsZW5ndGggb2ZcbiAqIEByZXR1cm5zIHtOdW1iZXJ9IHNxdWFyZWQgbGVuZ3RoIG9mIGFcbiAqL1xuZnVuY3Rpb24gc3F1YXJlZExlbmd0aChhKSB7XG4gICAgdmFyIHggPSBhWzBdLFxuICAgICAgICB5ID0gYVsxXSxcbiAgICAgICAgeiA9IGFbMl1cbiAgICByZXR1cm4geCp4ICsgeSp5ICsgeip6XG59IiwibW9kdWxlLmV4cG9ydHMgPSBzdWJ0cmFjdDtcblxuLyoqXG4gKiBTdWJ0cmFjdHMgdmVjdG9yIGIgZnJvbSB2ZWN0b3IgYVxuICpcbiAqIEBwYXJhbSB7dmVjM30gb3V0IHRoZSByZWNlaXZpbmcgdmVjdG9yXG4gKiBAcGFyYW0ge3ZlYzN9IGEgdGhlIGZpcnN0IG9wZXJhbmRcbiAqIEBwYXJhbSB7dmVjM30gYiB0aGUgc2Vjb25kIG9wZXJhbmRcbiAqIEByZXR1cm5zIHt2ZWMzfSBvdXRcbiAqL1xuZnVuY3Rpb24gc3VidHJhY3Qob3V0LCBhLCBiKSB7XG4gICAgb3V0WzBdID0gYVswXSAtIGJbMF1cbiAgICBvdXRbMV0gPSBhWzFdIC0gYlsxXVxuICAgIG91dFsyXSA9IGFbMl0gLSBiWzJdXG4gICAgcmV0dXJuIG91dFxufSIsIm1vZHVsZS5leHBvcnRzID0gdHJhbnNmb3JtTWF0MztcblxuLyoqXG4gKiBUcmFuc2Zvcm1zIHRoZSB2ZWMzIHdpdGggYSBtYXQzLlxuICpcbiAqIEBwYXJhbSB7dmVjM30gb3V0IHRoZSByZWNlaXZpbmcgdmVjdG9yXG4gKiBAcGFyYW0ge3ZlYzN9IGEgdGhlIHZlY3RvciB0byB0cmFuc2Zvcm1cbiAqIEBwYXJhbSB7bWF0NH0gbSB0aGUgM3gzIG1hdHJpeCB0byB0cmFuc2Zvcm0gd2l0aFxuICogQHJldHVybnMge3ZlYzN9IG91dFxuICovXG5mdW5jdGlvbiB0cmFuc2Zvcm1NYXQzKG91dCwgYSwgbSkge1xuICAgIHZhciB4ID0gYVswXSwgeSA9IGFbMV0sIHogPSBhWzJdXG4gICAgb3V0WzBdID0geCAqIG1bMF0gKyB5ICogbVszXSArIHogKiBtWzZdXG4gICAgb3V0WzFdID0geCAqIG1bMV0gKyB5ICogbVs0XSArIHogKiBtWzddXG4gICAgb3V0WzJdID0geCAqIG1bMl0gKyB5ICogbVs1XSArIHogKiBtWzhdXG4gICAgcmV0dXJuIG91dFxufSIsIm1vZHVsZS5leHBvcnRzID0gdHJhbnNmb3JtTWF0NDtcblxuLyoqXG4gKiBUcmFuc2Zvcm1zIHRoZSB2ZWMzIHdpdGggYSBtYXQ0LlxuICogNHRoIHZlY3RvciBjb21wb25lbnQgaXMgaW1wbGljaXRseSAnMSdcbiAqXG4gKiBAcGFyYW0ge3ZlYzN9IG91dCB0aGUgcmVjZWl2aW5nIHZlY3RvclxuICogQHBhcmFtIHt2ZWMzfSBhIHRoZSB2ZWN0b3IgdG8gdHJhbnNmb3JtXG4gKiBAcGFyYW0ge21hdDR9IG0gbWF0cml4IHRvIHRyYW5zZm9ybSB3aXRoXG4gKiBAcmV0dXJucyB7dmVjM30gb3V0XG4gKi9cbmZ1bmN0aW9uIHRyYW5zZm9ybU1hdDQob3V0LCBhLCBtKSB7XG4gICAgdmFyIHggPSBhWzBdLCB5ID0gYVsxXSwgeiA9IGFbMl0sXG4gICAgICAgIHcgPSBtWzNdICogeCArIG1bN10gKiB5ICsgbVsxMV0gKiB6ICsgbVsxNV1cbiAgICB3ID0gdyB8fCAxLjBcbiAgICBvdXRbMF0gPSAobVswXSAqIHggKyBtWzRdICogeSArIG1bOF0gKiB6ICsgbVsxMl0pIC8gd1xuICAgIG91dFsxXSA9IChtWzFdICogeCArIG1bNV0gKiB5ICsgbVs5XSAqIHogKyBtWzEzXSkgLyB3XG4gICAgb3V0WzJdID0gKG1bMl0gKiB4ICsgbVs2XSAqIHkgKyBtWzEwXSAqIHogKyBtWzE0XSkgLyB3XG4gICAgcmV0dXJuIG91dFxufSIsIm1vZHVsZS5leHBvcnRzID0gdHJhbnNmb3JtUXVhdDtcblxuLyoqXG4gKiBUcmFuc2Zvcm1zIHRoZSB2ZWMzIHdpdGggYSBxdWF0XG4gKlxuICogQHBhcmFtIHt2ZWMzfSBvdXQgdGhlIHJlY2VpdmluZyB2ZWN0b3JcbiAqIEBwYXJhbSB7dmVjM30gYSB0aGUgdmVjdG9yIHRvIHRyYW5zZm9ybVxuICogQHBhcmFtIHtxdWF0fSBxIHF1YXRlcm5pb24gdG8gdHJhbnNmb3JtIHdpdGhcbiAqIEByZXR1cm5zIHt2ZWMzfSBvdXRcbiAqL1xuZnVuY3Rpb24gdHJhbnNmb3JtUXVhdChvdXQsIGEsIHEpIHtcbiAgICAvLyBiZW5jaG1hcmtzOiBodHRwOi8vanNwZXJmLmNvbS9xdWF0ZXJuaW9uLXRyYW5zZm9ybS12ZWMzLWltcGxlbWVudGF0aW9uc1xuXG4gICAgdmFyIHggPSBhWzBdLCB5ID0gYVsxXSwgeiA9IGFbMl0sXG4gICAgICAgIHF4ID0gcVswXSwgcXkgPSBxWzFdLCBxeiA9IHFbMl0sIHF3ID0gcVszXSxcblxuICAgICAgICAvLyBjYWxjdWxhdGUgcXVhdCAqIHZlY1xuICAgICAgICBpeCA9IHF3ICogeCArIHF5ICogeiAtIHF6ICogeSxcbiAgICAgICAgaXkgPSBxdyAqIHkgKyBxeiAqIHggLSBxeCAqIHosXG4gICAgICAgIGl6ID0gcXcgKiB6ICsgcXggKiB5IC0gcXkgKiB4LFxuICAgICAgICBpdyA9IC1xeCAqIHggLSBxeSAqIHkgLSBxeiAqIHpcblxuICAgIC8vIGNhbGN1bGF0ZSByZXN1bHQgKiBpbnZlcnNlIHF1YXRcbiAgICBvdXRbMF0gPSBpeCAqIHF3ICsgaXcgKiAtcXggKyBpeSAqIC1xeiAtIGl6ICogLXF5XG4gICAgb3V0WzFdID0gaXkgKiBxdyArIGl3ICogLXF5ICsgaXogKiAtcXggLSBpeCAqIC1xelxuICAgIG91dFsyXSA9IGl6ICogcXcgKyBpdyAqIC1xeiArIGl4ICogLXF5IC0gaXkgKiAtcXhcbiAgICByZXR1cm4gb3V0XG59IiwibW9kdWxlLmV4cG9ydHMgPSB7XG4gIGNyZWF0ZTogcmVxdWlyZSgnLi9jcmVhdGUnKVxuICAsIGNsb25lOiByZXF1aXJlKCcuL2Nsb25lJylcbiAgLCBhbmdsZTogcmVxdWlyZSgnLi9hbmdsZScpXG4gICwgZnJvbVZhbHVlczogcmVxdWlyZSgnLi9mcm9tVmFsdWVzJylcbiAgLCBjb3B5OiByZXF1aXJlKCcuL2NvcHknKVxuICAsIHNldDogcmVxdWlyZSgnLi9zZXQnKVxuICAsIGFkZDogcmVxdWlyZSgnLi9hZGQnKVxuICAsIHN1YnRyYWN0OiByZXF1aXJlKCcuL3N1YnRyYWN0JylcbiAgLCBtdWx0aXBseTogcmVxdWlyZSgnLi9tdWx0aXBseScpXG4gICwgZGl2aWRlOiByZXF1aXJlKCcuL2RpdmlkZScpXG4gICwgbWluOiByZXF1aXJlKCcuL21pbicpXG4gICwgbWF4OiByZXF1aXJlKCcuL21heCcpXG4gICwgc2NhbGU6IHJlcXVpcmUoJy4vc2NhbGUnKVxuICAsIHNjYWxlQW5kQWRkOiByZXF1aXJlKCcuL3NjYWxlQW5kQWRkJylcbiAgLCBkaXN0YW5jZTogcmVxdWlyZSgnLi9kaXN0YW5jZScpXG4gICwgc3F1YXJlZERpc3RhbmNlOiByZXF1aXJlKCcuL3NxdWFyZWREaXN0YW5jZScpXG4gICwgbGVuZ3RoOiByZXF1aXJlKCcuL2xlbmd0aCcpXG4gICwgc3F1YXJlZExlbmd0aDogcmVxdWlyZSgnLi9zcXVhcmVkTGVuZ3RoJylcbiAgLCBuZWdhdGU6IHJlcXVpcmUoJy4vbmVnYXRlJylcbiAgLCBpbnZlcnNlOiByZXF1aXJlKCcuL2ludmVyc2UnKVxuICAsIG5vcm1hbGl6ZTogcmVxdWlyZSgnLi9ub3JtYWxpemUnKVxuICAsIGRvdDogcmVxdWlyZSgnLi9kb3QnKVxuICAsIGNyb3NzOiByZXF1aXJlKCcuL2Nyb3NzJylcbiAgLCBsZXJwOiByZXF1aXJlKCcuL2xlcnAnKVxuICAsIHJhbmRvbTogcmVxdWlyZSgnLi9yYW5kb20nKVxuICAsIHRyYW5zZm9ybU1hdDQ6IHJlcXVpcmUoJy4vdHJhbnNmb3JtTWF0NCcpXG4gICwgdHJhbnNmb3JtTWF0MzogcmVxdWlyZSgnLi90cmFuc2Zvcm1NYXQzJylcbiAgLCB0cmFuc2Zvcm1RdWF0OiByZXF1aXJlKCcuL3RyYW5zZm9ybVF1YXQnKVxuICAsIHJvdGF0ZVg6IHJlcXVpcmUoJy4vcm90YXRlWCcpXG4gICwgcm90YXRlWTogcmVxdWlyZSgnLi9yb3RhdGVZJylcbiAgLCByb3RhdGVaOiByZXF1aXJlKCcuL3JvdGF0ZVonKVxuICAsIGZvckVhY2g6IHJlcXVpcmUoJy4vZm9yRWFjaCcpXG59Il19
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){
function Assembler() {
this.flags = {};
this.positions = {};
this.faces = {};
}
Assembler.prototype.newFlag = function(face, v1, v2) {
if (!this.flags[face]) {
this.flags[face] = { };
}
this.flags[face][v1] = v2;
}
Assembler.prototype.newV = function(name, p) {
this.positions[name] = p;
}
Assembler.prototype.flags2poly = function() {
var rpositions = [];
var verts = {};
for (var i in this.positions) {
verts[i] = rpositions.length;
rpositions.push(this.positions[i]);
}
var rfaces = [];
for (var i in this.flags) {
var flag = this.flags[i];
var f = [];
var v0 = Object.keys(flag)[0];
var v = v0;
do {
f.push(verts[v]);
v = flag[v];
} while (v != v0);
rfaces.push(f);
}
return {
name: "?",
positions: rpositions,
faces: rfaces
};
}
module.exports = Assembler;
},{}],2:[function(require,module,exports){
//-------------------Canonicalization Algorithm--------------------------
// True canonicalization rather slow. Using center of gravity of vertices for each
// face gives a quick "adjustment" which planarizes faces at least.
"use strict";
var util = require("./util.js");
var makeDual = require("./dual.js");
function reciprocalN(poly) { // make array of vertices reciprocal to given planes
var ans = new Array(poly.faces.length);
for (var i=0; i<poly.faces.length; ++i) { // for each face:
var centroid = [0.0, 0.0, 0.0]; // running sum of vertex coords
var normal = [0.0, 0.0, 0.0]; // running sum of normal vectors
var avgEdgeDist = 0.; // running sum for avg edge distance
var v1 = poly.faces[i][poly.faces[i].length-2]; // preprevious vertex
var v2 = poly.faces[i][poly.faces[i].length-1]; // previous vertex
for (var j=0; j<poly.faces[i].length; j++) {
var v3 = poly.faces[i][j]; // this vertex
centroid = util.add(centroid, poly.positions[v3]);
normal = util.add(normal, util.orthogonal(poly.positions[v1], poly.positions[v2], poly.positions[v3]));
avgEdgeDist = avgEdgeDist + util.edgeDist(poly.positions[v1], poly.positions[v2]);
v1 = v2; // shift over one
v2 = v3;
}
centroid = util.mult(1.0/poly.faces[i].length, centroid);
normal = util.unit(normal);
avgEdgeDist = avgEdgeDist / poly.faces[i].length;
ans[i] = util.reciprocal(util.mult(util.dot(centroid, normal), normal)); // based on face
ans[i] = util.mult((1+avgEdgeDist)/2, ans[i]); // edge correction
}
return (ans);
}
function reciprocalC(poly) { // return array of reciprocals of face centers
var center = faceCenters(poly);
for (var i=0; i<poly.faces.length; i++) {
var m2 = center[i][0]*center[i][0] + center[i][1]*center[i][1] + center[i][2]*center[i][2];
center[i][0] = center[i][0] / m2; // divide each coord by magnitude squared
center[i][1] = center[i][1] / m2;
center[i][2] = center[i][2] / m2;
}
return(center);
}
function faceCenters(poly) { // return array of "face centers"
var ans = new Array(poly.faces.length);
for (var i=0; i<poly.faces.length; i++) {
ans[i] = util.vecZero(); // running sum
for (var j=0; j<poly.faces[i].length; j++) // just average vertex coords:
ans[i] = util.add(ans[i], poly.positions[poly.faces[i][j]]); // sum and...
ans[i] = util.mult(1./poly.faces[i].length, ans[i]); // ...divide by n
}
return (ans);
}
exports.faceCenters = faceCenters;
function canonicalpositions(poly, nIterations) { // compute new vertex coords.
var dpoly = makeDual(poly) // v's of dual are in order or arg's f's
for (var count=0; count<nIterations; count++) { // iteration:
dpoly.positions = reciprocalN(poly);
poly.positions = reciprocalN(dpoly);
}
}
exports.canonicalpositions = canonicalpositions;
function adjustpositions(poly, nIterations) {
var dpoly = makeDual(poly) // v's of dual are in order or arg's f's
for (var count=0; count<1; count++) { // iteration:
dpoly.positions = reciprocalC(poly); // reciprocate face centers
poly.positions = reciprocalC(dpoly); // reciprocate face centers
}
}
exports.adjustpositions = adjustpositions;
},{"./dual.js":3,"./util.js":6}],3:[function(require,module,exports){
//--------------------------------Dual------------------------------------------
// the makeDual function computes the dual's topology, needed for canonicalization,
// where positions's are determined. It is then saved in a global variable globSavedDual.
// when the d operator is executed, d just returns the saved value.
"use strict";
var Assembler = require("./assembler.js");
var util = require("./util.js");
module.exports = function(poly) { // compute dual of argument, matching V and F indices
var result = new Assembler();
var faces = new Array(poly.positions.length); // make table of face as fn of edge
for (var i=0; i<poly.positions.length; i++) {
faces[i] = new Object(); // create empty associative table
}
for (var i=0; i<poly.faces.length; i++) {
var v1 = poly.faces[i][poly.faces[i].length-1]; // previous vertex
for (j=0; j<poly.faces[i].length; j++) {
var v2 = poly.faces[i][j]; // this vertex
faces[v1]["v" + v2] = i; // fill it. 2nd index is associative
v1 = v2; // current becomes previous
}
}
for (var i=0; i<poly.faces.length; i++) { // create d's v's per p's f's
result.newV(i, [0,0,0]); // only topology needed for canonicalize
}
for (var i=0; i<poly.faces.length; i++) { // one new flag for each old one
var v1 = poly.faces[i][poly.faces[i].length-1]; // previous vertex
for (j=0; j<poly.faces[i].length; j++) {
var v2 = poly.faces[i][j]; // this vertex
result.newFlag(v1, faces[v2]["v" + v1], i); // look up face across edge
v1 = v2; // current becomes previous
}
}
var ans = result.flags2poly(); // this gives one indexing of answer
var sortF = new Array(ans.faces.length); // but f's of dual are randomly ordered, so sort
for (var i=0; i<ans.faces.length; i++) {
var j = util.intersect(poly.faces[ans.faces[i][0]],poly.faces[ans.faces[i][1]],poly.faces[ans.faces[i][2]]);
sortF[j] = ans.faces[i]; // p's v for d's f is common to three of p's f's
}
ans.faces = sortF; // replace with the sorted list of faces
if(poly.name) {
if (poly.name.substr(0,1)!="d") {
ans.name = "d" + poly.name; // dual name is same with "d" added...
} else {
ans.name = poly.name.substr(1); // ...or removed
}
}
return ans;
}
},{"./assembler.js":1,"./util.js":6}],4:[function(require,module,exports){
"use strict";
var util = require("./util.js");
var makeDual = require("./dual.js");
var Assembler = require("./assembler.js");
var canonicalize = require("./canonicalize.js");
exports.dual = function(poly) {
var dpoly = makeDual(poly);
dpoly.positions = canonicalize.faceCenters(poly);
return dpoly;
}
exports.canonicalize = function(poly) {
poly = util.clone(poly);
canonicalize.canonicalpositions(poly);
return poly;
}
function kis(poly, n) { // only kis n-sided faces, but n==0 means kiss all.
var result = new Assembler();
for (var i=0; i<poly.positions.length; i++) {
result.newV("v"+i, poly.positions[i]); // each old vertex is a new vertex
}
var centers = canonicalize.faceCenters(poly); // new vertices in centers of n-sided face
var foundAny = false; // alert if don't find any
for (var i=0; i<poly.faces.length; i++) {
var v1 = "v" + poly.faces[i][poly.faces[i].length-1]; // previous vertex
for (var j=0; j<poly.faces[i].length; j++) {
var v2 = "v" + poly.faces[i][j]; // this vertex
if (poly.faces[i].length == n || n==0) { // kiss the n's, or all
foundAny = true; // flag that we found some
result.newV("f"+i, centers[i]); // new vertex in face center
var fname = i + v1;
result.newFlag(fname, v1, v2); // three new flags, if n-sided
result.newFlag(fname, v2, "f"+i);
result.newFlag(fname, "f"+i, v1);
}
else
result.newFlag(i, v1, v2); // same old flag, if non-n
v1 = v2; // current becomes previous
}
}
var ans = result.flags2poly();
ans.name = "k" + (n===0?"":n) + poly.name;
canonicalize.adjustpositions(ans, 3); // adjust and
return (ans);
}
exports.kis = kis;
function ambo(poly) { // compute ambo of argument
var result = new Assembler();
for (var i=0; i<poly.faces.length; i++) {
var v1 = poly.faces[i][poly.faces[i].length-2]; // preprevious vertex
var v2 = poly.faces[i][poly.faces[i].length-1]; // previous vertex
for (var j=0; j<poly.faces[i].length; j++) {
var v3 = poly.faces[i][j]; // this vertex
if (v1 < v2) // new vertices at edge midpoints
result.newV(midName(v1,v2), util.midpoint(poly.positions[v1],poly.positions[v2]));
result.newFlag("f"+i, midName(v1,v2), midName(v2,v3)); // two new flags
result.newFlag("v"+v2, midName(v2,v3), midName(v1,v2));
v1 = v2; // shift over one
v2 = v3;
}
}
var ans = result.flags2poly();
ans.name = "a" + poly.name;
canonicalize.adjustpositions(ans, 2); // canonicalize lightly
return (ans);
}
exports.ambo = ambo;
function midName(v1,v2) { // unique symbolic name, e.g. "1_2"
if (v1<v2)
return (v1 + "_" + v2);
else
return (v2 + "_" + v1);
}
function gyro(poly) { // compute gyro of argument
var result = new Assembler();
for (var i=0; i<poly.positions.length; i++)
result.newV("v"+i, util.unit(poly.positions[i])); // each old vertex is a new vertex
var centers = canonicalize.faceCenters(poly); // new vertices in center of each face
for (var i=0; i<poly.faces.length; i++)
result.newV("f"+i, util.unit(centers[i]));
for (var i=0; i<poly.faces.length; i++) {
var v1 = poly.faces[i][poly.faces[i].length-2]; // preprevious vertex
var v2 = poly.faces[i][poly.faces[i].length-1]; // previous vertex
for (var j=0; j<poly.faces[i].length; j++) {
var v3 = poly.faces[i][j]; // this vertex
result.newV(v1+"~"+v2, util.oneThird(poly.positions[v1],poly.positions[v2])); // new v in face
var fname = i + "f" + v1;
result.newFlag(fname, "f"+i, v1+"~"+v2); // five new flags
result.newFlag(fname, v1+"~"+v2, v2+"~"+v1);
result.newFlag(fname, v2+"~"+v1, "v"+v2);
result.newFlag(fname, "v"+v2, v2+"~"+v3);
result.newFlag(fname, v2+"~"+v3, "f"+i);
v1 = v2; // shift over one
v2 = v3;
}
}
var ans = result.flags2poly();
ans.name = "g" + poly.name;
canonicalize.adjustpositions(ans, 3); // canonicalize lightly
return (ans);
}
exports.gyro = gyro;
function propellor(poly) { // compute propellor of argument
var result = new Assembler();
for (var i=0; i<poly.positions.length; i++)
result.newV("v"+i, util.unit(poly.positions[i])); // each old vertex is a new vertex
for (var i=0; i<poly.faces.length; i++) {
var v1 = poly.faces[i][poly.faces[i].length-2]; // preprevious vertex
var v2 = poly.faces[i][poly.faces[i].length-1]; // previous vertex
for (var j=0; j<poly.faces[i].length; j++) {
var v3 = poly.faces[i][j]; // this vertex
result.newV(v1+"~"+v2, util.oneThird(poly.positions[v1],poly.positions[v2])); // new v in face
var fname = i + "f" + v2;
result.newFlag("v"+i, v1+"~"+v2, v2+"~"+v3); // five new flags
result.newFlag(fname, v1+"~"+v2, v2+"~"+v1);
result.newFlag(fname, v2+"~"+v1, "v"+v2);
result.newFlag(fname, "v"+v2, v2+"~"+v3);
result.newFlag(fname, v2+"~"+v3, v1+"~"+v2);
v1 = v2; // shift over one
v2 = v3;
}
}
var ans = result.flags2poly();
ans.name = "p" + poly.name;
canonicalize.adjustpositions(ans, 3); // canonicalize lightly
return (ans);
}
exports.propellor = propellor;
function reflect(poly) { // compute reflection through origin
poly = util.clone(poly);
for (var i=0; i<poly.positions.length; i++)
poly.positions[i] = util.mult(-1, poly.positions[i]); // reflect each point
for (var i=0; i<poly.faces.length; i++)
poly.faces[i] = poly.faces[i].reverse(); // repair clockwise-ness
poly.name = "r" + poly.name;
canonicalize.adjustpositions(poly, 1); // build dual
return (poly);
}
exports.reflect = reflect;
exports.expand = function(poly) {
return ambo(ambo(poly));
}
exports.bevel = function(poly) {
return truncate(ambo(poly));
}
exports.ortho = function(poly) {
return join(join(poly));
}
exports.meta = function(poly) {
return kis(join(poly));
}
exports.truncate = function(poly, n) {
return dual(kis(dual(poly), n));
}
exports.join = function(poly) {
return dual(ambo(dual(poly)));
}
exports.split = function(poly) {
return dual(gyro(dual(poly)));
}
},{"./assembler.js":1,"./canonicalize.js":2,"./dual.js":3,"./util.js":6}],5:[function(require,module,exports){
"use strict";
var util = require("./util.js");
var canonicalize = require("./canonicalize.js");
module.exports = {
tetrahedron: function() {
return {
name: "T",
faces: [ [0,1,2], [0,2,3], [0,3,1], [1,3,2] ],
positions: [ [1.,1.,1.], [1.,-1.,-1.], [-1.,1.,-1.], [-1.,-1.,1.] ]
};
},
octahedron: function() {
return {
name: "O",
faces: [ [0,1,2], [0,2,3], [0,3,4], [0,4,1], [1,4,5], [1,5,2], [2,5,3], [3,5,4] ],
positions: [ [0,0,1.414], [1.414,0,0], [0,1.414,0], [-1.414,0,0], [0,-1.414,0], [0,0,-1.414] ]
};
},
cube: function() {
return {
name: "C",
faces: [ [3,0,1,2], [3,4,5,0], [0,5,6,1], [1,6,7,2], [2,7,4,3], [5,4,7,6] ],
positions: [ [ 0.707, 0.707,0.707], [-0.707,0.707,0.707],
[-0.707,-0.707,0.707], [0.707,-0.707,0.707],
[0.707,-0.707,-0.707], [0.707,0.707,-0.707],
[-0.707,0.707,-0.707], [-0.707,-0.707,-0.707] ]
};
},
icosahedron: function() {
return {
name: "I",
faces: [ [0,1,2], [0,2,3], [0,3,4], [0,4,5],
[0,5,1], [1,5,7], [1,7,6], [1,6,2],
[2,6,8], [2,8,3], [3,8,9], [3,9,4],
[4,9,10], [4,10,5], [5,10,7], [6,7,11],
[6,11,8], [7,10,11], [8,11,9], [9,11,10] ],
positions: [ [0,0,1.176], [1.051,0,0.526],
[0.324,1.,0.525], [-0.851,0.618,0.526],
[-0.851,-0.618,0.526], [0.325,-1.,0.526],
[0.851,0.618,-0.526], [0.851,-0.618,-0.526],
[-0.325,1.,-0.526], [-1.051,0,-0.526],
[-0.325,-1.,-0.526], [0,0,-1.176] ]
};
},
dodecahedron: function() {
return {
name: "D",
faces: [ [0,1,4,7,2], [0,2,6,9,3], [0,3,8,5,1],
[1,5,11,10,4], [2,7,13,12,6], [3,9,15,14,8],
[4,10,16,13,7], [5,8,14,17,11], [6,12,18,15,9],
[10,11,17,19,16], [12,13,16,19,18], [14,15,18,19,17] ],
positions: [ [0,0,1.07047], [0.713644,0,0.797878],
[-0.356822,0.618,0.797878], [-0.356822,-0.618,0.797878],
[0.797878,0.618034,0.356822], [0.797878,-0.618,0.356822],
[-0.934172,0.381966,0.356822], [0.136294,1.,0.356822],
[0.136294,-1.,0.356822], [-0.934172,-0.381966,0.356822],
[0.934172,0.381966,-0.356822], [0.934172,-0.381966,-0.356822],
[-0.797878,0.618,-0.356822], [-0.136294,1.,-0.356822],
[-0.136294,-1.,-0.356822], [-0.797878,-0.618034,-0.356822],
[0.356822,0.618,-0.797878], [0.356822,-0.618,-0.797878],
[-0.713644,0,-0.797878], [0,0,-1.07047] ]
};
},
prism: function(n) {
var theta = Math.PI * 2.0 / n;
var h = Math.sin(theta/2);
var positions = [];
for (var i=0; i<n; i++) {
positions.push([Math.cos(i*theta), Math.sin(i*theta), h]);
}
for (var i=0; i<n; i++) {
positions.push([Math.cos(i*theta), Math.sin(i*theta),-h]);
}
var faces = [ util.sequence(n-1, 0), util.sequence(n, 2*n-1) ];
for(var i=0; i<n; ++i) {
faces.push([i, (i+1)%n, (i+1)%n+n, i+n]);
}
var result = {
name: "P" + n,
positions: positions,
faces: faces
};
canonicalize.adjustpositions(result, 1);
return result;
},
antiprism: function(n) {
var theta = Math.PI * 2.0 / n;
var h = Math.sqrt(1-4/(4+2*Math.cos(theta/2)-2*Math.cos(theta)));
var r = Math.sqrt(1-h*h);
var f = Math.sqrt(h*h + Math.pow(r*Math.cos(theta/2), 2));
r=r/f;
h=h/f;
var positions = [];
for (var i=0; i<n; i++) {
positions.push([r*Math.cos(i*theta), r*Math.sin(i*theta), h]);
}
for (var i=0; i<n; i++) {
positions.push([r*Math.cos((i+0.5)*theta), r*Math.sin((i+0.5)*theta), -h]);
}
var faces = [ util.sequence(n-1, 0), util.sequence(n, 2*n-1) ]
for (var i=0; i<n; i++) {
faces.push([i, (i+1)%n, i+n]);
faces.push([i, i+n, ((n+i-1)%n+n)]);
}
var result = {
name: "A" + n,
positions: positions,
faces: faces
};
canonicalize.adjustpositions(result, 1);
return result;
},
pyramid: function(n) {
var theta = Math.PI * 2.0 / n;
var positions = [];
for(var i=0; i<n; ++i) {
positions.push([Math.cos(i*theta), Math.sin(i*theta), .2]);
}
positions.push([0, 0, -2]);
var faces = [ util.sequence(n-1, 0) ];
for (var i=0; i<n; ++i) {
faces.push([i, (i+1)%n, n]);
}
var result = {
name: "Y" + n,
positions: positions,
faces: faces
};
canonicalize.canonicalpositions(result, 3);
return result;
}
}
},{"./canonicalize.js":2,"./util.js":6}],6:[function(require,module,exports){
"use strict";
function clone(poly) {
var npositions = new Array(poly.positions.length);
for(var i=0; i<poly.positions.length; ++i) {
npositions[i] = poly.positions[i].slice(0);
}
var nfaces = [];
for(var i=0; i<poly.faces.length; ++i) {
nfaces[i] = poly.faces[i].slice(0);
}
return {
name: poly.name.slice(0),
positions: npositions,
faces: nfaces
}
}
exports.clone = clone;
function intersect(set1, set2, set3) { // find element common to 3 sets
for (var i=0; i<set1.length; i++) { // by brute force search
for (var j=0; j<set2.length; j++) {
if (set1[i]===set2[j]) {
for (var k=0; k<set3.length; k++) {
if (set1[i]===set3[k]) {
return set1[i];
}
}
}
}
}
throw new Error("program bug in intersect()");
return null;
}
exports.intersect = intersect;
function sequence(start, stop) { // make list of integers, inclusive
var ans = new Array();
if (start <= stop) {
for (var i=start; i<=stop; i++) {
ans.push(i);
}
} else {
for (var i=start; i>=stop; i--) {
ans.push(i);
}
}
return ans;
}
exports.sequence = sequence;
function orthogonal(v3, v2, v1) { // find unit vector orthog to plane of 3 pts
var d1 = sub(v2, v1); // adjacent edge vectors
var d2 = sub(v3, v2);
return [ d1[1]*d2[2] - d1[2]*d2[1], // cross product
d1[2]*d2[0] - d1[0]*d2[2],
d1[0]*d2[1] - d1[1]*d2[0] ]
}
exports.orthogonal = orthogonal;
function mag2(vec) { // magnitude squared of 3-vector
return vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2];
}
exports.mag2 = mag2;
function tangentPoint(v1, v2) { // point where line v1...v2 tangent to an origin sphere
var d = sub(v2,v1); // difference vector
console.log(d);
return(sub(v1, mult(dot(d,v1)/mag2(d), d)));
}
exports.tangentPoint = tangentPoint;
function edgeDist(v1, v2) { // distance of line v1...v2 to origin
return(Math.sqrt(mag2(tangentPoint(v1, v2))));
}
exports.edgeDist = edgeDist;
function vecZero() {
return [0.0,0.0,0.0];
}
exports.vecZero = vecZero;
function mult(c, vec) { // c times 3-vector
return [ c*vec[0],
c*vec[1],
c*vec[2] ];
}
exports.mult = mult;
function add(vec1, vec2) { // sum two 3-vectors
return [ vec1[0]+vec2[0],
vec1[1]+vec2[1],
vec1[2]+vec2[2] ];
}
exports.add = add;
function sub(vec1, vec2) { // subtract two 3-vectors
return [ vec1[0]-vec2[0],
vec1[1]-vec2[1],
vec1[2]-vec2[2] ]
}
exports.sub = sub;
function dot(vec1, vec2) { // dot product two 3-vectors
return (vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2]);
}
exports.dot = dot;
function midpoint(vec1, vec2) { // mean of two 3-vectors
return [ 0.5*(vec1[0] + vec2[0]),
0.5*(vec1[1] + vec2[1]),
0.5*(vec1[2] + vec2[2]) ]
}
exports.midpoint = midpoint;
function oneThird(vec1, vec2) { // approx. (2/3)v1 + (1/3)v2 (assumes 3-vector)
return [ 0.7*vec1[0] + 0.3*vec2[0],
0.7*vec1[1] + 0.3*vec2[1],
0.7*vec1[2] + 0.3*vec2[2] ]
return ans;
}
exports.oneThird = oneThird;
function reciprocal(vec) { // reflect 3-vector in unit sphere
var factor = 1./mag2(vec);
return [ factor*vec[0],
factor*vec[1],
factor*vec[2] ]
}
exports.reciprocal = reciprocal;
function unit(vec) { // normalize 3-vector to unit magnitude
var size = mag2(vec);
if (size <= 1e-8) { // remove this test someday...
return (vec);
}
var c = 1./Math.sqrt(size);
return mult(c, vec);
}
exports.unit = unit;
},{}],"conway-hart":[function(require,module,exports){
"use strict";
//Import operators
var seeds = require("./lib/seeds.js");
var operators = require("./lib/operators.js");
//Seed types
var SEED_FUNCS = {
"T": seeds.tetrahedron,
"O": seeds.octahedron,
"C": seeds.cube,
"I": seeds.icosahedron,
"D": seeds.dodecahedron,
"P": seeds.prism,
"A": seeds.antiprism,
"Y": seeds.pyramid
};
//Operator types
var OPERATOR_FUNCS = {
"k": operators.kis,
"a": operators.ambo,
"g": operators.gyro,
"p": operators.propellor,
"d": operators.dual,
"r": operators.reflect,
"c": operators.canonicalize
};
//Checks if a seed is a token
function isToken(c) {
return "kagpdcrTOCIDPAY".indexOf(c) >= 0;
}
//Checks if a value is numeric
function isNumeric(c) {
return 48 <= c && c <= 57;
}
//Tokenize an expression in Conway notation
function tokenize(expr) {
expr = expr.replace(/P4$/g, "C") // P4 --> C (C is prism)
.replace(/A3$/g, "O") // A3 --> O (O is antiprism)
.replace(/Y3$/g, "T") // Y3 --> T (T is pyramid)
.replace(/e/g, "aa") // e --> aa (abbr. for explode)
.replace(/b/g, "ta") // b --> ta (abbr. for bevel)
.replace(/o/g, "jj") // o --> jj (abbr. for ortho)
.replace(/m/g, "kj") // m --> kj (abbr. for meta)
.replace(/t(\d*)/g, "dk$1d") // t(n) --> dk(n)d (dual operations)
.replace(/j/g, "dad") // j --> dad (dual operations)
.replace(/s/g, "dgd") // s --> dgd (dual operations)
.replace(/dd/g, "") // dd --> null (order 2)
.replace(/ad/g, "a") // ad --> a (a_ = ad_)
.replace(/gd/g, "g") // gd --> g (g_ = gd_)
.replace(/aY/g, "A") // aY --> A (interesting fact)
.replace(/dT/g, "T") // dT --> T (self-dual)
.replace(/gT/g, "D") // gT --> D (symm change)
.replace(/aT/g, "O") // aT --> O (symm change)
.replace(/dC/g, "O") // dC --> O (dual pair)
.replace(/dO/g, "C") // dO --> C (dual pair)
.replace(/dI/g, "D") // dI --> D (dual pair)
.replace(/dD/g, "I") // dD --> I (dual pair)
.replace(/aO/g, "aC") // aO --> aC (for uniqueness)
.replace(/aI/g, "aD") // aI --> aD (for uniqueness)
.replace(/gO/g, "gC") // gO --> gC (for uniqueness)
.replace(/gI/g, "gD"); // gI --> gD (for uniqueness)
var toks = [];
var ptr = 0;
while(ptr < expr.length) {
var op = expr.charAt(ptr);
if(!isToken(op)) {
throw new Error("Unexpected token: " + c + " in input " + expr + " at " + ptr);
}
var start_n = ++ptr;
while(ptr < expr.length && isNumeric(expr.charCodeAt(ptr))) {
++ptr;
}
var n = parseInt(expr.substr(start_n, ptr));
toks.push({
op: op,
n: n | 0
});
}
toks.reverse();
return toks;
}
//Main expression interpreter
function evalConwayHart(expr) {
//Parse expression
var toks = tokenize(expr);
//Initialize seed
var ctor = SEED_FUNCS[toks[0].op];
if(!ctor) {
throw Error("Invalid seed type: " + JSON.stringify(ops[0]));
} else if("PAY".indexOf(toks[0].op) >= 0) {
if(toks[0].n < 3) {
throw Error("Invalid number of faces for seed");
}
} else if(toks[0].n !== 0) {
throw Error("Seed " + toks[0].op + " does not use a parameter");
}
var poly = ctor(toks[0].n);
//Apply operators
for(var i=1; i<toks.length; ++i) {
var op = OPERATOR_FUNCS[toks[i].op];
if(!op) {
throw Error("Invalid operator: " + toks[i]);
}
poly = op(poly, toks[i].n);
}
return { name: poly.name, cells: poly.faces, positions: poly.positions };
}
module.exports = evalConwayHart;
},{"./lib/operators.js":4,"./lib/seeds.js":5}]},{},[])
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImxpYi9hc3NlbWJsZXIuanMiLCJsaWIvY2Fub25pY2FsaXplLmpzIiwibGliL2R1YWwuanMiLCJsaWIvb3BlcmF0b3JzLmpzIiwibGliL3NlZWRzLmpzIiwibGliL3V0aWwuanMiLCJpbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdklBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1SUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJmdW5jdGlvbiBBc3NlbWJsZXIoKSB7XG4gIHRoaXMuZmxhZ3MgICAgICA9IHt9O1xuICB0aGlzLnBvc2l0aW9ucyAgPSB7fTtcbiAgdGhpcy5mYWNlcyAgICAgID0ge307XG59XG5cbkFzc2VtYmxlci5wcm90b3R5cGUubmV3RmxhZyA9IGZ1bmN0aW9uKGZhY2UsIHYxLCB2Mikge1xuICBpZiAoIXRoaXMuZmxhZ3NbZmFjZV0pIHtcbiAgICB0aGlzLmZsYWdzW2ZhY2VdID0geyB9O1xuICB9XG4gIHRoaXMuZmxhZ3NbZmFjZV1bdjFdID0gdjI7XG59XG5cbkFzc2VtYmxlci5wcm90b3R5cGUubmV3ViA9IGZ1bmN0aW9uKG5hbWUsIHApIHtcbiAgdGhpcy5wb3NpdGlvbnNbbmFtZV0gPSBwO1xufVxuXG5Bc3NlbWJsZXIucHJvdG90eXBlLmZsYWdzMnBvbHkgPSBmdW5jdGlvbigpIHtcbiAgdmFyIHJwb3NpdGlvbnMgPSBbXTtcbiAgdmFyIHZlcnRzICAgICAgPSB7fTtcbiAgZm9yICh2YXIgaSBpbiB0aGlzLnBvc2l0aW9ucykge1xuICAgIHZlcnRzW2ldID0gcnBvc2l0aW9ucy5sZW5ndGg7XG4gICAgcnBvc2l0aW9ucy5wdXNoKHRoaXMucG9zaXRpb25zW2ldKTtcbiAgfVxuICB2YXIgcmZhY2VzID0gW107XG4gIGZvciAodmFyIGkgaW4gdGhpcy5mbGFncykge1xuICAgIHZhciBmbGFnID0gdGhpcy5mbGFnc1tpXTtcbiAgICB2YXIgZiA9IFtdO1xuICAgIHZhciB2MCA9IE9iamVjdC5rZXlzKGZsYWcpWzBdO1xuICAgIHZhciB2ID0gdjA7XG4gICAgZG8ge1xuICAgICAgZi5wdXNoKHZlcnRzW3ZdKTtcbiAgICAgIHYgPSBmbGFnW3ZdO1xuICAgIH0gd2hpbGUgKHYgIT0gdjApO1xuICAgIHJmYWNlcy5wdXNoKGYpO1xuICB9XG4gIHJldHVybiB7XG4gICAgbmFtZTogICAgICAgXCI/XCIsXG4gICAgcG9zaXRpb25zOiAgcnBvc2l0aW9ucyxcbiAgICBmYWNlczogICAgICByZmFjZXNcbiAgfTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBBc3NlbWJsZXI7XG4iLCIvLy0tLS0tLS0tLS0tLS0tLS0tLS1DYW5vbmljYWxpemF0aW9uIEFsZ29yaXRobS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBUcnVlIGNhbm9uaWNhbGl6YXRpb24gcmF0aGVyIHNsb3cuICBVc2luZyBjZW50ZXIgb2YgZ3Jhdml0eSBvZiB2ZXJ0aWNlcyBmb3IgZWFjaFxuLy8gZmFjZSBnaXZlcyBhIHF1aWNrIFwiYWRqdXN0bWVudFwiIHdoaWNoIHBsYW5hcml6ZXMgZmFjZXMgYXQgbGVhc3QuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIHV0aWwgPSByZXF1aXJlKFwiLi91dGlsLmpzXCIpO1xudmFyIG1ha2VEdWFsID0gcmVxdWlyZShcIi4vZHVhbC5qc1wiKTtcblxuZnVuY3Rpb24gcmVjaXByb2NhbE4ocG9seSkgeyAgICAvLyBtYWtlIGFycmF5IG9mIHZlcnRpY2VzIHJlY2lwcm9jYWwgdG8gZ2l2ZW4gcGxhbmVzXG4gIHZhciBhbnMgPSBuZXcgQXJyYXkocG9seS5mYWNlcy5sZW5ndGgpO1xuICBmb3IgKHZhciBpPTA7IGk8cG9seS5mYWNlcy5sZW5ndGg7ICsraSkgeyAgICAvLyBmb3IgZWFjaCBmYWNlOlxuICAgIHZhciBjZW50cm9pZCA9IFswLjAsIDAuMCwgMC4wXTsgICAgICAgICAgIC8vIHJ1bm5pbmcgc3VtIG9mIHZlcnRleCBjb29yZHNcbiAgICB2YXIgbm9ybWFsID0gWzAuMCwgMC4wLCAwLjBdOyAgICAgICAgICAgICAvLyBydW5uaW5nIHN1bSBvZiBub3JtYWwgdmVjdG9yc1xuICAgIHZhciBhdmdFZGdlRGlzdCA9IDAuOyAgICAgICAgICAgICAgIC8vIHJ1bm5pbmcgc3VtIGZvciBhdmcgZWRnZSBkaXN0YW5jZVxuICAgIHZhciB2MSA9IHBvbHkuZmFjZXNbaV1bcG9seS5mYWNlc1tpXS5sZW5ndGgtMl07ICAvLyBwcmVwcmV2aW91cyB2ZXJ0ZXhcbiAgICB2YXIgdjIgPSBwb2x5LmZhY2VzW2ldW3BvbHkuZmFjZXNbaV0ubGVuZ3RoLTFdOyAgLy8gcHJldmlvdXMgdmVydGV4XG4gICAgZm9yICh2YXIgaj0wOyBqPHBvbHkuZmFjZXNbaV0ubGVuZ3RoOyBqKyspICB7XG4gICAgICB2YXIgdjMgPSBwb2x5LmZhY2VzW2ldW2pdOyAgICAgICAgICAgICAgICAgIC8vIHRoaXMgdmVydGV4XG4gICAgICBjZW50cm9pZCA9IHV0aWwuYWRkKGNlbnRyb2lkLCBwb2x5LnBvc2l0aW9uc1t2M10pO1xuICAgICAgbm9ybWFsID0gdXRpbC5hZGQobm9ybWFsLCB1dGlsLm9ydGhvZ29uYWwocG9seS5wb3NpdGlvbnNbdjFdLCBwb2x5LnBvc2l0aW9uc1t2Ml0sIHBvbHkucG9zaXRpb25zW3YzXSkpO1xuICAgICAgYXZnRWRnZURpc3QgPSBhdmdFZGdlRGlzdCArIHV0aWwuZWRnZURpc3QocG9seS5wb3NpdGlvbnNbdjFdLCBwb2x5LnBvc2l0aW9uc1t2Ml0pO1xuICAgICAgdjEgPSB2MjsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNoaWZ0IG92ZXIgb25lXG4gICAgICB2MiA9IHYzO1xuICAgIH1cbiAgICBjZW50cm9pZCA9IHV0aWwubXVsdCgxLjAvcG9seS5mYWNlc1tpXS5sZW5ndGgsIGNlbnRyb2lkKTtcbiAgICBub3JtYWwgPSB1dGlsLnVuaXQobm9ybWFsKTtcbiAgICBhdmdFZGdlRGlzdCA9IGF2Z0VkZ2VEaXN0IC8gcG9seS5mYWNlc1tpXS5sZW5ndGg7XG4gICAgYW5zW2ldID0gdXRpbC5yZWNpcHJvY2FsKHV0aWwubXVsdCh1dGlsLmRvdChjZW50cm9pZCwgbm9ybWFsKSwgbm9ybWFsKSk7ICAvLyBiYXNlZCBvbiBmYWNlXG4gICAgYW5zW2ldID0gdXRpbC5tdWx0KCgxK2F2Z0VkZ2VEaXN0KS8yLCBhbnNbaV0pOyAgICAgICAgICAgICAgICAgIC8vIGVkZ2UgY29ycmVjdGlvblxuICB9XG4gIHJldHVybiAoYW5zKTtcbn1cblxuZnVuY3Rpb24gcmVjaXByb2NhbEMocG9seSkgeyAgICAgICAgICAgLy8gcmV0dXJuIGFycmF5IG9mIHJlY2lwcm9jYWxzIG9mIGZhY2UgY2VudGVyc1xuICB2YXIgY2VudGVyID0gZmFjZUNlbnRlcnMocG9seSk7XG4gIGZvciAodmFyIGk9MDsgaTxwb2x5LmZhY2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIG0yID0gY2VudGVyW2ldWzBdKmNlbnRlcltpXVswXSArIGNlbnRlcltpXVsxXSpjZW50ZXJbaV1bMV0gKyBjZW50ZXJbaV1bMl0qY2VudGVyW2ldWzJdO1xuICAgIGNlbnRlcltpXVswXSA9IGNlbnRlcltpXVswXSAvIG0yOyAgIC8vIGRpdmlkZSBlYWNoIGNvb3JkIGJ5IG1hZ25pdHVkZSBzcXVhcmVkXG4gICAgY2VudGVyW2ldWzFdID0gY2VudGVyW2ldWzFdIC8gbTI7XG4gICAgY2VudGVyW2ldWzJdID0gY2VudGVyW2ldWzJdIC8gbTI7XG4gIH1cbiAgcmV0dXJuKGNlbnRlcik7XG59XG5cbmZ1bmN0aW9uIGZhY2VDZW50ZXJzKHBvbHkpIHsgICAgICAgICAgICAgIC8vIHJldHVybiBhcnJheSBvZiBcImZhY2UgY2VudGVyc1wiXG4gIHZhciBhbnMgPSBuZXcgQXJyYXkocG9seS5mYWNlcy5sZW5ndGgpO1xuICBmb3IgKHZhciBpPTA7IGk8cG9seS5mYWNlcy5sZW5ndGg7IGkrKykge1xuICAgIGFuc1tpXSA9IHV0aWwudmVjWmVybygpOyAgICAgICAgICAgICAgICAgICAgICAvLyBydW5uaW5nIHN1bVxuICAgIGZvciAodmFyIGo9MDsgajxwb2x5LmZhY2VzW2ldLmxlbmd0aDsgaisrKSAgICAvLyBqdXN0IGF2ZXJhZ2UgdmVydGV4IGNvb3JkczpcbiAgICAgIGFuc1tpXSA9IHV0aWwuYWRkKGFuc1tpXSwgcG9seS5wb3NpdGlvbnNbcG9seS5mYWNlc1tpXVtqXV0pOyAgLy8gc3VtIGFuZC4uLlxuICAgIGFuc1tpXSA9IHV0aWwubXVsdCgxLi9wb2x5LmZhY2VzW2ldLmxlbmd0aCwgYW5zW2ldKTsgICAgICAgIC8vIC4uLmRpdmlkZSBieSBuXG4gIH1cbiAgcmV0dXJuIChhbnMpO1xufVxuZXhwb3J0cy5mYWNlQ2VudGVycyA9IGZhY2VDZW50ZXJzO1xuXG5mdW5jdGlvbiBjYW5vbmljYWxwb3NpdGlvbnMocG9seSwgbkl0ZXJhdGlvbnMpIHsgICAgICAvLyBjb21wdXRlIG5ldyB2ZXJ0ZXggY29vcmRzLlxuICB2YXIgZHBvbHkgPSBtYWtlRHVhbChwb2x5KSAgICAgLy8gdidzIG9mIGR1YWwgYXJlIGluIG9yZGVyIG9yIGFyZydzIGYnc1xuICBmb3IgKHZhciBjb3VudD0wOyBjb3VudDxuSXRlcmF0aW9uczsgY291bnQrKykgeyAgICAvLyBpdGVyYXRpb246XG4gICAgZHBvbHkucG9zaXRpb25zID0gcmVjaXByb2NhbE4ocG9seSk7XG4gICAgcG9seS5wb3NpdGlvbnMgPSByZWNpcHJvY2FsTihkcG9seSk7XG4gIH1cbn1cbmV4cG9ydHMuY2Fub25pY2FscG9zaXRpb25zID0gY2Fub25pY2FscG9zaXRpb25zO1xuXG5mdW5jdGlvbiBhZGp1c3Rwb3NpdGlvbnMocG9seSwgbkl0ZXJhdGlvbnMpIHtcbiAgdmFyIGRwb2x5ID0gbWFrZUR1YWwocG9seSkgICAgIC8vIHYncyBvZiBkdWFsIGFyZSBpbiBvcmRlciBvciBhcmcncyBmJ3NcbiAgZm9yICh2YXIgY291bnQ9MDsgY291bnQ8MTsgY291bnQrKykgeyAgICAvLyBpdGVyYXRpb246XG4gICAgZHBvbHkucG9zaXRpb25zID0gcmVjaXByb2NhbEMocG9seSk7ICAgICAgICAgICAgIC8vIHJlY2lwcm9jYXRlIGZhY2UgY2VudGVyc1xuICAgIHBvbHkucG9zaXRpb25zID0gcmVjaXByb2NhbEMoZHBvbHkpOyAgICAgICAgICAgICAvLyByZWNpcHJvY2F0ZSBmYWNlIGNlbnRlcnNcbiAgfVxufVxuZXhwb3J0cy5hZGp1c3Rwb3NpdGlvbnMgPSBhZGp1c3Rwb3NpdGlvbnM7XG4iLCIvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tRHVhbC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gdGhlIG1ha2VEdWFsIGZ1bmN0aW9uIGNvbXB1dGVzIHRoZSBkdWFsJ3MgdG9wb2xvZ3ksIG5lZWRlZCBmb3IgY2Fub25pY2FsaXphdGlvbixcbi8vIHdoZXJlIHBvc2l0aW9ucydzIGFyZSBkZXRlcm1pbmVkLiAgSXQgaXMgdGhlbiBzYXZlZCBpbiBhIGdsb2JhbCB2YXJpYWJsZSBnbG9iU2F2ZWREdWFsLlxuLy8gd2hlbiB0aGUgZCBvcGVyYXRvciBpcyBleGVjdXRlZCwgZCBqdXN0IHJldHVybnMgdGhlIHNhdmVkIHZhbHVlLlxuXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIEFzc2VtYmxlciA9IHJlcXVpcmUoXCIuL2Fzc2VtYmxlci5qc1wiKTtcbnZhciB1dGlsID0gcmVxdWlyZShcIi4vdXRpbC5qc1wiKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbihwb2x5KSB7ICAgLy8gY29tcHV0ZSBkdWFsIG9mIGFyZ3VtZW50LCBtYXRjaGluZyBWIGFuZCBGIGluZGljZXNcbiAgdmFyIHJlc3VsdCA9IG5ldyBBc3NlbWJsZXIoKTtcbiAgdmFyIGZhY2VzID0gbmV3IEFycmF5KHBvbHkucG9zaXRpb25zLmxlbmd0aCk7IC8vIG1ha2UgdGFibGUgb2YgZmFjZSBhcyBmbiBvZiBlZGdlXG4gIGZvciAodmFyIGk9MDsgaTxwb2x5LnBvc2l0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgIGZhY2VzW2ldID0gbmV3IE9iamVjdCgpOyAgICAvLyBjcmVhdGUgZW1wdHkgYXNzb2NpYXRpdmUgdGFibGVcbiAgfVxuICBmb3IgKHZhciBpPTA7IGk8cG9seS5mYWNlcy5sZW5ndGg7IGkrKykge1xuICAgIHZhciB2MSA9IHBvbHkuZmFjZXNbaV1bcG9seS5mYWNlc1tpXS5sZW5ndGgtMV07ICAvLyBwcmV2aW91cyB2ZXJ0ZXhcbiAgICBmb3IgKGo9MDsgajxwb2x5LmZhY2VzW2ldLmxlbmd0aDsgaisrKSB7XG4gICAgICB2YXIgdjIgPSBwb2x5LmZhY2VzW2ldW2pdOyAgICAgICAgICAgICAgICAgIC8vIHRoaXMgdmVydGV4XG4gICAgICBmYWNlc1t2MV1bXCJ2XCIgKyB2Ml0gPSBpOyAgICAvLyBmaWxsIGl0LiAgMm5kIGluZGV4IGlzIGFzc29jaWF0aXZlXG4gICAgICB2MSA9IHYyOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY3VycmVudCBiZWNvbWVzIHByZXZpb3VzXG4gICAgfVxuICB9XG4gIGZvciAodmFyIGk9MDsgaTxwb2x5LmZhY2VzLmxlbmd0aDsgaSsrKSB7ICAgICAgICAgLy8gY3JlYXRlIGQncyB2J3MgcGVyIHAncyBmJ3NcbiAgICByZXN1bHQubmV3VihpLCBbMCwwLDBdKTsgICAgICAgICAgICAgICAgICAgICAgLy8gb25seSB0b3BvbG9neSBuZWVkZWQgZm9yIGNhbm9uaWNhbGl6ZVxuICB9XG4gIGZvciAodmFyIGk9MDsgaTxwb2x5LmZhY2VzLmxlbmd0aDsgaSsrKSB7ICAgICAgIC8vIG9uZSBuZXcgZmxhZyBmb3IgZWFjaCBvbGQgb25lXG4gICAgdmFyIHYxID0gcG9seS5mYWNlc1tpXVtwb2x5LmZhY2VzW2ldLmxlbmd0aC0xXTsgIC8vIHByZXZpb3VzIHZlcnRleFxuICAgIGZvciAoaj0wOyBqPHBvbHkuZmFjZXNbaV0ubGVuZ3RoOyBqKyspIHtcbiAgICAgIHZhciB2MiA9IHBvbHkuZmFjZXNbaV1bal07ICAgICAgICAgICAgICAgICAgLy8gdGhpcyB2ZXJ0ZXhcbiAgICAgIHJlc3VsdC5uZXdGbGFnKHYxLCBmYWNlc1t2Ml1bXCJ2XCIgKyB2MV0sIGkpOyAgICAgICAgLy8gbG9vayB1cCBmYWNlIGFjcm9zcyBlZGdlXG4gICAgICB2MSA9IHYyOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY3VycmVudCBiZWNvbWVzIHByZXZpb3VzXG4gICAgfVxuICB9XG4gIHZhciBhbnMgPSByZXN1bHQuZmxhZ3MycG9seSgpOyAgICAgIC8vIHRoaXMgZ2l2ZXMgb25lIGluZGV4aW5nIG9mIGFuc3dlclxuICB2YXIgc29ydEYgPSBuZXcgQXJyYXkoYW5zLmZhY2VzLmxlbmd0aCk7ICAgICAvLyBidXQgZidzIG9mIGR1YWwgYXJlIHJhbmRvbWx5IG9yZGVyZWQsIHNvIHNvcnRcbiAgZm9yICh2YXIgaT0wOyBpPGFucy5mYWNlcy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBqID0gdXRpbC5pbnRlcnNlY3QocG9seS5mYWNlc1thbnMuZmFjZXNbaV1bMF1dLHBvbHkuZmFjZXNbYW5zLmZhY2VzW2ldWzFdXSxwb2x5LmZhY2VzW2Fucy5mYWNlc1tpXVsyXV0pO1xuICAgIHNvcnRGW2pdID0gYW5zLmZhY2VzW2ldOyAgLy8gcCdzIHYgZm9yIGQncyBmIGlzIGNvbW1vbiB0byB0aHJlZSBvZiBwJ3MgZidzXG4gIH1cbiAgYW5zLmZhY2VzID0gc29ydEY7ICAgICAgICAgICAgLy8gcmVwbGFjZSB3aXRoIHRoZSBzb3J0ZWQgbGlzdCBvZiBmYWNlc1xuICBpZihwb2x5Lm5hbWUpIHtcbiAgICBpZiAocG9seS5uYW1lLnN1YnN0cigwLDEpIT1cImRcIikge1xuICAgICAgYW5zLm5hbWUgPSBcImRcIiArIHBvbHkubmFtZTsgICAgICAgIC8vIGR1YWwgbmFtZSBpcyBzYW1lIHdpdGggXCJkXCIgYWRkZWQuLi5cbiAgICB9IGVsc2Uge1xuICAgICAgYW5zLm5hbWUgPSBwb2x5Lm5hbWUuc3Vic3RyKDEpOyAgICAvLyAuLi5vciByZW1vdmVkXG4gICAgfVxuICB9XG4gIHJldHVybiBhbnM7XG59XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIHV0aWwgPSByZXF1aXJlKFwiLi91dGlsLmpzXCIpO1xudmFyIG1ha2VEdWFsID0gcmVxdWlyZShcIi4vZHVhbC5qc1wiKTtcbnZhciBBc3NlbWJsZXIgPSByZXF1aXJlKFwiLi9hc3NlbWJsZXIuanNcIik7XG52YXIgY2Fub25pY2FsaXplID0gcmVxdWlyZShcIi4vY2Fub25pY2FsaXplLmpzXCIpO1xuXG5leHBvcnRzLmR1YWwgPSBmdW5jdGlvbihwb2x5KSB7XG4gIHZhciBkcG9seSA9IG1ha2VEdWFsKHBvbHkpO1xuICBkcG9seS5wb3NpdGlvbnMgPSBjYW5vbmljYWxpemUuZmFjZUNlbnRlcnMocG9seSk7XG4gIHJldHVybiBkcG9seTtcbn1cblxuZXhwb3J0cy5jYW5vbmljYWxpemUgPSBmdW5jdGlvbihwb2x5KSB7XG4gIHBvbHkgPSB1dGlsLmNsb25lKHBvbHkpO1xuICBjYW5vbmljYWxpemUuY2Fub25pY2FscG9zaXRpb25zKHBvbHkpO1xuICByZXR1cm4gcG9seTtcbn1cblxuZnVuY3Rpb24ga2lzKHBvbHksIG4pIHsgICAgIC8vIG9ubHkga2lzIG4tc2lkZWQgZmFjZXMsIGJ1dCBuPT0wIG1lYW5zIGtpc3MgYWxsLlxuICB2YXIgcmVzdWx0ID0gbmV3IEFzc2VtYmxlcigpO1xuICBmb3IgKHZhciBpPTA7IGk8cG9seS5wb3NpdGlvbnMubGVuZ3RoOyBpKyspIHtcbiAgICByZXN1bHQubmV3VihcInZcIitpLCBwb2x5LnBvc2l0aW9uc1tpXSk7ICAgICAgICAgICAgICAvLyBlYWNoIG9sZCB2ZXJ0ZXggaXMgYSBuZXcgdmVydGV4XG4gIH1cbiAgdmFyIGNlbnRlcnMgPSBjYW5vbmljYWxpemUuZmFjZUNlbnRlcnMocG9seSk7ICAgICAgICAgICAvLyBuZXcgdmVydGljZXMgaW4gY2VudGVycyBvZiBuLXNpZGVkIGZhY2VcbiAgdmFyIGZvdW5kQW55ID0gZmFsc2U7ICAgICAgICAgICAgICAgICAgICAgIC8vIGFsZXJ0IGlmIGRvbid0IGZpbmQgYW55XG4gIGZvciAodmFyIGk9MDsgaTxwb2x5LmZhY2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIHYxID0gXCJ2XCIgKyBwb2x5LmZhY2VzW2ldW3BvbHkuZmFjZXNbaV0ubGVuZ3RoLTFdOyAgLy8gcHJldmlvdXMgdmVydGV4XG4gICAgZm9yICh2YXIgaj0wOyBqPHBvbHkuZmFjZXNbaV0ubGVuZ3RoOyBqKyspICB7XG4gICAgICB2YXIgdjIgPSBcInZcIiArIHBvbHkuZmFjZXNbaV1bal07ICAgICAgICAgICAgICAgICAgLy8gdGhpcyB2ZXJ0ZXhcbiAgICAgIGlmIChwb2x5LmZhY2VzW2ldLmxlbmd0aCA9PSBuIHx8IG49PTApIHsgICAgLy8ga2lzcyB0aGUgbidzLCBvciBhbGxcbiAgICAgICAgZm91bmRBbnkgPSB0cnVlOyAgICAgICAgICAgICAgICAvLyBmbGFnIHRoYXQgd2UgZm91bmQgc29tZVxuICAgICAgICByZXN1bHQubmV3VihcImZcIitpLCBjZW50ZXJzW2ldKTsgICAgICAgIC8vIG5ldyB2ZXJ0ZXggaW4gZmFjZSBjZW50ZXJcbiAgICAgICAgdmFyIGZuYW1lID0gaSArIHYxO1xuICAgICAgICByZXN1bHQubmV3RmxhZyhmbmFtZSwgdjEsIHYyKTsgICAgICAgICAvLyB0aHJlZSBuZXcgZmxhZ3MsIGlmIG4tc2lkZWRcbiAgICAgICAgcmVzdWx0Lm5ld0ZsYWcoZm5hbWUsIHYyLCBcImZcIitpKTtcbiAgICAgICAgcmVzdWx0Lm5ld0ZsYWcoZm5hbWUsIFwiZlwiK2ksIHYxKTtcbiAgICAgIH1cbiAgICAgIGVsc2VcbiAgICAgICAgcmVzdWx0Lm5ld0ZsYWcoaSwgdjEsIHYyKTsgICAgICAgICAgICAgLy8gc2FtZSBvbGQgZmxhZywgaWYgbm9uLW5cbiAgICAgIHYxID0gdjI7ICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY3VycmVudCBiZWNvbWVzIHByZXZpb3VzXG4gICAgfVxuICB9XG4gIHZhciBhbnMgPSByZXN1bHQuZmxhZ3MycG9seSgpO1xuICBhbnMubmFtZSA9IFwia1wiICsgKG49PT0wP1wiXCI6bikgKyBwb2x5Lm5hbWU7XG4gIGNhbm9uaWNhbGl6ZS5hZGp1c3Rwb3NpdGlvbnMoYW5zLCAzKTsgICAgICAgICAgICAgICAvLyBhZGp1c3QgYW5kXG4gIHJldHVybiAoYW5zKTtcbn1cbmV4cG9ydHMua2lzID0ga2lzO1xuXG5mdW5jdGlvbiBhbWJvKHBvbHkpIHsgICAgICAgICAgICAgICAgICAgICAgLy8gY29tcHV0ZSBhbWJvIG9mIGFyZ3VtZW50XG4gIHZhciByZXN1bHQgPSBuZXcgQXNzZW1ibGVyKCk7XG4gIGZvciAodmFyIGk9MDsgaTxwb2x5LmZhY2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIHYxID0gcG9seS5mYWNlc1tpXVtwb2x5LmZhY2VzW2ldLmxlbmd0aC0yXTsgIC8vIHByZXByZXZpb3VzIHZlcnRleFxuICAgIHZhciB2MiA9IHBvbHkuZmFjZXNbaV1bcG9seS5mYWNlc1tpXS5sZW5ndGgtMV07ICAvLyBwcmV2aW91cyB2ZXJ0ZXhcbiAgICBmb3IgKHZhciBqPTA7IGo8cG9seS5mYWNlc1tpXS5sZW5ndGg7IGorKykgIHtcbiAgICAgIHZhciB2MyA9IHBvbHkuZmFjZXNbaV1bal07ICAgICAgICAvLyB0aGlzIHZlcnRleFxuICAgICAgaWYgKHYxIDwgdjIpICAgICAgICAgICAgICAgICAgICAgLy8gbmV3IHZlcnRpY2VzIGF0IGVkZ2UgbWlkcG9pbnRzXG4gICAgICAgIHJlc3VsdC5uZXdWKG1pZE5hbWUodjEsdjIpLCB1dGlsLm1pZHBvaW50KHBvbHkucG9zaXRpb25zW3YxXSxwb2x5LnBvc2l0aW9uc1t2Ml0pKTtcbiAgICAgIHJlc3VsdC5uZXdGbGFnKFwiZlwiK2ksIG1pZE5hbWUodjEsdjIpLCBtaWROYW1lKHYyLHYzKSk7ICAgICAvLyB0d28gbmV3IGZsYWdzXG4gICAgICByZXN1bHQubmV3RmxhZyhcInZcIit2MiwgbWlkTmFtZSh2Mix2MyksIG1pZE5hbWUodjEsdjIpKTtcbiAgICAgIHYxID0gdjI7ICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNoaWZ0IG92ZXIgb25lXG4gICAgICB2MiA9IHYzO1xuICAgIH1cbiAgfVxuICB2YXIgYW5zID0gcmVzdWx0LmZsYWdzMnBvbHkoKTtcbiAgYW5zLm5hbWUgPSBcImFcIiArIHBvbHkubmFtZTtcbiAgY2Fub25pY2FsaXplLmFkanVzdHBvc2l0aW9ucyhhbnMsIDIpOyAgICAgICAgICAgICAvLyBjYW5vbmljYWxpemUgbGlnaHRseVxuICByZXR1cm4gKGFucyk7XG59XG5leHBvcnRzLmFtYm8gPSBhbWJvO1xuXG5mdW5jdGlvbiBtaWROYW1lKHYxLHYyKSB7ICAgICAgICAgICAgICAvLyB1bmlxdWUgc3ltYm9saWMgbmFtZSwgZS5nLiBcIjFfMlwiXG4gIGlmICh2MTx2MilcbiAgICByZXR1cm4gKHYxICsgXCJfXCIgKyB2Mik7XG4gIGVsc2VcbiAgICByZXR1cm4gKHYyICsgXCJfXCIgKyB2MSk7XG59XG5cbmZ1bmN0aW9uIGd5cm8ocG9seSkgeyAgICAgICAgICAgICAgICAgICAgICAvLyBjb21wdXRlIGd5cm8gb2YgYXJndW1lbnRcbiAgdmFyIHJlc3VsdCA9IG5ldyBBc3NlbWJsZXIoKTtcbiAgZm9yICh2YXIgaT0wOyBpPHBvbHkucG9zaXRpb25zLmxlbmd0aDsgaSsrKVxuICAgIHJlc3VsdC5uZXdWKFwidlwiK2ksIHV0aWwudW5pdChwb2x5LnBvc2l0aW9uc1tpXSkpOyAgICAgICAgICAgLy8gZWFjaCBvbGQgdmVydGV4IGlzIGEgbmV3IHZlcnRleFxuICB2YXIgY2VudGVycyA9IGNhbm9uaWNhbGl6ZS5mYWNlQ2VudGVycyhwb2x5KTsgICAgICAgICAgICAgIC8vIG5ldyB2ZXJ0aWNlcyBpbiBjZW50ZXIgb2YgZWFjaCBmYWNlXG4gIGZvciAodmFyIGk9MDsgaTxwb2x5LmZhY2VzLmxlbmd0aDsgaSsrKVxuICAgIHJlc3VsdC5uZXdWKFwiZlwiK2ksIHV0aWwudW5pdChjZW50ZXJzW2ldKSk7XG4gIGZvciAodmFyIGk9MDsgaTxwb2x5LmZhY2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIHYxID0gcG9seS5mYWNlc1tpXVtwb2x5LmZhY2VzW2ldLmxlbmd0aC0yXTsgIC8vIHByZXByZXZpb3VzIHZlcnRleFxuICAgIHZhciB2MiA9IHBvbHkuZmFjZXNbaV1bcG9seS5mYWNlc1tpXS5sZW5ndGgtMV07ICAvLyBwcmV2aW91cyB2ZXJ0ZXhcbiAgICBmb3IgKHZhciBqPTA7IGo8cG9seS5mYWNlc1tpXS5sZW5ndGg7IGorKykgIHtcbiAgICAgIHZhciB2MyA9IHBvbHkuZmFjZXNbaV1bal07ICAgICAgICAgICAgICAgICAgLy8gdGhpcyB2ZXJ0ZXhcbiAgICAgIHJlc3VsdC5uZXdWKHYxK1wiflwiK3YyLCB1dGlsLm9uZVRoaXJkKHBvbHkucG9zaXRpb25zW3YxXSxwb2x5LnBvc2l0aW9uc1t2Ml0pKTsgIC8vIG5ldyB2IGluIGZhY2VcbiAgICAgIHZhciBmbmFtZSA9IGkgKyBcImZcIiArIHYxO1xuICAgICAgcmVzdWx0Lm5ld0ZsYWcoZm5hbWUsIFwiZlwiK2ksIHYxK1wiflwiK3YyKTsgICAgICAgICAgLy8gZml2ZSBuZXcgZmxhZ3NcbiAgICAgIHJlc3VsdC5uZXdGbGFnKGZuYW1lLCB2MStcIn5cIit2MiwgdjIrXCJ+XCIrdjEpO1xuICAgICAgcmVzdWx0Lm5ld0ZsYWcoZm5hbWUsIHYyK1wiflwiK3YxLCBcInZcIit2Mik7XG4gICAgICByZXN1bHQubmV3RmxhZyhmbmFtZSwgXCJ2XCIrdjIsIHYyK1wiflwiK3YzKTtcbiAgICAgIHJlc3VsdC5uZXdGbGFnKGZuYW1lLCB2MitcIn5cIit2MywgXCJmXCIraSk7XG4gICAgICB2MSA9IHYyOyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gc2hpZnQgb3ZlciBvbmVcbiAgICAgIHYyID0gdjM7XG4gICAgfVxuICB9XG4gIHZhciBhbnMgPSByZXN1bHQuZmxhZ3MycG9seSgpO1xuICBhbnMubmFtZSA9IFwiZ1wiICsgcG9seS5uYW1lO1xuICBjYW5vbmljYWxpemUuYWRqdXN0cG9zaXRpb25zKGFucywgMyk7ICAgICAgICAgICAgICAgICAgICAgICAvLyBjYW5vbmljYWxpemUgbGlnaHRseVxuICByZXR1cm4gKGFucyk7XG59XG5leHBvcnRzLmd5cm8gPSBneXJvO1xuXG5mdW5jdGlvbiBwcm9wZWxsb3IocG9seSkgeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY29tcHV0ZSBwcm9wZWxsb3Igb2YgYXJndW1lbnRcbiAgdmFyIHJlc3VsdCA9IG5ldyBBc3NlbWJsZXIoKTtcbiAgZm9yICh2YXIgaT0wOyBpPHBvbHkucG9zaXRpb25zLmxlbmd0aDsgaSsrKVxuICAgIHJlc3VsdC5uZXdWKFwidlwiK2ksIHV0aWwudW5pdChwb2x5LnBvc2l0aW9uc1tpXSkpOyAgICAgICAgICAgLy8gZWFjaCBvbGQgdmVydGV4IGlzIGEgbmV3IHZlcnRleFxuICBmb3IgKHZhciBpPTA7IGk8cG9seS5mYWNlcy5sZW5ndGg7IGkrKykge1xuICAgIHZhciB2MSA9IHBvbHkuZmFjZXNbaV1bcG9seS5mYWNlc1tpXS5sZW5ndGgtMl07ICAvLyBwcmVwcmV2aW91cyB2ZXJ0ZXhcbiAgICB2YXIgdjIgPSBwb2x5LmZhY2VzW2ldW3BvbHkuZmFjZXNbaV0ubGVuZ3RoLTFdOyAgLy8gcHJldmlvdXMgdmVydGV4XG4gICAgZm9yICh2YXIgaj0wOyBqPHBvbHkuZmFjZXNbaV0ubGVuZ3RoOyBqKyspICB7XG4gICAgICB2YXIgdjMgPSBwb2x5LmZhY2VzW2ldW2pdOyAgICAgICAgICAgICAgICAgIC8vIHRoaXMgdmVydGV4XG4gICAgICByZXN1bHQubmV3Vih2MStcIn5cIit2MiwgdXRpbC5vbmVUaGlyZChwb2x5LnBvc2l0aW9uc1t2MV0scG9seS5wb3NpdGlvbnNbdjJdKSk7ICAvLyBuZXcgdiBpbiBmYWNlXG4gICAgICB2YXIgZm5hbWUgPSBpICsgXCJmXCIgKyB2MjtcbiAgICAgIHJlc3VsdC5uZXdGbGFnKFwidlwiK2ksIHYxK1wiflwiK3YyLCB2MitcIn5cIit2Myk7ICAgICAgLy8gZml2ZSBuZXcgZmxhZ3NcbiAgICAgIHJlc3VsdC5uZXdGbGFnKGZuYW1lLCB2MStcIn5cIit2MiwgdjIrXCJ+XCIrdjEpO1xuICAgICAgcmVzdWx0Lm5ld0ZsYWcoZm5hbWUsIHYyK1wiflwiK3YxLCBcInZcIit2Mik7XG4gICAgICByZXN1bHQubmV3RmxhZyhmbmFtZSwgXCJ2XCIrdjIsIHYyK1wiflwiK3YzKTtcbiAgICAgIHJlc3VsdC5uZXdGbGFnKGZuYW1lLCB2MitcIn5cIit2MywgdjErXCJ+XCIrdjIpO1xuICAgICAgdjEgPSB2MjsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNoaWZ0IG92ZXIgb25lXG4gICAgICB2MiA9IHYzO1xuICAgIH1cbiAgfVxuICB2YXIgYW5zID0gcmVzdWx0LmZsYWdzMnBvbHkoKTtcbiAgYW5zLm5hbWUgPSBcInBcIiArIHBvbHkubmFtZTtcbiAgY2Fub25pY2FsaXplLmFkanVzdHBvc2l0aW9ucyhhbnMsIDMpOyAgICAgICAgICAgICAgICAgICAgICAgLy8gY2Fub25pY2FsaXplIGxpZ2h0bHlcbiAgcmV0dXJuIChhbnMpO1xufVxuZXhwb3J0cy5wcm9wZWxsb3IgPSBwcm9wZWxsb3I7XG5cbmZ1bmN0aW9uIHJlZmxlY3QocG9seSkgeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNvbXB1dGUgcmVmbGVjdGlvbiB0aHJvdWdoIG9yaWdpblxuICBwb2x5ID0gdXRpbC5jbG9uZShwb2x5KTtcbiAgZm9yICh2YXIgaT0wOyBpPHBvbHkucG9zaXRpb25zLmxlbmd0aDsgaSsrKVxuICAgIHBvbHkucG9zaXRpb25zW2ldID0gdXRpbC5tdWx0KC0xLCBwb2x5LnBvc2l0aW9uc1tpXSk7ICAgICAgICAgICAvLyByZWZsZWN0IGVhY2ggcG9pbnRcbiAgZm9yICh2YXIgaT0wOyBpPHBvbHkuZmFjZXMubGVuZ3RoOyBpKyspXG4gICAgcG9seS5mYWNlc1tpXSA9IHBvbHkuZmFjZXNbaV0ucmV2ZXJzZSgpOyAgICAgICAgIC8vIHJlcGFpciBjbG9ja3dpc2UtbmVzc1xuICBwb2x5Lm5hbWUgPSBcInJcIiArIHBvbHkubmFtZTtcbiAgY2Fub25pY2FsaXplLmFkanVzdHBvc2l0aW9ucyhwb2x5LCAxKTsgICAgICAgICAgICAgICAgICAgICAvLyBidWlsZCBkdWFsXG4gIHJldHVybiAocG9seSk7XG59XG5leHBvcnRzLnJlZmxlY3QgPSByZWZsZWN0O1xuXG5cbmV4cG9ydHMuZXhwYW5kID0gZnVuY3Rpb24ocG9seSkge1xuICByZXR1cm4gYW1ibyhhbWJvKHBvbHkpKTtcbn1cblxuZXhwb3J0cy5iZXZlbCA9IGZ1bmN0aW9uKHBvbHkpIHtcbiAgcmV0dXJuIHRydW5jYXRlKGFtYm8ocG9seSkpO1xufVxuXG5leHBvcnRzLm9ydGhvID0gZnVuY3Rpb24ocG9seSkge1xuICByZXR1cm4gam9pbihqb2luKHBvbHkpKTtcbn1cblxuZXhwb3J0cy5tZXRhID0gZnVuY3Rpb24ocG9seSkge1xuICByZXR1cm4ga2lzKGpvaW4ocG9seSkpO1xufVxuXG5leHBvcnRzLnRydW5jYXRlID0gZnVuY3Rpb24ocG9seSwgbikge1xuICByZXR1cm4gZHVhbChraXMoZHVhbChwb2x5KSwgbikpO1xufVxuXG5leHBvcnRzLmpvaW4gPSBmdW5jdGlvbihwb2x5KSB7XG4gIHJldHVybiBkdWFsKGFtYm8oZHVhbChwb2x5KSkpO1xufVxuXG5leHBvcnRzLnNwbGl0ID0gZnVuY3Rpb24ocG9seSkge1xuICByZXR1cm4gZHVhbChneXJvKGR1YWwocG9seSkpKTtcbn1cbiIsIlwidXNlIHN0cmljdFwiO1xuXG52YXIgdXRpbCAgICAgICAgICA9IHJlcXVpcmUoXCIuL3V0aWwuanNcIik7XG52YXIgY2Fub25pY2FsaXplICA9IHJlcXVpcmUoXCIuL2Nhbm9uaWNhbGl6ZS5qc1wiKTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIHRldHJhaGVkcm9uOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4ge1xuICAgICAgbmFtZTogICAgICAgXCJUXCIsXG4gICAgICBmYWNlczogICAgICBbIFswLDEsMl0sIFswLDIsM10sIFswLDMsMV0sIFsxLDMsMl0gXSxcbiAgICAgIHBvc2l0aW9uczogIFsgWzEuLDEuLDEuXSwgWzEuLC0xLiwtMS5dLCBbLTEuLDEuLC0xLl0sIFstMS4sLTEuLDEuXSBdXG4gICAgfTtcbiAgfSxcbiAgb2N0YWhlZHJvbjogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG5hbWU6ICAgICAgIFwiT1wiLFxuICAgICAgZmFjZXM6ICAgICAgWyBbMCwxLDJdLCBbMCwyLDNdLCBbMCwzLDRdLCBbMCw0LDFdLCBbMSw0LDVdLCBbMSw1LDJdLCBbMiw1LDNdLCBbMyw1LDRdIF0sXG4gICAgICBwb3NpdGlvbnM6ICBbIFswLDAsMS40MTRdLCBbMS40MTQsMCwwXSwgWzAsMS40MTQsMF0sIFstMS40MTQsMCwwXSwgWzAsLTEuNDE0LDBdLCBbMCwwLC0xLjQxNF0gXVxuICAgIH07XG4gIH0sXG4gIGN1YmU6IGZ1bmN0aW9uKCkge1xuICAgIHJldHVybiB7XG4gICAgICBuYW1lOiAgICAgICBcIkNcIixcbiAgICAgIGZhY2VzOiAgICAgIFsgWzMsMCwxLDJdLCBbMyw0LDUsMF0sIFswLDUsNiwxXSwgWzEsNiw3LDJdLCBbMiw3LDQsM10sIFs1LDQsNyw2XSBdLFxuICAgICAgcG9zaXRpb25zOiAgWyBbIDAuNzA3LCAwLjcwNywwLjcwN10sIFstMC43MDcsMC43MDcsMC43MDddLFxuICAgICAgICAgICAgICAgICAgICBbLTAuNzA3LC0wLjcwNywwLjcwN10sIFswLjcwNywtMC43MDcsMC43MDddLFxuICAgICAgICAgICAgICAgICAgICBbMC43MDcsLTAuNzA3LC0wLjcwN10sIFswLjcwNywwLjcwNywtMC43MDddLFxuICAgICAgICAgICAgICAgICAgICBbLTAuNzA3LDAuNzA3LC0wLjcwN10sIFstMC43MDcsLTAuNzA3LC0wLjcwN10gXVxuICAgIH07XG4gIH0sXG4gIGljb3NhaGVkcm9uOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4ge1xuICAgICAgbmFtZTogICAgICAgXCJJXCIsXG4gICAgICBmYWNlczogICAgICBbIFswLDEsMl0sICBbMCwyLDNdLCAgIFswLDMsNF0sICBbMCw0LDVdLFxuICAgICAgICAgICAgICAgICAgICBbMCw1LDFdLCAgWzEsNSw3XSwgICBbMSw3LDZdLCAgWzEsNiwyXSxcbiAgICAgICAgICAgICAgICAgICAgWzIsNiw4XSwgIFsyLDgsM10sICAgWzMsOCw5XSwgIFszLDksNF0sXG4gICAgICAgICAgICAgICAgICAgIFs0LDksMTBdLCBbNCwxMCw1XSwgIFs1LDEwLDddLCBbNiw3LDExXSxcbiAgICAgICAgICAgICAgICAgICAgWzYsMTEsOF0sIFs3LDEwLDExXSwgWzgsMTEsOV0sIFs5LDExLDEwXSBdLFxuICAgICAgcG9zaXRpb25zOiAgWyBbMCwwLDEuMTc2XSwgICAgICAgICAgICBbMS4wNTEsMCwwLjUyNl0sXG4gICAgICAgICAgICAgICAgICAgIFswLjMyNCwxLiwwLjUyNV0sICAgICAgIFstMC44NTEsMC42MTgsMC41MjZdLFxuICAgICAgICAgICAgICAgICAgICBbLTAuODUxLC0wLjYxOCwwLjUyNl0sICBbMC4zMjUsLTEuLDAuNTI2XSxcbiAgICAgICAgICAgICAgICAgICAgWzAuODUxLDAuNjE4LC0wLjUyNl0sICAgWzAuODUxLC0wLjYxOCwtMC41MjZdLFxuICAgICAgICAgICAgICAgICAgICBbLTAuMzI1LDEuLC0wLjUyNl0sICAgICBbLTEuMDUxLDAsLTAuNTI2XSxcbiAgICAgICAgICAgICAgICAgICAgWy0wLjMyNSwtMS4sLTAuNTI2XSwgICAgWzAsMCwtMS4xNzZdIF1cblxuICAgIH07XG4gIH0sXG4gIGRvZGVjYWhlZHJvbjogZnVuY3Rpb24oKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG5hbWU6ICAgICAgIFwiRFwiLFxuICAgICAgZmFjZXM6ICAgICAgWyBbMCwxLDQsNywyXSwgICAgICBbMCwyLDYsOSwzXSwgICAgICBbMCwzLDgsNSwxXSxcbiAgICAgICAgICAgICAgICAgICAgWzEsNSwxMSwxMCw0XSwgICAgWzIsNywxMywxMiw2XSwgICAgWzMsOSwxNSwxNCw4XSxcbiAgICAgICAgICAgICAgICAgICAgWzQsMTAsMTYsMTMsN10sICAgWzUsOCwxNCwxNywxMV0sICAgWzYsMTIsMTgsMTUsOV0sXG4gICAgICAgICAgICAgICAgICAgIFsxMCwxMSwxNywxOSwxNl0sIFsxMiwxMywxNiwxOSwxOF0sIFsxNCwxNSwxOCwxOSwxN10gXSxcbiAgICAgIHBvc2l0aW9uczogIFsgWzAsMCwxLjA3MDQ3XSwgWzAuNzEzNjQ0LDAsMC43OTc4NzhdLFxuICAgICAgICAgICAgICAgICAgICBbLTAuMzU2ODIyLDAuNjE4LDAuNzk3ODc4XSwgWy0wLjM1NjgyMiwtMC42MTgsMC43OTc4NzhdLFxuICAgICAgICAgICAgICAgICAgICBbMC43OTc4NzgsMC42MTgwMzQsMC4zNTY4MjJdLCBbMC43OTc4NzgsLTAuNjE4LDAuMzU2ODIyXSxcbiAgICAgICAgICAgICAgICAgICAgWy0wLjkzNDE3MiwwLjM4MTk2NiwwLjM1NjgyMl0sIFswLjEzNjI5NCwxLiwwLjM1NjgyMl0sXG4gICAgICAgICAgICAgICAgICAgIFswLjEzNjI5NCwtMS4sMC4zNTY4MjJdLCBbLTAuOTM0MTcyLC0wLjM4MTk2NiwwLjM1NjgyMl0sXG4gICAgICAgICAgICAgICAgICAgIFswLjkzNDE3MiwwLjM4MTk2NiwtMC4zNTY4MjJdLCBbMC45MzQxNzIsLTAuMzgxOTY2LC0wLjM1NjgyMl0sXG4gICAgICAgICAgICAgICAgICAgIFstMC43OTc4NzgsMC42MTgsLTAuMzU2ODIyXSwgWy0wLjEzNjI5NCwxLiwtMC4zNTY4MjJdLFxuICAgICAgICAgICAgICAgICAgICBbLTAuMTM2Mjk0LC0xLiwtMC4zNTY4MjJdLCBbLTAuNzk3ODc4LC0wLjYxODAzNCwtMC4zNTY4MjJdLFxuICAgICAgICAgICAgICAgICAgICBbMC4zNTY4MjIsMC42MTgsLTAuNzk3ODc4XSwgWzAuMzU2ODIyLC0wLjYxOCwtMC43OTc4NzhdLFxuICAgICAgICAgICAgICAgICAgICBbLTAuNzEzNjQ0LDAsLTAuNzk3ODc4XSwgWzAsMCwtMS4wNzA0N10gXVxuICAgIH07XG4gIH0sXG4gIHByaXNtOiBmdW5jdGlvbihuKSB7XG4gICAgdmFyIHRoZXRhICAgICA9IE1hdGguUEkgKiAyLjAgLyBuO1xuICAgIHZhciBoICAgICAgICAgPSBNYXRoLnNpbih0aGV0YS8yKTtcbiAgICB2YXIgcG9zaXRpb25zID0gW107XG4gICAgZm9yICh2YXIgaT0wOyBpPG47IGkrKykge1xuICAgICAgcG9zaXRpb25zLnB1c2goW01hdGguY29zKGkqdGhldGEpLCBNYXRoLnNpbihpKnRoZXRhKSwgaF0pO1xuICAgIH1cbiAgICBmb3IgKHZhciBpPTA7IGk8bjsgaSsrKSB7XG4gICAgICBwb3NpdGlvbnMucHVzaChbTWF0aC5jb3MoaSp0aGV0YSksIE1hdGguc2luKGkqdGhldGEpLC1oXSk7XG4gICAgfVxuICAgIHZhciBmYWNlcyAgICAgPSBbIHV0aWwuc2VxdWVuY2Uobi0xLCAwKSwgdXRpbC5zZXF1ZW5jZShuLCAyKm4tMSkgXTtcbiAgICBmb3IodmFyIGk9MDsgaTxuOyArK2kpIHtcbiAgICAgIGZhY2VzLnB1c2goW2ksIChpKzEpJW4sIChpKzEpJW4rbiwgaStuXSk7XG4gICAgfVxuICAgIHZhciByZXN1bHQgPSB7XG4gICAgICBuYW1lOiAgICAgICBcIlBcIiArIG4sXG4gICAgICBwb3NpdGlvbnM6ICBwb3NpdGlvbnMsXG4gICAgICBmYWNlczogICAgICBmYWNlc1xuICAgIH07XG4gICAgY2Fub25pY2FsaXplLmFkanVzdHBvc2l0aW9ucyhyZXN1bHQsIDEpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH0sXG4gIGFudGlwcmlzbTogZnVuY3Rpb24obikge1xuICAgIHZhciB0aGV0YSA9IE1hdGguUEkgKiAyLjAgLyBuO1xuICAgIHZhciBoID0gTWF0aC5zcXJ0KDEtNC8oNCsyKk1hdGguY29zKHRoZXRhLzIpLTIqTWF0aC5jb3ModGhldGEpKSk7XG4gICAgdmFyIHIgPSBNYXRoLnNxcnQoMS1oKmgpO1xuICAgIHZhciBmID0gTWF0aC5zcXJ0KGgqaCArIE1hdGgucG93KHIqTWF0aC5jb3ModGhldGEvMiksIDIpKTsgXG4gICAgcj1yL2Y7XG4gICAgaD1oL2Y7XG4gICAgdmFyIHBvc2l0aW9ucyA9IFtdO1xuICAgIGZvciAodmFyIGk9MDsgaTxuOyBpKyspIHtcbiAgICAgIHBvc2l0aW9ucy5wdXNoKFtyKk1hdGguY29zKGkqdGhldGEpLCByKk1hdGguc2luKGkqdGhldGEpLCBoXSk7XG4gICAgfVxuICAgIGZvciAodmFyIGk9MDsgaTxuOyBpKyspIHtcbiAgICAgIHBvc2l0aW9ucy5wdXNoKFtyKk1hdGguY29zKChpKzAuNSkqdGhldGEpLCByKk1hdGguc2luKChpKzAuNSkqdGhldGEpLCAtaF0pO1xuICAgIH1cbiAgICB2YXIgZmFjZXMgPSBbIHV0aWwuc2VxdWVuY2Uobi0xLCAwKSwgdXRpbC5zZXF1ZW5jZShuLCAyKm4tMSkgXVxuICAgIGZvciAodmFyIGk9MDsgaTxuOyBpKyspIHtcbiAgICAgIGZhY2VzLnB1c2goW2ksIChpKzEpJW4sIGkrbl0pO1xuICAgICAgZmFjZXMucHVzaChbaSwgaStuLCAgICAgKChuK2ktMSklbituKV0pO1xuICAgIH1cbiAgICB2YXIgcmVzdWx0ID0ge1xuICAgICAgbmFtZTogICAgICAgICBcIkFcIiArIG4sXG4gICAgICBwb3NpdGlvbnM6ICAgIHBvc2l0aW9ucyxcbiAgICAgIGZhY2VzOiAgICAgICAgZmFjZXNcbiAgICB9O1xuICAgIGNhbm9uaWNhbGl6ZS5hZGp1c3Rwb3NpdGlvbnMocmVzdWx0LCAxKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9LFxuICBweXJhbWlkOiBmdW5jdGlvbihuKSB7XG4gICAgdmFyIHRoZXRhID0gTWF0aC5QSSAqIDIuMCAvIG47XG4gICAgdmFyIHBvc2l0aW9ucyA9IFtdO1xuICAgIGZvcih2YXIgaT0wOyBpPG47ICsraSkge1xuICAgICAgcG9zaXRpb25zLnB1c2goW01hdGguY29zKGkqdGhldGEpLCBNYXRoLnNpbihpKnRoZXRhKSwgLjJdKTtcbiAgICB9XG4gICAgcG9zaXRpb25zLnB1c2goWzAsIDAsIC0yXSk7XG4gICAgdmFyIGZhY2VzID0gWyB1dGlsLnNlcXVlbmNlKG4tMSwgMCkgXTtcbiAgICBmb3IgKHZhciBpPTA7IGk8bjsgKytpKSB7XG4gICAgICBmYWNlcy5wdXNoKFtpLCAoaSsxKSVuLCBuXSk7XG4gICAgfVxuICAgIHZhciByZXN1bHQgPSB7XG4gICAgICBuYW1lOiAgICAgICBcIllcIiArIG4sXG4gICAgICBwb3NpdGlvbnM6ICBwb3NpdGlvbnMsXG4gICAgICBmYWNlczogICAgICBmYWNlc1xuICAgIH07XG4gICAgY2Fub25pY2FsaXplLmNhbm9uaWNhbHBvc2l0aW9ucyhyZXN1bHQsIDMpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbn1cbiIsIlwidXNlIHN0cmljdFwiO1xuXG5mdW5jdGlvbiBjbG9uZShwb2x5KSB7XG4gIHZhciBucG9zaXRpb25zID0gbmV3IEFycmF5KHBvbHkucG9zaXRpb25zLmxlbmd0aCk7XG4gIGZvcih2YXIgaT0wOyBpPHBvbHkucG9zaXRpb25zLmxlbmd0aDsgKytpKSB7XG4gICAgbnBvc2l0aW9uc1tpXSA9IHBvbHkucG9zaXRpb25zW2ldLnNsaWNlKDApO1xuICB9XG4gIHZhciBuZmFjZXMgPSBbXTtcbiAgZm9yKHZhciBpPTA7IGk8cG9seS5mYWNlcy5sZW5ndGg7ICsraSkge1xuICAgIG5mYWNlc1tpXSA9IHBvbHkuZmFjZXNbaV0uc2xpY2UoMCk7XG4gIH1cbiAgcmV0dXJuIHtcbiAgICBuYW1lOiBwb2x5Lm5hbWUuc2xpY2UoMCksXG4gICAgcG9zaXRpb25zOiBucG9zaXRpb25zLFxuICAgIGZhY2VzOiBuZmFjZXNcbiAgfVxufVxuZXhwb3J0cy5jbG9uZSA9IGNsb25lO1xuXG5mdW5jdGlvbiBpbnRlcnNlY3Qoc2V0MSwgc2V0Miwgc2V0MykgeyAgLy8gZmluZCBlbGVtZW50IGNvbW1vbiB0byAzIHNldHNcbiAgZm9yICh2YXIgaT0wOyBpPHNldDEubGVuZ3RoOyBpKyspIHsgICAgLy8gYnkgYnJ1dGUgZm9yY2Ugc2VhcmNoXG4gICAgZm9yICh2YXIgaj0wOyBqPHNldDIubGVuZ3RoOyBqKyspIHtcbiAgICAgIGlmIChzZXQxW2ldPT09c2V0MltqXSkge1xuICAgICAgICBmb3IgKHZhciBrPTA7IGs8c2V0My5sZW5ndGg7IGsrKykge1xuICAgICAgICAgIGlmIChzZXQxW2ldPT09c2V0M1trXSkge1xuICAgICAgICAgICAgcmV0dXJuIHNldDFbaV07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHRocm93IG5ldyBFcnJvcihcInByb2dyYW0gYnVnIGluIGludGVyc2VjdCgpXCIpO1xuICByZXR1cm4gbnVsbDtcbn1cbmV4cG9ydHMuaW50ZXJzZWN0ID0gaW50ZXJzZWN0O1xuXG5mdW5jdGlvbiBzZXF1ZW5jZShzdGFydCwgc3RvcCkgeyAgICAvLyBtYWtlIGxpc3Qgb2YgaW50ZWdlcnMsIGluY2x1c2l2ZVxuICB2YXIgYW5zID0gbmV3IEFycmF5KCk7XG4gIGlmIChzdGFydCA8PSBzdG9wKSB7XG4gICAgZm9yICh2YXIgaT1zdGFydDsgaTw9c3RvcDsgaSsrKSB7XG4gICAgICBhbnMucHVzaChpKTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgZm9yICh2YXIgaT1zdGFydDsgaT49c3RvcDsgaS0tKSB7XG4gICAgICBhbnMucHVzaChpKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGFucztcbn1cbmV4cG9ydHMuc2VxdWVuY2UgPSBzZXF1ZW5jZTtcblxuZnVuY3Rpb24gb3J0aG9nb25hbCh2MywgdjIsIHYxKSB7ICAgLy8gZmluZCB1bml0IHZlY3RvciBvcnRob2cgdG8gcGxhbmUgb2YgMyBwdHNcbiAgdmFyIGQxID0gc3ViKHYyLCB2MSk7ICAgICAgICAgICAgLy8gYWRqYWNlbnQgZWRnZSB2ZWN0b3JzXG4gIHZhciBkMiA9IHN1Yih2MywgdjIpO1xuICByZXR1cm4gWyAgZDFbMV0qZDJbMl0gLSBkMVsyXSpkMlsxXSwgICAgLy8gY3Jvc3MgcHJvZHVjdFxuICAgICAgICAgICAgZDFbMl0qZDJbMF0gLSBkMVswXSpkMlsyXSxcbiAgICAgICAgICAgIGQxWzBdKmQyWzFdIC0gZDFbMV0qZDJbMF0gXVxufVxuZXhwb3J0cy5vcnRob2dvbmFsID0gb3J0aG9nb25hbDtcblxuZnVuY3Rpb24gbWFnMih2ZWMpIHsgICAgICAgICAgLy8gbWFnbml0dWRlIHNxdWFyZWQgb2YgMy12ZWN0b3JcbiAgcmV0dXJuIHZlY1swXSp2ZWNbMF0gKyB2ZWNbMV0qdmVjWzFdICsgdmVjWzJdKnZlY1syXTtcbn1cbmV4cG9ydHMubWFnMiA9IG1hZzI7XG5cbmZ1bmN0aW9uIHRhbmdlbnRQb2ludCh2MSwgdjIpIHsgICAgLy8gcG9pbnQgd2hlcmUgbGluZSB2MS4uLnYyIHRhbmdlbnQgdG8gYW4gb3JpZ2luIHNwaGVyZVxuICB2YXIgZCA9IHN1Yih2Mix2MSk7ICAgICAgICAgICAgIC8vIGRpZmZlcmVuY2UgdmVjdG9yXG4gIGNvbnNvbGUubG9nKGQpO1xuICByZXR1cm4oc3ViKHYxLCBtdWx0KGRvdChkLHYxKS9tYWcyKGQpLCBkKSkpO1xufVxuZXhwb3J0cy50YW5nZW50UG9pbnQgPSB0YW5nZW50UG9pbnQ7XG5cbmZ1bmN0aW9uIGVkZ2VEaXN0KHYxLCB2MikgeyAgICAgICAgIC8vIGRpc3RhbmNlIG9mIGxpbmUgdjEuLi52MiB0byBvcmlnaW5cbiAgcmV0dXJuKE1hdGguc3FydChtYWcyKHRhbmdlbnRQb2ludCh2MSwgdjIpKSkpO1xufVxuZXhwb3J0cy5lZGdlRGlzdCA9IGVkZ2VEaXN0O1xuXG5mdW5jdGlvbiB2ZWNaZXJvKCkge1xuICByZXR1cm4gWzAuMCwwLjAsMC4wXTtcbn1cbmV4cG9ydHMudmVjWmVybyA9IHZlY1plcm87XG5cbmZ1bmN0aW9uIG11bHQoYywgdmVjKSB7ICAgICAgIC8vIGMgdGltZXMgMy12ZWN0b3JcbiAgcmV0dXJuIFsgYyp2ZWNbMF0sXG4gICAgICAgICAgIGMqdmVjWzFdLFxuICAgICAgICAgICBjKnZlY1syXSBdO1xufVxuZXhwb3J0cy5tdWx0ID0gbXVsdDtcblxuZnVuY3Rpb24gYWRkKHZlYzEsIHZlYzIpIHsgICAgLy8gc3VtIHR3byAzLXZlY3RvcnNcbiAgcmV0dXJuIFsgIHZlYzFbMF0rdmVjMlswXSxcbiAgICAgICAgICAgIHZlYzFbMV0rdmVjMlsxXSxcbiAgICAgICAgICAgIHZlYzFbMl0rdmVjMlsyXSBdO1xufVxuZXhwb3J0cy5hZGQgPSBhZGQ7XG5cbmZ1bmN0aW9uIHN1Yih2ZWMxLCB2ZWMyKSB7ICAgIC8vIHN1YnRyYWN0IHR3byAzLXZlY3RvcnNcbiAgcmV0dXJuIFsgIHZlYzFbMF0tdmVjMlswXSxcbiAgICAgICAgICAgIHZlYzFbMV0tdmVjMlsxXSxcbiAgICAgICAgICAgIHZlYzFbMl0tdmVjMlsyXSBdXG59XG5leHBvcnRzLnN1YiA9IHN1YjtcblxuZnVuY3Rpb24gZG90KHZlYzEsIHZlYzIpIHsgICAgLy8gZG90IHByb2R1Y3QgdHdvIDMtdmVjdG9yc1xuICByZXR1cm4gKHZlYzFbMF0qdmVjMlswXSArIHZlYzFbMV0qdmVjMlsxXSArIHZlYzFbMl0qdmVjMlsyXSk7XG59XG5leHBvcnRzLmRvdCA9IGRvdDtcblxuZnVuY3Rpb24gbWlkcG9pbnQodmVjMSwgdmVjMikgeyAgICAvLyBtZWFuIG9mIHR3byAzLXZlY3RvcnNcbiAgcmV0dXJuIFsgIDAuNSoodmVjMVswXSArIHZlYzJbMF0pLFxuICAgICAgICAgICAgMC41Kih2ZWMxWzFdICsgdmVjMlsxXSksXG4gICAgICAgICAgICAwLjUqKHZlYzFbMl0gKyB2ZWMyWzJdKSBdXG59XG5leHBvcnRzLm1pZHBvaW50ID0gbWlkcG9pbnQ7XG5cbmZ1bmN0aW9uIG9uZVRoaXJkKHZlYzEsIHZlYzIpIHsgICAgLy8gYXBwcm94LiAoMi8zKXYxICsgKDEvMyl2MiAgIChhc3N1bWVzIDMtdmVjdG9yKVxuICByZXR1cm4gWyAgMC43KnZlYzFbMF0gKyAwLjMqdmVjMlswXSxcbiAgICAgICAgICAgIDAuNyp2ZWMxWzFdICsgMC4zKnZlYzJbMV0sXG4gICAgICAgICAgICAwLjcqdmVjMVsyXSArIDAuMyp2ZWMyWzJdIF1cbiAgcmV0dXJuIGFucztcbn1cbmV4cG9ydHMub25lVGhpcmQgPSBvbmVUaGlyZDtcblxuZnVuY3Rpb24gcmVjaXByb2NhbCh2ZWMpIHsgICAgLy8gcmVmbGVjdCAzLXZlY3RvciBpbiB1bml0IHNwaGVyZVxuICB2YXIgZmFjdG9yID0gMS4vbWFnMih2ZWMpO1xuICByZXR1cm4gWyAgZmFjdG9yKnZlY1swXSxcbiAgICAgICAgICAgIGZhY3Rvcip2ZWNbMV0sXG4gICAgICAgICAgICBmYWN0b3IqdmVjWzJdIF1cbn1cbmV4cG9ydHMucmVjaXByb2NhbCA9IHJlY2lwcm9jYWw7XG5cbmZ1bmN0aW9uIHVuaXQodmVjKSB7ICAgICAgICAgIC8vIG5vcm1hbGl6ZSAzLXZlY3RvciB0byB1bml0IG1hZ25pdHVkZVxuICB2YXIgc2l6ZSA9IG1hZzIodmVjKTtcbiAgaWYgKHNpemUgPD0gMWUtOCkgeyAgICAgICAgICAvLyByZW1vdmUgdGhpcyB0ZXN0IHNvbWVkYXkuLi5cbiAgICByZXR1cm4gKHZlYyk7XG4gIH1cbiAgdmFyIGMgPSAxLi9NYXRoLnNxcnQoc2l6ZSk7XG4gIHJldHVybiBtdWx0KGMsIHZlYyk7XG59XG5leHBvcnRzLnVuaXQgPSB1bml0O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbi8vSW1wb3J0IG9wZXJhdG9yc1xudmFyIHNlZWRzID0gcmVxdWlyZShcIi4vbGliL3NlZWRzLmpzXCIpO1xudmFyIG9wZXJhdG9ycyA9IHJlcXVpcmUoXCIuL2xpYi9vcGVyYXRvcnMuanNcIik7XG5cbi8vU2VlZCB0eXBlc1xudmFyIFNFRURfRlVOQ1MgPSB7XG4gIFwiVFwiOiAgc2VlZHMudGV0cmFoZWRyb24sXG4gIFwiT1wiOiAgc2VlZHMub2N0YWhlZHJvbixcbiAgXCJDXCI6ICBzZWVkcy5jdWJlLFxuICBcIklcIjogIHNlZWRzLmljb3NhaGVkcm9uLFxuICBcIkRcIjogIHNlZWRzLmRvZGVjYWhlZHJvbixcbiAgXCJQXCI6ICBzZWVkcy5wcmlzbSxcbiAgXCJBXCI6ICBzZWVkcy5hbnRpcHJpc20sXG4gIFwiWVwiOiAgc2VlZHMucHlyYW1pZFxufTtcblxuLy9PcGVyYXRvciB0eXBlc1xudmFyIE9QRVJBVE9SX0ZVTkNTID0ge1xuICBcImtcIjogIG9wZXJhdG9ycy5raXMsXG4gIFwiYVwiOiAgb3BlcmF0b3JzLmFtYm8sXG4gIFwiZ1wiOiAgb3BlcmF0b3JzLmd5cm8sXG4gIFwicFwiOiAgb3BlcmF0b3JzLnByb3BlbGxvcixcbiAgXCJkXCI6ICBvcGVyYXRvcnMuZHVhbCxcbiAgXCJyXCI6ICBvcGVyYXRvcnMucmVmbGVjdCxcbiAgXCJjXCI6ICBvcGVyYXRvcnMuY2Fub25pY2FsaXplXG59O1xuXG4vL0NoZWNrcyBpZiBhIHNlZWQgaXMgYSB0b2tlblxuZnVuY3Rpb24gaXNUb2tlbihjKSB7XG4gIHJldHVybiBcImthZ3BkY3JUT0NJRFBBWVwiLmluZGV4T2YoYykgPj0gMDtcbn1cblxuLy9DaGVja3MgaWYgYSB2YWx1ZSBpcyBudW1lcmljXG5mdW5jdGlvbiBpc051bWVyaWMoYykge1xuICByZXR1cm4gNDggPD0gYyAmJiBjIDw9IDU3O1xufVxuXG4vL1Rva2VuaXplIGFuIGV4cHJlc3Npb24gaW4gQ29ud2F5IG5vdGF0aW9uXG5mdW5jdGlvbiB0b2tlbml6ZShleHByKSB7XG4gIGV4cHIgPSBleHByLnJlcGxhY2UoL1A0JC9nLCBcIkNcIikgIC8vIFA0IC0tPiBDICAgKEMgaXMgcHJpc20pXG4gICAgICAgICAgICAgLnJlcGxhY2UoL0EzJC9nLCBcIk9cIikgIC8vIEEzIC0tPiBPICAgKE8gaXMgYW50aXByaXNtKVxuICAgICAgICAgICAgIC5yZXBsYWNlKC9ZMyQvZywgXCJUXCIpICAvLyBZMyAtLT4gVCAgIChUIGlzIHB5cmFtaWQpXG4gICAgICAgICAgICAgLnJlcGxhY2UoL2UvZywgXCJhYVwiKSAgIC8vIGUgLS0+IGFhICAgKGFiYnIuIGZvciBleHBsb2RlKVxuICAgICAgICAgICAgIC5yZXBsYWNlKC9iL2csIFwidGFcIikgICAvLyBiIC0tPiB0YSAgIChhYmJyLiBmb3IgYmV2ZWwpXG4gICAgICAgICAgICAgLnJlcGxhY2UoL28vZywgXCJqalwiKSAgIC8vIG8gLS0+IGpqICAgKGFiYnIuIGZvciBvcnRobylcbiAgICAgICAgICAgICAucmVwbGFjZSgvbS9nLCBcImtqXCIpICAgLy8gbSAtLT4ga2ogICAoYWJici4gZm9yIG1ldGEpXG4gICAgICAgICAgICAgLnJlcGxhY2UoL3QoXFxkKikvZywgXCJkayQxZFwiKSAgLy8gdChuKSAtLT4gZGsobilkICAoZHVhbCBvcGVyYXRpb25zKVxuICAgICAgICAgICAgIC5yZXBsYWNlKC9qL2csIFwiZGFkXCIpICAvLyBqIC0tPiBkYWQgIChkdWFsIG9wZXJhdGlvbnMpXG4gICAgICAgICAgICAgLnJlcGxhY2UoL3MvZywgXCJkZ2RcIikgIC8vIHMgLS0+IGRnZCAgKGR1YWwgb3BlcmF0aW9ucylcbiAgICAgICAgICAgICAucmVwbGFjZSgvZGQvZywgXCJcIikgICAgLy8gZGQgLS0+IG51bGwgIChvcmRlciAyKVxuICAgICAgICAgICAgIC5yZXBsYWNlKC9hZC9nLCBcImFcIikgICAvLyBhZCAtLT4gYSAgIChhXyA9IGFkXylcbiAgICAgICAgICAgICAucmVwbGFjZSgvZ2QvZywgXCJnXCIpICAgLy8gZ2QgLS0+IGcgICAoZ18gPSBnZF8pXG4gICAgICAgICAgICAgLnJlcGxhY2UoL2FZL2csIFwiQVwiKSAgIC8vIGFZIC0tPiBBICAgKGludGVyZXN0aW5nIGZhY3QpXG4gICAgICAgICAgICAgLnJlcGxhY2UoL2RUL2csIFwiVFwiKSAgIC8vIGRUIC0tPiBUICAgKHNlbGYtZHVhbClcbiAgICAgICAgICAgICAucmVwbGFjZSgvZ1QvZywgXCJEXCIpICAgLy8gZ1QgLS0+IEQgICAoc3ltbSBjaGFuZ2UpXG4gICAgICAgICAgICAgLnJlcGxhY2UoL2FUL2csIFwiT1wiKSAgIC8vIGFUIC0tPiBPICAgKHN5bW0gY2hhbmdlKVxuICAgICAgICAgICAgIC5yZXBsYWNlKC9kQy9nLCBcIk9cIikgICAvLyBkQyAtLT4gTyAgIChkdWFsIHBhaXIpXG4gICAgICAgICAgICAgLnJlcGxhY2UoL2RPL2csIFwiQ1wiKSAgIC8vIGRPIC0tPiBDICAgKGR1YWwgcGFpcilcbiAgICAgICAgICAgICAucmVwbGFjZSgvZEkvZywgXCJEXCIpICAgLy8gZEkgLS0+IEQgICAoZHVhbCBwYWlyKVxuICAgICAgICAgICAgIC5yZXBsYWNlKC9kRC9nLCBcIklcIikgICAvLyBkRCAtLT4gSSAgIChkdWFsIHBhaXIpXG4gICAgICAgICAgICAgLnJlcGxhY2UoL2FPL2csIFwiYUNcIikgIC8vIGFPIC0tPiBhQyAgKGZvciB1bmlxdWVuZXNzKVxuICAgICAgICAgICAgIC5yZXBsYWNlKC9hSS9nLCBcImFEXCIpICAvLyBhSSAtLT4gYUQgIChmb3IgdW5pcXVlbmVzcylcbiAgICAgICAgICAgICAucmVwbGFjZSgvZ08vZywgXCJnQ1wiKSAgLy8gZ08gLS0+IGdDICAoZm9yIHVuaXF1ZW5lc3MpXG4gICAgICAgICAgICAgLnJlcGxhY2UoL2dJL2csIFwiZ0RcIik7IC8vIGdJIC0tPiBnRCAgKGZvciB1bmlxdWVuZXNzKVxuICB2YXIgdG9rcyA9IFtdO1xuICB2YXIgcHRyID0gMDtcbiAgd2hpbGUocHRyIDwgZXhwci5sZW5ndGgpIHtcbiAgICB2YXIgb3AgPSBleHByLmNoYXJBdChwdHIpO1xuICAgIGlmKCFpc1Rva2VuKG9wKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVW5leHBlY3RlZCB0b2tlbjogXCIgKyBjICsgXCIgaW4gaW5wdXQgXCIgKyBleHByICsgXCIgYXQgXCIgKyBwdHIpO1xuICAgIH1cbiAgICB2YXIgc3RhcnRfbiA9ICsrcHRyO1xuICAgIHdoaWxlKHB0ciA8IGV4cHIubGVuZ3RoICYmIGlzTnVtZXJpYyhleHByLmNoYXJDb2RlQXQocHRyKSkpIHtcbiAgICAgICsrcHRyO1xuICAgIH1cbiAgICB2YXIgbiA9IHBhcnNlSW50KGV4cHIuc3Vic3RyKHN0YXJ0X24sIHB0cikpO1xuICAgIHRva3MucHVzaCh7XG4gICAgICBvcDogb3AsXG4gICAgICBuOiAgbiB8IDBcbiAgICB9KTtcbiAgfVxuICB0b2tzLnJldmVyc2UoKTtcbiAgcmV0dXJuIHRva3M7XG59XG5cbi8vTWFpbiBleHByZXNzaW9uIGludGVycHJldGVyXG5mdW5jdGlvbiBldmFsQ29ud2F5SGFydChleHByKSB7XG5cbiAgLy9QYXJzZSBleHByZXNzaW9uXG4gIHZhciB0b2tzID0gdG9rZW5pemUoZXhwcik7XG4gIFxuICAvL0luaXRpYWxpemUgc2VlZFxuICB2YXIgY3RvciA9IFNFRURfRlVOQ1NbdG9rc1swXS5vcF07XG4gIGlmKCFjdG9yKSB7XG4gICAgdGhyb3cgRXJyb3IoXCJJbnZhbGlkIHNlZWQgdHlwZTogXCIgKyBKU09OLnN0cmluZ2lmeShvcHNbMF0pKTtcbiAgfSBlbHNlIGlmKFwiUEFZXCIuaW5kZXhPZih0b2tzWzBdLm9wKSA+PSAwKSB7XG4gICAgaWYodG9rc1swXS5uIDwgMykge1xuICAgICAgdGhyb3cgRXJyb3IoXCJJbnZhbGlkIG51bWJlciBvZiBmYWNlcyBmb3Igc2VlZFwiKTtcbiAgICB9XG4gIH0gZWxzZSBpZih0b2tzWzBdLm4gIT09IDApIHtcbiAgICB0aHJvdyBFcnJvcihcIlNlZWQgXCIgICsgdG9rc1swXS5vcCArIFwiIGRvZXMgbm90IHVzZSBhIHBhcmFtZXRlclwiKTtcbiAgfVxuICB2YXIgcG9seSA9IGN0b3IodG9rc1swXS5uKTtcbiAgXG4gIC8vQXBwbHkgb3BlcmF0b3JzXG4gIGZvcih2YXIgaT0xOyBpPHRva3MubGVuZ3RoOyArK2kpIHtcbiAgICB2YXIgb3AgPSBPUEVSQVRPUl9GVU5DU1t0b2tzW2ldLm9wXTtcbiAgICBpZighb3ApIHtcbiAgICAgIHRocm93IEVycm9yKFwiSW52YWxpZCBvcGVyYXRvcjogXCIgKyB0b2tzW2ldKTtcbiAgICB9XG4gICAgcG9seSA9IG9wKHBvbHksIHRva3NbaV0ubik7XG4gIH0gIFxuICByZXR1cm4geyBuYW1lOiBwb2x5Lm5hbWUsIGNlbGxzOiBwb2x5LmZhY2VzLCBwb3NpdGlvbnM6IHBvbHkucG9zaXRpb25zIH07XG59XG5tb2R1bGUuZXhwb3J0cyA9IGV2YWxDb253YXlIYXJ0O1xuXG4iXX0=
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})({"bound-points":[function(require,module,exports){
'use strict'
module.exports = findBounds
function findBounds(points) {
var n = points.length
if(n === 0) {
return [[], []]
}
var d = points[0].length
var lo = points[0].slice()
var hi = points[0].slice()
for(var i=1; i<n; ++i) {
var p = points[i]
for(var j=0; j<d; ++j) {
var x = p[j]
lo[j] = Math.min(lo[j], x)
hi[j] = Math.max(hi[j], x)
}
}
return [lo, hi]
}
},{}]},{},[])
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImJvdW5kcy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIid1c2Ugc3RyaWN0J1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZpbmRCb3VuZHNcblxuZnVuY3Rpb24gZmluZEJvdW5kcyhwb2ludHMpIHtcbiAgdmFyIG4gPSBwb2ludHMubGVuZ3RoXG4gIGlmKG4gPT09IDApIHtcbiAgICByZXR1cm4gW1tdLCBbXV1cbiAgfVxuICB2YXIgZCA9IHBvaW50c1swXS5sZW5ndGhcbiAgdmFyIGxvID0gcG9pbnRzWzBdLnNsaWNlKClcbiAgdmFyIGhpID0gcG9pbnRzWzBdLnNsaWNlKClcbiAgZm9yKHZhciBpPTE7IGk8bjsgKytpKSB7XG4gICAgdmFyIHAgPSBwb2ludHNbaV1cbiAgICBmb3IodmFyIGo9MDsgajxkOyArK2opIHtcbiAgICAgIHZhciB4ID0gcFtqXVxuICAgICAgbG9bal0gPSBNYXRoLm1pbihsb1tqXSwgeClcbiAgICAgIGhpW2pdID0gTWF0aC5tYXgoaGlbal0sIHgpXG4gICAgfVxuICB9XG4gIHJldHVybiBbbG8sIGhpXVxufSJdfQ==
const polytope = require('conway-hart')('tI')
const vec3 = require('gl-vec3')
const HEIGHT = 6
const bounds = require('bound-points')(polytope.positions)
const radius = Math.max(
bounds[1][0] - bounds[0][0],
bounds[1][1] - bounds[0][1],
bounds[1][2] - bounds[0][2])
const scale = HEIGHT / radius
const edges = []
polytope.cells.forEach((c) => {
for (let i = 0; i < c.length; ++i) {
edges.push([c[i], c[(i + 1) % c.length]])
}
})
const lengths = edges.map(([i, j]) =>
vec3.length(vec3.subtract([], polytope.positions[i], polytope.positions[j])))
lengths.sort(function (a, b) {
return a - b
})
const histogram = {}
let total = 0
lengths.forEach((l) => {
const x = Math.round(scale * l * 1000.0) / 1000.0
histogram[x] = (histogram[x] | 0) + 1
total += x
})
Object.keys(histogram).forEach(function (l) {
histogram[l] /= 2
})
if (typeof document !== 'undefined') {
document.body.appendChild(document.createTextNode(
`dome height: ${HEIGHT} lengths: ${JSON.stringify(histogram)} total: ${total / 2}`))
}
console.log('dome height: ', HEIGHT)
console.log('lengths: ', histogram)
console.log('total: ', total / 2)
;}, 0)
{
"name": "requirebin-sketch",
"version": "1.0.0",
"dependencies": {
"gl-vec3": "1.0.3",
"conway-hart": "0.1.0",
"bound-points": "1.0.0"
}
}
<!-- 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