Last active
May 20, 2016 17:20
-
-
Save tmpvar/bf99d3103f4c80d2acc4376d30d62a4d to your computer and use it in GitHub Desktop.
requirebin sketch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var fc = require('fc') | |
var center = require('ctx-translate-center') | |
var grid = require('ctx-render-grid-lines') | |
var circle = require('ctx-circle') | |
var ndarray = require('ndarray') | |
var fillArray = require('ndarray-fill') | |
var marchingSquares = require('marching-squares') | |
var surfaceNets = require('surface-nets') | |
// where size is the bin size from 0..1 | |
function createBinner(radius, width, height) { | |
var cx = Math.ceil(width/radius) | |
var cy = Math.ceil(height/radius) | |
var bins = ndarray(new Int32Array(cx * cy), [cx, cy]) | |
fillArray(bins, function(i, j) { return -1 }) | |
var tests = [[-1, -1], [0, 1], [-1, 1], [0, 1], [1, 1], [1, -1]] | |
function toCell(point) { | |
return [ | |
Math.floor(point[0] / radius) * radius, | |
Math.floor(point[1] / radius) * radius | |
] | |
} | |
function add(point) { | |
var cell = toCell(point) | |
findAHome(cell[0], cell[1], point, new Set()) | |
} | |
add.toCell = toCell | |
var points = add.points = [] | |
function findAHome(x, y, point, seen) { | |
seen = new Set(seen) | |
seen.add(bins.index(x, y)) | |
// cell is empty | |
if (bins.get(x, y) === -1) { | |
var index = points.length | |
points.push(point) | |
bins.set(x, y, 1) | |
return true | |
} | |
var closest = tests.map(function(t, i) { | |
var dx = x + t[0] - point[0] | |
var dy = y + t[1] - point[1] | |
return [ | |
dx*dx + dy*dy, | |
i | |
] | |
}).sort(function(a, b) { | |
return a[0] - b[0] | |
}) | |
for (var i=0; i<tests.length; i++) { | |
var test = tests[closest[i][1]] | |
var tx = x + test[0] | |
var ty = y + test[1] | |
if (!seen.has(bins.index(tx, ty)) && findAHome(tx, ty, point, seen)) { | |
return true | |
} | |
} | |
} | |
function render(ctx) { | |
var perc = 360/points.length | |
var loc = 1 | |
for (var x = 0; x < cx; x++) { | |
for (var y = 0; y < cy; y++) { | |
if (bins.get(x, y) !== -1) { | |
ctx.fillStyle = `hsl(${perc * loc}, 100%, 50%)` | |
ctx.fillRect(x*radius + 1, y*radius + 1, radius - 2, radius - 2) | |
loc++ | |
} | |
} | |
} | |
} | |
add.bins = bins | |
add.render = render | |
return add | |
} | |
var width = 600 | |
var height = 400 | |
var radius = 10 | |
var binner = createBinner(radius, width, height) | |
// binner([50, 50]) | |
// binner([20, 50]) | |
setInterval(function() { | |
binner([30, 60]) | |
binner([40, 100]) | |
ctx.dirty() | |
}, 100) | |
function point(ctx, vec, r) { | |
ctx.beginPath() | |
circle(ctx, vec[0], vec[1], r) | |
return ctx | |
} | |
function fill(ctx, color) { | |
ctx.fillStyle = color | |
ctx.fill() | |
} | |
var ctx = fc(function() { | |
ctx.clear() | |
center(ctx) | |
ctx.scale(1, -1) | |
ctx.translate(-400, -200) | |
ctx.beginPath() | |
grid(ctx, radius, 0, 0, width, height) | |
ctx.stroke() | |
ctx.fillStyle = 'orange' | |
binner.render(ctx) | |
var nets = surfaceNets(binner.bins, 0) | |
ctx.strokeStyle = "white" | |
nets.cells.forEach(function(cell) { | |
var start = nets.positions[cell[0]] | |
var end = nets.positions[cell[1]] | |
ctx.beginPath() | |
ctx.moveTo(start[0] * radius, start[1] * radius) | |
ctx.lineTo(end[0] * radius, end[1] * radius) | |
ctx.stroke() | |
}) | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
setTimeout(function(){ | |
;require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({"fc":[function(require,module,exports){ | |
;(function() { | |
var performance = window.performance || {} | |
var performanceNow = | |
performance.now || | |
performance.now || | |
performance.mozNow || | |
performance.msNow || | |
performance.oNow || | |
performance.webkitNow || | |
function(){ return (new Date()).getTime() } | |
performanceNow = performanceNow.bind(performance) | |
// Fullscreen canvas | |
function fc(fn, autorun, dimensions) { | |
document.body.style.margin = "0px"; | |
document.body.style.padding = "0px"; | |
var canvas = document.createElement('canvas'); | |
document.body.appendChild(canvas); | |
canvas.style.position = 'absolute'; | |
canvas.style.left = '0px'; | |
canvas.style.top = '0px'; | |
var ctx; | |
dimensions = dimensions || 2; | |
if (dimensions === 2) { | |
ctx = canvas.getContext('2d'); | |
} else if (dimensions === 3) { | |
ctx = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); | |
} | |
if (!ctx) { | |
return; | |
} | |
var last = performanceNow(), request; | |
function requestFrame() { | |
if (request === null) { | |
request = requestAnimationFrame(tick); | |
} | |
} | |
function tick() { | |
request = null; | |
var time = performanceNow(); | |
var delta = time-last; | |
last = time; | |
ctx.reset(); | |
dimensions === 2 && ctx.save(); | |
fn && fn.call(ctx, delta); | |
dimensions === 2 && ctx.restore(); | |
if (autorun) { | |
requestFrame(); | |
} | |
} | |
if (dimensions === 2) { | |
ctx.reset = function fc_reset() { | |
canvas.width = 0; | |
canvas.width = window.innerWidth; | |
canvas.height = window.innerHeight; | |
}; | |
ctx.clear = function fc_clear(color) { | |
var orig = ctx.fillStyle; | |
ctx.fillStyle = color || "#223"; | |
ctx.fillRect(0, 0, canvas.width, canvas.height); | |
ctx.fillStyle = orig; | |
}; | |
} else { | |
ctx.reset = function fc_reset() { | |
if (canvas.width !== window.innerWidth) { | |
canvas.width = window.innerWidth; | |
} | |
if (canvas.height !== window.innerHeight) { | |
canvas.height = window.innerHeight; | |
} | |
} | |
} | |
setTimeout(tick, 0); | |
ctx.dirty = function fc_dirty() { | |
last = performanceNow(); | |
requestFrame(); | |
}; | |
ctx.stop = function fc_stop() { | |
autorun = false; | |
request && cancelAnimationFrame(request); | |
request = null; | |
}; | |
ctx.start = function fc_start() { | |
autorun = true; | |
requestFrame(); | |
}; | |
(window.attachEvent || window.addEventListener)('resize', ctx.dirty); | |
// resize to fullscreen immediately | |
ctx.reset(); | |
ctx.canvas = canvas; | |
return ctx; | |
}; | |
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { | |
module.exports = fc; | |
} | |
if (typeof window !== 'undefined') { | |
window.fc = window.fc || fc; | |
} | |
})(); | |
},{}]},{},[]) | |
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi91c3IvbGliL25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCIvdG1wL2ZjMTE2MDE3LTE4MTg2LTFjNjBseW4vbm9kZV9tb2R1bGVzL2ZjL2ZjLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIjsoZnVuY3Rpb24oKSB7XG4gIHZhciBwZXJmb3JtYW5jZSA9IHdpbmRvdy5wZXJmb3JtYW5jZSB8fCB7fVxuICB2YXIgcGVyZm9ybWFuY2VOb3cgPVxuICAgIHBlcmZvcm1hbmNlLm5vdyAgICAgICAgfHxcbiAgICBwZXJmb3JtYW5jZS5ub3cgICAgICAgIHx8XG4gICAgcGVyZm9ybWFuY2UubW96Tm93ICAgICB8fFxuICAgIHBlcmZvcm1hbmNlLm1zTm93ICAgICAgfHxcbiAgICBwZXJmb3JtYW5jZS5vTm93ICAgICAgIHx8XG4gICAgcGVyZm9ybWFuY2Uud2Via2l0Tm93ICB8fFxuICAgIGZ1bmN0aW9uKCl7IHJldHVybiAobmV3IERhdGUoKSkuZ2V0VGltZSgpIH1cbiAgcGVyZm9ybWFuY2VOb3cgPSBwZXJmb3JtYW5jZU5vdy5iaW5kKHBlcmZvcm1hbmNlKVxuXG4gIC8vIEZ1bGxzY3JlZW4gY2FudmFzXG4gIGZ1bmN0aW9uIGZjKGZuLCBhdXRvcnVuLCBkaW1lbnNpb25zKSB7XG4gICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSBcIjBweFwiO1xuICAgIGRvY3VtZW50LmJvZHkuc3R5bGUucGFkZGluZyA9IFwiMHB4XCI7XG5cbiAgICB2YXIgY2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG4gICAgZG9jdW1lbnQuYm9keS5hcHBlbmRDaGlsZChjYW52YXMpO1xuICAgIGNhbnZhcy5zdHlsZS5wb3NpdGlvbiA9ICdhYnNvbHV0ZSc7XG4gICAgY2FudmFzLnN0eWxlLmxlZnQgPSAnMHB4JztcbiAgICBjYW52YXMuc3R5bGUudG9wID0gJzBweCc7XG5cbiAgICB2YXIgY3R4O1xuICAgIGRpbWVuc2lvbnMgPSBkaW1lbnNpb25zIHx8IDI7XG5cbiAgICBpZiAoZGltZW5zaW9ucyA9PT0gMikge1xuICAgICAgY3R4ID0gY2FudmFzLmdldENvbnRleHQoJzJkJyk7XG4gICAgfSBlbHNlIGlmIChkaW1lbnNpb25zID09PSAzKSB7XG4gICAgICBjdHggPSBjYW52YXMuZ2V0Q29udGV4dCgnd2ViZ2wnKSB8fCBjYW52YXMuZ2V0Q29udGV4dCgnZXhwZXJpbWVudGFsLXdlYmdsJyk7XG4gICAgfVxuXG4gICAgaWYgKCFjdHgpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgbGFzdCA9IHBlcmZvcm1hbmNlTm93KCksIHJlcXVlc3Q7XG5cbiAgICBmdW5jdGlvbiByZXF1ZXN0RnJhbWUoKSB7XG4gICAgICBpZiAocmVxdWVzdCA9PT0gbnVsbCkge1xuICAgICAgICByZXF1ZXN0ID0gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKHRpY2spO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHRpY2soKSB7XG4gICAgICByZXF1ZXN0ID0gbnVsbDtcbiAgICAgIHZhciB0aW1lID0gcGVyZm9ybWFuY2VOb3coKTtcbiAgICAgIHZhciBkZWx0YSA9IHRpbWUtbGFzdDtcbiAgICAgIGxhc3QgPSB0aW1lO1xuXG4gICAgICBjdHgucmVzZXQoKTtcblxuICAgICAgZGltZW5zaW9ucyA9PT0gMiAmJiBjdHguc2F2ZSgpO1xuXG4gICAgICBmbiAmJiBmbi5jYWxsKGN0eCwgZGVsdGEpO1xuXG4gICAgICBkaW1lbnNpb25zID09PSAyICYmIGN0eC5yZXN0b3JlKCk7XG4gICAgICBpZiAoYXV0b3J1bikge1xuICAgICAgICByZXF1ZXN0RnJhbWUoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoZGltZW5zaW9ucyA9PT0gMikge1xuICAgICAgY3R4LnJlc2V0ID0gZnVuY3Rpb24gZmNfcmVzZXQoKSB7XG4gICAgICAgIGNhbnZhcy53aWR0aCA9IDA7XG4gICAgICAgIGNhbnZhcy53aWR0aCA9IHdpbmRvdy5pbm5lcldpZHRoO1xuICAgICAgICBjYW52YXMuaGVpZ2h0ID0gd2luZG93LmlubmVySGVpZ2h0O1xuICAgICAgfTtcblxuICAgICAgY3R4LmNsZWFyID0gZnVuY3Rpb24gZmNfY2xlYXIoY29sb3IpIHtcbiAgICAgICAgdmFyIG9yaWcgPSBjdHguZmlsbFN0eWxlO1xuICAgICAgICBjdHguZmlsbFN0eWxlID0gY29sb3IgfHwgXCIjMjIzXCI7XG4gICAgICAgIGN0eC5maWxsUmVjdCgwLCAwLCBjYW52YXMud2lkdGgsIGNhbnZhcy5oZWlnaHQpO1xuICAgICAgICBjdHguZmlsbFN0eWxlID0gb3JpZztcbiAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgIGN0eC5yZXNldCA9IGZ1bmN0aW9uIGZjX3Jlc2V0KCkge1xuICAgICAgICBpZiAoY2FudmFzLndpZHRoICE9PSB3aW5kb3cuaW5uZXJXaWR0aCkge1xuICAgICAgICAgIGNhbnZhcy53aWR0aCA9IHdpbmRvdy5pbm5lcldpZHRoO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNhbnZhcy5oZWlnaHQgIT09IHdpbmRvdy5pbm5lckhlaWdodCkge1xuICAgICAgICAgIGNhbnZhcy5oZWlnaHQgPSB3aW5kb3cuaW5uZXJIZWlnaHQ7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBzZXRUaW1lb3V0KHRpY2ssIDApO1xuXG4gICAgY3R4LmRpcnR5ID0gZnVuY3Rpb24gZmNfZGlydHkoKSB7XG4gICAgICBsYXN0ID0gcGVyZm9ybWFuY2VOb3coKTtcbiAgICAgIHJlcXVlc3RGcmFtZSgpO1xuICAgIH07XG5cbiAgICBjdHguc3RvcCA9IGZ1bmN0aW9uIGZjX3N0b3AoKSB7XG4gICAgICBhdXRvcnVuID0gZmFsc2U7XG4gICAgICByZXF1ZXN0ICYmIGNhbmNlbEFuaW1hdGlvbkZyYW1lKHJlcXVlc3QpO1xuICAgICAgcmVxdWVzdCA9IG51bGw7XG4gICAgfTtcblxuICAgIGN0eC5zdGFydCA9IGZ1bmN0aW9uIGZjX3N0YXJ0KCkge1xuICAgICAgYXV0b3J1biA9IHRydWU7XG4gICAgICByZXF1ZXN0RnJhbWUoKTtcbiAgICB9O1xuXG4gICAgKHdpbmRvdy5hdHRhY2hFdmVudCB8fCB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcikoJ3Jlc2l6ZScsIGN0eC5kaXJ0eSk7XG5cbiAgICAvLyByZXNpemUgdG8gZnVsbHNjcmVlbiBpbW1lZGlhdGVseVxuICAgIGN0eC5yZXNldCgpO1xuXG4gICAgY3R4LmNhbnZhcyA9IGNhbnZhcztcbiAgICByZXR1cm4gY3R4O1xuICB9O1xuXG4gIGlmICh0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJyAmJiB0eXBlb2YgbW9kdWxlLmV4cG9ydHMgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgbW9kdWxlLmV4cG9ydHMgPSBmYztcbiAgfVxuXG4gIGlmICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJykge1xuICAgIHdpbmRvdy5mYyA9IHdpbmRvdy5mYyB8fCBmYztcbiAgfVxufSkoKTtcbiJdfQ== | |
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})({"ctx-translate-center":[function(require,module,exports){ | |
module.exports = center; | |
function center(ctx) { | |
var w = (ctx.canvas.width/2)|0; | |
var h = (ctx.canvas.height/2)|0; | |
ctx.translate(w, h); | |
} | |
},{}]},{},[]) | |
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImN0eC10cmFuc2xhdGUtY2VudGVyLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIm1vZHVsZS5leHBvcnRzID0gY2VudGVyO1xuXG5mdW5jdGlvbiBjZW50ZXIoY3R4KSB7XG4gIHZhciB3ID0gKGN0eC5jYW52YXMud2lkdGgvMil8MDtcbiAgdmFyIGggPSAoY3R4LmNhbnZhcy5oZWlnaHQvMil8MDtcblxuICBjdHgudHJhbnNsYXRlKHcsIGgpO1xufVxuIl19 | |
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})({"ctx-render-grid-lines":[function(require,module,exports){ | |
module.exports = gridlines; | |
var min = Math.min; | |
var max = Math.max; | |
var abs = Math.abs; | |
function gridlines(ctx, spacing, minx, miny, maxx, maxy) { | |
var lx = min(minx, maxx); | |
var ly = min(miny, maxy); | |
var ux = max(minx, maxx); | |
var uy = max(miny, maxy); | |
spacing = abs(spacing|0); | |
if (!spacing) { | |
return; | |
} | |
for (var x = lx; x <= ux; x += spacing) { | |
ctx.moveTo(x, ly); | |
ctx.lineTo(x, uy); | |
} | |
for (var y = ly; y <= uy; y += spacing) { | |
ctx.moveTo(lx, y); | |
ctx.lineTo(ux, y); | |
} | |
} | |
},{}]},{},[]) | |
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImN0eC1yZW5kZXItZ3JpZC1saW5lcy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwibW9kdWxlLmV4cG9ydHMgPSBncmlkbGluZXM7XG5cbnZhciBtaW4gPSBNYXRoLm1pbjtcbnZhciBtYXggPSBNYXRoLm1heDtcbnZhciBhYnMgPSBNYXRoLmFicztcblxuZnVuY3Rpb24gZ3JpZGxpbmVzKGN0eCwgc3BhY2luZywgbWlueCwgbWlueSwgbWF4eCwgbWF4eSkge1xuICB2YXIgbHggPSBtaW4obWlueCwgbWF4eCk7XG4gIHZhciBseSA9IG1pbihtaW55LCBtYXh5KTtcbiAgdmFyIHV4ID0gbWF4KG1pbngsIG1heHgpO1xuICB2YXIgdXkgPSBtYXgobWlueSwgbWF4eSk7XG5cbiAgc3BhY2luZyA9IGFicyhzcGFjaW5nfDApO1xuXG4gIGlmICghc3BhY2luZykge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGZvciAodmFyIHggPSBseDsgeCA8PSB1eDsgeCArPSBzcGFjaW5nKSB7XG4gICAgY3R4Lm1vdmVUbyh4LCBseSk7XG4gICAgY3R4LmxpbmVUbyh4LCB1eSk7XG4gIH1cblxuICBmb3IgKHZhciB5ID0gbHk7IHkgPD0gdXk7IHkgKz0gc3BhY2luZykge1xuICAgIGN0eC5tb3ZlVG8obHgsIHkpO1xuICAgIGN0eC5saW5lVG8odXgsIHkpO1xuICB9XG59XG4iXX0= | |
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})({"ctx-circle":[function(require,module,exports){ | |
var TAU = Math.PI*2; | |
module.exports = circle; | |
function circle(ctx, x, y, r, reverse) { | |
ctx.moveTo(x+r, y); | |
ctx.arc(x, y, r, 0, TAU, !!reverse); | |
} | |
},{}]},{},[]) | |
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImN0eC1jaXJjbGUuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwidmFyIFRBVSA9IE1hdGguUEkqMjtcblxubW9kdWxlLmV4cG9ydHMgPSBjaXJjbGU7XG5cbmZ1bmN0aW9uIGNpcmNsZShjdHgsIHgsIHksIHIsIHJldmVyc2UpIHtcbiAgY3R4Lm1vdmVUbyh4K3IsIHkpO1xuICBjdHguYXJjKHgsIHksIHIsIDAsIFRBVSwgISFyZXZlcnNlKTtcbn1cbiJdfQ== | |
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){ | |
"use strict" | |
function iota(n) { | |
var result = new Array(n) | |
for(var i=0; i<n; ++i) { | |
result[i] = i | |
} | |
return result | |
} | |
module.exports = iota | |
},{}],2:[function(require,module,exports){ | |
/** | |
* Determine if an object is Buffer | |
* | |
* Author: Feross Aboukhadijeh <feross@feross.org> <http://feross.org> | |
* License: MIT | |
* | |
* `npm install is-buffer` | |
*/ | |
module.exports = function (obj) { | |
return !!(obj != null && | |
(obj._isBuffer || // For Safari 5-7 (missing Object.prototype.constructor) | |
(obj.constructor && | |
typeof obj.constructor.isBuffer === 'function' && | |
obj.constructor.isBuffer(obj)) | |
)) | |
} | |
},{}],"ndarray":[function(require,module,exports){ | |
var iota = require("iota-array") | |
var isBuffer = require("is-buffer") | |
var hasTypedArrays = ((typeof Float64Array) !== "undefined") | |
function compare1st(a, b) { | |
return a[0] - b[0] | |
} | |
function order() { | |
var stride = this.stride | |
var terms = new Array(stride.length) | |
var i | |
for(i=0; i<terms.length; ++i) { | |
terms[i] = [Math.abs(stride[i]), i] | |
} | |
terms.sort(compare1st) | |
var result = new Array(terms.length) | |
for(i=0; i<result.length; ++i) { | |
result[i] = terms[i][1] | |
} | |
return result | |
} | |
function compileConstructor(dtype, dimension) { | |
var className = ["View", dimension, "d", dtype].join("") | |
if(dimension < 0) { | |
className = "View_Nil" + dtype | |
} | |
var useGetters = (dtype === "generic") | |
if(dimension === -1) { | |
//Special case for trivial arrays | |
var code = | |
"function "+className+"(a){this.data=a;};\ | |
var proto="+className+".prototype;\ | |
proto.dtype='"+dtype+"';\ | |
proto.index=function(){return -1};\ | |
proto.size=0;\ | |
proto.dimension=-1;\ | |
proto.shape=proto.stride=proto.order=[];\ | |
proto.lo=proto.hi=proto.transpose=proto.step=\ | |
function(){return new "+className+"(this.data);};\ | |
proto.get=proto.set=function(){};\ | |
proto.pick=function(){return null};\ | |
return function construct_"+className+"(a){return new "+className+"(a);}" | |
var procedure = new Function(code) | |
return procedure() | |
} else if(dimension === 0) { | |
//Special case for 0d arrays | |
var code = | |
"function "+className+"(a,d) {\ | |
this.data = a;\ | |
this.offset = d\ | |
};\ | |
var proto="+className+".prototype;\ | |
proto.dtype='"+dtype+"';\ | |
proto.index=function(){return this.offset};\ | |
proto.dimension=0;\ | |
proto.size=1;\ | |
proto.shape=\ | |
proto.stride=\ | |
proto.order=[];\ | |
proto.lo=\ | |
proto.hi=\ | |
proto.transpose=\ | |
proto.step=function "+className+"_copy() {\ | |
return new "+className+"(this.data,this.offset)\ | |
};\ | |
proto.pick=function "+className+"_pick(){\ | |
return TrivialArray(this.data);\ | |
};\ | |
proto.valueOf=proto.get=function "+className+"_get(){\ | |
return "+(useGetters ? "this.data.get(this.offset)" : "this.data[this.offset]")+ | |
"};\ | |
proto.set=function "+className+"_set(v){\ | |
return "+(useGetters ? "this.data.set(this.offset,v)" : "this.data[this.offset]=v")+"\ | |
};\ | |
return function construct_"+className+"(a,b,c,d){return new "+className+"(a,d)}" | |
var procedure = new Function("TrivialArray", code) | |
return procedure(CACHED_CONSTRUCTORS[dtype][0]) | |
} | |
var code = ["'use strict'"] | |
//Create constructor for view | |
var indices = iota(dimension) | |
var args = indices.map(function(i) { return "i"+i }) | |
var index_str = "this.offset+" + indices.map(function(i) { | |
return "this.stride[" + i + "]*i" + i | |
}).join("+") | |
var shapeArg = indices.map(function(i) { | |
return "b"+i | |
}).join(",") | |
var strideArg = indices.map(function(i) { | |
return "c"+i | |
}).join(",") | |
code.push( | |
"function "+className+"(a," + shapeArg + "," + strideArg + ",d){this.data=a", | |
"this.shape=[" + shapeArg + "]", | |
"this.stride=[" + strideArg + "]", | |
"this.offset=d|0}", | |
"var proto="+className+".prototype", | |
"proto.dtype='"+dtype+"'", | |
"proto.dimension="+dimension) | |
//view.size: | |
code.push("Object.defineProperty(proto,'size',{get:function "+className+"_size(){\ | |
return "+indices.map(function(i) { return "this.shape["+i+"]" }).join("*"), | |
"}})") | |
//view.order: | |
if(dimension === 1) { | |
code.push("proto.order=[0]") | |
} else { | |
code.push("Object.defineProperty(proto,'order',{get:") | |
if(dimension < 4) { | |
code.push("function "+className+"_order(){") | |
if(dimension === 2) { | |
code.push("return (Math.abs(this.stride[0])>Math.abs(this.stride[1]))?[1,0]:[0,1]}})") | |
} else if(dimension === 3) { | |
code.push( | |
"var s0=Math.abs(this.stride[0]),s1=Math.abs(this.stride[1]),s2=Math.abs(this.stride[2]);\ | |
if(s0>s1){\ | |
if(s1>s2){\ | |
return [2,1,0];\ | |
}else if(s0>s2){\ | |
return [1,2,0];\ | |
}else{\ | |
return [1,0,2];\ | |
}\ | |
}else if(s0>s2){\ | |
return [2,0,1];\ | |
}else if(s2>s1){\ | |
return [0,1,2];\ | |
}else{\ | |
return [0,2,1];\ | |
}}})") | |
} | |
} else { | |
code.push("ORDER})") | |
} | |
} | |
//view.set(i0, ..., v): | |
code.push( | |
"proto.set=function "+className+"_set("+args.join(",")+",v){") | |
if(useGetters) { | |
code.push("return this.data.set("+index_str+",v)}") | |
} else { | |
code.push("return this.data["+index_str+"]=v}") | |
} | |
//view.get(i0, ...): | |
code.push("proto.get=function "+className+"_get("+args.join(",")+"){") | |
if(useGetters) { | |
code.push("return this.data.get("+index_str+")}") | |
} else { | |
code.push("return this.data["+index_str+"]}") | |
} | |
//view.index: | |
code.push( | |
"proto.index=function "+className+"_index(", args.join(), "){return "+index_str+"}") | |
//view.hi(): | |
code.push("proto.hi=function "+className+"_hi("+args.join(",")+"){return new "+className+"(this.data,"+ | |
indices.map(function(i) { | |
return ["(typeof i",i,"!=='number'||i",i,"<0)?this.shape[", i, "]:i", i,"|0"].join("") | |
}).join(",")+","+ | |
indices.map(function(i) { | |
return "this.stride["+i + "]" | |
}).join(",")+",this.offset)}") | |
//view.lo(): | |
var a_vars = indices.map(function(i) { return "a"+i+"=this.shape["+i+"]" }) | |
var c_vars = indices.map(function(i) { return "c"+i+"=this.stride["+i+"]" }) | |
code.push("proto.lo=function "+className+"_lo("+args.join(",")+"){var b=this.offset,d=0,"+a_vars.join(",")+","+c_vars.join(",")) | |
for(var i=0; i<dimension; ++i) { | |
code.push( | |
"if(typeof i"+i+"==='number'&&i"+i+">=0){\ | |
d=i"+i+"|0;\ | |
b+=c"+i+"*d;\ | |
a"+i+"-=d}") | |
} | |
code.push("return new "+className+"(this.data,"+ | |
indices.map(function(i) { | |
return "a"+i | |
}).join(",")+","+ | |
indices.map(function(i) { | |
return "c"+i | |
}).join(",")+",b)}") | |
//view.step(): | |
code.push("proto.step=function "+className+"_step("+args.join(",")+"){var "+ | |
indices.map(function(i) { | |
return "a"+i+"=this.shape["+i+"]" | |
}).join(",")+","+ | |
indices.map(function(i) { | |
return "b"+i+"=this.stride["+i+"]" | |
}).join(",")+",c=this.offset,d=0,ceil=Math.ceil") | |
for(var i=0; i<dimension; ++i) { | |
code.push( | |
"if(typeof i"+i+"==='number'){\ | |
d=i"+i+"|0;\ | |
if(d<0){\ | |
c+=b"+i+"*(a"+i+"-1);\ | |
a"+i+"=ceil(-a"+i+"/d)\ | |
}else{\ | |
a"+i+"=ceil(a"+i+"/d)\ | |
}\ | |
b"+i+"*=d\ | |
}") | |
} | |
code.push("return new "+className+"(this.data,"+ | |
indices.map(function(i) { | |
return "a" + i | |
}).join(",")+","+ | |
indices.map(function(i) { | |
return "b" + i | |
}).join(",")+",c)}") | |
//view.transpose(): | |
var tShape = new Array(dimension) | |
var tStride = new Array(dimension) | |
for(var i=0; i<dimension; ++i) { | |
tShape[i] = "a[i"+i+"]" | |
tStride[i] = "b[i"+i+"]" | |
} | |
code.push("proto.transpose=function "+className+"_transpose("+args+"){"+ | |
args.map(function(n,idx) { return n + "=(" + n + "===undefined?" + idx + ":" + n + "|0)"}).join(";"), | |
"var a=this.shape,b=this.stride;return new "+className+"(this.data,"+tShape.join(",")+","+tStride.join(",")+",this.offset)}") | |
//view.pick(): | |
code.push("proto.pick=function "+className+"_pick("+args+"){var a=[],b=[],c=this.offset") | |
for(var i=0; i<dimension; ++i) { | |
code.push("if(typeof i"+i+"==='number'&&i"+i+">=0){c=(c+this.stride["+i+"]*i"+i+")|0}else{a.push(this.shape["+i+"]);b.push(this.stride["+i+"])}") | |
} | |
code.push("var ctor=CTOR_LIST[a.length+1];return ctor(this.data,a,b,c)}") | |
//Add return statement | |
code.push("return function construct_"+className+"(data,shape,stride,offset){return new "+className+"(data,"+ | |
indices.map(function(i) { | |
return "shape["+i+"]" | |
}).join(",")+","+ | |
indices.map(function(i) { | |
return "stride["+i+"]" | |
}).join(",")+",offset)}") | |
//Compile procedure | |
var procedure = new Function("CTOR_LIST", "ORDER", code.join("\n")) | |
return procedure(CACHED_CONSTRUCTORS[dtype], order) | |
} | |
function arrayDType(data) { | |
if(isBuffer(data)) { | |
return "buffer" | |
} | |
if(hasTypedArrays) { | |
switch(Object.prototype.toString.call(data)) { | |
case "[object Float64Array]": | |
return "float64" | |
case "[object Float32Array]": | |
return "float32" | |
case "[object Int8Array]": | |
return "int8" | |
case "[object Int16Array]": | |
return "int16" | |
case "[object Int32Array]": | |
return "int32" | |
case "[object Uint8Array]": | |
return "uint8" | |
case "[object Uint16Array]": | |
return "uint16" | |
case "[object Uint32Array]": | |
return "uint32" | |
case "[object Uint8ClampedArray]": | |
return "uint8_clamped" | |
} | |
} | |
if(Array.isArray(data)) { | |
return "array" | |
} | |
return "generic" | |
} | |
var CACHED_CONSTRUCTORS = { | |
"float32":[], | |
"float64":[], | |
"int8":[], | |
"int16":[], | |
"int32":[], | |
"uint8":[], | |
"uint16":[], | |
"uint32":[], | |
"array":[], | |
"uint8_clamped":[], | |
"buffer":[], | |
"generic":[] | |
} | |
;(function() { | |
for(var id in CACHED_CONSTRUCTORS) { | |
CACHED_CONSTRUCTORS[id].push(compileConstructor(id, -1)) | |
} | |
}); | |
function wrappedNDArrayCtor(data, shape, stride, offset) { | |
if(data === undefined) { | |
var ctor = CACHED_CONSTRUCTORS.array[0] | |
return ctor([]) | |
} else if(typeof data === "number") { | |
data = [data] | |
} | |
if(shape === undefined) { | |
shape = [ data.length ] | |
} | |
var d = shape.length | |
if(stride === undefined) { | |
stride = new Array(d) | |
for(var i=d-1, sz=1; i>=0; --i) { | |
stride[i] = sz | |
sz *= shape[i] | |
} | |
} | |
if(offset === undefined) { | |
offset = 0 | |
for(var i=0; i<d; ++i) { | |
if(stride[i] < 0) { | |
offset -= (shape[i]-1)*stride[i] | |
} | |
} | |
} | |
var dtype = arrayDType(data) | |
var ctor_list = CACHED_CONSTRUCTORS[dtype] | |
while(ctor_list.length <= d+1) { | |
ctor_list.push(compileConstructor(dtype, ctor_list.length-1)) | |
} | |
var ctor = ctor_list[d+1] | |
return ctor(data, shape, stride, offset) | |
} | |
module.exports = wrappedNDArrayCtor | |
},{"iota-array":1,"is-buffer":2}]},{},[]) | |
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsIm5vZGVfbW9kdWxlcy9pb3RhLWFycmF5L2lvdGEuanMiLCJub2RlX21vZHVsZXMvaXMtYnVmZmVyL2luZGV4LmpzIiwibmRhcnJheS5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIlwidXNlIHN0cmljdFwiXG5cbmZ1bmN0aW9uIGlvdGEobikge1xuICB2YXIgcmVzdWx0ID0gbmV3IEFycmF5KG4pXG4gIGZvcih2YXIgaT0wOyBpPG47ICsraSkge1xuICAgIHJlc3VsdFtpXSA9IGlcbiAgfVxuICByZXR1cm4gcmVzdWx0XG59XG5cbm1vZHVsZS5leHBvcnRzID0gaW90YSIsIi8qKlxuICogRGV0ZXJtaW5lIGlmIGFuIG9iamVjdCBpcyBCdWZmZXJcbiAqXG4gKiBBdXRob3I6ICAgRmVyb3NzIEFib3VraGFkaWplaCA8ZmVyb3NzQGZlcm9zcy5vcmc+IDxodHRwOi8vZmVyb3NzLm9yZz5cbiAqIExpY2Vuc2U6ICBNSVRcbiAqXG4gKiBgbnBtIGluc3RhbGwgaXMtYnVmZmVyYFxuICovXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKG9iaikge1xuICByZXR1cm4gISEob2JqICE9IG51bGwgJiZcbiAgICAob2JqLl9pc0J1ZmZlciB8fCAvLyBGb3IgU2FmYXJpIDUtNyAobWlzc2luZyBPYmplY3QucHJvdG90eXBlLmNvbnN0cnVjdG9yKVxuICAgICAgKG9iai5jb25zdHJ1Y3RvciAmJlxuICAgICAgdHlwZW9mIG9iai5jb25zdHJ1Y3Rvci5pc0J1ZmZlciA9PT0gJ2Z1bmN0aW9uJyAmJlxuICAgICAgb2JqLmNvbnN0cnVjdG9yLmlzQnVmZmVyKG9iaikpXG4gICAgKSlcbn1cbiIsInZhciBpb3RhID0gcmVxdWlyZShcImlvdGEtYXJyYXlcIilcbnZhciBpc0J1ZmZlciA9IHJlcXVpcmUoXCJpcy1idWZmZXJcIilcblxudmFyIGhhc1R5cGVkQXJyYXlzICA9ICgodHlwZW9mIEZsb2F0NjRBcnJheSkgIT09IFwidW5kZWZpbmVkXCIpXG5cbmZ1bmN0aW9uIGNvbXBhcmUxc3QoYSwgYikge1xuICByZXR1cm4gYVswXSAtIGJbMF1cbn1cblxuZnVuY3Rpb24gb3JkZXIoKSB7XG4gIHZhciBzdHJpZGUgPSB0aGlzLnN0cmlkZVxuICB2YXIgdGVybXMgPSBuZXcgQXJyYXkoc3RyaWRlLmxlbmd0aClcbiAgdmFyIGlcbiAgZm9yKGk9MDsgaTx0ZXJtcy5sZW5ndGg7ICsraSkge1xuICAgIHRlcm1zW2ldID0gW01hdGguYWJzKHN0cmlkZVtpXSksIGldXG4gIH1cbiAgdGVybXMuc29ydChjb21wYXJlMXN0KVxuICB2YXIgcmVzdWx0ID0gbmV3IEFycmF5KHRlcm1zLmxlbmd0aClcbiAgZm9yKGk9MDsgaTxyZXN1bHQubGVuZ3RoOyArK2kpIHtcbiAgICByZXN1bHRbaV0gPSB0ZXJtc1tpXVsxXVxuICB9XG4gIHJldHVybiByZXN1bHRcbn1cblxuZnVuY3Rpb24gY29tcGlsZUNvbnN0cnVjdG9yKGR0eXBlLCBkaW1lbnNpb24pIHtcbiAgdmFyIGNsYXNzTmFtZSA9IFtcIlZpZXdcIiwgZGltZW5zaW9uLCBcImRcIiwgZHR5cGVdLmpvaW4oXCJcIilcbiAgaWYoZGltZW5zaW9uIDwgMCkge1xuICAgIGNsYXNzTmFtZSA9IFwiVmlld19OaWxcIiArIGR0eXBlXG4gIH1cbiAgdmFyIHVzZUdldHRlcnMgPSAoZHR5cGUgPT09IFwiZ2VuZXJpY1wiKVxuXG4gIGlmKGRpbWVuc2lvbiA9PT0gLTEpIHtcbiAgICAvL1NwZWNpYWwgY2FzZSBmb3IgdHJpdmlhbCBhcnJheXNcbiAgICB2YXIgY29kZSA9XG4gICAgICBcImZ1bmN0aW9uIFwiK2NsYXNzTmFtZStcIihhKXt0aGlzLmRhdGE9YTt9O1xcXG52YXIgcHJvdG89XCIrY2xhc3NOYW1lK1wiLnByb3RvdHlwZTtcXFxucHJvdG8uZHR5cGU9J1wiK2R0eXBlK1wiJztcXFxucHJvdG8uaW5kZXg9ZnVuY3Rpb24oKXtyZXR1cm4gLTF9O1xcXG5wcm90by5zaXplPTA7XFxcbnByb3RvLmRpbWVuc2lvbj0tMTtcXFxucHJvdG8uc2hhcGU9cHJvdG8uc3RyaWRlPXByb3RvLm9yZGVyPVtdO1xcXG5wcm90by5sbz1wcm90by5oaT1wcm90by50cmFuc3Bvc2U9cHJvdG8uc3RlcD1cXFxuZnVuY3Rpb24oKXtyZXR1cm4gbmV3IFwiK2NsYXNzTmFtZStcIih0aGlzLmRhdGEpO307XFxcbnByb3RvLmdldD1wcm90by5zZXQ9ZnVuY3Rpb24oKXt9O1xcXG5wcm90by5waWNrPWZ1bmN0aW9uKCl7cmV0dXJuIG51bGx9O1xcXG5yZXR1cm4gZnVuY3Rpb24gY29uc3RydWN0X1wiK2NsYXNzTmFtZStcIihhKXtyZXR1cm4gbmV3IFwiK2NsYXNzTmFtZStcIihhKTt9XCJcbiAgICB2YXIgcHJvY2VkdXJlID0gbmV3IEZ1bmN0aW9uKGNvZGUpXG4gICAgcmV0dXJuIHByb2NlZHVyZSgpXG4gIH0gZWxzZSBpZihkaW1lbnNpb24gPT09IDApIHtcbiAgICAvL1NwZWNpYWwgY2FzZSBmb3IgMGQgYXJyYXlzXG4gICAgdmFyIGNvZGUgPVxuICAgICAgXCJmdW5jdGlvbiBcIitjbGFzc05hbWUrXCIoYSxkKSB7XFxcbnRoaXMuZGF0YSA9IGE7XFxcbnRoaXMub2Zmc2V0ID0gZFxcXG59O1xcXG52YXIgcHJvdG89XCIrY2xhc3NOYW1lK1wiLnByb3RvdHlwZTtcXFxucHJvdG8uZHR5cGU9J1wiK2R0eXBlK1wiJztcXFxucHJvdG8uaW5kZXg9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5vZmZzZXR9O1xcXG5wcm90by5kaW1lbnNpb249MDtcXFxucHJvdG8uc2l6ZT0xO1xcXG5wcm90by5zaGFwZT1cXFxucHJvdG8uc3RyaWRlPVxcXG5wcm90by5vcmRlcj1bXTtcXFxucHJvdG8ubG89XFxcbnByb3RvLmhpPVxcXG5wcm90by50cmFuc3Bvc2U9XFxcbnByb3RvLnN0ZXA9ZnVuY3Rpb24gXCIrY2xhc3NOYW1lK1wiX2NvcHkoKSB7XFxcbnJldHVybiBuZXcgXCIrY2xhc3NOYW1lK1wiKHRoaXMuZGF0YSx0aGlzLm9mZnNldClcXFxufTtcXFxucHJvdG8ucGljaz1mdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfcGljaygpe1xcXG5yZXR1cm4gVHJpdmlhbEFycmF5KHRoaXMuZGF0YSk7XFxcbn07XFxcbnByb3RvLnZhbHVlT2Y9cHJvdG8uZ2V0PWZ1bmN0aW9uIFwiK2NsYXNzTmFtZStcIl9nZXQoKXtcXFxucmV0dXJuIFwiKyh1c2VHZXR0ZXJzID8gXCJ0aGlzLmRhdGEuZ2V0KHRoaXMub2Zmc2V0KVwiIDogXCJ0aGlzLmRhdGFbdGhpcy5vZmZzZXRdXCIpK1xuXCJ9O1xcXG5wcm90by5zZXQ9ZnVuY3Rpb24gXCIrY2xhc3NOYW1lK1wiX3NldCh2KXtcXFxucmV0dXJuIFwiKyh1c2VHZXR0ZXJzID8gXCJ0aGlzLmRhdGEuc2V0KHRoaXMub2Zmc2V0LHYpXCIgOiBcInRoaXMuZGF0YVt0aGlzLm9mZnNldF09dlwiKStcIlxcXG59O1xcXG5yZXR1cm4gZnVuY3Rpb24gY29uc3RydWN0X1wiK2NsYXNzTmFtZStcIihhLGIsYyxkKXtyZXR1cm4gbmV3IFwiK2NsYXNzTmFtZStcIihhLGQpfVwiXG4gICAgdmFyIHByb2NlZHVyZSA9IG5ldyBGdW5jdGlvbihcIlRyaXZpYWxBcnJheVwiLCBjb2RlKVxuICAgIHJldHVybiBwcm9jZWR1cmUoQ0FDSEVEX0NPTlNUUlVDVE9SU1tkdHlwZV1bMF0pXG4gIH1cblxuICB2YXIgY29kZSA9IFtcIid1c2Ugc3RyaWN0J1wiXVxuXG4gIC8vQ3JlYXRlIGNvbnN0cnVjdG9yIGZvciB2aWV3XG4gIHZhciBpbmRpY2VzID0gaW90YShkaW1lbnNpb24pXG4gIHZhciBhcmdzID0gaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgeyByZXR1cm4gXCJpXCIraSB9KVxuICB2YXIgaW5kZXhfc3RyID0gXCJ0aGlzLm9mZnNldCtcIiArIGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHtcbiAgICAgICAgcmV0dXJuIFwidGhpcy5zdHJpZGVbXCIgKyBpICsgXCJdKmlcIiArIGlcbiAgICAgIH0pLmpvaW4oXCIrXCIpXG4gIHZhciBzaGFwZUFyZyA9IGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHtcbiAgICAgIHJldHVybiBcImJcIitpXG4gICAgfSkuam9pbihcIixcIilcbiAgdmFyIHN0cmlkZUFyZyA9IGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHtcbiAgICAgIHJldHVybiBcImNcIitpXG4gICAgfSkuam9pbihcIixcIilcbiAgY29kZS5wdXNoKFxuICAgIFwiZnVuY3Rpb24gXCIrY2xhc3NOYW1lK1wiKGEsXCIgKyBzaGFwZUFyZyArIFwiLFwiICsgc3RyaWRlQXJnICsgXCIsZCl7dGhpcy5kYXRhPWFcIixcbiAgICAgIFwidGhpcy5zaGFwZT1bXCIgKyBzaGFwZUFyZyArIFwiXVwiLFxuICAgICAgXCJ0aGlzLnN0cmlkZT1bXCIgKyBzdHJpZGVBcmcgKyBcIl1cIixcbiAgICAgIFwidGhpcy5vZmZzZXQ9ZHwwfVwiLFxuICAgIFwidmFyIHByb3RvPVwiK2NsYXNzTmFtZStcIi5wcm90b3R5cGVcIixcbiAgICBcInByb3RvLmR0eXBlPSdcIitkdHlwZStcIidcIixcbiAgICBcInByb3RvLmRpbWVuc2lvbj1cIitkaW1lbnNpb24pXG5cbiAgLy92aWV3LnNpemU6XG4gIGNvZGUucHVzaChcIk9iamVjdC5kZWZpbmVQcm9wZXJ0eShwcm90bywnc2l6ZScse2dldDpmdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfc2l6ZSgpe1xcXG5yZXR1cm4gXCIraW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgeyByZXR1cm4gXCJ0aGlzLnNoYXBlW1wiK2krXCJdXCIgfSkuam9pbihcIipcIiksXG5cIn19KVwiKVxuXG4gIC8vdmlldy5vcmRlcjpcbiAgaWYoZGltZW5zaW9uID09PSAxKSB7XG4gICAgY29kZS5wdXNoKFwicHJvdG8ub3JkZXI9WzBdXCIpXG4gIH0gZWxzZSB7XG4gICAgY29kZS5wdXNoKFwiT2JqZWN0LmRlZmluZVByb3BlcnR5KHByb3RvLCdvcmRlcicse2dldDpcIilcbiAgICBpZihkaW1lbnNpb24gPCA0KSB7XG4gICAgICBjb2RlLnB1c2goXCJmdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfb3JkZXIoKXtcIilcbiAgICAgIGlmKGRpbWVuc2lvbiA9PT0gMikge1xuICAgICAgICBjb2RlLnB1c2goXCJyZXR1cm4gKE1hdGguYWJzKHRoaXMuc3RyaWRlWzBdKT5NYXRoLmFicyh0aGlzLnN0cmlkZVsxXSkpP1sxLDBdOlswLDFdfX0pXCIpXG4gICAgICB9IGVsc2UgaWYoZGltZW5zaW9uID09PSAzKSB7XG4gICAgICAgIGNvZGUucHVzaChcblwidmFyIHMwPU1hdGguYWJzKHRoaXMuc3RyaWRlWzBdKSxzMT1NYXRoLmFicyh0aGlzLnN0cmlkZVsxXSksczI9TWF0aC5hYnModGhpcy5zdHJpZGVbMl0pO1xcXG5pZihzMD5zMSl7XFxcbmlmKHMxPnMyKXtcXFxucmV0dXJuIFsyLDEsMF07XFxcbn1lbHNlIGlmKHMwPnMyKXtcXFxucmV0dXJuIFsxLDIsMF07XFxcbn1lbHNle1xcXG5yZXR1cm4gWzEsMCwyXTtcXFxufVxcXG59ZWxzZSBpZihzMD5zMil7XFxcbnJldHVybiBbMiwwLDFdO1xcXG59ZWxzZSBpZihzMj5zMSl7XFxcbnJldHVybiBbMCwxLDJdO1xcXG59ZWxzZXtcXFxucmV0dXJuIFswLDIsMV07XFxcbn19fSlcIilcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgY29kZS5wdXNoKFwiT1JERVJ9KVwiKVxuICAgIH1cbiAgfVxuXG4gIC8vdmlldy5zZXQoaTAsIC4uLiwgdik6XG4gIGNvZGUucHVzaChcblwicHJvdG8uc2V0PWZ1bmN0aW9uIFwiK2NsYXNzTmFtZStcIl9zZXQoXCIrYXJncy5qb2luKFwiLFwiKStcIix2KXtcIilcbiAgaWYodXNlR2V0dGVycykge1xuICAgIGNvZGUucHVzaChcInJldHVybiB0aGlzLmRhdGEuc2V0KFwiK2luZGV4X3N0citcIix2KX1cIilcbiAgfSBlbHNlIHtcbiAgICBjb2RlLnB1c2goXCJyZXR1cm4gdGhpcy5kYXRhW1wiK2luZGV4X3N0citcIl09dn1cIilcbiAgfVxuXG4gIC8vdmlldy5nZXQoaTAsIC4uLik6XG4gIGNvZGUucHVzaChcInByb3RvLmdldD1mdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfZ2V0KFwiK2FyZ3Muam9pbihcIixcIikrXCIpe1wiKVxuICBpZih1c2VHZXR0ZXJzKSB7XG4gICAgY29kZS5wdXNoKFwicmV0dXJuIHRoaXMuZGF0YS5nZXQoXCIraW5kZXhfc3RyK1wiKX1cIilcbiAgfSBlbHNlIHtcbiAgICBjb2RlLnB1c2goXCJyZXR1cm4gdGhpcy5kYXRhW1wiK2luZGV4X3N0citcIl19XCIpXG4gIH1cblxuICAvL3ZpZXcuaW5kZXg6XG4gIGNvZGUucHVzaChcbiAgICBcInByb3RvLmluZGV4PWZ1bmN0aW9uIFwiK2NsYXNzTmFtZStcIl9pbmRleChcIiwgYXJncy5qb2luKCksIFwiKXtyZXR1cm4gXCIraW5kZXhfc3RyK1wifVwiKVxuXG4gIC8vdmlldy5oaSgpOlxuICBjb2RlLnB1c2goXCJwcm90by5oaT1mdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfaGkoXCIrYXJncy5qb2luKFwiLFwiKStcIil7cmV0dXJuIG5ldyBcIitjbGFzc05hbWUrXCIodGhpcy5kYXRhLFwiK1xuICAgIGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHtcbiAgICAgIHJldHVybiBbXCIodHlwZW9mIGlcIixpLFwiIT09J251bWJlcid8fGlcIixpLFwiPDApP3RoaXMuc2hhcGVbXCIsIGksIFwiXTppXCIsIGksXCJ8MFwiXS5qb2luKFwiXCIpXG4gICAgfSkuam9pbihcIixcIikrXCIsXCIrXG4gICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkge1xuICAgICAgcmV0dXJuIFwidGhpcy5zdHJpZGVbXCIraSArIFwiXVwiXG4gICAgfSkuam9pbihcIixcIikrXCIsdGhpcy5vZmZzZXQpfVwiKVxuXG4gIC8vdmlldy5sbygpOlxuICB2YXIgYV92YXJzID0gaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkgeyByZXR1cm4gXCJhXCIraStcIj10aGlzLnNoYXBlW1wiK2krXCJdXCIgfSlcbiAgdmFyIGNfdmFycyA9IGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHsgcmV0dXJuIFwiY1wiK2krXCI9dGhpcy5zdHJpZGVbXCIraStcIl1cIiB9KVxuICBjb2RlLnB1c2goXCJwcm90by5sbz1mdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfbG8oXCIrYXJncy5qb2luKFwiLFwiKStcIil7dmFyIGI9dGhpcy5vZmZzZXQsZD0wLFwiK2FfdmFycy5qb2luKFwiLFwiKStcIixcIitjX3ZhcnMuam9pbihcIixcIikpXG4gIGZvcih2YXIgaT0wOyBpPGRpbWVuc2lvbjsgKytpKSB7XG4gICAgY29kZS5wdXNoKFxuXCJpZih0eXBlb2YgaVwiK2krXCI9PT0nbnVtYmVyJyYmaVwiK2krXCI+PTApe1xcXG5kPWlcIitpK1wifDA7XFxcbmIrPWNcIitpK1wiKmQ7XFxcbmFcIitpK1wiLT1kfVwiKVxuICB9XG4gIGNvZGUucHVzaChcInJldHVybiBuZXcgXCIrY2xhc3NOYW1lK1wiKHRoaXMuZGF0YSxcIitcbiAgICBpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7XG4gICAgICByZXR1cm4gXCJhXCIraVxuICAgIH0pLmpvaW4oXCIsXCIpK1wiLFwiK1xuICAgIGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHtcbiAgICAgIHJldHVybiBcImNcIitpXG4gICAgfSkuam9pbihcIixcIikrXCIsYil9XCIpXG5cbiAgLy92aWV3LnN0ZXAoKTpcbiAgY29kZS5wdXNoKFwicHJvdG8uc3RlcD1mdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfc3RlcChcIithcmdzLmpvaW4oXCIsXCIpK1wiKXt2YXIgXCIrXG4gICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkge1xuICAgICAgcmV0dXJuIFwiYVwiK2krXCI9dGhpcy5zaGFwZVtcIitpK1wiXVwiXG4gICAgfSkuam9pbihcIixcIikrXCIsXCIrXG4gICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkge1xuICAgICAgcmV0dXJuIFwiYlwiK2krXCI9dGhpcy5zdHJpZGVbXCIraStcIl1cIlxuICAgIH0pLmpvaW4oXCIsXCIpK1wiLGM9dGhpcy5vZmZzZXQsZD0wLGNlaWw9TWF0aC5jZWlsXCIpXG4gIGZvcih2YXIgaT0wOyBpPGRpbWVuc2lvbjsgKytpKSB7XG4gICAgY29kZS5wdXNoKFxuXCJpZih0eXBlb2YgaVwiK2krXCI9PT0nbnVtYmVyJyl7XFxcbmQ9aVwiK2krXCJ8MDtcXFxuaWYoZDwwKXtcXFxuYys9YlwiK2krXCIqKGFcIitpK1wiLTEpO1xcXG5hXCIraStcIj1jZWlsKC1hXCIraStcIi9kKVxcXG59ZWxzZXtcXFxuYVwiK2krXCI9Y2VpbChhXCIraStcIi9kKVxcXG59XFxcbmJcIitpK1wiKj1kXFxcbn1cIilcbiAgfVxuICBjb2RlLnB1c2goXCJyZXR1cm4gbmV3IFwiK2NsYXNzTmFtZStcIih0aGlzLmRhdGEsXCIrXG4gICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkge1xuICAgICAgcmV0dXJuIFwiYVwiICsgaVxuICAgIH0pLmpvaW4oXCIsXCIpK1wiLFwiK1xuICAgIGluZGljZXMubWFwKGZ1bmN0aW9uKGkpIHtcbiAgICAgIHJldHVybiBcImJcIiArIGlcbiAgICB9KS5qb2luKFwiLFwiKStcIixjKX1cIilcblxuICAvL3ZpZXcudHJhbnNwb3NlKCk6XG4gIHZhciB0U2hhcGUgPSBuZXcgQXJyYXkoZGltZW5zaW9uKVxuICB2YXIgdFN0cmlkZSA9IG5ldyBBcnJheShkaW1lbnNpb24pXG4gIGZvcih2YXIgaT0wOyBpPGRpbWVuc2lvbjsgKytpKSB7XG4gICAgdFNoYXBlW2ldID0gXCJhW2lcIitpK1wiXVwiXG4gICAgdFN0cmlkZVtpXSA9IFwiYltpXCIraStcIl1cIlxuICB9XG4gIGNvZGUucHVzaChcInByb3RvLnRyYW5zcG9zZT1mdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfdHJhbnNwb3NlKFwiK2FyZ3MrXCIpe1wiK1xuICAgIGFyZ3MubWFwKGZ1bmN0aW9uKG4saWR4KSB7IHJldHVybiBuICsgXCI9KFwiICsgbiArIFwiPT09dW5kZWZpbmVkP1wiICsgaWR4ICsgXCI6XCIgKyBuICsgXCJ8MClcIn0pLmpvaW4oXCI7XCIpLFxuICAgIFwidmFyIGE9dGhpcy5zaGFwZSxiPXRoaXMuc3RyaWRlO3JldHVybiBuZXcgXCIrY2xhc3NOYW1lK1wiKHRoaXMuZGF0YSxcIit0U2hhcGUuam9pbihcIixcIikrXCIsXCIrdFN0cmlkZS5qb2luKFwiLFwiKStcIix0aGlzLm9mZnNldCl9XCIpXG5cbiAgLy92aWV3LnBpY2soKTpcbiAgY29kZS5wdXNoKFwicHJvdG8ucGljaz1mdW5jdGlvbiBcIitjbGFzc05hbWUrXCJfcGljayhcIithcmdzK1wiKXt2YXIgYT1bXSxiPVtdLGM9dGhpcy5vZmZzZXRcIilcbiAgZm9yKHZhciBpPTA7IGk8ZGltZW5zaW9uOyArK2kpIHtcbiAgICBjb2RlLnB1c2goXCJpZih0eXBlb2YgaVwiK2krXCI9PT0nbnVtYmVyJyYmaVwiK2krXCI+PTApe2M9KGMrdGhpcy5zdHJpZGVbXCIraStcIl0qaVwiK2krXCIpfDB9ZWxzZXthLnB1c2godGhpcy5zaGFwZVtcIitpK1wiXSk7Yi5wdXNoKHRoaXMuc3RyaWRlW1wiK2krXCJdKX1cIilcbiAgfVxuICBjb2RlLnB1c2goXCJ2YXIgY3Rvcj1DVE9SX0xJU1RbYS5sZW5ndGgrMV07cmV0dXJuIGN0b3IodGhpcy5kYXRhLGEsYixjKX1cIilcblxuICAvL0FkZCByZXR1cm4gc3RhdGVtZW50XG4gIGNvZGUucHVzaChcInJldHVybiBmdW5jdGlvbiBjb25zdHJ1Y3RfXCIrY2xhc3NOYW1lK1wiKGRhdGEsc2hhcGUsc3RyaWRlLG9mZnNldCl7cmV0dXJuIG5ldyBcIitjbGFzc05hbWUrXCIoZGF0YSxcIitcbiAgICBpbmRpY2VzLm1hcChmdW5jdGlvbihpKSB7XG4gICAgICByZXR1cm4gXCJzaGFwZVtcIitpK1wiXVwiXG4gICAgfSkuam9pbihcIixcIikrXCIsXCIrXG4gICAgaW5kaWNlcy5tYXAoZnVuY3Rpb24oaSkge1xuICAgICAgcmV0dXJuIFwic3RyaWRlW1wiK2krXCJdXCJcbiAgICB9KS5qb2luKFwiLFwiKStcIixvZmZzZXQpfVwiKVxuXG4gIC8vQ29tcGlsZSBwcm9jZWR1cmVcbiAgdmFyIHByb2NlZHVyZSA9IG5ldyBGdW5jdGlvbihcIkNUT1JfTElTVFwiLCBcIk9SREVSXCIsIGNvZGUuam9pbihcIlxcblwiKSlcbiAgcmV0dXJuIHByb2NlZHVyZShDQUNIRURfQ09OU1RSVUNUT1JTW2R0eXBlXSwgb3JkZXIpXG59XG5cbmZ1bmN0aW9uIGFycmF5RFR5cGUoZGF0YSkge1xuICBpZihpc0J1ZmZlcihkYXRhKSkge1xuICAgIHJldHVybiBcImJ1ZmZlclwiXG4gIH1cbiAgaWYoaGFzVHlwZWRBcnJheXMpIHtcbiAgICBzd2l0Y2goT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGRhdGEpKSB7XG4gICAgICBjYXNlIFwiW29iamVjdCBGbG9hdDY0QXJyYXldXCI6XG4gICAgICAgIHJldHVybiBcImZsb2F0NjRcIlxuICAgICAgY2FzZSBcIltvYmplY3QgRmxvYXQzMkFycmF5XVwiOlxuICAgICAgICByZXR1cm4gXCJmbG9hdDMyXCJcbiAgICAgIGNhc2UgXCJbb2JqZWN0IEludDhBcnJheV1cIjpcbiAgICAgICAgcmV0dXJuIFwiaW50OFwiXG4gICAgICBjYXNlIFwiW29iamVjdCBJbnQxNkFycmF5XVwiOlxuICAgICAgICByZXR1cm4gXCJpbnQxNlwiXG4gICAgICBjYXNlIFwiW29iamVjdCBJbnQzMkFycmF5XVwiOlxuICAgICAgICByZXR1cm4gXCJpbnQzMlwiXG4gICAgICBjYXNlIFwiW29iamVjdCBVaW50OEFycmF5XVwiOlxuICAgICAgICByZXR1cm4gXCJ1aW50OFwiXG4gICAgICBjYXNlIFwiW29iamVjdCBVaW50MTZBcnJheV1cIjpcbiAgICAgICAgcmV0dXJuIFwidWludDE2XCJcbiAgICAgIGNhc2UgXCJbb2JqZWN0IFVpbnQzMkFycmF5XVwiOlxuICAgICAgICByZXR1cm4gXCJ1aW50MzJcIlxuICAgICAgY2FzZSBcIltvYmplY3QgVWludDhDbGFtcGVkQXJyYXldXCI6XG4gICAgICAgIHJldHVybiBcInVpbnQ4X2NsYW1wZWRcIlxuICAgIH1cbiAgfVxuICBpZihBcnJheS5pc0FycmF5KGRhdGEpKSB7XG4gICAgcmV0dXJuIFwiYXJyYXlcIlxuICB9XG4gIHJldHVybiBcImdlbmVyaWNcIlxufVxuXG52YXIgQ0FDSEVEX0NPTlNUUlVDVE9SUyA9IHtcbiAgXCJmbG9hdDMyXCI6W10sXG4gIFwiZmxvYXQ2NFwiOltdLFxuICBcImludDhcIjpbXSxcbiAgXCJpbnQxNlwiOltdLFxuICBcImludDMyXCI6W10sXG4gIFwidWludDhcIjpbXSxcbiAgXCJ1aW50MTZcIjpbXSxcbiAgXCJ1aW50MzJcIjpbXSxcbiAgXCJhcnJheVwiOltdLFxuICBcInVpbnQ4X2NsYW1wZWRcIjpbXSxcbiAgXCJidWZmZXJcIjpbXSxcbiAgXCJnZW5lcmljXCI6W11cbn1cblxuOyhmdW5jdGlvbigpIHtcbiAgZm9yKHZhciBpZCBpbiBDQUNIRURfQ09OU1RSVUNUT1JTKSB7XG4gICAgQ0FDSEVEX0NPTlNUUlVDVE9SU1tpZF0ucHVzaChjb21waWxlQ29uc3RydWN0b3IoaWQsIC0xKSlcbiAgfVxufSk7XG5cbmZ1bmN0aW9uIHdyYXBwZWROREFycmF5Q3RvcihkYXRhLCBzaGFwZSwgc3RyaWRlLCBvZmZzZXQpIHtcbiAgaWYoZGF0YSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgdmFyIGN0b3IgPSBDQUNIRURfQ09OU1RSVUNUT1JTLmFycmF5WzBdXG4gICAgcmV0dXJuIGN0b3IoW10pXG4gIH0gZWxzZSBpZih0eXBlb2YgZGF0YSA9PT0gXCJudW1iZXJcIikge1xuICAgIGRhdGEgPSBbZGF0YV1cbiAgfVxuICBpZihzaGFwZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgc2hhcGUgPSBbIGRhdGEubGVuZ3RoIF1cbiAgfVxuICB2YXIgZCA9IHNoYXBlLmxlbmd0aFxuICBpZihzdHJpZGUgPT09IHVuZGVmaW5lZCkge1xuICAgIHN0cmlkZSA9IG5ldyBBcnJheShkKVxuICAgIGZvcih2YXIgaT1kLTEsIHN6PTE7IGk+PTA7IC0taSkge1xuICAgICAgc3RyaWRlW2ldID0gc3pcbiAgICAgIHN6ICo9IHNoYXBlW2ldXG4gICAgfVxuICB9XG4gIGlmKG9mZnNldCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgb2Zmc2V0ID0gMFxuICAgIGZvcih2YXIgaT0wOyBpPGQ7ICsraSkge1xuICAgICAgaWYoc3RyaWRlW2ldIDwgMCkge1xuICAgICAgICBvZmZzZXQgLT0gKHNoYXBlW2ldLTEpKnN0cmlkZVtpXVxuICAgICAgfVxuICAgIH1cbiAgfVxuICB2YXIgZHR5cGUgPSBhcnJheURUeXBlKGRhdGEpXG4gIHZhciBjdG9yX2xpc3QgPSBDQUNIRURfQ09OU1RSVUNUT1JTW2R0eXBlXVxuICB3aGlsZShjdG9yX2xpc3QubGVuZ3RoIDw9IGQrMSkge1xuICAgIGN0b3JfbGlzdC5wdXNoKGNvbXBpbGVDb25zdHJ1Y3RvcihkdHlwZSwgY3Rvcl9saXN0Lmxlbmd0aC0xKSlcbiAgfVxuICB2YXIgY3RvciA9IGN0b3JfbGlzdFtkKzFdXG4gIHJldHVybiBjdG9yKGRhdGEsIHNoYXBlLCBzdHJpZGUsIG9mZnNldClcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB3cmFwcGVkTkRBcnJheUN0b3JcbiJdfQ== | |
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 = require("cwise-compiler") | |
},{"cwise-compiler":2}],2:[function(require,module,exports){ | |
"use strict" | |
var createThunk = require("./lib/thunk.js") | |
function Procedure() { | |
this.argTypes = [] | |
this.shimArgs = [] | |
this.arrayArgs = [] | |
this.arrayBlockIndices = [] | |
this.scalarArgs = [] | |
this.offsetArgs = [] | |
this.offsetArgIndex = [] | |
this.indexArgs = [] | |
this.shapeArgs = [] | |
this.funcName = "" | |
this.pre = null | |
this.body = null | |
this.post = null | |
this.debug = false | |
} | |
function compileCwise(user_args) { | |
//Create procedure | |
var proc = new Procedure() | |
//Parse blocks | |
proc.pre = user_args.pre | |
proc.body = user_args.body | |
proc.post = user_args.post | |
//Parse arguments | |
var proc_args = user_args.args.slice(0) | |
proc.argTypes = proc_args | |
for(var i=0; i<proc_args.length; ++i) { | |
var arg_type = proc_args[i] | |
if(arg_type === "array" || (typeof arg_type === "object" && arg_type.blockIndices)) { | |
proc.argTypes[i] = "array" | |
proc.arrayArgs.push(i) | |
proc.arrayBlockIndices.push(arg_type.blockIndices ? arg_type.blockIndices : 0) | |
proc.shimArgs.push("array" + i) | |
if(i < proc.pre.args.length && proc.pre.args[i].count>0) { | |
throw new Error("cwise: pre() block may not reference array args") | |
} | |
if(i < proc.post.args.length && proc.post.args[i].count>0) { | |
throw new Error("cwise: post() block may not reference array args") | |
} | |
} else if(arg_type === "scalar") { | |
proc.scalarArgs.push(i) | |
proc.shimArgs.push("scalar" + i) | |
} else if(arg_type === "index") { | |
proc.indexArgs.push(i) | |
if(i < proc.pre.args.length && proc.pre.args[i].count > 0) { | |
throw new Error("cwise: pre() block may not reference array index") | |
} | |
if(i < proc.body.args.length && proc.body.args[i].lvalue) { | |
throw new Error("cwise: body() block may not write to array index") | |
} | |
if(i < proc.post.args.length && proc.post.args[i].count > 0) { | |
throw new Error("cwise: post() block may not reference array index") | |
} | |
} else if(arg_type === "shape") { | |
proc.shapeArgs.push(i) | |
if(i < proc.pre.args.length && proc.pre.args[i].lvalue) { | |
throw new Error("cwise: pre() block may not write to array shape") | |
} | |
if(i < proc.body.args.length && proc.body.args[i].lvalue) { | |
throw new Error("cwise: body() block may not write to array shape") | |
} | |
if(i < proc.post.args.length && proc.post.args[i].lvalue) { | |
throw new Error("cwise: post() block may not write to array shape") | |
} | |
} else if(typeof arg_type === "object" && arg_type.offset) { | |
proc.argTypes[i] = "offset" | |
proc.offsetArgs.push({ array: arg_type.array, offset:arg_type.offset }) | |
proc.offsetArgIndex.push(i) | |
} else { | |
throw new Error("cwise: Unknown argument type " + proc_args[i]) | |
} | |
} | |
//Make sure at least one array argument was specified | |
if(proc.arrayArgs.length <= 0) { | |
throw new Error("cwise: No array arguments specified") | |
} | |
//Make sure arguments are correct | |
if(proc.pre.args.length > proc_args.length) { | |
throw new Error("cwise: Too many arguments in pre() block") | |
} | |
if(proc.body.args.length > proc_args.length) { | |
throw new Error("cwise: Too many arguments in body() block") | |
} | |
if(proc.post.args.length > proc_args.length) { | |
throw new Error("cwise: Too many arguments in post() block") | |
} | |
//Check debug flag | |
proc.debug = !!user_args.printCode || !!user_args.debug | |
//Retrieve name | |
proc.funcName = user_args.funcName || "cwise" | |
//Read in block size | |
proc.blockSize = user_args.blockSize || 64 | |
return createThunk(proc) | |
} | |
module.exports = compileCwise | |
},{"./lib/thunk.js":4}],3:[function(require,module,exports){ | |
"use strict" | |
var uniq = require("uniq") | |
// This function generates very simple loops analogous to how you typically traverse arrays (the outermost loop corresponds to the slowest changing index, the innermost loop to the fastest changing index) | |
// TODO: If two arrays have the same strides (and offsets) there is potential for decreasing the number of "pointers" and related variables. The drawback is that the type signature would become more specific and that there would thus be less potential for caching, but it might still be worth it, especially when dealing with large numbers of arguments. | |
function innerFill(order, proc, body) { | |
var dimension = order.length | |
, nargs = proc.arrayArgs.length | |
, has_index = proc.indexArgs.length>0 | |
, code = [] | |
, vars = [] | |
, idx=0, pidx=0, i, j | |
for(i=0; i<dimension; ++i) { // Iteration variables | |
vars.push(["i",i,"=0"].join("")) | |
} | |
//Compute scan deltas | |
for(j=0; j<nargs; ++j) { | |
for(i=0; i<dimension; ++i) { | |
pidx = idx | |
idx = order[i] | |
if(i === 0) { // The innermost/fastest dimension's delta is simply its stride | |
vars.push(["d",j,"s",i,"=t",j,"p",idx].join("")) | |
} else { // For other dimensions the delta is basically the stride minus something which essentially "rewinds" the previous (more inner) dimension | |
vars.push(["d",j,"s",i,"=(t",j,"p",idx,"-s",pidx,"*t",j,"p",pidx,")"].join("")) | |
} | |
} | |
} | |
code.push("var " + vars.join(",")) | |
//Scan loop | |
for(i=dimension-1; i>=0; --i) { // Start at largest stride and work your way inwards | |
idx = order[i] | |
code.push(["for(i",i,"=0;i",i,"<s",idx,";++i",i,"){"].join("")) | |
} | |
//Push body of inner loop | |
code.push(body) | |
//Advance scan pointers | |
for(i=0; i<dimension; ++i) { | |
pidx = idx | |
idx = order[i] | |
for(j=0; j<nargs; ++j) { | |
code.push(["p",j,"+=d",j,"s",i].join("")) | |
} | |
if(has_index) { | |
if(i > 0) { | |
code.push(["index[",pidx,"]-=s",pidx].join("")) | |
} | |
code.push(["++index[",idx,"]"].join("")) | |
} | |
code.push("}") | |
} | |
return code.join("\n") | |
} | |
// Generate "outer" loops that loop over blocks of data, applying "inner" loops to the blocks by manipulating the local variables in such a way that the inner loop only "sees" the current block. | |
// TODO: If this is used, then the previous declaration (done by generateCwiseOp) of s* is essentially unnecessary. | |
// I believe the s* are not used elsewhere (in particular, I don't think they're used in the pre/post parts and "shape" is defined independently), so it would be possible to make defining the s* dependent on what loop method is being used. | |
function outerFill(matched, order, proc, body) { | |
var dimension = order.length | |
, nargs = proc.arrayArgs.length | |
, blockSize = proc.blockSize | |
, has_index = proc.indexArgs.length > 0 | |
, code = [] | |
for(var i=0; i<nargs; ++i) { | |
code.push(["var offset",i,"=p",i].join("")) | |
} | |
//Generate loops for unmatched dimensions | |
// The order in which these dimensions are traversed is fairly arbitrary (from small stride to large stride, for the first argument) | |
// TODO: It would be nice if the order in which these loops are placed would also be somehow "optimal" (at the very least we should check that it really doesn't hurt us if they're not). | |
for(var i=matched; i<dimension; ++i) { | |
code.push(["for(var j"+i+"=SS[", order[i], "]|0;j", i, ">0;){"].join("")) // Iterate back to front | |
code.push(["if(j",i,"<",blockSize,"){"].join("")) // Either decrease j by blockSize (s = blockSize), or set it to zero (after setting s = j). | |
code.push(["s",order[i],"=j",i].join("")) | |
code.push(["j",i,"=0"].join("")) | |
code.push(["}else{s",order[i],"=",blockSize].join("")) | |
code.push(["j",i,"-=",blockSize,"}"].join("")) | |
if(has_index) { | |
code.push(["index[",order[i],"]=j",i].join("")) | |
} | |
} | |
for(var i=0; i<nargs; ++i) { | |
var indexStr = ["offset"+i] | |
for(var j=matched; j<dimension; ++j) { | |
indexStr.push(["j",j,"*t",i,"p",order[j]].join("")) | |
} | |
code.push(["p",i,"=(",indexStr.join("+"),")"].join("")) | |
} | |
code.push(innerFill(order, proc, body)) | |
for(var i=matched; i<dimension; ++i) { | |
code.push("}") | |
} | |
return code.join("\n") | |
} | |
//Count the number of compatible inner orders | |
// This is the length of the longest common prefix of the arrays in orders. | |
// Each array in orders lists the dimensions of the correspond ndarray in order of increasing stride. | |
// This is thus the maximum number of dimensions that can be efficiently traversed by simple nested loops for all arrays. | |
function countMatches(orders) { | |
var matched = 0, dimension = orders[0].length | |
while(matched < dimension) { | |
for(var j=1; j<orders.length; ++j) { | |
if(orders[j][matched] !== orders[0][matched]) { | |
return matched | |
} | |
} | |
++matched | |
} | |
return matched | |
} | |
//Processes a block according to the given data types | |
// Replaces variable names by different ones, either "local" ones (that are then ferried in and out of the given array) or ones matching the arguments that the function performing the ultimate loop will accept. | |
function processBlock(block, proc, dtypes) { | |
var code = block.body | |
var pre = [] | |
var post = [] | |
for(var i=0; i<block.args.length; ++i) { | |
var carg = block.args[i] | |
if(carg.count <= 0) { | |
continue | |
} | |
var re = new RegExp(carg.name, "g") | |
var ptrStr = "" | |
var arrNum = proc.arrayArgs.indexOf(i) | |
switch(proc.argTypes[i]) { | |
case "offset": | |
var offArgIndex = proc.offsetArgIndex.indexOf(i) | |
var offArg = proc.offsetArgs[offArgIndex] | |
arrNum = offArg.array | |
ptrStr = "+q" + offArgIndex // Adds offset to the "pointer" in the array | |
case "array": | |
ptrStr = "p" + arrNum + ptrStr | |
var localStr = "l" + i | |
var arrStr = "a" + arrNum | |
if (proc.arrayBlockIndices[arrNum] === 0) { // Argument to body is just a single value from this array | |
if(carg.count === 1) { // Argument/array used only once(?) | |
if(dtypes[arrNum] === "generic") { | |
if(carg.lvalue) { | |
pre.push(["var ", localStr, "=", arrStr, ".get(", ptrStr, ")"].join("")) // Is this necessary if the argument is ONLY used as an lvalue? (keep in mind that we can have a += something, so we would actually need to check carg.rvalue) | |
code = code.replace(re, localStr) | |
post.push([arrStr, ".set(", ptrStr, ",", localStr,")"].join("")) | |
} else { | |
code = code.replace(re, [arrStr, ".get(", ptrStr, ")"].join("")) | |
} | |
} else { | |
code = code.replace(re, [arrStr, "[", ptrStr, "]"].join("")) | |
} | |
} else if(dtypes[arrNum] === "generic") { | |
pre.push(["var ", localStr, "=", arrStr, ".get(", ptrStr, ")"].join("")) // TODO: Could we optimize by checking for carg.rvalue? | |
code = code.replace(re, localStr) | |
if(carg.lvalue) { | |
post.push([arrStr, ".set(", ptrStr, ",", localStr,")"].join("")) | |
} | |
} else { | |
pre.push(["var ", localStr, "=", arrStr, "[", ptrStr, "]"].join("")) // TODO: Could we optimize by checking for carg.rvalue? | |
code = code.replace(re, localStr) | |
if(carg.lvalue) { | |
post.push([arrStr, "[", ptrStr, "]=", localStr].join("")) | |
} | |
} | |
} else { // Argument to body is a "block" | |
var reStrArr = [carg.name], ptrStrArr = [ptrStr] | |
for(var j=0; j<Math.abs(proc.arrayBlockIndices[arrNum]); j++) { | |
reStrArr.push("\\s*\\[([^\\]]+)\\]") | |
ptrStrArr.push("$" + (j+1) + "*t" + arrNum + "b" + j) // Matched index times stride | |
} | |
re = new RegExp(reStrArr.join(""), "g") | |
ptrStr = ptrStrArr.join("+") | |
if(dtypes[arrNum] === "generic") { | |
/*if(carg.lvalue) { | |
pre.push(["var ", localStr, "=", arrStr, ".get(", ptrStr, ")"].join("")) // Is this necessary if the argument is ONLY used as an lvalue? (keep in mind that we can have a += something, so we would actually need to check carg.rvalue) | |
code = code.replace(re, localStr) | |
post.push([arrStr, ".set(", ptrStr, ",", localStr,")"].join("")) | |
} else { | |
code = code.replace(re, [arrStr, ".get(", ptrStr, ")"].join("")) | |
}*/ | |
throw new Error("cwise: Generic arrays not supported in combination with blocks!") | |
} else { | |
// This does not produce any local variables, even if variables are used multiple times. It would be possible to do so, but it would complicate things quite a bit. | |
code = code.replace(re, [arrStr, "[", ptrStr, "]"].join("")) | |
} | |
} | |
break | |
case "scalar": | |
code = code.replace(re, "Y" + proc.scalarArgs.indexOf(i)) | |
break | |
case "index": | |
code = code.replace(re, "index") | |
break | |
case "shape": | |
code = code.replace(re, "shape") | |
break | |
} | |
} | |
return [pre.join("\n"), code, post.join("\n")].join("\n").trim() | |
} | |
function typeSummary(dtypes) { | |
var summary = new Array(dtypes.length) | |
var allEqual = true | |
for(var i=0; i<dtypes.length; ++i) { | |
var t = dtypes[i] | |
var digits = t.match(/\d+/) | |
if(!digits) { | |
digits = "" | |
} else { | |
digits = digits[0] | |
} | |
if(t.charAt(0) === 0) { | |
summary[i] = "u" + t.charAt(1) + digits | |
} else { | |
summary[i] = t.charAt(0) + digits | |
} | |
if(i > 0) { | |
allEqual = allEqual && summary[i] === summary[i-1] | |
} | |
} | |
if(allEqual) { | |
return summary[0] | |
} | |
return summary.join("") | |
} | |
//Generates a cwise operator | |
function generateCWiseOp(proc, typesig) { | |
//Compute dimension | |
// Arrays get put first in typesig, and there are two entries per array (dtype and order), so this gets the number of dimensions in the first array arg. | |
var dimension = (typesig[1].length - Math.abs(proc.arrayBlockIndices[0]))|0 | |
var orders = new Array(proc.arrayArgs.length) | |
var dtypes = new Array(proc.arrayArgs.length) | |
for(var i=0; i<proc.arrayArgs.length; ++i) { | |
dtypes[i] = typesig[2*i] | |
orders[i] = typesig[2*i+1] | |
} | |
//Determine where block and loop indices start and end | |
var blockBegin = [], blockEnd = [] // These indices are exposed as blocks | |
var loopBegin = [], loopEnd = [] // These indices are iterated over | |
var loopOrders = [] // orders restricted to the loop indices | |
for(var i=0; i<proc.arrayArgs.length; ++i) { | |
if (proc.arrayBlockIndices[i]<0) { | |
loopBegin.push(0) | |
loopEnd.push(dimension) | |
blockBegin.push(dimension) | |
blockEnd.push(dimension+proc.arrayBlockIndices[i]) | |
} else { | |
loopBegin.push(proc.arrayBlockIndices[i]) // Non-negative | |
loopEnd.push(proc.arrayBlockIndices[i]+dimension) | |
blockBegin.push(0) | |
blockEnd.push(proc.arrayBlockIndices[i]) | |
} | |
var newOrder = [] | |
for(var j=0; j<orders[i].length; j++) { | |
if (loopBegin[i]<=orders[i][j] && orders[i][j]<loopEnd[i]) { | |
newOrder.push(orders[i][j]-loopBegin[i]) // If this is a loop index, put it in newOrder, subtracting loopBegin, to make sure that all loopOrders are using a common set of indices. | |
} | |
} | |
loopOrders.push(newOrder) | |
} | |
//First create arguments for procedure | |
var arglist = ["SS"] // SS is the overall shape over which we iterate | |
var code = ["'use strict'"] | |
var vars = [] | |
for(var j=0; j<dimension; ++j) { | |
vars.push(["s", j, "=SS[", j, "]"].join("")) // The limits for each dimension. | |
} | |
for(var i=0; i<proc.arrayArgs.length; ++i) { | |
arglist.push("a"+i) // Actual data array | |
arglist.push("t"+i) // Strides | |
arglist.push("p"+i) // Offset in the array at which the data starts (also used for iterating over the data) | |
for(var j=0; j<dimension; ++j) { // Unpack the strides into vars for looping | |
vars.push(["t",i,"p",j,"=t",i,"[",loopBegin[i]+j,"]"].join("")) | |
} | |
for(var j=0; j<Math.abs(proc.arrayBlockIndices[i]); ++j) { // Unpack the strides into vars for block iteration | |
vars.push(["t",i,"b",j,"=t",i,"[",blockBegin[i]+j,"]"].join("")) | |
} | |
} | |
for(var i=0; i<proc.scalarArgs.length; ++i) { | |
arglist.push("Y" + i) | |
} | |
if(proc.shapeArgs.length > 0) { | |
vars.push("shape=SS.slice(0)") // Makes the shape over which we iterate available to the user defined functions (so you can use width/height for example) | |
} | |
if(proc.indexArgs.length > 0) { | |
// Prepare an array to keep track of the (logical) indices, initialized to dimension zeroes. | |
var zeros = new Array(dimension) | |
for(var i=0; i<dimension; ++i) { | |
zeros[i] = "0" | |
} | |
vars.push(["index=[", zeros.join(","), "]"].join("")) | |
} | |
for(var i=0; i<proc.offsetArgs.length; ++i) { // Offset arguments used for stencil operations | |
var off_arg = proc.offsetArgs[i] | |
var init_string = [] | |
for(var j=0; j<off_arg.offset.length; ++j) { | |
if(off_arg.offset[j] === 0) { | |
continue | |
} else if(off_arg.offset[j] === 1) { | |
init_string.push(["t", off_arg.array, "p", j].join("")) | |
} else { | |
init_string.push([off_arg.offset[j], "*t", off_arg.array, "p", j].join("")) | |
} | |
} | |
if(init_string.length === 0) { | |
vars.push("q" + i + "=0") | |
} else { | |
vars.push(["q", i, "=", init_string.join("+")].join("")) | |
} | |
} | |
//Prepare this variables | |
var thisVars = uniq([].concat(proc.pre.thisVars) | |
.concat(proc.body.thisVars) | |
.concat(proc.post.thisVars)) | |
vars = vars.concat(thisVars) | |
code.push("var " + vars.join(",")) | |
for(var i=0; i<proc.arrayArgs.length; ++i) { | |
code.push("p"+i+"|=0") | |
} | |
//Inline prelude | |
if(proc.pre.body.length > 3) { | |
code.push(processBlock(proc.pre, proc, dtypes)) | |
} | |
//Process body | |
var body = processBlock(proc.body, proc, dtypes) | |
var matched = countMatches(loopOrders) | |
if(matched < dimension) { | |
code.push(outerFill(matched, loopOrders[0], proc, body)) // TODO: Rather than passing loopOrders[0], it might be interesting to look at passing an order that represents the majority of the arguments for example. | |
} else { | |
code.push(innerFill(loopOrders[0], proc, body)) | |
} | |
//Inline epilog | |
if(proc.post.body.length > 3) { | |
code.push(processBlock(proc.post, proc, dtypes)) | |
} | |
if(proc.debug) { | |
console.log("-----Generated cwise routine for ", typesig, ":\n" + code.join("\n") + "\n----------") | |
} | |
var loopName = [(proc.funcName||"unnamed"), "_cwise_loop_", orders[0].join("s"),"m",matched,typeSummary(dtypes)].join("") | |
var f = new Function(["function ",loopName,"(", arglist.join(","),"){", code.join("\n"),"} return ", loopName].join("")) | |
return f() | |
} | |
module.exports = generateCWiseOp | |
},{"uniq":5}],4:[function(require,module,exports){ | |
"use strict" | |
// The function below is called when constructing a cwise function object, and does the following: | |
// A function object is constructed which accepts as argument a compilation function and returns another function. | |
// It is this other function that is eventually returned by createThunk, and this function is the one that actually | |
// checks whether a certain pattern of arguments has already been used before and compiles new loops as needed. | |
// The compilation passed to the first function object is used for compiling new functions. | |
// Once this function object is created, it is called with compile as argument, where the first argument of compile | |
// is bound to "proc" (essentially containing a preprocessed version of the user arguments to cwise). | |
// So createThunk roughly works like this: | |
// function createThunk(proc) { | |
// var thunk = function(compileBound) { | |
// var CACHED = {} | |
// return function(arrays and scalars) { | |
// if (dtype and order of arrays in CACHED) { | |
// var func = CACHED[dtype and order of arrays] | |
// } else { | |
// var func = CACHED[dtype and order of arrays] = compileBound(dtype and order of arrays) | |
// } | |
// return func(arrays and scalars) | |
// } | |
// } | |
// return thunk(compile.bind1(proc)) | |
// } | |
var compile = require("./compile.js") | |
function createThunk(proc) { | |
var code = ["'use strict'", "var CACHED={}"] | |
var vars = [] | |
var thunkName = proc.funcName + "_cwise_thunk" | |
//Build thunk | |
code.push(["return function ", thunkName, "(", proc.shimArgs.join(","), "){"].join("")) | |
var typesig = [] | |
var string_typesig = [] | |
var proc_args = [["array",proc.arrayArgs[0],".shape.slice(", // Slice shape so that we only retain the shape over which we iterate (which gets passed to the cwise operator as SS). | |
Math.max(0,proc.arrayBlockIndices[0]),proc.arrayBlockIndices[0]<0?(","+proc.arrayBlockIndices[0]+")"):")"].join("")] | |
var shapeLengthConditions = [], shapeConditions = [] | |
// Process array arguments | |
for(var i=0; i<proc.arrayArgs.length; ++i) { | |
var j = proc.arrayArgs[i] | |
vars.push(["t", j, "=array", j, ".dtype,", | |
"r", j, "=array", j, ".order"].join("")) | |
typesig.push("t" + j) | |
typesig.push("r" + j) | |
string_typesig.push("t"+j) | |
string_typesig.push("r"+j+".join()") | |
proc_args.push("array" + j + ".data") | |
proc_args.push("array" + j + ".stride") | |
proc_args.push("array" + j + ".offset|0") | |
if (i>0) { // Gather conditions to check for shape equality (ignoring block indices) | |
shapeLengthConditions.push("array" + proc.arrayArgs[0] + ".shape.length===array" + j + ".shape.length+" + (Math.abs(proc.arrayBlockIndices[0])-Math.abs(proc.arrayBlockIndices[i]))) | |
shapeConditions.push("array" + proc.arrayArgs[0] + ".shape[shapeIndex+" + Math.max(0,proc.arrayBlockIndices[0]) + "]===array" + j + ".shape[shapeIndex+" + Math.max(0,proc.arrayBlockIndices[i]) + "]") | |
} | |
} | |
// Check for shape equality | |
if (proc.arrayArgs.length > 1) { | |
code.push("if (!(" + shapeLengthConditions.join(" && ") + ")) throw new Error('cwise: Arrays do not all have the same dimensionality!')") | |
code.push("for(var shapeIndex=array" + proc.arrayArgs[0] + ".shape.length-" + Math.abs(proc.arrayBlockIndices[0]) + "; shapeIndex-->0;) {") | |
code.push("if (!(" + shapeConditions.join(" && ") + ")) throw new Error('cwise: Arrays do not all have the same shape!')") | |
code.push("}") | |
} | |
// Process scalar arguments | |
for(var i=0; i<proc.scalarArgs.length; ++i) { | |
proc_args.push("scalar" + proc.scalarArgs[i]) | |
} | |
// Check for cached function (and if not present, generate it) | |
vars.push(["type=[", string_typesig.join(","), "].join()"].join("")) | |
vars.push("proc=CACHED[type]") | |
code.push("var " + vars.join(",")) | |
code.push(["if(!proc){", | |
"CACHED[type]=proc=compile([", typesig.join(","), "])}", | |
"return proc(", proc_args.join(","), ")}"].join("")) | |
if(proc.debug) { | |
console.log("-----Generated thunk:\n" + code.join("\n") + "\n----------") | |
} | |
//Compile thunk | |
var thunk = new Function("compile", code.join("\n")) | |
return thunk(compile.bind(undefined, proc)) | |
} | |
module.exports = createThunk | |
},{"./compile.js":3}],5:[function(require,module,exports){ | |
"use strict" | |
function unique_pred(list, compare) { | |
var ptr = 1 | |
, len = list.length | |
, a=list[0], b=list[0] | |
for(var i=1; i<len; ++i) { | |
b = a | |
a = list[i] | |
if(compare(a, b)) { | |
if(i === ptr) { | |
ptr++ | |
continue | |
} | |
list[ptr++] = a | |
} | |
} | |
list.length = ptr | |
return list | |
} | |
function unique_eq(list) { | |
var ptr = 1 | |
, len = list.length | |
, a=list[0], b = list[0] | |
for(var i=1; i<len; ++i, b=a) { | |
b = a | |
a = list[i] | |
if(a !== b) { | |
if(i === ptr) { | |
ptr++ | |
continue | |
} | |
list[ptr++] = a | |
} | |
} | |
list.length = ptr | |
return list | |
} | |
function unique(list, compare, sorted) { | |
if(list.length === 0) { | |
return list | |
} | |
if(compare) { | |
if(!sorted) { | |
list.sort(compare) | |
} | |
return unique_pred(list, compare) | |
} | |
if(!sorted) { | |
list.sort() | |
} | |
return unique_eq(list) | |
} | |
module.exports = unique | |
},{}],"ndarray-fill":[function(require,module,exports){ | |
"use strict" | |
var fill = require('cwise/lib/wrapper')({"args":["index","array","scalar"],"pre":{"body":"{}","args":[],"thisVars":[],"localVars":[]},"body":{"body":"{_inline_1_arg1_=_inline_1_arg2_.apply(void 0,_inline_1_arg0_)}","args":[{"name":"_inline_1_arg0_","lvalue":false,"rvalue":true,"count":1},{"name":"_inline_1_arg1_","lvalue":true,"rvalue":false,"count":1},{"name":"_inline_1_arg2_","lvalue":false,"rvalue":true,"count":1}],"thisVars":[],"localVars":[]},"post":{"body":"{}","args":[],"thisVars":[],"localVars":[]},"debug":false,"funcName":"cwise","blockSize":64}) | |
module.exports = function(array, f) { | |
fill(array, f) | |
return array | |
} | |
},{"cwise/lib/wrapper":1}]},{},[]) | |
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsIm5vZGVfbW9kdWxlcy9jd2lzZS9saWIvd3JhcHBlci5qcyIsIm5vZGVfbW9kdWxlcy9jd2lzZS9ub2RlX21vZHVsZXMvY3dpc2UtY29tcGlsZXIvY29tcGlsZXIuanMiLCJub2RlX21vZHVsZXMvY3dpc2Uvbm9kZV9tb2R1bGVzL2N3aXNlLWNvbXBpbGVyL2xpYi9jb21waWxlLmpzIiwibm9kZV9tb2R1bGVzL2N3aXNlL25vZGVfbW9kdWxlcy9jd2lzZS1jb21waWxlci9saWIvdGh1bmsuanMiLCJub2RlX21vZHVsZXMvY3dpc2Uvbm9kZV9tb2R1bGVzL2N3aXNlLWNvbXBpbGVyL25vZGVfbW9kdWxlcy91bmlxL3VuaXEuanMiLCJpbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBOztBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0dBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xXQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZShcImN3aXNlLWNvbXBpbGVyXCIpIiwiXCJ1c2Ugc3RyaWN0XCJcclxuXHJcbnZhciBjcmVhdGVUaHVuayA9IHJlcXVpcmUoXCIuL2xpYi90aHVuay5qc1wiKVxyXG5cclxuZnVuY3Rpb24gUHJvY2VkdXJlKCkge1xyXG4gIHRoaXMuYXJnVHlwZXMgPSBbXVxyXG4gIHRoaXMuc2hpbUFyZ3MgPSBbXVxyXG4gIHRoaXMuYXJyYXlBcmdzID0gW11cclxuICB0aGlzLmFycmF5QmxvY2tJbmRpY2VzID0gW11cclxuICB0aGlzLnNjYWxhckFyZ3MgPSBbXVxyXG4gIHRoaXMub2Zmc2V0QXJncyA9IFtdXHJcbiAgdGhpcy5vZmZzZXRBcmdJbmRleCA9IFtdXHJcbiAgdGhpcy5pbmRleEFyZ3MgPSBbXVxyXG4gIHRoaXMuc2hhcGVBcmdzID0gW11cclxuICB0aGlzLmZ1bmNOYW1lID0gXCJcIlxyXG4gIHRoaXMucHJlID0gbnVsbFxyXG4gIHRoaXMuYm9keSA9IG51bGxcclxuICB0aGlzLnBvc3QgPSBudWxsXHJcbiAgdGhpcy5kZWJ1ZyA9IGZhbHNlXHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNvbXBpbGVDd2lzZSh1c2VyX2FyZ3MpIHtcclxuICAvL0NyZWF0ZSBwcm9jZWR1cmVcclxuICB2YXIgcHJvYyA9IG5ldyBQcm9jZWR1cmUoKVxyXG4gIFxyXG4gIC8vUGFyc2UgYmxvY2tzXHJcbiAgcHJvYy5wcmUgICAgPSB1c2VyX2FyZ3MucHJlXHJcbiAgcHJvYy5ib2R5ICAgPSB1c2VyX2FyZ3MuYm9keVxyXG4gIHByb2MucG9zdCAgID0gdXNlcl9hcmdzLnBvc3RcclxuXHJcbiAgLy9QYXJzZSBhcmd1bWVudHNcclxuICB2YXIgcHJvY19hcmdzID0gdXNlcl9hcmdzLmFyZ3Muc2xpY2UoMClcclxuICBwcm9jLmFyZ1R5cGVzID0gcHJvY19hcmdzXHJcbiAgZm9yKHZhciBpPTA7IGk8cHJvY19hcmdzLmxlbmd0aDsgKytpKSB7XHJcbiAgICB2YXIgYXJnX3R5cGUgPSBwcm9jX2FyZ3NbaV1cclxuICAgIGlmKGFyZ190eXBlID09PSBcImFycmF5XCIgfHwgKHR5cGVvZiBhcmdfdHlwZSA9PT0gXCJvYmplY3RcIiAmJiBhcmdfdHlwZS5ibG9ja0luZGljZXMpKSB7XHJcbiAgICAgIHByb2MuYXJnVHlwZXNbaV0gPSBcImFycmF5XCJcclxuICAgICAgcHJvYy5hcnJheUFyZ3MucHVzaChpKVxyXG4gICAgICBwcm9jLmFycmF5QmxvY2tJbmRpY2VzLnB1c2goYXJnX3R5cGUuYmxvY2tJbmRpY2VzID8gYXJnX3R5cGUuYmxvY2tJbmRpY2VzIDogMClcclxuICAgICAgcHJvYy5zaGltQXJncy5wdXNoKFwiYXJyYXlcIiArIGkpXHJcbiAgICAgIGlmKGkgPCBwcm9jLnByZS5hcmdzLmxlbmd0aCAmJiBwcm9jLnByZS5hcmdzW2ldLmNvdW50PjApIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJjd2lzZTogcHJlKCkgYmxvY2sgbWF5IG5vdCByZWZlcmVuY2UgYXJyYXkgYXJnc1wiKVxyXG4gICAgICB9XHJcbiAgICAgIGlmKGkgPCBwcm9jLnBvc3QuYXJncy5sZW5ndGggJiYgcHJvYy5wb3N0LmFyZ3NbaV0uY291bnQ+MCkge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcImN3aXNlOiBwb3N0KCkgYmxvY2sgbWF5IG5vdCByZWZlcmVuY2UgYXJyYXkgYXJnc1wiKVxyXG4gICAgICB9XHJcbiAgICB9IGVsc2UgaWYoYXJnX3R5cGUgPT09IFwic2NhbGFyXCIpIHtcclxuICAgICAgcHJvYy5zY2FsYXJBcmdzLnB1c2goaSlcclxuICAgICAgcHJvYy5zaGltQXJncy5wdXNoKFwic2NhbGFyXCIgKyBpKVxyXG4gICAgfSBlbHNlIGlmKGFyZ190eXBlID09PSBcImluZGV4XCIpIHtcclxuICAgICAgcHJvYy5pbmRleEFyZ3MucHVzaChpKVxyXG4gICAgICBpZihpIDwgcHJvYy5wcmUuYXJncy5sZW5ndGggJiYgcHJvYy5wcmUuYXJnc1tpXS5jb3VudCA+IDApIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJjd2lzZTogcHJlKCkgYmxvY2sgbWF5IG5vdCByZWZlcmVuY2UgYXJyYXkgaW5kZXhcIilcclxuICAgICAgfVxyXG4gICAgICBpZihpIDwgcHJvYy5ib2R5LmFyZ3MubGVuZ3RoICYmIHByb2MuYm9keS5hcmdzW2ldLmx2YWx1ZSkge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcImN3aXNlOiBib2R5KCkgYmxvY2sgbWF5IG5vdCB3cml0ZSB0byBhcnJheSBpbmRleFwiKVxyXG4gICAgICB9XHJcbiAgICAgIGlmKGkgPCBwcm9jLnBvc3QuYXJncy5sZW5ndGggJiYgcHJvYy5wb3N0LmFyZ3NbaV0uY291bnQgPiAwKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiY3dpc2U6IHBvc3QoKSBibG9jayBtYXkgbm90IHJlZmVyZW5jZSBhcnJheSBpbmRleFwiKVxyXG4gICAgICB9XHJcbiAgICB9IGVsc2UgaWYoYXJnX3R5cGUgPT09IFwic2hhcGVcIikge1xyXG4gICAgICBwcm9jLnNoYXBlQXJncy5wdXNoKGkpXHJcbiAgICAgIGlmKGkgPCBwcm9jLnByZS5hcmdzLmxlbmd0aCAmJiBwcm9jLnByZS5hcmdzW2ldLmx2YWx1ZSkge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcImN3aXNlOiBwcmUoKSBibG9jayBtYXkgbm90IHdyaXRlIHRvIGFycmF5IHNoYXBlXCIpXHJcbiAgICAgIH1cclxuICAgICAgaWYoaSA8IHByb2MuYm9keS5hcmdzLmxlbmd0aCAmJiBwcm9jLmJvZHkuYXJnc1tpXS5sdmFsdWUpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJjd2lzZTogYm9keSgpIGJsb2NrIG1heSBub3Qgd3JpdGUgdG8gYXJyYXkgc2hhcGVcIilcclxuICAgICAgfVxyXG4gICAgICBpZihpIDwgcHJvYy5wb3N0LmFyZ3MubGVuZ3RoICYmIHByb2MucG9zdC5hcmdzW2ldLmx2YWx1ZSkge1xyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcImN3aXNlOiBwb3N0KCkgYmxvY2sgbWF5IG5vdCB3cml0ZSB0byBhcnJheSBzaGFwZVwiKVxyXG4gICAgICB9XHJcbiAgICB9IGVsc2UgaWYodHlwZW9mIGFyZ190eXBlID09PSBcIm9iamVjdFwiICYmIGFyZ190eXBlLm9mZnNldCkge1xyXG4gICAgICBwcm9jLmFyZ1R5cGVzW2ldID0gXCJvZmZzZXRcIlxyXG4gICAgICBwcm9jLm9mZnNldEFyZ3MucHVzaCh7IGFycmF5OiBhcmdfdHlwZS5hcnJheSwgb2Zmc2V0OmFyZ190eXBlLm9mZnNldCB9KVxyXG4gICAgICBwcm9jLm9mZnNldEFyZ0luZGV4LnB1c2goaSlcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRocm93IG5ldyBFcnJvcihcImN3aXNlOiBVbmtub3duIGFyZ3VtZW50IHR5cGUgXCIgKyBwcm9jX2FyZ3NbaV0pXHJcbiAgICB9XHJcbiAgfVxyXG4gIFxyXG4gIC8vTWFrZSBzdXJlIGF0IGxlYXN0IG9uZSBhcnJheSBhcmd1bWVudCB3YXMgc3BlY2lmaWVkXHJcbiAgaWYocHJvYy5hcnJheUFyZ3MubGVuZ3RoIDw9IDApIHtcclxuICAgIHRocm93IG5ldyBFcnJvcihcImN3aXNlOiBObyBhcnJheSBhcmd1bWVudHMgc3BlY2lmaWVkXCIpXHJcbiAgfVxyXG4gIFxyXG4gIC8vTWFrZSBzdXJlIGFyZ3VtZW50cyBhcmUgY29ycmVjdFxyXG4gIGlmKHByb2MucHJlLmFyZ3MubGVuZ3RoID4gcHJvY19hcmdzLmxlbmd0aCkge1xyXG4gICAgdGhyb3cgbmV3IEVycm9yKFwiY3dpc2U6IFRvbyBtYW55IGFyZ3VtZW50cyBpbiBwcmUoKSBibG9ja1wiKVxyXG4gIH1cclxuICBpZihwcm9jLmJvZHkuYXJncy5sZW5ndGggPiBwcm9jX2FyZ3MubGVuZ3RoKSB7XHJcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJjd2lzZTogVG9vIG1hbnkgYXJndW1lbnRzIGluIGJvZHkoKSBibG9ja1wiKVxyXG4gIH1cclxuICBpZihwcm9jLnBvc3QuYXJncy5sZW5ndGggPiBwcm9jX2FyZ3MubGVuZ3RoKSB7XHJcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJjd2lzZTogVG9vIG1hbnkgYXJndW1lbnRzIGluIHBvc3QoKSBibG9ja1wiKVxyXG4gIH1cclxuXHJcbiAgLy9DaGVjayBkZWJ1ZyBmbGFnXHJcbiAgcHJvYy5kZWJ1ZyA9ICEhdXNlcl9hcmdzLnByaW50Q29kZSB8fCAhIXVzZXJfYXJncy5kZWJ1Z1xyXG4gIFxyXG4gIC8vUmV0cmlldmUgbmFtZVxyXG4gIHByb2MuZnVuY05hbWUgPSB1c2VyX2FyZ3MuZnVuY05hbWUgfHwgXCJjd2lzZVwiXHJcbiAgXHJcbiAgLy9SZWFkIGluIGJsb2NrIHNpemVcclxuICBwcm9jLmJsb2NrU2l6ZSA9IHVzZXJfYXJncy5ibG9ja1NpemUgfHwgNjRcclxuXHJcbiAgcmV0dXJuIGNyZWF0ZVRodW5rKHByb2MpXHJcbn1cclxuXHJcbm1vZHVsZS5leHBvcnRzID0gY29tcGlsZUN3aXNlXHJcbiIsIlwidXNlIHN0cmljdFwiXHJcblxyXG52YXIgdW5pcSA9IHJlcXVpcmUoXCJ1bmlxXCIpXHJcblxyXG4vLyBUaGlzIGZ1bmN0aW9uIGdlbmVyYXRlcyB2ZXJ5IHNpbXBsZSBsb29wcyBhbmFsb2dvdXMgdG8gaG93IHlvdSB0eXBpY2FsbHkgdHJhdmVyc2UgYXJyYXlzICh0aGUgb3V0ZXJtb3N0IGxvb3AgY29ycmVzcG9uZHMgdG8gdGhlIHNsb3dlc3QgY2hhbmdpbmcgaW5kZXgsIHRoZSBpbm5lcm1vc3QgbG9vcCB0byB0aGUgZmFzdGVzdCBjaGFuZ2luZyBpbmRleClcclxuLy8gVE9ETzogSWYgdHdvIGFycmF5cyBoYXZlIHRoZSBzYW1lIHN0cmlkZXMgKGFuZCBvZmZzZXRzKSB0aGVyZSBpcyBwb3RlbnRpYWwgZm9yIGRlY3JlYXNpbmcgdGhlIG51bWJlciBvZiBcInBvaW50ZXJzXCIgYW5kIHJlbGF0ZWQgdmFyaWFibGVzLiBUaGUgZHJhd2JhY2sgaXMgdGhhdCB0aGUgdHlwZSBzaWduYXR1cmUgd291bGQgYmVjb21lIG1vcmUgc3BlY2lmaWMgYW5kIHRoYXQgdGhlcmUgd291bGQgdGh1cyBiZSBsZXNzIHBvdGVudGlhbCBmb3IgY2FjaGluZywgYnV0IGl0IG1pZ2h0IHN0aWxsIGJlIHdvcnRoIGl0LCBlc3BlY2lhbGx5IHdoZW4gZGVhbGluZyB3aXRoIGxhcmdlIG51bWJlcnMgb2YgYXJndW1lbnRzLlxyXG5mdW5jdGlvbiBpbm5lckZpbGwob3JkZXIsIHByb2MsIGJvZHkpIHtcclxuICB2YXIgZGltZW5zaW9uID0gb3JkZXIubGVuZ3RoXHJcbiAgICAsIG5hcmdzID0gcHJvYy5hcnJheUFyZ3MubGVuZ3RoXHJcbiAgICAsIGhhc19pbmRleCA9IHByb2MuaW5kZXhBcmdzLmxlbmd0aD4wXHJcbiAgICAsIGNvZGUgPSBbXVxyXG4gICAgLCB2YXJzID0gW11cclxuICAgICwgaWR4PTAsIHBpZHg9MCwgaSwgalxyXG4gIGZvcihpPTA7IGk8ZGltZW5zaW9uOyArK2kpIHsgLy8gSXRlcmF0aW9uIHZhcmlhYmxlc1xyXG4gICAgdmFycy5wdXNoKFtcImlcIixpLFwiPTBcIl0uam9pbihcIlwiKSlcclxuICB9XHJcbiAgLy9Db21wdXRlIHNjYW4gZGVsdGFzXHJcbiAgZm9yKGo9MDsgajxuYXJnczsgKytqKSB7XHJcbiAgICBmb3IoaT0wOyBpPGRpbWVuc2lvbjsgKytpKSB7XHJcbiAgICAgIHBpZHggPSBpZHhcclxuICAgICAgaWR4ID0gb3JkZXJbaV1cclxuICAgICAgaWYoaSA9PT0gMCkgeyAvLyBUaGUgaW5uZXJtb3N0L2Zhc3Rlc3QgZGltZW5zaW9uJ3MgZGVsdGEgaXMgc2ltcGx5IGl0cyBzdHJpZGVcclxuICAgICAgICB2YXJzLnB1c2goW1wiZFwiLGosXCJzXCIsaSxcIj10XCIsaixcInBcIixpZHhdLmpvaW4oXCJcIikpXHJcbiAgICAgIH0gZWxzZSB7IC8vIEZvciBvdGhlciBkaW1lbnNpb25zIHRoZSBkZWx0YSBpcyBiYXNpY2FsbHkgdGhlIHN0cmlkZSBtaW51cyBzb21ldGhpbmcgd2hpY2ggZXNzZW50aWFsbHkgXCJyZXdpbmRzXCIgdGhlIHByZXZpb3VzIChtb3JlIGlubmVyKSBkaW1lbnNpb25cclxuICAgICAgICB2YXJzLnB1c2goW1wiZFwiLGosXCJzXCIsaSxcIj0odFwiLGosXCJwXCIsaWR4LFwiLXNcIixwaWR4LFwiKnRcIixqLFwicFwiLHBpZHgsXCIpXCJdLmpvaW4oXCJcIikpXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbiAgY29kZS5wdXNoKFwidmFyIFwiICsgdmFycy5qb2luKFwiLFwiKSlcclxuICAvL1NjYW4gbG9vcFxyXG4gIGZvcihpPWRpbWVuc2lvbi0xOyBpPj0wOyAtLWkpIHsgLy8gU3RhcnQgYXQgbGFyZ2VzdCBzdHJpZGUgYW5kIHdvcmsgeW91ciB3YXkgaW53YXJkc1xyXG4gICAgaWR4ID0gb3JkZXJbaV1cclxuICAgIGNvZGUucHVzaChbXCJmb3IoaVwiLGksXCI9MDtpXCIsaSxcIjxzXCIsaWR4LFwiOysraVwiLGksXCIpe1wiXS5qb2luKFwiXCIpKVxyXG4gIH1cclxuICAvL1B1c2ggYm9keSBvZiBpbm5lciBsb29wXHJcbiAgY29kZS5wdXNoKGJvZHkpXHJcbiAgLy9BZHZhbmNlIHNjYW4gcG9pbnRlcnNcclxuICBmb3IoaT0wOyBpPGRpbWVuc2lvbjsgKytpKSB7XHJcbiAgICBwaWR4ID0gaWR4XHJcbiAgICBpZHggPSBvcmRlcltpXVxyXG4gICAgZm9yKGo9MDsgajxuYXJnczsgKytqKSB7XHJcbiAgICAgIGNvZGUucHVzaChbXCJwXCIsaixcIis9ZFwiLGosXCJzXCIsaV0uam9pbihcIlwiKSlcclxuICAgIH1cclxuICAgIGlmKGhhc19pbmRleCkge1xyXG4gICAgICBpZihpID4gMCkge1xyXG4gICAgICAgIGNvZGUucHVzaChbXCJpbmRleFtcIixwaWR4LFwiXS09c1wiLHBpZHhdLmpvaW4oXCJcIikpXHJcbiAgICAgIH1cclxuICAgICAgY29kZS5wdXNoKFtcIisraW5kZXhbXCIsaWR4LFwiXVwiXS5qb2luKFwiXCIpKVxyXG4gICAgfVxyXG4gICAgY29kZS5wdXNoKFwifVwiKVxyXG4gIH1cclxuICByZXR1cm4gY29kZS5qb2luKFwiXFxuXCIpXHJcbn1cclxuXHJcbi8vIEdlbmVyYXRlIFwib3V0ZXJcIiBsb29wcyB0aGF0IGxvb3Agb3ZlciBibG9ja3Mgb2YgZGF0YSwgYXBwbHlpbmcgXCJpbm5lclwiIGxvb3BzIHRvIHRoZSBibG9ja3MgYnkgbWFuaXB1bGF0aW5nIHRoZSBsb2NhbCB2YXJpYWJsZXMgaW4gc3VjaCBhIHdheSB0aGF0IHRoZSBpbm5lciBsb29wIG9ubHkgXCJzZWVzXCIgdGhlIGN1cnJlbnQgYmxvY2suXHJcbi8vIFRPRE86IElmIHRoaXMgaXMgdXNlZCwgdGhlbiB0aGUgcHJldmlvdXMgZGVjbGFyYXRpb24gKGRvbmUgYnkgZ2VuZXJhdGVDd2lzZU9wKSBvZiBzKiBpcyBlc3NlbnRpYWxseSB1bm5lY2Vzc2FyeS5cclxuLy8gICAgICAgSSBiZWxpZXZlIHRoZSBzKiBhcmUgbm90IHVzZWQgZWxzZXdoZXJlIChpbiBwYXJ0aWN1bGFyLCBJIGRvbid0IHRoaW5rIHRoZXkncmUgdXNlZCBpbiB0aGUgcHJlL3Bvc3QgcGFydHMgYW5kIFwic2hhcGVcIiBpcyBkZWZpbmVkIGluZGVwZW5kZW50bHkpLCBzbyBpdCB3b3VsZCBiZSBwb3NzaWJsZSB0byBtYWtlIGRlZmluaW5nIHRoZSBzKiBkZXBlbmRlbnQgb24gd2hhdCBsb29wIG1ldGhvZCBpcyBiZWluZyB1c2VkLlxyXG5mdW5jdGlvbiBvdXRlckZpbGwobWF0Y2hlZCwgb3JkZXIsIHByb2MsIGJvZHkpIHtcclxuICB2YXIgZGltZW5zaW9uID0gb3JkZXIubGVuZ3RoXHJcbiAgICAsIG5hcmdzID0gcHJvYy5hcnJheUFyZ3MubGVuZ3RoXHJcbiAgICAsIGJsb2NrU2l6ZSA9IHByb2MuYmxvY2tTaXplXHJcbiAgICAsIGhhc19pbmRleCA9IHByb2MuaW5kZXhBcmdzLmxlbmd0aCA+IDBcclxuICAgICwgY29kZSA9IFtdXHJcbiAgZm9yKHZhciBpPTA7IGk8bmFyZ3M7ICsraSkge1xyXG4gICAgY29kZS5wdXNoKFtcInZhciBvZmZzZXRcIixpLFwiPXBcIixpXS5qb2luKFwiXCIpKVxyXG4gIH1cclxuICAvL0dlbmVyYXRlIGxvb3BzIGZvciB1bm1hdGNoZWQgZGltZW5zaW9uc1xyXG4gIC8vIFRoZSBvcmRlciBpbiB3aGljaCB0aGVzZSBkaW1lbnNpb25zIGFyZSB0cmF2ZXJzZWQgaXMgZmFpcmx5IGFyYml0cmFyeSAoZnJvbSBzbWFsbCBzdHJpZGUgdG8gbGFyZ2Ugc3RyaWRlLCBmb3IgdGhlIGZpcnN0IGFyZ3VtZW50KVxyXG4gIC8vIFRPRE86IEl0IHdvdWxkIGJlIG5pY2UgaWYgdGhlIG9yZGVyIGluIHdoaWNoIHRoZXNlIGxvb3BzIGFyZSBwbGFjZWQgd291bGQgYWxzbyBiZSBzb21laG93IFwib3B0aW1hbFwiIChhdCB0aGUgdmVyeSBsZWFzdCB3ZSBzaG91bGQgY2hlY2sgdGhhdCBpdCByZWFsbHkgZG9lc24ndCBodXJ0IHVzIGlmIHRoZXkncmUgbm90KS5cclxuICBmb3IodmFyIGk9bWF0Y2hlZDsgaTxkaW1lbnNpb247ICsraSkge1xyXG4gICAgY29kZS5wdXNoKFtcImZvcih2YXIgalwiK2krXCI9U1NbXCIsIG9yZGVyW2ldLCBcIl18MDtqXCIsIGksIFwiPjA7KXtcIl0uam9pbihcIlwiKSkgLy8gSXRlcmF0ZSBiYWNrIHRvIGZyb250XHJcbiAgICBjb2RlLnB1c2goW1wiaWYoalwiLGksXCI8XCIsYmxvY2tTaXplLFwiKXtcIl0uam9pbihcIlwiKSkgLy8gRWl0aGVyIGRlY3JlYXNlIGogYnkgYmxvY2tTaXplIChzID0gYmxvY2tTaXplKSwgb3Igc2V0IGl0IHRvIHplcm8gKGFmdGVyIHNldHRpbmcgcyA9IGopLlxyXG4gICAgY29kZS5wdXNoKFtcInNcIixvcmRlcltpXSxcIj1qXCIsaV0uam9pbihcIlwiKSlcclxuICAgIGNvZGUucHVzaChbXCJqXCIsaSxcIj0wXCJdLmpvaW4oXCJcIikpXHJcbiAgICBjb2RlLnB1c2goW1wifWVsc2V7c1wiLG9yZGVyW2ldLFwiPVwiLGJsb2NrU2l6ZV0uam9pbihcIlwiKSlcclxuICAgIGNvZGUucHVzaChbXCJqXCIsaSxcIi09XCIsYmxvY2tTaXplLFwifVwiXS5qb2luKFwiXCIpKVxyXG4gICAgaWYoaGFzX2luZGV4KSB7XHJcbiAgICAgIGNvZGUucHVzaChbXCJpbmRleFtcIixvcmRlcltpXSxcIl09alwiLGldLmpvaW4oXCJcIikpXHJcbiAgICB9XHJcbiAgfVxyXG4gIGZvcih2YXIgaT0wOyBpPG5hcmdzOyArK2kpIHtcclxuICAgIHZhciBpbmRleFN0ciA9IFtcIm9mZnNldFwiK2ldXHJcbiAgICBmb3IodmFyIGo9bWF0Y2hlZDsgajxkaW1lbnNpb247ICsraikge1xyXG4gICAgICBpbmRleFN0ci5wdXNoKFtcImpcIixqLFwiKnRcIixpLFwicFwiLG9yZGVyW2pdXS5qb2luKFwiXCIpKVxyXG4gICAgfVxyXG4gICAgY29kZS5wdXNoKFtcInBcIixpLFwiPShcIixpbmRleFN0ci5qb2luKFwiK1wiKSxcIilcIl0uam9pbihcIlwiKSlcclxuICB9XHJcbiAgY29kZS5wdXNoKGlubmVyRmlsbChvcmRlciwgcHJvYywgYm9keSkpXHJcbiAgZm9yKHZhciBpPW1hdGNoZWQ7IGk8ZGltZW5zaW9uOyArK2kpIHtcclxuICAgIGNvZGUucHVzaChcIn1cIilcclxuICB9XHJcbiAgcmV0dXJuIGNvZGUuam9pbihcIlxcblwiKVxyXG59XHJcblxyXG4vL0NvdW50IHRoZSBudW1iZXIgb2YgY29tcGF0aWJsZSBpbm5lciBvcmRlcnNcclxuLy8gVGhpcyBpcyB0aGUgbGVuZ3RoIG9mIHRoZSBsb25nZXN0IGNvbW1vbiBwcmVmaXggb2YgdGhlIGFycmF5cyBpbiBvcmRlcnMuXHJcbi8vIEVhY2ggYXJyYXkgaW4gb3JkZXJzIGxpc3RzIHRoZSBkaW1lbnNpb25zIG9mIHRoZSBjb3JyZXNwb25kIG5kYXJyYXkgaW4gb3JkZXIgb2YgaW5jcmVhc2luZyBzdHJpZGUuXHJcbi8vIFRoaXMgaXMgdGh1cyB0aGUgbWF4aW11bSBudW1iZXIgb2YgZGltZW5zaW9ucyB0aGF0IGNhbiBiZSBlZmZpY2llbnRseSB0cmF2ZXJzZWQgYnkgc2ltcGxlIG5lc3RlZCBsb29wcyBmb3IgYWxsIGFycmF5cy5cclxuZnVuY3Rpb24gY291bnRNYXRjaGVzKG9yZGVycykge1xyXG4gIHZhciBtYXRjaGVkID0gMCwgZGltZW5zaW9uID0gb3JkZXJzWzBdLmxlbmd0aFxyXG4gIHdoaWxlKG1hdGNoZWQgPCBkaW1lbnNpb24pIHtcclxuICAgIGZvcih2YXIgaj0xOyBqPG9yZGVycy5sZW5ndGg7ICsraikge1xyXG4gICAgICBpZihvcmRlcnNbal1bbWF0Y2hlZF0gIT09IG9yZGVyc1swXVttYXRjaGVkXSkge1xyXG4gICAgICAgIHJldHVybiBtYXRjaGVkXHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgICsrbWF0Y2hlZFxyXG4gIH1cclxuICByZXR1cm4gbWF0Y2hlZFxyXG59XHJcblxyXG4vL1Byb2Nlc3NlcyBhIGJsb2NrIGFjY29yZGluZyB0byB0aGUgZ2l2ZW4gZGF0YSB0eXBlc1xyXG4vLyBSZXBsYWNlcyB2YXJpYWJsZSBuYW1lcyBieSBkaWZmZXJlbnQgb25lcywgZWl0aGVyIFwibG9jYWxcIiBvbmVzICh0aGF0IGFyZSB0aGVuIGZlcnJpZWQgaW4gYW5kIG91dCBvZiB0aGUgZ2l2ZW4gYXJyYXkpIG9yIG9uZXMgbWF0Y2hpbmcgdGhlIGFyZ3VtZW50cyB0aGF0IHRoZSBmdW5jdGlvbiBwZXJmb3JtaW5nIHRoZSB1bHRpbWF0ZSBsb29wIHdpbGwgYWNjZXB0LlxyXG5mdW5jdGlvbiBwcm9jZXNzQmxvY2soYmxvY2ssIHByb2MsIGR0eXBlcykge1xyXG4gIHZhciBjb2RlID0gYmxvY2suYm9keVxyXG4gIHZhciBwcmUgPSBbXVxyXG4gIHZhciBwb3N0ID0gW11cclxuICBmb3IodmFyIGk9MDsgaTxibG9jay5hcmdzLmxlbmd0aDsgKytpKSB7XHJcbiAgICB2YXIgY2FyZyA9IGJsb2NrLmFyZ3NbaV1cclxuICAgIGlmKGNhcmcuY291bnQgPD0gMCkge1xyXG4gICAgICBjb250aW51ZVxyXG4gICAgfVxyXG4gICAgdmFyIHJlID0gbmV3IFJlZ0V4cChjYXJnLm5hbWUsIFwiZ1wiKVxyXG4gICAgdmFyIHB0clN0ciA9IFwiXCJcclxuICAgIHZhciBhcnJOdW0gPSBwcm9jLmFycmF5QXJncy5pbmRleE9mKGkpXHJcbiAgICBzd2l0Y2gocHJvYy5hcmdUeXBlc1tpXSkge1xyXG4gICAgICBjYXNlIFwib2Zmc2V0XCI6XHJcbiAgICAgICAgdmFyIG9mZkFyZ0luZGV4ID0gcHJvYy5vZmZzZXRBcmdJbmRleC5pbmRleE9mKGkpXHJcbiAgICAgICAgdmFyIG9mZkFyZyA9IHByb2Mub2Zmc2V0QXJnc1tvZmZBcmdJbmRleF1cclxuICAgICAgICBhcnJOdW0gPSBvZmZBcmcuYXJyYXlcclxuICAgICAgICBwdHJTdHIgPSBcIitxXCIgKyBvZmZBcmdJbmRleCAvLyBBZGRzIG9mZnNldCB0byB0aGUgXCJwb2ludGVyXCIgaW4gdGhlIGFycmF5XHJcbiAgICAgIGNhc2UgXCJhcnJheVwiOlxyXG4gICAgICAgIHB0clN0ciA9IFwicFwiICsgYXJyTnVtICsgcHRyU3RyXHJcbiAgICAgICAgdmFyIGxvY2FsU3RyID0gXCJsXCIgKyBpXHJcbiAgICAgICAgdmFyIGFyclN0ciA9IFwiYVwiICsgYXJyTnVtXHJcbiAgICAgICAgaWYgKHByb2MuYXJyYXlCbG9ja0luZGljZXNbYXJyTnVtXSA9PT0gMCkgeyAvLyBBcmd1bWVudCB0byBib2R5IGlzIGp1c3QgYSBzaW5nbGUgdmFsdWUgZnJvbSB0aGlzIGFycmF5XHJcbiAgICAgICAgICBpZihjYXJnLmNvdW50ID09PSAxKSB7IC8vIEFyZ3VtZW50L2FycmF5IHVzZWQgb25seSBvbmNlKD8pXHJcbiAgICAgICAgICAgIGlmKGR0eXBlc1thcnJOdW1dID09PSBcImdlbmVyaWNcIikge1xyXG4gICAgICAgICAgICAgIGlmKGNhcmcubHZhbHVlKSB7XHJcbiAgICAgICAgICAgICAgICBwcmUucHVzaChbXCJ2YXIgXCIsIGxvY2FsU3RyLCBcIj1cIiwgYXJyU3RyLCBcIi5nZXQoXCIsIHB0clN0ciwgXCIpXCJdLmpvaW4oXCJcIikpIC8vIElzIHRoaXMgbmVjZXNzYXJ5IGlmIHRoZSBhcmd1bWVudCBpcyBPTkxZIHVzZWQgYXMgYW4gbHZhbHVlPyAoa2VlcCBpbiBtaW5kIHRoYXQgd2UgY2FuIGhhdmUgYSArPSBzb21ldGhpbmcsIHNvIHdlIHdvdWxkIGFjdHVhbGx5IG5lZWQgdG8gY2hlY2sgY2FyZy5ydmFsdWUpXHJcbiAgICAgICAgICAgICAgICBjb2RlID0gY29kZS5yZXBsYWNlKHJlLCBsb2NhbFN0cilcclxuICAgICAgICAgICAgICAgIHBvc3QucHVzaChbYXJyU3RyLCBcIi5zZXQoXCIsIHB0clN0ciwgXCIsXCIsIGxvY2FsU3RyLFwiKVwiXS5qb2luKFwiXCIpKVxyXG4gICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICBjb2RlID0gY29kZS5yZXBsYWNlKHJlLCBbYXJyU3RyLCBcIi5nZXQoXCIsIHB0clN0ciwgXCIpXCJdLmpvaW4oXCJcIikpXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIGNvZGUgPSBjb2RlLnJlcGxhY2UocmUsIFthcnJTdHIsIFwiW1wiLCBwdHJTdHIsIFwiXVwiXS5qb2luKFwiXCIpKVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9IGVsc2UgaWYoZHR5cGVzW2Fyck51bV0gPT09IFwiZ2VuZXJpY1wiKSB7XHJcbiAgICAgICAgICAgIHByZS5wdXNoKFtcInZhciBcIiwgbG9jYWxTdHIsIFwiPVwiLCBhcnJTdHIsIFwiLmdldChcIiwgcHRyU3RyLCBcIilcIl0uam9pbihcIlwiKSkgLy8gVE9ETzogQ291bGQgd2Ugb3B0aW1pemUgYnkgY2hlY2tpbmcgZm9yIGNhcmcucnZhbHVlP1xyXG4gICAgICAgICAgICBjb2RlID0gY29kZS5yZXBsYWNlKHJlLCBsb2NhbFN0cilcclxuICAgICAgICAgICAgaWYoY2FyZy5sdmFsdWUpIHtcclxuICAgICAgICAgICAgICBwb3N0LnB1c2goW2FyclN0ciwgXCIuc2V0KFwiLCBwdHJTdHIsIFwiLFwiLCBsb2NhbFN0cixcIilcIl0uam9pbihcIlwiKSlcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgcHJlLnB1c2goW1widmFyIFwiLCBsb2NhbFN0ciwgXCI9XCIsIGFyclN0ciwgXCJbXCIsIHB0clN0ciwgXCJdXCJdLmpvaW4oXCJcIikpIC8vIFRPRE86IENvdWxkIHdlIG9wdGltaXplIGJ5IGNoZWNraW5nIGZvciBjYXJnLnJ2YWx1ZT9cclxuICAgICAgICAgICAgY29kZSA9IGNvZGUucmVwbGFjZShyZSwgbG9jYWxTdHIpXHJcbiAgICAgICAgICAgIGlmKGNhcmcubHZhbHVlKSB7XHJcbiAgICAgICAgICAgICAgcG9zdC5wdXNoKFthcnJTdHIsIFwiW1wiLCBwdHJTdHIsIFwiXT1cIiwgbG9jYWxTdHJdLmpvaW4oXCJcIikpXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2UgeyAvLyBBcmd1bWVudCB0byBib2R5IGlzIGEgXCJibG9ja1wiXHJcbiAgICAgICAgICB2YXIgcmVTdHJBcnIgPSBbY2FyZy5uYW1lXSwgcHRyU3RyQXJyID0gW3B0clN0cl1cclxuICAgICAgICAgIGZvcih2YXIgaj0wOyBqPE1hdGguYWJzKHByb2MuYXJyYXlCbG9ja0luZGljZXNbYXJyTnVtXSk7IGorKykge1xyXG4gICAgICAgICAgICByZVN0ckFyci5wdXNoKFwiXFxcXHMqXFxcXFsoW15cXFxcXV0rKVxcXFxdXCIpXHJcbiAgICAgICAgICAgIHB0clN0ckFyci5wdXNoKFwiJFwiICsgKGorMSkgKyBcIip0XCIgKyBhcnJOdW0gKyBcImJcIiArIGopIC8vIE1hdGNoZWQgaW5kZXggdGltZXMgc3RyaWRlXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZSA9IG5ldyBSZWdFeHAocmVTdHJBcnIuam9pbihcIlwiKSwgXCJnXCIpXHJcbiAgICAgICAgICBwdHJTdHIgPSBwdHJTdHJBcnIuam9pbihcIitcIilcclxuICAgICAgICAgIGlmKGR0eXBlc1thcnJOdW1dID09PSBcImdlbmVyaWNcIikge1xyXG4gICAgICAgICAgICAvKmlmKGNhcmcubHZhbHVlKSB7XHJcbiAgICAgICAgICAgICAgcHJlLnB1c2goW1widmFyIFwiLCBsb2NhbFN0ciwgXCI9XCIsIGFyclN0ciwgXCIuZ2V0KFwiLCBwdHJTdHIsIFwiKVwiXS5qb2luKFwiXCIpKSAvLyBJcyB0aGlzIG5lY2Vzc2FyeSBpZiB0aGUgYXJndW1lbnQgaXMgT05MWSB1c2VkIGFzIGFuIGx2YWx1ZT8gKGtlZXAgaW4gbWluZCB0aGF0IHdlIGNhbiBoYXZlIGEgKz0gc29tZXRoaW5nLCBzbyB3ZSB3b3VsZCBhY3R1YWxseSBuZWVkIHRvIGNoZWNrIGNhcmcucnZhbHVlKVxyXG4gICAgICAgICAgICAgIGNvZGUgPSBjb2RlLnJlcGxhY2UocmUsIGxvY2FsU3RyKVxyXG4gICAgICAgICAgICAgIHBvc3QucHVzaChbYXJyU3RyLCBcIi5zZXQoXCIsIHB0clN0ciwgXCIsXCIsIGxvY2FsU3RyLFwiKVwiXS5qb2luKFwiXCIpKVxyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIGNvZGUgPSBjb2RlLnJlcGxhY2UocmUsIFthcnJTdHIsIFwiLmdldChcIiwgcHRyU3RyLCBcIilcIl0uam9pbihcIlwiKSlcclxuICAgICAgICAgICAgfSovXHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcImN3aXNlOiBHZW5lcmljIGFycmF5cyBub3Qgc3VwcG9ydGVkIGluIGNvbWJpbmF0aW9uIHdpdGggYmxvY2tzIVwiKVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gVGhpcyBkb2VzIG5vdCBwcm9kdWNlIGFueSBsb2NhbCB2YXJpYWJsZXMsIGV2ZW4gaWYgdmFyaWFibGVzIGFyZSB1c2VkIG11bHRpcGxlIHRpbWVzLiBJdCB3b3VsZCBiZSBwb3NzaWJsZSB0byBkbyBzbywgYnV0IGl0IHdvdWxkIGNvbXBsaWNhdGUgdGhpbmdzIHF1aXRlIGEgYml0LlxyXG4gICAgICAgICAgICBjb2RlID0gY29kZS5yZXBsYWNlKHJlLCBbYXJyU3RyLCBcIltcIiwgcHRyU3RyLCBcIl1cIl0uam9pbihcIlwiKSlcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIGJyZWFrXHJcbiAgICAgIGNhc2UgXCJzY2FsYXJcIjpcclxuICAgICAgICBjb2RlID0gY29kZS5yZXBsYWNlKHJlLCBcIllcIiArIHByb2Muc2NhbGFyQXJncy5pbmRleE9mKGkpKVxyXG4gICAgICBicmVha1xyXG4gICAgICBjYXNlIFwiaW5kZXhcIjpcclxuICAgICAgICBjb2RlID0gY29kZS5yZXBsYWNlKHJlLCBcImluZGV4XCIpXHJcbiAgICAgIGJyZWFrXHJcbiAgICAgIGNhc2UgXCJzaGFwZVwiOlxyXG4gICAgICAgIGNvZGUgPSBjb2RlLnJlcGxhY2UocmUsIFwic2hhcGVcIilcclxuICAgICAgYnJlYWtcclxuICAgIH1cclxuICB9XHJcbiAgcmV0dXJuIFtwcmUuam9pbihcIlxcblwiKSwgY29kZSwgcG9zdC5qb2luKFwiXFxuXCIpXS5qb2luKFwiXFxuXCIpLnRyaW0oKVxyXG59XHJcblxyXG5mdW5jdGlvbiB0eXBlU3VtbWFyeShkdHlwZXMpIHtcclxuICB2YXIgc3VtbWFyeSA9IG5ldyBBcnJheShkdHlwZXMubGVuZ3RoKVxyXG4gIHZhciBhbGxFcXVhbCA9IHRydWVcclxuICBmb3IodmFyIGk9MDsgaTxkdHlwZXMubGVuZ3RoOyArK2kpIHtcclxuICAgIHZhciB0ID0gZHR5cGVzW2ldXHJcbiAgICB2YXIgZGlnaXRzID0gdC5tYXRjaCgvXFxkKy8pXHJcbiAgICBpZighZGlnaXRzKSB7XHJcbiAgICAgIGRpZ2l0cyA9IFwiXCJcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGRpZ2l0cyA9IGRpZ2l0c1swXVxyXG4gICAgfVxyXG4gICAgaWYodC5jaGFyQXQoMCkgPT09IDApIHtcclxuICAgICAgc3VtbWFyeVtpXSA9IFwidVwiICsgdC5jaGFyQXQoMSkgKyBkaWdpdHNcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHN1bW1hcnlbaV0gPSB0LmNoYXJBdCgwKSArIGRpZ2l0c1xyXG4gICAgfVxyXG4gICAgaWYoaSA+IDApIHtcclxuICAgICAgYWxsRXF1YWwgPSBhbGxFcXVhbCAmJiBzdW1tYXJ5W2ldID09PSBzdW1tYXJ5W2ktMV1cclxuICAgIH1cclxuICB9XHJcbiAgaWYoYWxsRXF1YWwpIHtcclxuICAgIHJldHVybiBzdW1tYXJ5WzBdXHJcbiAgfVxyXG4gIHJldHVybiBzdW1tYXJ5LmpvaW4oXCJcIilcclxufVxyXG5cclxuLy9HZW5lcmF0ZXMgYSBjd2lzZSBvcGVyYXRvclxyXG5mdW5jdGlvbiBnZW5lcmF0ZUNXaXNlT3AocHJvYywgdHlwZXNpZykge1xyXG5cclxuICAvL0NvbXB1dGUgZGltZW5zaW9uXHJcbiAgLy8gQXJyYXlzIGdldCBwdXQgZmlyc3QgaW4gdHlwZXNpZywgYW5kIHRoZXJlIGFyZSB0d28gZW50cmllcyBwZXIgYXJyYXkgKGR0eXBlIGFuZCBvcmRlciksIHNvIHRoaXMgZ2V0cyB0aGUgbnVtYmVyIG9mIGRpbWVuc2lvbnMgaW4gdGhlIGZpcnN0IGFycmF5IGFyZy5cclxuICB2YXIgZGltZW5zaW9uID0gKHR5cGVzaWdbMV0ubGVuZ3RoIC0gTWF0aC5hYnMocHJvYy5hcnJheUJsb2NrSW5kaWNlc1swXSkpfDBcclxuICB2YXIgb3JkZXJzID0gbmV3IEFycmF5KHByb2MuYXJyYXlBcmdzLmxlbmd0aClcclxuICB2YXIgZHR5cGVzID0gbmV3IEFycmF5KHByb2MuYXJyYXlBcmdzLmxlbmd0aClcclxuICBmb3IodmFyIGk9MDsgaTxwcm9jLmFycmF5QXJncy5sZW5ndGg7ICsraSkge1xyXG4gICAgZHR5cGVzW2ldID0gdHlwZXNpZ1syKmldXHJcbiAgICBvcmRlcnNbaV0gPSB0eXBlc2lnWzIqaSsxXVxyXG4gIH1cclxuICBcclxuICAvL0RldGVybWluZSB3aGVyZSBibG9jayBhbmQgbG9vcCBpbmRpY2VzIHN0YXJ0IGFuZCBlbmRcclxuICB2YXIgYmxvY2tCZWdpbiA9IFtdLCBibG9ja0VuZCA9IFtdIC8vIFRoZXNlIGluZGljZXMgYXJlIGV4cG9zZWQgYXMgYmxvY2tzXHJcbiAgdmFyIGxvb3BCZWdpbiA9IFtdLCBsb29wRW5kID0gW10gLy8gVGhlc2UgaW5kaWNlcyBhcmUgaXRlcmF0ZWQgb3ZlclxyXG4gIHZhciBsb29wT3JkZXJzID0gW10gLy8gb3JkZXJzIHJlc3RyaWN0ZWQgdG8gdGhlIGxvb3AgaW5kaWNlc1xyXG4gIGZvcih2YXIgaT0wOyBpPHByb2MuYXJyYXlBcmdzLmxlbmd0aDsgKytpKSB7XHJcbiAgICBpZiAocHJvYy5hcnJheUJsb2NrSW5kaWNlc1tpXTwwKSB7XHJcbiAgICAgIGxvb3BCZWdpbi5wdXNoKDApXHJcbiAgICAgIGxvb3BFbmQucHVzaChkaW1lbnNpb24pXHJcbiAgICAgIGJsb2NrQmVnaW4ucHVzaChkaW1lbnNpb24pXHJcbiAgICAgIGJsb2NrRW5kLnB1c2goZGltZW5zaW9uK3Byb2MuYXJyYXlCbG9ja0luZGljZXNbaV0pXHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb29wQmVnaW4ucHVzaChwcm9jLmFycmF5QmxvY2tJbmRpY2VzW2ldKSAvLyBOb24tbmVnYXRpdmVcclxuICAgICAgbG9vcEVuZC5wdXNoKHByb2MuYXJyYXlCbG9ja0luZGljZXNbaV0rZGltZW5zaW9uKVxyXG4gICAgICBibG9ja0JlZ2luLnB1c2goMClcclxuICAgICAgYmxvY2tFbmQucHVzaChwcm9jLmFycmF5QmxvY2tJbmRpY2VzW2ldKVxyXG4gICAgfVxyXG4gICAgdmFyIG5ld09yZGVyID0gW11cclxuICAgIGZvcih2YXIgaj0wOyBqPG9yZGVyc1tpXS5sZW5ndGg7IGorKykge1xyXG4gICAgICBpZiAobG9vcEJlZ2luW2ldPD1vcmRlcnNbaV1bal0gJiYgb3JkZXJzW2ldW2pdPGxvb3BFbmRbaV0pIHtcclxuICAgICAgICBuZXdPcmRlci5wdXNoKG9yZGVyc1tpXVtqXS1sb29wQmVnaW5baV0pIC8vIElmIHRoaXMgaXMgYSBsb29wIGluZGV4LCBwdXQgaXQgaW4gbmV3T3JkZXIsIHN1YnRyYWN0aW5nIGxvb3BCZWdpbiwgdG8gbWFrZSBzdXJlIHRoYXQgYWxsIGxvb3BPcmRlcnMgYXJlIHVzaW5nIGEgY29tbW9uIHNldCBvZiBpbmRpY2VzLlxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBsb29wT3JkZXJzLnB1c2gobmV3T3JkZXIpXHJcbiAgfVxyXG5cclxuICAvL0ZpcnN0IGNyZWF0ZSBhcmd1bWVudHMgZm9yIHByb2NlZHVyZVxyXG4gIHZhciBhcmdsaXN0ID0gW1wiU1NcIl0gLy8gU1MgaXMgdGhlIG92ZXJhbGwgc2hhcGUgb3ZlciB3aGljaCB3ZSBpdGVyYXRlXHJcbiAgdmFyIGNvZGUgPSBbXCIndXNlIHN0cmljdCdcIl1cclxuICB2YXIgdmFycyA9IFtdXHJcbiAgXHJcbiAgZm9yKHZhciBqPTA7IGo8ZGltZW5zaW9uOyArK2opIHtcclxuICAgIHZhcnMucHVzaChbXCJzXCIsIGosIFwiPVNTW1wiLCBqLCBcIl1cIl0uam9pbihcIlwiKSkgLy8gVGhlIGxpbWl0cyBmb3IgZWFjaCBkaW1lbnNpb24uXHJcbiAgfVxyXG4gIGZvcih2YXIgaT0wOyBpPHByb2MuYXJyYXlBcmdzLmxlbmd0aDsgKytpKSB7XHJcbiAgICBhcmdsaXN0LnB1c2goXCJhXCIraSkgLy8gQWN0dWFsIGRhdGEgYXJyYXlcclxuICAgIGFyZ2xpc3QucHVzaChcInRcIitpKSAvLyBTdHJpZGVzXHJcbiAgICBhcmdsaXN0LnB1c2goXCJwXCIraSkgLy8gT2Zmc2V0IGluIHRoZSBhcnJheSBhdCB3aGljaCB0aGUgZGF0YSBzdGFydHMgKGFsc28gdXNlZCBmb3IgaXRlcmF0aW5nIG92ZXIgdGhlIGRhdGEpXHJcbiAgICBcclxuICAgIGZvcih2YXIgaj0wOyBqPGRpbWVuc2lvbjsgKytqKSB7IC8vIFVucGFjayB0aGUgc3RyaWRlcyBpbnRvIHZhcnMgZm9yIGxvb3BpbmdcclxuICAgICAgdmFycy5wdXNoKFtcInRcIixpLFwicFwiLGosXCI9dFwiLGksXCJbXCIsbG9vcEJlZ2luW2ldK2osXCJdXCJdLmpvaW4oXCJcIikpXHJcbiAgICB9XHJcbiAgICBcclxuICAgIGZvcih2YXIgaj0wOyBqPE1hdGguYWJzKHByb2MuYXJyYXlCbG9ja0luZGljZXNbaV0pOyArK2opIHsgLy8gVW5wYWNrIHRoZSBzdHJpZGVzIGludG8gdmFycyBmb3IgYmxvY2sgaXRlcmF0aW9uXHJcbiAgICAgIHZhcnMucHVzaChbXCJ0XCIsaSxcImJcIixqLFwiPXRcIixpLFwiW1wiLGJsb2NrQmVnaW5baV0raixcIl1cIl0uam9pbihcIlwiKSlcclxuICAgIH1cclxuICB9XHJcbiAgZm9yKHZhciBpPTA7IGk8cHJvYy5zY2FsYXJBcmdzLmxlbmd0aDsgKytpKSB7XHJcbiAgICBhcmdsaXN0LnB1c2goXCJZXCIgKyBpKVxyXG4gIH1cclxuICBpZihwcm9jLnNoYXBlQXJncy5sZW5ndGggPiAwKSB7XHJcbiAgICB2YXJzLnB1c2goXCJzaGFwZT1TUy5zbGljZSgwKVwiKSAvLyBNYWtlcyB0aGUgc2hhcGUgb3ZlciB3aGljaCB3ZSBpdGVyYXRlIGF2YWlsYWJsZSB0byB0aGUgdXNlciBkZWZpbmVkIGZ1bmN0aW9ucyAoc28geW91IGNhbiB1c2Ugd2lkdGgvaGVpZ2h0IGZvciBleGFtcGxlKVxyXG4gIH1cclxuICBpZihwcm9jLmluZGV4QXJncy5sZW5ndGggPiAwKSB7XHJcbiAgICAvLyBQcmVwYXJlIGFuIGFycmF5IHRvIGtlZXAgdHJhY2sgb2YgdGhlIChsb2dpY2FsKSBpbmRpY2VzLCBpbml0aWFsaXplZCB0byBkaW1lbnNpb24gemVyb2VzLlxyXG4gICAgdmFyIHplcm9zID0gbmV3IEFycmF5KGRpbWVuc2lvbilcclxuICAgIGZvcih2YXIgaT0wOyBpPGRpbWVuc2lvbjsgKytpKSB7XHJcbiAgICAgIHplcm9zW2ldID0gXCIwXCJcclxuICAgIH1cclxuICAgIHZhcnMucHVzaChbXCJpbmRleD1bXCIsIHplcm9zLmpvaW4oXCIsXCIpLCBcIl1cIl0uam9pbihcIlwiKSlcclxuICB9XHJcbiAgZm9yKHZhciBpPTA7IGk8cHJvYy5vZmZzZXRBcmdzLmxlbmd0aDsgKytpKSB7IC8vIE9mZnNldCBhcmd1bWVudHMgdXNlZCBmb3Igc3RlbmNpbCBvcGVyYXRpb25zXHJcbiAgICB2YXIgb2ZmX2FyZyA9IHByb2Mub2Zmc2V0QXJnc1tpXVxyXG4gICAgdmFyIGluaXRfc3RyaW5nID0gW11cclxuICAgIGZvcih2YXIgaj0wOyBqPG9mZl9hcmcub2Zmc2V0Lmxlbmd0aDsgKytqKSB7XHJcbiAgICAgIGlmKG9mZl9hcmcub2Zmc2V0W2pdID09PSAwKSB7XHJcbiAgICAgICAgY29udGludWVcclxuICAgICAgfSBlbHNlIGlmKG9mZl9hcmcub2Zmc2V0W2pdID09PSAxKSB7XHJcbiAgICAgICAgaW5pdF9zdHJpbmcucHVzaChbXCJ0XCIsIG9mZl9hcmcuYXJyYXksIFwicFwiLCBqXS5qb2luKFwiXCIpKSAgICAgIFxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGluaXRfc3RyaW5nLnB1c2goW29mZl9hcmcub2Zmc2V0W2pdLCBcIip0XCIsIG9mZl9hcmcuYXJyYXksIFwicFwiLCBqXS5qb2luKFwiXCIpKVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpZihpbml0X3N0cmluZy5sZW5ndGggPT09IDApIHtcclxuICAgICAgdmFycy5wdXNoKFwicVwiICsgaSArIFwiPTBcIilcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHZhcnMucHVzaChbXCJxXCIsIGksIFwiPVwiLCBpbml0X3N0cmluZy5qb2luKFwiK1wiKV0uam9pbihcIlwiKSlcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vUHJlcGFyZSB0aGlzIHZhcmlhYmxlc1xyXG4gIHZhciB0aGlzVmFycyA9IHVuaXEoW10uY29uY2F0KHByb2MucHJlLnRoaXNWYXJzKVxyXG4gICAgICAgICAgICAgICAgICAgICAgLmNvbmNhdChwcm9jLmJvZHkudGhpc1ZhcnMpXHJcbiAgICAgICAgICAgICAgICAgICAgICAuY29uY2F0KHByb2MucG9zdC50aGlzVmFycykpXHJcbiAgdmFycyA9IHZhcnMuY29uY2F0KHRoaXNWYXJzKVxyXG4gIGNvZGUucHVzaChcInZhciBcIiArIHZhcnMuam9pbihcIixcIikpXHJcbiAgZm9yKHZhciBpPTA7IGk8cHJvYy5hcnJheUFyZ3MubGVuZ3RoOyArK2kpIHtcclxuICAgIGNvZGUucHVzaChcInBcIitpK1wifD0wXCIpXHJcbiAgfVxyXG4gIFxyXG4gIC8vSW5saW5lIHByZWx1ZGVcclxuICBpZihwcm9jLnByZS5ib2R5Lmxlbmd0aCA+IDMpIHtcclxuICAgIGNvZGUucHVzaChwcm9jZXNzQmxvY2socHJvYy5wcmUsIHByb2MsIGR0eXBlcykpXHJcbiAgfVxyXG5cclxuICAvL1Byb2Nlc3MgYm9keVxyXG4gIHZhciBib2R5ID0gcHJvY2Vzc0Jsb2NrKHByb2MuYm9keSwgcHJvYywgZHR5cGVzKVxyXG4gIHZhciBtYXRjaGVkID0gY291bnRNYXRjaGVzKGxvb3BPcmRlcnMpXHJcbiAgaWYobWF0Y2hlZCA8IGRpbWVuc2lvbikge1xyXG4gICAgY29kZS5wdXNoKG91dGVyRmlsbChtYXRjaGVkLCBsb29wT3JkZXJzWzBdLCBwcm9jLCBib2R5KSkgLy8gVE9ETzogUmF0aGVyIHRoYW4gcGFzc2luZyBsb29wT3JkZXJzWzBdLCBpdCBtaWdodCBiZSBpbnRlcmVzdGluZyB0byBsb29rIGF0IHBhc3NpbmcgYW4gb3JkZXIgdGhhdCByZXByZXNlbnRzIHRoZSBtYWpvcml0eSBvZiB0aGUgYXJndW1lbnRzIGZvciBleGFtcGxlLlxyXG4gIH0gZWxzZSB7XHJcbiAgICBjb2RlLnB1c2goaW5uZXJGaWxsKGxvb3BPcmRlcnNbMF0sIHByb2MsIGJvZHkpKVxyXG4gIH1cclxuXHJcbiAgLy9JbmxpbmUgZXBpbG9nXHJcbiAgaWYocHJvYy5wb3N0LmJvZHkubGVuZ3RoID4gMykge1xyXG4gICAgY29kZS5wdXNoKHByb2Nlc3NCbG9jayhwcm9jLnBvc3QsIHByb2MsIGR0eXBlcykpXHJcbiAgfVxyXG4gIFxyXG4gIGlmKHByb2MuZGVidWcpIHtcclxuICAgIGNvbnNvbGUubG9nKFwiLS0tLS1HZW5lcmF0ZWQgY3dpc2Ugcm91dGluZSBmb3IgXCIsIHR5cGVzaWcsIFwiOlxcblwiICsgY29kZS5qb2luKFwiXFxuXCIpICsgXCJcXG4tLS0tLS0tLS0tXCIpXHJcbiAgfVxyXG4gIFxyXG4gIHZhciBsb29wTmFtZSA9IFsocHJvYy5mdW5jTmFtZXx8XCJ1bm5hbWVkXCIpLCBcIl9jd2lzZV9sb29wX1wiLCBvcmRlcnNbMF0uam9pbihcInNcIiksXCJtXCIsbWF0Y2hlZCx0eXBlU3VtbWFyeShkdHlwZXMpXS5qb2luKFwiXCIpXHJcbiAgdmFyIGYgPSBuZXcgRnVuY3Rpb24oW1wiZnVuY3Rpb24gXCIsbG9vcE5hbWUsXCIoXCIsIGFyZ2xpc3Quam9pbihcIixcIiksXCIpe1wiLCBjb2RlLmpvaW4oXCJcXG5cIiksXCJ9IHJldHVybiBcIiwgbG9vcE5hbWVdLmpvaW4oXCJcIikpXHJcbiAgcmV0dXJuIGYoKVxyXG59XHJcbm1vZHVsZS5leHBvcnRzID0gZ2VuZXJhdGVDV2lzZU9wXHJcbiIsIlwidXNlIHN0cmljdFwiXHJcblxyXG4vLyBUaGUgZnVuY3Rpb24gYmVsb3cgaXMgY2FsbGVkIHdoZW4gY29uc3RydWN0aW5nIGEgY3dpc2UgZnVuY3Rpb24gb2JqZWN0LCBhbmQgZG9lcyB0aGUgZm9sbG93aW5nOlxyXG4vLyBBIGZ1bmN0aW9uIG9iamVjdCBpcyBjb25zdHJ1Y3RlZCB3aGljaCBhY2NlcHRzIGFzIGFyZ3VtZW50IGEgY29tcGlsYXRpb24gZnVuY3Rpb24gYW5kIHJldHVybnMgYW5vdGhlciBmdW5jdGlvbi5cclxuLy8gSXQgaXMgdGhpcyBvdGhlciBmdW5jdGlvbiB0aGF0IGlzIGV2ZW50dWFsbHkgcmV0dXJuZWQgYnkgY3JlYXRlVGh1bmssIGFuZCB0aGlzIGZ1bmN0aW9uIGlzIHRoZSBvbmUgdGhhdCBhY3R1YWxseVxyXG4vLyBjaGVja3Mgd2hldGhlciBhIGNlcnRhaW4gcGF0dGVybiBvZiBhcmd1bWVudHMgaGFzIGFscmVhZHkgYmVlbiB1c2VkIGJlZm9yZSBhbmQgY29tcGlsZXMgbmV3IGxvb3BzIGFzIG5lZWRlZC5cclxuLy8gVGhlIGNvbXBpbGF0aW9uIHBhc3NlZCB0byB0aGUgZmlyc3QgZnVuY3Rpb24gb2JqZWN0IGlzIHVzZWQgZm9yIGNvbXBpbGluZyBuZXcgZnVuY3Rpb25zLlxyXG4vLyBPbmNlIHRoaXMgZnVuY3Rpb24gb2JqZWN0IGlzIGNyZWF0ZWQsIGl0IGlzIGNhbGxlZCB3aXRoIGNvbXBpbGUgYXMgYXJndW1lbnQsIHdoZXJlIHRoZSBmaXJzdCBhcmd1bWVudCBvZiBjb21waWxlXHJcbi8vIGlzIGJvdW5kIHRvIFwicHJvY1wiIChlc3NlbnRpYWxseSBjb250YWluaW5nIGEgcHJlcHJvY2Vzc2VkIHZlcnNpb24gb2YgdGhlIHVzZXIgYXJndW1lbnRzIHRvIGN3aXNlKS5cclxuLy8gU28gY3JlYXRlVGh1bmsgcm91Z2hseSB3b3JrcyBsaWtlIHRoaXM6XHJcbi8vIGZ1bmN0aW9uIGNyZWF0ZVRodW5rKHByb2MpIHtcclxuLy8gICB2YXIgdGh1bmsgPSBmdW5jdGlvbihjb21waWxlQm91bmQpIHtcclxuLy8gICAgIHZhciBDQUNIRUQgPSB7fVxyXG4vLyAgICAgcmV0dXJuIGZ1bmN0aW9uKGFycmF5cyBhbmQgc2NhbGFycykge1xyXG4vLyAgICAgICBpZiAoZHR5cGUgYW5kIG9yZGVyIG9mIGFycmF5cyBpbiBDQUNIRUQpIHtcclxuLy8gICAgICAgICB2YXIgZnVuYyA9IENBQ0hFRFtkdHlwZSBhbmQgb3JkZXIgb2YgYXJyYXlzXVxyXG4vLyAgICAgICB9IGVsc2Uge1xyXG4vLyAgICAgICAgIHZhciBmdW5jID0gQ0FDSEVEW2R0eXBlIGFuZCBvcmRlciBvZiBhcnJheXNdID0gY29tcGlsZUJvdW5kKGR0eXBlIGFuZCBvcmRlciBvZiBhcnJheXMpXHJcbi8vICAgICAgIH1cclxuLy8gICAgICAgcmV0dXJuIGZ1bmMoYXJyYXlzIGFuZCBzY2FsYXJzKVxyXG4vLyAgICAgfVxyXG4vLyAgIH1cclxuLy8gICByZXR1cm4gdGh1bmsoY29tcGlsZS5iaW5kMShwcm9jKSlcclxuLy8gfVxyXG5cclxudmFyIGNvbXBpbGUgPSByZXF1aXJlKFwiLi9jb21waWxlLmpzXCIpXHJcblxyXG5mdW5jdGlvbiBjcmVhdGVUaHVuayhwcm9jKSB7XHJcbiAgdmFyIGNvZGUgPSBbXCIndXNlIHN0cmljdCdcIiwgXCJ2YXIgQ0FDSEVEPXt9XCJdXHJcbiAgdmFyIHZhcnMgPSBbXVxyXG4gIHZhciB0aHVua05hbWUgPSBwcm9jLmZ1bmNOYW1lICsgXCJfY3dpc2VfdGh1bmtcIlxyXG4gIFxyXG4gIC8vQnVpbGQgdGh1bmtcclxuICBjb2RlLnB1c2goW1wicmV0dXJuIGZ1bmN0aW9uIFwiLCB0aHVua05hbWUsIFwiKFwiLCBwcm9jLnNoaW1BcmdzLmpvaW4oXCIsXCIpLCBcIil7XCJdLmpvaW4oXCJcIikpXHJcbiAgdmFyIHR5cGVzaWcgPSBbXVxyXG4gIHZhciBzdHJpbmdfdHlwZXNpZyA9IFtdXHJcbiAgdmFyIHByb2NfYXJncyA9IFtbXCJhcnJheVwiLHByb2MuYXJyYXlBcmdzWzBdLFwiLnNoYXBlLnNsaWNlKFwiLCAvLyBTbGljZSBzaGFwZSBzbyB0aGF0IHdlIG9ubHkgcmV0YWluIHRoZSBzaGFwZSBvdmVyIHdoaWNoIHdlIGl0ZXJhdGUgKHdoaWNoIGdldHMgcGFzc2VkIHRvIHRoZSBjd2lzZSBvcGVyYXRvciBhcyBTUykuXHJcbiAgICAgICAgICAgICAgICAgICAgTWF0aC5tYXgoMCxwcm9jLmFycmF5QmxvY2tJbmRpY2VzWzBdKSxwcm9jLmFycmF5QmxvY2tJbmRpY2VzWzBdPDA/KFwiLFwiK3Byb2MuYXJyYXlCbG9ja0luZGljZXNbMF0rXCIpXCIpOlwiKVwiXS5qb2luKFwiXCIpXVxyXG4gIHZhciBzaGFwZUxlbmd0aENvbmRpdGlvbnMgPSBbXSwgc2hhcGVDb25kaXRpb25zID0gW11cclxuICAvLyBQcm9jZXNzIGFycmF5IGFyZ3VtZW50c1xyXG4gIGZvcih2YXIgaT0wOyBpPHByb2MuYXJyYXlBcmdzLmxlbmd0aDsgKytpKSB7XHJcbiAgICB2YXIgaiA9IHByb2MuYXJyYXlBcmdzW2ldXHJcbiAgICB2YXJzLnB1c2goW1widFwiLCBqLCBcIj1hcnJheVwiLCBqLCBcIi5kdHlwZSxcIixcclxuICAgICAgICAgICAgICAgXCJyXCIsIGosIFwiPWFycmF5XCIsIGosIFwiLm9yZGVyXCJdLmpvaW4oXCJcIikpXHJcbiAgICB0eXBlc2lnLnB1c2goXCJ0XCIgKyBqKVxyXG4gICAgdHlwZXNpZy5wdXNoKFwiclwiICsgailcclxuICAgIHN0cmluZ190eXBlc2lnLnB1c2goXCJ0XCIrailcclxuICAgIHN0cmluZ190eXBlc2lnLnB1c2goXCJyXCIraitcIi5qb2luKClcIilcclxuICAgIHByb2NfYXJncy5wdXNoKFwiYXJyYXlcIiArIGogKyBcIi5kYXRhXCIpXHJcbiAgICBwcm9jX2FyZ3MucHVzaChcImFycmF5XCIgKyBqICsgXCIuc3RyaWRlXCIpXHJcbiAgICBwcm9jX2FyZ3MucHVzaChcImFycmF5XCIgKyBqICsgXCIub2Zmc2V0fDBcIilcclxuICAgIGlmIChpPjApIHsgLy8gR2F0aGVyIGNvbmRpdGlvbnMgdG8gY2hlY2sgZm9yIHNoYXBlIGVxdWFsaXR5IChpZ25vcmluZyBibG9jayBpbmRpY2VzKVxyXG4gICAgICBzaGFwZUxlbmd0aENvbmRpdGlvbnMucHVzaChcImFycmF5XCIgKyBwcm9jLmFycmF5QXJnc1swXSArIFwiLnNoYXBlLmxlbmd0aD09PWFycmF5XCIgKyBqICsgXCIuc2hhcGUubGVuZ3RoK1wiICsgKE1hdGguYWJzKHByb2MuYXJyYXlCbG9ja0luZGljZXNbMF0pLU1hdGguYWJzKHByb2MuYXJyYXlCbG9ja0luZGljZXNbaV0pKSlcclxuICAgICAgc2hhcGVDb25kaXRpb25zLnB1c2goXCJhcnJheVwiICsgcHJvYy5hcnJheUFyZ3NbMF0gKyBcIi5zaGFwZVtzaGFwZUluZGV4K1wiICsgTWF0aC5tYXgoMCxwcm9jLmFycmF5QmxvY2tJbmRpY2VzWzBdKSArIFwiXT09PWFycmF5XCIgKyBqICsgXCIuc2hhcGVbc2hhcGVJbmRleCtcIiArIE1hdGgubWF4KDAscHJvYy5hcnJheUJsb2NrSW5kaWNlc1tpXSkgKyBcIl1cIilcclxuICAgIH1cclxuICB9XHJcbiAgLy8gQ2hlY2sgZm9yIHNoYXBlIGVxdWFsaXR5XHJcbiAgaWYgKHByb2MuYXJyYXlBcmdzLmxlbmd0aCA+IDEpIHtcclxuICAgIGNvZGUucHVzaChcImlmICghKFwiICsgc2hhcGVMZW5ndGhDb25kaXRpb25zLmpvaW4oXCIgJiYgXCIpICsgXCIpKSB0aHJvdyBuZXcgRXJyb3IoJ2N3aXNlOiBBcnJheXMgZG8gbm90IGFsbCBoYXZlIHRoZSBzYW1lIGRpbWVuc2lvbmFsaXR5IScpXCIpXHJcbiAgICBjb2RlLnB1c2goXCJmb3IodmFyIHNoYXBlSW5kZXg9YXJyYXlcIiArIHByb2MuYXJyYXlBcmdzWzBdICsgXCIuc2hhcGUubGVuZ3RoLVwiICsgTWF0aC5hYnMocHJvYy5hcnJheUJsb2NrSW5kaWNlc1swXSkgKyBcIjsgc2hhcGVJbmRleC0tPjA7KSB7XCIpXHJcbiAgICBjb2RlLnB1c2goXCJpZiAoIShcIiArIHNoYXBlQ29uZGl0aW9ucy5qb2luKFwiICYmIFwiKSArIFwiKSkgdGhyb3cgbmV3IEVycm9yKCdjd2lzZTogQXJyYXlzIGRvIG5vdCBhbGwgaGF2ZSB0aGUgc2FtZSBzaGFwZSEnKVwiKVxyXG4gICAgY29kZS5wdXNoKFwifVwiKVxyXG4gIH1cclxuICAvLyBQcm9jZXNzIHNjYWxhciBhcmd1bWVudHNcclxuICBmb3IodmFyIGk9MDsgaTxwcm9jLnNjYWxhckFyZ3MubGVuZ3RoOyArK2kpIHtcclxuICAgIHByb2NfYXJncy5wdXNoKFwic2NhbGFyXCIgKyBwcm9jLnNjYWxhckFyZ3NbaV0pXHJcbiAgfVxyXG4gIC8vIENoZWNrIGZvciBjYWNoZWQgZnVuY3Rpb24gKGFuZCBpZiBub3QgcHJlc2VudCwgZ2VuZXJhdGUgaXQpXHJcbiAgdmFycy5wdXNoKFtcInR5cGU9W1wiLCBzdHJpbmdfdHlwZXNpZy5qb2luKFwiLFwiKSwgXCJdLmpvaW4oKVwiXS5qb2luKFwiXCIpKVxyXG4gIHZhcnMucHVzaChcInByb2M9Q0FDSEVEW3R5cGVdXCIpXHJcbiAgY29kZS5wdXNoKFwidmFyIFwiICsgdmFycy5qb2luKFwiLFwiKSlcclxuICBcclxuICBjb2RlLnB1c2goW1wiaWYoIXByb2Mpe1wiLFxyXG4gICAgICAgICAgICAgXCJDQUNIRURbdHlwZV09cHJvYz1jb21waWxlKFtcIiwgdHlwZXNpZy5qb2luKFwiLFwiKSwgXCJdKX1cIixcclxuICAgICAgICAgICAgIFwicmV0dXJuIHByb2MoXCIsIHByb2NfYXJncy5qb2luKFwiLFwiKSwgXCIpfVwiXS5qb2luKFwiXCIpKVxyXG5cclxuICBpZihwcm9jLmRlYnVnKSB7XHJcbiAgICBjb25zb2xlLmxvZyhcIi0tLS0tR2VuZXJhdGVkIHRodW5rOlxcblwiICsgY29kZS5qb2luKFwiXFxuXCIpICsgXCJcXG4tLS0tLS0tLS0tXCIpXHJcbiAgfVxyXG4gIFxyXG4gIC8vQ29tcGlsZSB0aHVua1xyXG4gIHZhciB0aHVuayA9IG5ldyBGdW5jdGlvbihcImNvbXBpbGVcIiwgY29kZS5qb2luKFwiXFxuXCIpKVxyXG4gIHJldHVybiB0aHVuayhjb21waWxlLmJpbmQodW5kZWZpbmVkLCBwcm9jKSlcclxufVxyXG5cclxubW9kdWxlLmV4cG9ydHMgPSBjcmVhdGVUaHVua1xyXG4iLCJcInVzZSBzdHJpY3RcIlxuXG5mdW5jdGlvbiB1bmlxdWVfcHJlZChsaXN0LCBjb21wYXJlKSB7XG4gIHZhciBwdHIgPSAxXG4gICAgLCBsZW4gPSBsaXN0Lmxlbmd0aFxuICAgICwgYT1saXN0WzBdLCBiPWxpc3RbMF1cbiAgZm9yKHZhciBpPTE7IGk8bGVuOyArK2kpIHtcbiAgICBiID0gYVxuICAgIGEgPSBsaXN0W2ldXG4gICAgaWYoY29tcGFyZShhLCBiKSkge1xuICAgICAgaWYoaSA9PT0gcHRyKSB7XG4gICAgICAgIHB0cisrXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG4gICAgICBsaXN0W3B0cisrXSA9IGFcbiAgICB9XG4gIH1cbiAgbGlzdC5sZW5ndGggPSBwdHJcbiAgcmV0dXJuIGxpc3Rcbn1cblxuZnVuY3Rpb24gdW5pcXVlX2VxKGxpc3QpIHtcbiAgdmFyIHB0ciA9IDFcbiAgICAsIGxlbiA9IGxpc3QubGVuZ3RoXG4gICAgLCBhPWxpc3RbMF0sIGIgPSBsaXN0WzBdXG4gIGZvcih2YXIgaT0xOyBpPGxlbjsgKytpLCBiPWEpIHtcbiAgICBiID0gYVxuICAgIGEgPSBsaXN0W2ldXG4gICAgaWYoYSAhPT0gYikge1xuICAgICAgaWYoaSA9PT0gcHRyKSB7XG4gICAgICAgIHB0cisrXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG4gICAgICBsaXN0W3B0cisrXSA9IGFcbiAgICB9XG4gIH1cbiAgbGlzdC5sZW5ndGggPSBwdHJcbiAgcmV0dXJuIGxpc3Rcbn1cblxuZnVuY3Rpb24gdW5pcXVlKGxpc3QsIGNvbXBhcmUsIHNvcnRlZCkge1xuICBpZihsaXN0Lmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBsaXN0XG4gIH1cbiAgaWYoY29tcGFyZSkge1xuICAgIGlmKCFzb3J0ZWQpIHtcbiAgICAgIGxpc3Quc29ydChjb21wYXJlKVxuICAgIH1cbiAgICByZXR1cm4gdW5pcXVlX3ByZWQobGlzdCwgY29tcGFyZSlcbiAgfVxuICBpZighc29ydGVkKSB7XG4gICAgbGlzdC5zb3J0KClcbiAgfVxuICByZXR1cm4gdW5pcXVlX2VxKGxpc3QpXG59XG5cbm1vZHVsZS5leHBvcnRzID0gdW5pcXVlXG4iLCJcInVzZSBzdHJpY3RcIlxuXG5cblxudmFyIGZpbGwgPSByZXF1aXJlKCdjd2lzZS9saWIvd3JhcHBlcicpKHtcImFyZ3NcIjpbXCJpbmRleFwiLFwiYXJyYXlcIixcInNjYWxhclwiXSxcInByZVwiOntcImJvZHlcIjpcInt9XCIsXCJhcmdzXCI6W10sXCJ0aGlzVmFyc1wiOltdLFwibG9jYWxWYXJzXCI6W119LFwiYm9keVwiOntcImJvZHlcIjpcIntfaW5saW5lXzFfYXJnMV89X2lubGluZV8xX2FyZzJfLmFwcGx5KHZvaWQgMCxfaW5saW5lXzFfYXJnMF8pfVwiLFwiYXJnc1wiOlt7XCJuYW1lXCI6XCJfaW5saW5lXzFfYXJnMF9cIixcImx2YWx1ZVwiOmZhbHNlLFwicnZhbHVlXCI6dHJ1ZSxcImNvdW50XCI6MX0se1wibmFtZVwiOlwiX2lubGluZV8xX2FyZzFfXCIsXCJsdmFsdWVcIjp0cnVlLFwicnZhbHVlXCI6ZmFsc2UsXCJjb3VudFwiOjF9LHtcIm5hbWVcIjpcIl9pbmxpbmVfMV9hcmcyX1wiLFwibHZhbHVlXCI6ZmFsc2UsXCJydmFsdWVcIjp0cnVlLFwiY291bnRcIjoxfV0sXCJ0aGlzVmFyc1wiOltdLFwibG9jYWxWYXJzXCI6W119LFwicG9zdFwiOntcImJvZHlcIjpcInt9XCIsXCJhcmdzXCI6W10sXCJ0aGlzVmFyc1wiOltdLFwibG9jYWxWYXJzXCI6W119LFwiZGVidWdcIjpmYWxzZSxcImZ1bmNOYW1lXCI6XCJjd2lzZVwiLFwiYmxvY2tTaXplXCI6NjR9KVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKGFycmF5LCBmKSB7XG4gIGZpbGwoYXJyYXksIGYpXG4gIHJldHVybiBhcnJheVxufVxuIl19 | |
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})({"marching-squares":[function(require,module,exports){ | |
'use strict'; | |
/** | |
* @module marching-squares | |
*/ | |
// [dx, dy, is-down-or-right?0:1] | |
var UP = [0,-1,1], | |
DOWN = [0,1,0], | |
LEFT = [-1,0,1], | |
RIGHT = [1,0,0]; | |
// There are 16 possible 2-by-2 square configurations. | |
// We number them by adding the shown value when the cell in the square is in the region. | |
// | |
// ---------------- | |
// |x-1,y-1| x,y-1| | |
// | 1 | 2 | | |
// |--------------- | |
// | x-1,y | x,y | | |
// | 4 | 8 | | |
// ---------------- | |
// | |
// The transitions are designed to proceed in a clockwise direction around the region. | |
// Squares 6 and 9 are ambiguous cases where we need to see which direction the previous | |
// transition was to avoid getting caught looping around a sub-region forever. | |
var transitions = [ | |
null, // 0 | |
// [direction-if-coming-from-down-or-right, direction-if-coming-from-up-or-left] | |
[LEFT, LEFT], // 1 | |
[UP, UP], // 2 | |
[LEFT, LEFT], // 3 | |
[DOWN, DOWN], // 4 | |
[DOWN, DOWN], // 5 | |
[UP, DOWN], // 6 | |
[DOWN, DOWN], // 7 | |
[RIGHT, RIGHT], // 8 | |
[RIGHT, LEFT], // 9 | |
[UP, UP], // 10 | |
[LEFT, LEFT], // 11 | |
[RIGHT, RIGHT], // 12 | |
[RIGHT, RIGHT], // 13 | |
[UP, UP] // 14 | |
]; | |
/** | |
* @alias module:marching-squares.traceImageRegion | |
* Trace a closed polygon around a region in a two-dimensional grid. The | |
* isInside function is called to determine if a given point is inside or | |
* outside the region. | |
* | |
* The starting point MUST be on the edge of the region. Specifically this | |
* means that among these four calls | |
* 1. isInside(x-1, y-1) | |
* 2. isInside(x, y-1) | |
* 3. isInside(x-1, y) | |
* 4. isInside(x,y) | |
* At least one must return falsy and at least one must return truthy. If | |
* this is not the case, an Error is thrown. | |
* | |
* An efficient marching-squares algorithm is used to trace the region, | |
* using minimal memory and calling isInside() only as neccessary. | |
* | |
* @param {int} x - starting x coordinate. | |
* @param {int} y - starting y coordinate. | |
* @param {function} isInside - function with signature isInside(x,y) returning | |
* truthy if the given point is inside the region to trace (for | |
* example, it is an opaque pixel in a bitmap) and falsy if it is outside | |
* (for example, it is transparent). The function should be able to handle | |
* any x and y including negative values "outside the bitmap" (for which it | |
* should return false). | |
* @returns {array[object]} array of point objects with x & y properties tracing | |
* a closed polygon around the region. The first point is NOT repeated | |
* as the last point. The polygon consists entirely of one-unit-long | |
* horizontal or vertical segments. Use a polygon simplification routine on | |
* the results to simplify and/or smooth it. | |
* (Might I suggest https://www.npmjs.com/package/line-simplify-rdp ?) | |
*/ | |
function traceRegion(x, y, isInside) { | |
var startX = x, startY = y; | |
var ret = [{x:x, y:y}]; | |
var dir = DOWN; // arbitrary | |
var square = | |
(isInside(x-1, y-1) ? 1 : 0) + | |
(isInside(x, y-1) ? 2 : 0) + | |
(isInside(x-1, y) ? 4 : 0) + | |
(isInside(x, y) ? 8 : 0); | |
if (square === 0 || square === 15) | |
throw new Error("Bad Starting point."); | |
while (true) { | |
dir = transitions[square][dir[2]]; | |
x += dir[0]; | |
y += dir[1]; | |
if (x === startX && y === startY) | |
return ret; | |
ret.push({x:x, y:y}); | |
if (dir === DOWN) | |
square = ((square & 12) >> 2); | |
else if (dir === UP) | |
square = ((square & 3) << 2); | |
else if (dir === RIGHT) | |
square = ((square & 10) >> 1); | |
else if (dir === LEFT) | |
square = ((square & 5) << 1); | |
if (dir === DOWN || dir === LEFT) | |
square += (isInside(x-1, y) ? 4 : 0); | |
else | |
square += (isInside(x, y-1) ? 2 : 0); | |
if (dir === DOWN || dir === RIGHT) | |
square += (isInside(x, y) ? 8 : 0); | |
else | |
square += (isInside(x-1, y-1) ? 1 : 0); | |
} | |
} | |
module.exports = traceRegion; | |
},{}]},{},[]) | |
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImluZGV4LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIid1c2Ugc3RyaWN0JztcblxuLyoqXG4gKiBAbW9kdWxlIG1hcmNoaW5nLXNxdWFyZXNcbiAqL1xuXG4vLyBbZHgsIGR5LCBpcy1kb3duLW9yLXJpZ2h0PzA6MV1cbnZhciBVUCA9IFswLC0xLDFdLFxuICAgIERPV04gPSBbMCwxLDBdLFxuICAgIExFRlQgPSBbLTEsMCwxXSxcbiAgICBSSUdIVCA9IFsxLDAsMF07XG5cbi8vIFRoZXJlIGFyZSAxNiBwb3NzaWJsZSAyLWJ5LTIgc3F1YXJlIGNvbmZpZ3VyYXRpb25zLlxuLy8gV2UgbnVtYmVyIHRoZW0gYnkgYWRkaW5nIHRoZSBzaG93biB2YWx1ZSB3aGVuIHRoZSBjZWxsIGluIHRoZSBzcXVhcmUgaXMgaW4gdGhlIHJlZ2lvbi5cbi8vXG4vLyAtLS0tLS0tLS0tLS0tLS0tXG4vLyB8eC0xLHktMXwgeCx5LTF8XG4vLyB8ICAgMSAgIHwgIDIgICB8XG4vLyB8LS0tLS0tLS0tLS0tLS0tXG4vLyB8IHgtMSx5IHwgeCx5ICB8XG4vLyB8ICAgNCAgIHwgIDggICB8IFxuLy8gLS0tLS0tLS0tLS0tLS0tLVxuLy9cbi8vIFRoZSB0cmFuc2l0aW9ucyBhcmUgZGVzaWduZWQgdG8gcHJvY2VlZCBpbiBhIGNsb2Nrd2lzZSBkaXJlY3Rpb24gYXJvdW5kIHRoZSByZWdpb24uXG4vLyBTcXVhcmVzIDYgYW5kIDkgYXJlIGFtYmlndW91cyBjYXNlcyB3aGVyZSB3ZSBuZWVkIHRvIHNlZSB3aGljaCBkaXJlY3Rpb24gdGhlIHByZXZpb3VzXG4vLyB0cmFuc2l0aW9uIHdhcyB0byBhdm9pZCBnZXR0aW5nIGNhdWdodCBsb29waW5nIGFyb3VuZCBhIHN1Yi1yZWdpb24gZm9yZXZlci5cblxudmFyIHRyYW5zaXRpb25zID0gW1xuICAgbnVsbCwgLy8gMFxuICAgLy8gW2RpcmVjdGlvbi1pZi1jb21pbmctZnJvbS1kb3duLW9yLXJpZ2h0LCBkaXJlY3Rpb24taWYtY29taW5nLWZyb20tdXAtb3ItbGVmdF1cbiAgIFtMRUZULCBMRUZUXSwgLy8gMVxuICAgW1VQLCBVUF0sIC8vIDJcbiAgIFtMRUZULCBMRUZUXSwgLy8gM1xuICAgW0RPV04sIERPV05dLCAgLy8gNFxuICAgW0RPV04sIERPV05dLCAgLy8gNVxuICAgW1VQLCBET1dOXSwgICAgLy8gNlxuICAgW0RPV04sIERPV05dLCAvLyA3XG4gICBbUklHSFQsIFJJR0hUXSwgLy8gOFxuICAgW1JJR0hULCBMRUZUXSwgLy8gOVxuICAgW1VQLCBVUF0sIC8vIDEwXG4gICBbTEVGVCwgTEVGVF0sIC8vIDExXG4gICBbUklHSFQsIFJJR0hUXSwgLy8gMTJcbiAgIFtSSUdIVCwgUklHSFRdLCAvLyAxM1xuICAgW1VQLCBVUF0gLy8gMTRcbl07XG5cbi8qKlxuICogQGFsaWFzIG1vZHVsZTptYXJjaGluZy1zcXVhcmVzLnRyYWNlSW1hZ2VSZWdpb25cbiAqIFRyYWNlIGEgY2xvc2VkIHBvbHlnb24gYXJvdW5kIGEgcmVnaW9uIGluIGEgdHdvLWRpbWVuc2lvbmFsIGdyaWQuIFRoZSBcbiAqIGlzSW5zaWRlIGZ1bmN0aW9uIGlzIGNhbGxlZCB0byBkZXRlcm1pbmUgaWYgYSBnaXZlbiBwb2ludCBpcyBpbnNpZGUgb3IgXG4gKiBvdXRzaWRlIHRoZSByZWdpb24uIFxuICogXG4gKiBUaGUgc3RhcnRpbmcgcG9pbnQgTVVTVCBiZSBvbiB0aGUgZWRnZSBvZiB0aGUgcmVnaW9uLiBTcGVjaWZpY2FsbHkgdGhpc1xuICogbWVhbnMgdGhhdCBhbW9uZyB0aGVzZSBmb3VyIGNhbGxzXG4gKiAxLiBpc0luc2lkZSh4LTEsIHktMSlcbiAqIDIuIGlzSW5zaWRlKHgsIHktMSlcbiAqIDMuIGlzSW5zaWRlKHgtMSwgeSlcbiAqIDQuIGlzSW5zaWRlKHgseSlcbiAqIEF0IGxlYXN0IG9uZSBtdXN0IHJldHVybiBmYWxzeSBhbmQgYXQgbGVhc3Qgb25lIG11c3QgcmV0dXJuIHRydXRoeS4gSWZcbiAqIHRoaXMgaXMgbm90IHRoZSBjYXNlLCBhbiBFcnJvciBpcyB0aHJvd24uXG4gKiBcbiAqIEFuIGVmZmljaWVudCBtYXJjaGluZy1zcXVhcmVzIGFsZ29yaXRobSBpcyB1c2VkIHRvIHRyYWNlIHRoZSByZWdpb24sXG4gKiB1c2luZyBtaW5pbWFsIG1lbW9yeSBhbmQgY2FsbGluZyBpc0luc2lkZSgpIG9ubHkgYXMgbmVjY2Vzc2FyeS5cbiAqIFxuICogQHBhcmFtIHtpbnR9IHggLSBzdGFydGluZyB4IGNvb3JkaW5hdGUuIFxuICogQHBhcmFtIHtpbnR9IHkgLSBzdGFydGluZyB5IGNvb3JkaW5hdGUuXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBpc0luc2lkZSAtIGZ1bmN0aW9uIHdpdGggc2lnbmF0dXJlIGlzSW5zaWRlKHgseSkgcmV0dXJuaW5nICBcbiAqICAgdHJ1dGh5IGlmIHRoZSBnaXZlbiBwb2ludCBpcyBpbnNpZGUgdGhlIHJlZ2lvbiB0byB0cmFjZSAoZm9yIFxuICogICBleGFtcGxlLCBpdCBpcyBhbiBvcGFxdWUgcGl4ZWwgaW4gYSBiaXRtYXApIGFuZCBmYWxzeSBpZiBpdCBpcyBvdXRzaWRlIFxuICogICAoZm9yIGV4YW1wbGUsIGl0IGlzIHRyYW5zcGFyZW50KS4gVGhlIGZ1bmN0aW9uIHNob3VsZCBiZSBhYmxlIHRvIGhhbmRsZSBcbiAqICAgYW55IHggYW5kIHkgaW5jbHVkaW5nIG5lZ2F0aXZlIHZhbHVlcyBcIm91dHNpZGUgdGhlIGJpdG1hcFwiIChmb3Igd2hpY2ggaXRcbiAqICAgc2hvdWxkIHJldHVybiBmYWxzZSkuXG4gKiBAcmV0dXJucyB7YXJyYXlbb2JqZWN0XX0gYXJyYXkgb2YgcG9pbnQgb2JqZWN0cyB3aXRoIHggJiB5IHByb3BlcnRpZXMgdHJhY2luZ1xuICogICBhIGNsb3NlZCBwb2x5Z29uIGFyb3VuZCB0aGUgcmVnaW9uLiBUaGUgZmlyc3QgcG9pbnQgaXMgTk9UIHJlcGVhdGVkIFxuICogICBhcyB0aGUgbGFzdCBwb2ludC4gVGhlIHBvbHlnb24gY29uc2lzdHMgZW50aXJlbHkgb2Ygb25lLXVuaXQtbG9uZyBcbiAqICAgaG9yaXpvbnRhbCBvciB2ZXJ0aWNhbCBzZWdtZW50cy4gVXNlIGEgcG9seWdvbiBzaW1wbGlmaWNhdGlvbiByb3V0aW5lIG9uIFxuICogICB0aGUgcmVzdWx0cyB0byBzaW1wbGlmeSBhbmQvb3Igc21vb3RoIGl0LlxuICogIChNaWdodCBJIHN1Z2dlc3QgaHR0cHM6Ly93d3cubnBtanMuY29tL3BhY2thZ2UvbGluZS1zaW1wbGlmeS1yZHAgPylcbiAqL1xuZnVuY3Rpb24gdHJhY2VSZWdpb24oeCwgeSwgaXNJbnNpZGUpIHtcbiAgIHZhciBzdGFydFggPSB4LCBzdGFydFkgPSB5O1xuICAgdmFyIHJldCA9IFt7eDp4LCB5Onl9XTtcbiAgIHZhciBkaXIgPSBET1dOOyAvLyBhcmJpdHJhcnlcblxuIHZhciBzcXVhcmUgPSBcbiAgICAgIChpc0luc2lkZSh4LTEsIHktMSkgPyAxIDogMCkgKyBcbiAgICAgIChpc0luc2lkZSh4LCB5LTEpID8gMiA6IDApICsgXG4gICAgICAoaXNJbnNpZGUoeC0xLCB5KSA/IDQgOiAwKSArIFxuICAgICAgKGlzSW5zaWRlKHgsIHkpID8gOCA6IDApO1xuICAgICAgICAgXG4gICBpZiAoc3F1YXJlID09PSAwIHx8IHNxdWFyZSA9PT0gMTUpIFxuICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQmFkIFN0YXJ0aW5nIHBvaW50LlwiKTtcblxuICAgd2hpbGUgKHRydWUpIHtcbiAgICAgIGRpciA9IHRyYW5zaXRpb25zW3NxdWFyZV1bZGlyWzJdXTtcbiAgICAgIHggKz0gZGlyWzBdO1xuICAgICAgeSArPSBkaXJbMV07XG4gICAgICBcbiAgICAgIGlmICh4ID09PSBzdGFydFggJiYgeSA9PT0gc3RhcnRZKVxuICAgICAgICAgcmV0dXJuIHJldDtcbiAgICAgIFxuICAgICAgcmV0LnB1c2goe3g6eCwgeTp5fSk7XG5cbiAgICAgIGlmIChkaXIgPT09IERPV04pIFxuICAgICAgICAgc3F1YXJlID0gKChzcXVhcmUgJiAxMikgPj4gMik7XG4gICAgICBlbHNlIGlmIChkaXIgPT09IFVQKSBcbiAgICAgICAgIHNxdWFyZSA9ICgoc3F1YXJlICYgMykgPDwgMik7IFxuICAgICAgZWxzZSBpZiAoZGlyID09PSBSSUdIVCkgXG4gICAgICAgICBzcXVhcmUgPSAoKHNxdWFyZSAmIDEwKSA+PiAxKTtcbiAgICAgIGVsc2UgaWYgKGRpciA9PT0gTEVGVCkgXG4gICAgICAgICBzcXVhcmUgPSAoKHNxdWFyZSAmIDUpIDw8IDEpO1xuICAgICAgICAgXG4gICAgICBpZiAoZGlyID09PSBET1dOIHx8IGRpciA9PT0gTEVGVClcbiAgICAgICAgIHNxdWFyZSArPSAoaXNJbnNpZGUoeC0xLCB5KSA/IDQgOiAwKTtcbiAgICAgIGVsc2UgICBcbiAgICAgICAgIHNxdWFyZSArPSAoaXNJbnNpZGUoeCwgeS0xKSA/IDIgOiAwKTtcbiAgICAgXG4gICAgICBpZiAoZGlyID09PSBET1dOIHx8IGRpciA9PT0gUklHSFQpXG4gICAgICAgICBzcXVhcmUgKz0gKGlzSW5zaWRlKHgsIHkpID8gOCA6IDApO1xuICAgICAgZWxzZVxuICAgICAgICAgc3F1YXJlICs9ICAoaXNJbnNpZGUoeC0xLCB5LTEpID8gMSA6IDApO1xuICAgIFxuICAgICAgICBcbiAgIH1cbiAgIFxufVxuXG5cbm1vZHVsZS5leHBvcnRzID0gdHJhY2VSZWdpb247Il19 | |
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 (global){ | |
/*! | |
* The buffer module from node.js, for the browser. | |
* | |
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org> | |
* @license MIT | |
*/ | |
/* eslint-disable no-proto */ | |
'use strict' | |
var base64 = require('base64-js') | |
var ieee754 = require('ieee754') | |
var isArray = require('isarray') | |
exports.Buffer = Buffer | |
exports.SlowBuffer = SlowBuffer | |
exports.INSPECT_MAX_BYTES = 50 | |
Buffer.poolSize = 8192 // not used by this implementation | |
var rootParent = {} | |
/** | |
* If `Buffer.TYPED_ARRAY_SUPPORT`: | |
* === true Use Uint8Array implementation (fastest) | |
* === false Use Object implementation (most compatible, even IE6) | |
* | |
* Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, | |
* Opera 11.6+, iOS 4.2+. | |
* | |
* Due to various browser bugs, sometimes the Object implementation will be used even | |
* when the browser supports typed arrays. | |
* | |
* Note: | |
* | |
* - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, | |
* See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. | |
* | |
* - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property | |
* on objects. | |
* | |
* - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. | |
* | |
* - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of | |
* incorrect length in some situations. | |
* We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they | |
* get the Object implementation, which is slower but behaves correctly. | |
*/ | |
Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined | |
? global.TYPED_ARRAY_SUPPORT | |
: typedArraySupport() | |
function typedArraySupport () { | |
function Bar () {} | |
try { | |
var arr = new Uint8Array(1) | |
arr.foo = function () { return 42 } | |
arr.constructor = Bar | |
return arr.foo() === 42 && // typed array instances can be augmented | |
arr.constructor === Bar && // constructor can be set | |
typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` | |
arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` | |
} catch (e) { | |
return false | |
} | |
} | |
function kMaxLength () { | |
return Buffer.TYPED_ARRAY_SUPPORT | |
? 0x7fffffff | |
: 0x3fffffff | |
} | |
/** | |
* Class: Buffer | |
* ============= | |
* | |
* The Buffer constructor returns instances of `Uint8Array` that are augmented | |
* with function properties for all the node `Buffer` API functions. We use | |
* `Uint8Array` so that square bracket notation works as expected -- it returns | |
* a single octet. | |
* | |
* By augmenting the instances, we can avoid modifying the `Uint8Array` | |
* prototype. | |
*/ | |
function Buffer (arg) { | |
if (!(this instanceof Buffer)) { | |
// Avoid going through an ArgumentsAdaptorTrampoline in the common case. | |
if (arguments.length > 1) return new Buffer(arg, arguments[1]) | |
return new Buffer(arg) | |
} | |
if (!Buffer.TYPED_ARRAY_SUPPORT) { | |
this.length = 0 | |
this.parent = undefined | |
} | |
// Common case. | |
if (typeof arg === 'number') { | |
return fromNumber(this, arg) | |
} | |
// Slightly less common case. | |
if (typeof arg === 'string') { | |
return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8') | |
} | |
// Unusual. | |
return fromObject(this, arg) | |
} | |
function fromNumber (that, length) { | |
that = allocate(that, length < 0 ? 0 : checked(length) | 0) | |
if (!Buffer.TYPED_ARRAY_SUPPORT) { | |
for (var i = 0; i < length; i++) { | |
that[i] = 0 | |
} | |
} | |
return that | |
} | |
function fromString (that, string, encoding) { | |
if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8' | |
// Assumption: byteLength() return value is always < kMaxLength. | |
var length = byteLength(string, encoding) | 0 | |
that = allocate(that, length) | |
that.write(string, encoding) | |
return that | |
} | |
function fromObject (that, object) { | |
if (Buffer.isBuffer(object)) return fromBuffer(that, object) | |
if (isArray(object)) return fromArray(that, object) | |
if (object == null) { | |
throw new TypeError('must start with number, buffer, array or string') | |
} | |
if (typeof ArrayBuffer !== 'undefined') { | |
if (object.buffer instanceof ArrayBuffer) { | |
return fromTypedArray(that, object) | |
} | |
if (object instanceof ArrayBuffer) { | |
return fromArrayBuffer(that, object) | |
} | |
} | |
if (object.length) return fromArrayLike(that, object) | |
return fromJsonObject(that, object) | |
} | |
function fromBuffer (that, buffer) { | |
var length = checked(buffer.length) | 0 | |
that = allocate(that, length) | |
buffer.copy(that, 0, 0, length) | |
return that | |
} | |
function fromArray (that, array) { | |
var length = checked(array.length) | 0 | |
that = allocate(that, length) | |
for (var i = 0; i < length; i += 1) { | |
that[i] = array[i] & 255 | |
} | |
return that | |
} | |
// Duplicate of fromArray() to keep fromArray() monomorphic. | |
function fromTypedArray (that, array) { | |
var length = checked(array.length) | 0 | |
that = allocate(that, length) | |
// Truncating the elements is probably not what people expect from typed | |
// arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior | |
// of the old Buffer constructor. | |
for (var i = 0; i < length; i += 1) { | |
that[i] = array[i] & 255 | |
} | |
return that | |
} | |
function fromArrayBuffer (that, array) { | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
// Return an augmented `Uint8Array` instance, for best performance | |
array.byteLength | |
that = Buffer._augment(new Uint8Array(array)) | |
} else { | |
// Fallback: Return an object instance of the Buffer class | |
that = fromTypedArray(that, new Uint8Array(array)) | |
} | |
return that | |
} | |
function fromArrayLike (that, array) { | |
var length = checked(array.length) | 0 | |
that = allocate(that, length) | |
for (var i = 0; i < length; i += 1) { | |
that[i] = array[i] & 255 | |
} | |
return that | |
} | |
// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object. | |
// Returns a zero-length buffer for inputs that don't conform to the spec. | |
function fromJsonObject (that, object) { | |
var array | |
var length = 0 | |
if (object.type === 'Buffer' && isArray(object.data)) { | |
array = object.data | |
length = checked(array.length) | 0 | |
} | |
that = allocate(that, length) | |
for (var i = 0; i < length; i += 1) { | |
that[i] = array[i] & 255 | |
} | |
return that | |
} | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
Buffer.prototype.__proto__ = Uint8Array.prototype | |
Buffer.__proto__ = Uint8Array | |
} else { | |
// pre-set for values that may exist in the future | |
Buffer.prototype.length = undefined | |
Buffer.prototype.parent = undefined | |
} | |
function allocate (that, length) { | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
// Return an augmented `Uint8Array` instance, for best performance | |
that = Buffer._augment(new Uint8Array(length)) | |
that.__proto__ = Buffer.prototype | |
} else { | |
// Fallback: Return an object instance of the Buffer class | |
that.length = length | |
that._isBuffer = true | |
} | |
var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1 | |
if (fromPool) that.parent = rootParent | |
return that | |
} | |
function checked (length) { | |
// Note: cannot use `length < kMaxLength` here because that fails when | |
// length is NaN (which is otherwise coerced to zero.) | |
if (length >= kMaxLength()) { | |
throw new RangeError('Attempt to allocate Buffer larger than maximum ' + | |
'size: 0x' + kMaxLength().toString(16) + ' bytes') | |
} | |
return length | 0 | |
} | |
function SlowBuffer (subject, encoding) { | |
if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding) | |
var buf = new Buffer(subject, encoding) | |
delete buf.parent | |
return buf | |
} | |
Buffer.isBuffer = function isBuffer (b) { | |
return !!(b != null && b._isBuffer) | |
} | |
Buffer.compare = function compare (a, b) { | |
if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { | |
throw new TypeError('Arguments must be Buffers') | |
} | |
if (a === b) return 0 | |
var x = a.length | |
var y = b.length | |
var i = 0 | |
var len = Math.min(x, y) | |
while (i < len) { | |
if (a[i] !== b[i]) break | |
++i | |
} | |
if (i !== len) { | |
x = a[i] | |
y = b[i] | |
} | |
if (x < y) return -1 | |
if (y < x) return 1 | |
return 0 | |
} | |
Buffer.isEncoding = function isEncoding (encoding) { | |
switch (String(encoding).toLowerCase()) { | |
case 'hex': | |
case 'utf8': | |
case 'utf-8': | |
case 'ascii': | |
case 'binary': | |
case 'base64': | |
case 'raw': | |
case 'ucs2': | |
case 'ucs-2': | |
case 'utf16le': | |
case 'utf-16le': | |
return true | |
default: | |
return false | |
} | |
} | |
Buffer.concat = function concat (list, length) { | |
if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.') | |
if (list.length === 0) { | |
return new Buffer(0) | |
} | |
var i | |
if (length === undefined) { | |
length = 0 | |
for (i = 0; i < list.length; i++) { | |
length += list[i].length | |
} | |
} | |
var buf = new Buffer(length) | |
var pos = 0 | |
for (i = 0; i < list.length; i++) { | |
var item = list[i] | |
item.copy(buf, pos) | |
pos += item.length | |
} | |
return buf | |
} | |
function byteLength (string, encoding) { | |
if (typeof string !== 'string') string = '' + string | |
var len = string.length | |
if (len === 0) return 0 | |
// Use a for loop to avoid recursion | |
var loweredCase = false | |
for (;;) { | |
switch (encoding) { | |
case 'ascii': | |
case 'binary': | |
// Deprecated | |
case 'raw': | |
case 'raws': | |
return len | |
case 'utf8': | |
case 'utf-8': | |
return utf8ToBytes(string).length | |
case 'ucs2': | |
case 'ucs-2': | |
case 'utf16le': | |
case 'utf-16le': | |
return len * 2 | |
case 'hex': | |
return len >>> 1 | |
case 'base64': | |
return base64ToBytes(string).length | |
default: | |
if (loweredCase) return utf8ToBytes(string).length // assume utf8 | |
encoding = ('' + encoding).toLowerCase() | |
loweredCase = true | |
} | |
} | |
} | |
Buffer.byteLength = byteLength | |
function slowToString (encoding, start, end) { | |
var loweredCase = false | |
start = start | 0 | |
end = end === undefined || end === Infinity ? this.length : end | 0 | |
if (!encoding) encoding = 'utf8' | |
if (start < 0) start = 0 | |
if (end > this.length) end = this.length | |
if (end <= start) return '' | |
while (true) { | |
switch (encoding) { | |
case 'hex': | |
return hexSlice(this, start, end) | |
case 'utf8': | |
case 'utf-8': | |
return utf8Slice(this, start, end) | |
case 'ascii': | |
return asciiSlice(this, start, end) | |
case 'binary': | |
return binarySlice(this, start, end) | |
case 'base64': | |
return base64Slice(this, start, end) | |
case 'ucs2': | |
case 'ucs-2': | |
case 'utf16le': | |
case 'utf-16le': | |
return utf16leSlice(this, start, end) | |
default: | |
if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) | |
encoding = (encoding + '').toLowerCase() | |
loweredCase = true | |
} | |
} | |
} | |
Buffer.prototype.toString = function toString () { | |
var length = this.length | 0 | |
if (length === 0) return '' | |
if (arguments.length === 0) return utf8Slice(this, 0, length) | |
return slowToString.apply(this, arguments) | |
} | |
Buffer.prototype.equals = function equals (b) { | |
if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') | |
if (this === b) return true | |
return Buffer.compare(this, b) === 0 | |
} | |
Buffer.prototype.inspect = function inspect () { | |
var str = '' | |
var max = exports.INSPECT_MAX_BYTES | |
if (this.length > 0) { | |
str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') | |
if (this.length > max) str += ' ... ' | |
} | |
return '<Buffer ' + str + '>' | |
} | |
Buffer.prototype.compare = function compare (b) { | |
if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') | |
if (this === b) return 0 | |
return Buffer.compare(this, b) | |
} | |
Buffer.prototype.indexOf = function indexOf (val, byteOffset) { | |
if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff | |
else if (byteOffset < -0x80000000) byteOffset = -0x80000000 | |
byteOffset >>= 0 | |
if (this.length === 0) return -1 | |
if (byteOffset >= this.length) return -1 | |
// Negative offsets start from the end of the buffer | |
if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0) | |
if (typeof val === 'string') { | |
if (val.length === 0) return -1 // special case: looking for empty string always fails | |
return String.prototype.indexOf.call(this, val, byteOffset) | |
} | |
if (Buffer.isBuffer(val)) { | |
return arrayIndexOf(this, val, byteOffset) | |
} | |
if (typeof val === 'number') { | |
if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') { | |
return Uint8Array.prototype.indexOf.call(this, val, byteOffset) | |
} | |
return arrayIndexOf(this, [ val ], byteOffset) | |
} | |
function arrayIndexOf (arr, val, byteOffset) { | |
var foundIndex = -1 | |
for (var i = 0; byteOffset + i < arr.length; i++) { | |
if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) { | |
if (foundIndex === -1) foundIndex = i | |
if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex | |
} else { | |
foundIndex = -1 | |
} | |
} | |
return -1 | |
} | |
throw new TypeError('val must be string, number or Buffer') | |
} | |
// `get` is deprecated | |
Buffer.prototype.get = function get (offset) { | |
console.log('.get() is deprecated. Access using array indexes instead.') | |
return this.readUInt8(offset) | |
} | |
// `set` is deprecated | |
Buffer.prototype.set = function set (v, offset) { | |
console.log('.set() is deprecated. Access using array indexes instead.') | |
return this.writeUInt8(v, offset) | |
} | |
function hexWrite (buf, string, offset, length) { | |
offset = Number(offset) || 0 | |
var remaining = buf.length - offset | |
if (!length) { | |
length = remaining | |
} else { | |
length = Number(length) | |
if (length > remaining) { | |
length = remaining | |
} | |
} | |
// must be an even number of digits | |
var strLen = string.length | |
if (strLen % 2 !== 0) throw new Error('Invalid hex string') | |
if (length > strLen / 2) { | |
length = strLen / 2 | |
} | |
for (var i = 0; i < length; i++) { | |
var parsed = parseInt(string.substr(i * 2, 2), 16) | |
if (isNaN(parsed)) throw new Error('Invalid hex string') | |
buf[offset + i] = parsed | |
} | |
return i | |
} | |
function utf8Write (buf, string, offset, length) { | |
return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) | |
} | |
function asciiWrite (buf, string, offset, length) { | |
return blitBuffer(asciiToBytes(string), buf, offset, length) | |
} | |
function binaryWrite (buf, string, offset, length) { | |
return asciiWrite(buf, string, offset, length) | |
} | |
function base64Write (buf, string, offset, length) { | |
return blitBuffer(base64ToBytes(string), buf, offset, length) | |
} | |
function ucs2Write (buf, string, offset, length) { | |
return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) | |
} | |
Buffer.prototype.write = function write (string, offset, length, encoding) { | |
// Buffer#write(string) | |
if (offset === undefined) { | |
encoding = 'utf8' | |
length = this.length | |
offset = 0 | |
// Buffer#write(string, encoding) | |
} else if (length === undefined && typeof offset === 'string') { | |
encoding = offset | |
length = this.length | |
offset = 0 | |
// Buffer#write(string, offset[, length][, encoding]) | |
} else if (isFinite(offset)) { | |
offset = offset | 0 | |
if (isFinite(length)) { | |
length = length | 0 | |
if (encoding === undefined) encoding = 'utf8' | |
} else { | |
encoding = length | |
length = undefined | |
} | |
// legacy write(string, encoding, offset, length) - remove in v0.13 | |
} else { | |
var swap = encoding | |
encoding = offset | |
offset = length | 0 | |
length = swap | |
} | |
var remaining = this.length - offset | |
if (length === undefined || length > remaining) length = remaining | |
if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { | |
throw new RangeError('attempt to write outside buffer bounds') | |
} | |
if (!encoding) encoding = 'utf8' | |
var loweredCase = false | |
for (;;) { | |
switch (encoding) { | |
case 'hex': | |
return hexWrite(this, string, offset, length) | |
case 'utf8': | |
case 'utf-8': | |
return utf8Write(this, string, offset, length) | |
case 'ascii': | |
return asciiWrite(this, string, offset, length) | |
case 'binary': | |
return binaryWrite(this, string, offset, length) | |
case 'base64': | |
// Warning: maxLength not taken into account in base64Write | |
return base64Write(this, string, offset, length) | |
case 'ucs2': | |
case 'ucs-2': | |
case 'utf16le': | |
case 'utf-16le': | |
return ucs2Write(this, string, offset, length) | |
default: | |
if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) | |
encoding = ('' + encoding).toLowerCase() | |
loweredCase = true | |
} | |
} | |
} | |
Buffer.prototype.toJSON = function toJSON () { | |
return { | |
type: 'Buffer', | |
data: Array.prototype.slice.call(this._arr || this, 0) | |
} | |
} | |
function base64Slice (buf, start, end) { | |
if (start === 0 && end === buf.length) { | |
return base64.fromByteArray(buf) | |
} else { | |
return base64.fromByteArray(buf.slice(start, end)) | |
} | |
} | |
function utf8Slice (buf, start, end) { | |
end = Math.min(buf.length, end) | |
var res = [] | |
var i = start | |
while (i < end) { | |
var firstByte = buf[i] | |
var codePoint = null | |
var bytesPerSequence = (firstByte > 0xEF) ? 4 | |
: (firstByte > 0xDF) ? 3 | |
: (firstByte > 0xBF) ? 2 | |
: 1 | |
if (i + bytesPerSequence <= end) { | |
var secondByte, thirdByte, fourthByte, tempCodePoint | |
switch (bytesPerSequence) { | |
case 1: | |
if (firstByte < 0x80) { | |
codePoint = firstByte | |
} | |
break | |
case 2: | |
secondByte = buf[i + 1] | |
if ((secondByte & 0xC0) === 0x80) { | |
tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) | |
if (tempCodePoint > 0x7F) { | |
codePoint = tempCodePoint | |
} | |
} | |
break | |
case 3: | |
secondByte = buf[i + 1] | |
thirdByte = buf[i + 2] | |
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { | |
tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) | |
if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { | |
codePoint = tempCodePoint | |
} | |
} | |
break | |
case 4: | |
secondByte = buf[i + 1] | |
thirdByte = buf[i + 2] | |
fourthByte = buf[i + 3] | |
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { | |
tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) | |
if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { | |
codePoint = tempCodePoint | |
} | |
} | |
} | |
} | |
if (codePoint === null) { | |
// we did not generate a valid codePoint so insert a | |
// replacement char (U+FFFD) and advance only 1 byte | |
codePoint = 0xFFFD | |
bytesPerSequence = 1 | |
} else if (codePoint > 0xFFFF) { | |
// encode to utf16 (surrogate pair dance) | |
codePoint -= 0x10000 | |
res.push(codePoint >>> 10 & 0x3FF | 0xD800) | |
codePoint = 0xDC00 | codePoint & 0x3FF | |
} | |
res.push(codePoint) | |
i += bytesPerSequence | |
} | |
return decodeCodePointsArray(res) | |
} | |
// Based on http://stackoverflow.com/a/22747272/680742, the browser with | |
// the lowest limit is Chrome, with 0x10000 args. | |
// We go 1 magnitude less, for safety | |
var MAX_ARGUMENTS_LENGTH = 0x1000 | |
function decodeCodePointsArray (codePoints) { | |
var len = codePoints.length | |
if (len <= MAX_ARGUMENTS_LENGTH) { | |
return String.fromCharCode.apply(String, codePoints) // avoid extra slice() | |
} | |
// Decode in chunks to avoid "call stack size exceeded". | |
var res = '' | |
var i = 0 | |
while (i < len) { | |
res += String.fromCharCode.apply( | |
String, | |
codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) | |
) | |
} | |
return res | |
} | |
function asciiSlice (buf, start, end) { | |
var ret = '' | |
end = Math.min(buf.length, end) | |
for (var i = start; i < end; i++) { | |
ret += String.fromCharCode(buf[i] & 0x7F) | |
} | |
return ret | |
} | |
function binarySlice (buf, start, end) { | |
var ret = '' | |
end = Math.min(buf.length, end) | |
for (var i = start; i < end; i++) { | |
ret += String.fromCharCode(buf[i]) | |
} | |
return ret | |
} | |
function hexSlice (buf, start, end) { | |
var len = buf.length | |
if (!start || start < 0) start = 0 | |
if (!end || end < 0 || end > len) end = len | |
var out = '' | |
for (var i = start; i < end; i++) { | |
out += toHex(buf[i]) | |
} | |
return out | |
} | |
function utf16leSlice (buf, start, end) { | |
var bytes = buf.slice(start, end) | |
var res = '' | |
for (var i = 0; i < bytes.length; i += 2) { | |
res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) | |
} | |
return res | |
} | |
Buffer.prototype.slice = function slice (start, end) { | |
var len = this.length | |
start = ~~start | |
end = end === undefined ? len : ~~end | |
if (start < 0) { | |
start += len | |
if (start < 0) start = 0 | |
} else if (start > len) { | |
start = len | |
} | |
if (end < 0) { | |
end += len | |
if (end < 0) end = 0 | |
} else if (end > len) { | |
end = len | |
} | |
if (end < start) end = start | |
var newBuf | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
newBuf = Buffer._augment(this.subarray(start, end)) | |
} else { | |
var sliceLen = end - start | |
newBuf = new Buffer(sliceLen, undefined) | |
for (var i = 0; i < sliceLen; i++) { | |
newBuf[i] = this[i + start] | |
} | |
} | |
if (newBuf.length) newBuf.parent = this.parent || this | |
return newBuf | |
} | |
/* | |
* Need to make sure that buffer isn't trying to write out of bounds. | |
*/ | |
function checkOffset (offset, ext, length) { | |
if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') | |
if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') | |
} | |
Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { | |
offset = offset | 0 | |
byteLength = byteLength | 0 | |
if (!noAssert) checkOffset(offset, byteLength, this.length) | |
var val = this[offset] | |
var mul = 1 | |
var i = 0 | |
while (++i < byteLength && (mul *= 0x100)) { | |
val += this[offset + i] * mul | |
} | |
return val | |
} | |
Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { | |
offset = offset | 0 | |
byteLength = byteLength | 0 | |
if (!noAssert) { | |
checkOffset(offset, byteLength, this.length) | |
} | |
var val = this[offset + --byteLength] | |
var mul = 1 | |
while (byteLength > 0 && (mul *= 0x100)) { | |
val += this[offset + --byteLength] * mul | |
} | |
return val | |
} | |
Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 1, this.length) | |
return this[offset] | |
} | |
Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 2, this.length) | |
return this[offset] | (this[offset + 1] << 8) | |
} | |
Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 2, this.length) | |
return (this[offset] << 8) | this[offset + 1] | |
} | |
Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 4, this.length) | |
return ((this[offset]) | | |
(this[offset + 1] << 8) | | |
(this[offset + 2] << 16)) + | |
(this[offset + 3] * 0x1000000) | |
} | |
Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 4, this.length) | |
return (this[offset] * 0x1000000) + | |
((this[offset + 1] << 16) | | |
(this[offset + 2] << 8) | | |
this[offset + 3]) | |
} | |
Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { | |
offset = offset | 0 | |
byteLength = byteLength | 0 | |
if (!noAssert) checkOffset(offset, byteLength, this.length) | |
var val = this[offset] | |
var mul = 1 | |
var i = 0 | |
while (++i < byteLength && (mul *= 0x100)) { | |
val += this[offset + i] * mul | |
} | |
mul *= 0x80 | |
if (val >= mul) val -= Math.pow(2, 8 * byteLength) | |
return val | |
} | |
Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { | |
offset = offset | 0 | |
byteLength = byteLength | 0 | |
if (!noAssert) checkOffset(offset, byteLength, this.length) | |
var i = byteLength | |
var mul = 1 | |
var val = this[offset + --i] | |
while (i > 0 && (mul *= 0x100)) { | |
val += this[offset + --i] * mul | |
} | |
mul *= 0x80 | |
if (val >= mul) val -= Math.pow(2, 8 * byteLength) | |
return val | |
} | |
Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 1, this.length) | |
if (!(this[offset] & 0x80)) return (this[offset]) | |
return ((0xff - this[offset] + 1) * -1) | |
} | |
Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 2, this.length) | |
var val = this[offset] | (this[offset + 1] << 8) | |
return (val & 0x8000) ? val | 0xFFFF0000 : val | |
} | |
Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 2, this.length) | |
var val = this[offset + 1] | (this[offset] << 8) | |
return (val & 0x8000) ? val | 0xFFFF0000 : val | |
} | |
Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 4, this.length) | |
return (this[offset]) | | |
(this[offset + 1] << 8) | | |
(this[offset + 2] << 16) | | |
(this[offset + 3] << 24) | |
} | |
Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 4, this.length) | |
return (this[offset] << 24) | | |
(this[offset + 1] << 16) | | |
(this[offset + 2] << 8) | | |
(this[offset + 3]) | |
} | |
Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 4, this.length) | |
return ieee754.read(this, offset, true, 23, 4) | |
} | |
Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 4, this.length) | |
return ieee754.read(this, offset, false, 23, 4) | |
} | |
Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 8, this.length) | |
return ieee754.read(this, offset, true, 52, 8) | |
} | |
Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { | |
if (!noAssert) checkOffset(offset, 8, this.length) | |
return ieee754.read(this, offset, false, 52, 8) | |
} | |
function checkInt (buf, value, offset, ext, max, min) { | |
if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance') | |
if (value > max || value < min) throw new RangeError('value is out of bounds') | |
if (offset + ext > buf.length) throw new RangeError('index out of range') | |
} | |
Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { | |
value = +value | |
offset = offset | 0 | |
byteLength = byteLength | 0 | |
if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) | |
var mul = 1 | |
var i = 0 | |
this[offset] = value & 0xFF | |
while (++i < byteLength && (mul *= 0x100)) { | |
this[offset + i] = (value / mul) & 0xFF | |
} | |
return offset + byteLength | |
} | |
Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { | |
value = +value | |
offset = offset | 0 | |
byteLength = byteLength | 0 | |
if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) | |
var i = byteLength - 1 | |
var mul = 1 | |
this[offset + i] = value & 0xFF | |
while (--i >= 0 && (mul *= 0x100)) { | |
this[offset + i] = (value / mul) & 0xFF | |
} | |
return offset + byteLength | |
} | |
Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) | |
if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) | |
this[offset] = (value & 0xff) | |
return offset + 1 | |
} | |
function objectWriteUInt16 (buf, value, offset, littleEndian) { | |
if (value < 0) value = 0xffff + value + 1 | |
for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) { | |
buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> | |
(littleEndian ? i : 1 - i) * 8 | |
} | |
} | |
Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset] = (value & 0xff) | |
this[offset + 1] = (value >>> 8) | |
} else { | |
objectWriteUInt16(this, value, offset, true) | |
} | |
return offset + 2 | |
} | |
Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset] = (value >>> 8) | |
this[offset + 1] = (value & 0xff) | |
} else { | |
objectWriteUInt16(this, value, offset, false) | |
} | |
return offset + 2 | |
} | |
function objectWriteUInt32 (buf, value, offset, littleEndian) { | |
if (value < 0) value = 0xffffffff + value + 1 | |
for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) { | |
buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff | |
} | |
} | |
Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset + 3] = (value >>> 24) | |
this[offset + 2] = (value >>> 16) | |
this[offset + 1] = (value >>> 8) | |
this[offset] = (value & 0xff) | |
} else { | |
objectWriteUInt32(this, value, offset, true) | |
} | |
return offset + 4 | |
} | |
Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset] = (value >>> 24) | |
this[offset + 1] = (value >>> 16) | |
this[offset + 2] = (value >>> 8) | |
this[offset + 3] = (value & 0xff) | |
} else { | |
objectWriteUInt32(this, value, offset, false) | |
} | |
return offset + 4 | |
} | |
Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) { | |
var limit = Math.pow(2, 8 * byteLength - 1) | |
checkInt(this, value, offset, byteLength, limit - 1, -limit) | |
} | |
var i = 0 | |
var mul = 1 | |
var sub = value < 0 ? 1 : 0 | |
this[offset] = value & 0xFF | |
while (++i < byteLength && (mul *= 0x100)) { | |
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF | |
} | |
return offset + byteLength | |
} | |
Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) { | |
var limit = Math.pow(2, 8 * byteLength - 1) | |
checkInt(this, value, offset, byteLength, limit - 1, -limit) | |
} | |
var i = byteLength - 1 | |
var mul = 1 | |
var sub = value < 0 ? 1 : 0 | |
this[offset + i] = value & 0xFF | |
while (--i >= 0 && (mul *= 0x100)) { | |
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF | |
} | |
return offset + byteLength | |
} | |
Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) | |
if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) | |
if (value < 0) value = 0xff + value + 1 | |
this[offset] = (value & 0xff) | |
return offset + 1 | |
} | |
Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset] = (value & 0xff) | |
this[offset + 1] = (value >>> 8) | |
} else { | |
objectWriteUInt16(this, value, offset, true) | |
} | |
return offset + 2 | |
} | |
Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset] = (value >>> 8) | |
this[offset + 1] = (value & 0xff) | |
} else { | |
objectWriteUInt16(this, value, offset, false) | |
} | |
return offset + 2 | |
} | |
Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset] = (value & 0xff) | |
this[offset + 1] = (value >>> 8) | |
this[offset + 2] = (value >>> 16) | |
this[offset + 3] = (value >>> 24) | |
} else { | |
objectWriteUInt32(this, value, offset, true) | |
} | |
return offset + 4 | |
} | |
Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { | |
value = +value | |
offset = offset | 0 | |
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) | |
if (value < 0) value = 0xffffffff + value + 1 | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
this[offset] = (value >>> 24) | |
this[offset + 1] = (value >>> 16) | |
this[offset + 2] = (value >>> 8) | |
this[offset + 3] = (value & 0xff) | |
} else { | |
objectWriteUInt32(this, value, offset, false) | |
} | |
return offset + 4 | |
} | |
function checkIEEE754 (buf, value, offset, ext, max, min) { | |
if (value > max || value < min) throw new RangeError('value is out of bounds') | |
if (offset + ext > buf.length) throw new RangeError('index out of range') | |
if (offset < 0) throw new RangeError('index out of range') | |
} | |
function writeFloat (buf, value, offset, littleEndian, noAssert) { | |
if (!noAssert) { | |
checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) | |
} | |
ieee754.write(buf, value, offset, littleEndian, 23, 4) | |
return offset + 4 | |
} | |
Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { | |
return writeFloat(this, value, offset, true, noAssert) | |
} | |
Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { | |
return writeFloat(this, value, offset, false, noAssert) | |
} | |
function writeDouble (buf, value, offset, littleEndian, noAssert) { | |
if (!noAssert) { | |
checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) | |
} | |
ieee754.write(buf, value, offset, littleEndian, 52, 8) | |
return offset + 8 | |
} | |
Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { | |
return writeDouble(this, value, offset, true, noAssert) | |
} | |
Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { | |
return writeDouble(this, value, offset, false, noAssert) | |
} | |
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) | |
Buffer.prototype.copy = function copy (target, targetStart, start, end) { | |
if (!start) start = 0 | |
if (!end && end !== 0) end = this.length | |
if (targetStart >= target.length) targetStart = target.length | |
if (!targetStart) targetStart = 0 | |
if (end > 0 && end < start) end = start | |
// Copy 0 bytes; we're done | |
if (end === start) return 0 | |
if (target.length === 0 || this.length === 0) return 0 | |
// Fatal error conditions | |
if (targetStart < 0) { | |
throw new RangeError('targetStart out of bounds') | |
} | |
if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') | |
if (end < 0) throw new RangeError('sourceEnd out of bounds') | |
// Are we oob? | |
if (end > this.length) end = this.length | |
if (target.length - targetStart < end - start) { | |
end = target.length - targetStart + start | |
} | |
var len = end - start | |
var i | |
if (this === target && start < targetStart && targetStart < end) { | |
// descending copy from end | |
for (i = len - 1; i >= 0; i--) { | |
target[i + targetStart] = this[i + start] | |
} | |
} else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { | |
// ascending copy from start | |
for (i = 0; i < len; i++) { | |
target[i + targetStart] = this[i + start] | |
} | |
} else { | |
target._set(this.subarray(start, start + len), targetStart) | |
} | |
return len | |
} | |
// fill(value, start=0, end=buffer.length) | |
Buffer.prototype.fill = function fill (value, start, end) { | |
if (!value) value = 0 | |
if (!start) start = 0 | |
if (!end) end = this.length | |
if (end < start) throw new RangeError('end < start') | |
// Fill 0 bytes; we're done | |
if (end === start) return | |
if (this.length === 0) return | |
if (start < 0 || start >= this.length) throw new RangeError('start out of bounds') | |
if (end < 0 || end > this.length) throw new RangeError('end out of bounds') | |
var i | |
if (typeof value === 'number') { | |
for (i = start; i < end; i++) { | |
this[i] = value | |
} | |
} else { | |
var bytes = utf8ToBytes(value.toString()) | |
var len = bytes.length | |
for (i = start; i < end; i++) { | |
this[i] = bytes[i % len] | |
} | |
} | |
return this | |
} | |
/** | |
* Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance. | |
* Added in Node 0.12. Only available in browsers that support ArrayBuffer. | |
*/ | |
Buffer.prototype.toArrayBuffer = function toArrayBuffer () { | |
if (typeof Uint8Array !== 'undefined') { | |
if (Buffer.TYPED_ARRAY_SUPPORT) { | |
return (new Buffer(this)).buffer | |
} else { | |
var buf = new Uint8Array(this.length) | |
for (var i = 0, len = buf.length; i < len; i += 1) { | |
buf[i] = this[i] | |
} | |
return buf.buffer | |
} | |
} else { | |
throw new TypeError('Buffer.toArrayBuffer not supported in this browser') | |
} | |
} | |
// HELPER FUNCTIONS | |
// ================ | |
var BP = Buffer.prototype | |
/** | |
* Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods | |
*/ | |
Buffer._augment = function _augment (arr) { | |
arr.constructor = Buffer | |
arr._isBuffer = true | |
// save reference to original Uint8Array set method before overwriting | |
arr._set = arr.set | |
// deprecated | |
arr.get = BP.get | |
arr.set = BP.set | |
arr.write = BP.write | |
arr.toString = BP.toString | |
arr.toLocaleString = BP.toString | |
arr.toJSON = BP.toJSON | |
arr.equals = BP.equals | |
arr.compare = BP.compare | |
arr.indexOf = BP.indexOf | |
arr.copy = BP.copy | |
arr.slice = BP.slice | |
arr.readUIntLE = BP.readUIntLE | |
arr.readUIntBE = BP.readUIntBE | |
arr.readUInt8 = BP.readUInt8 | |
arr.readUInt16LE = BP.readUInt16LE | |
arr.readUInt16BE = BP.readUInt16BE | |
arr.readUInt32LE = BP.readUInt32LE | |
arr.readUInt32BE = BP.readUInt32BE | |
arr.readIntLE = BP.readIntLE | |
arr.readIntBE = BP.readIntBE | |
arr.readInt8 = BP.readInt8 | |
arr.readInt16LE = BP.readInt16LE | |
arr.readInt16BE = BP.readInt16BE | |
arr.readInt32LE = BP.readInt32LE | |
arr.readInt32BE = BP.readInt32BE | |
arr.readFloatLE = BP.readFloatLE | |
arr.readFloatBE = BP.readFloatBE | |
arr.readDoubleLE = BP.readDoubleLE | |
arr.readDoubleBE = BP.readDoubleBE | |
arr.writeUInt8 = BP.writeUInt8 | |
arr.writeUIntLE = BP.writeUIntLE | |
arr.writeUIntBE = BP.writeUIntBE | |
arr.writeUInt16LE = BP.writeUInt16LE | |
arr.writeUInt16BE = BP.writeUInt16BE | |
arr.writeUInt32LE = BP.writeUInt32LE | |
arr.writeUInt32BE = BP.writeUInt32BE | |
arr.writeIntLE = BP.writeIntLE | |
arr.writeIntBE = BP.writeIntBE | |
arr.writeInt8 = BP.writeInt8 | |
arr.writeInt16LE = BP.writeInt16LE | |
arr.writeInt16BE = BP.writeInt16BE | |
arr.writeInt32LE = BP.writeInt32LE | |
arr.writeInt32BE = BP.writeInt32BE | |
arr.writeFloatLE = BP.writeFloatLE | |
arr.writeFloatBE = BP.writeFloatBE | |
arr.writeDoubleLE = BP.writeDoubleLE | |
arr.writeDoubleBE = BP.writeDoubleBE | |
arr.fill = BP.fill | |
arr.inspect = BP.inspect | |
arr.toArrayBuffer = BP.toArrayBuffer | |
return arr | |
} | |
var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g | |
function base64clean (str) { | |
// Node strips out invalid characters like \n and \t from the string, base64-js does not | |
str = stringtrim(str).replace(INVALID_BASE64_RE, '') | |
// Node converts strings with length < 2 to '' | |
if (str.length < 2) return '' | |
// Node allows for non-padded base64 strings (missing trailing ===), base64-js does not | |
while (str.length % 4 !== 0) { | |
str = str + '=' | |
} | |
return str | |
} | |
function stringtrim (str) { | |
if (str.trim) return str.trim() | |
return str.replace(/^\s+|\s+$/g, '') | |
} | |
function toHex (n) { | |
if (n < 16) return '0' + n.toString(16) | |
return n.toString(16) | |
} | |
function utf8ToBytes (string, units) { | |
units = units || Infinity | |
var codePoint | |
var length = string.length | |
var leadSurrogate = null | |
var bytes = [] | |
for (var i = 0; i < length; i++) { | |
codePoint = string.charCodeAt(i) | |
// is surrogate component | |
if (codePoint > 0xD7FF && codePoint < 0xE000) { | |
// last char was a lead | |
if (!leadSurrogate) { | |
// no lead yet | |
if (codePoint > 0xDBFF) { | |
// unexpected trail | |
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) | |
continue | |
} else if (i + 1 === length) { | |
// unpaired lead | |
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) | |
continue | |
} | |
// valid lead | |
leadSurrogate = codePoint | |
continue | |
} | |
// 2 leads in a row | |
if (codePoint < 0xDC00) { | |
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) | |
leadSurrogate = codePoint | |
continue | |
} | |
// valid surrogate pair | |
codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 | |
} else if (leadSurrogate) { | |
// valid bmp char, but last char was a lead | |
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) | |
} | |
leadSurrogate = null | |
// encode utf8 | |
if (codePoint < 0x80) { | |
if ((units -= 1) < 0) break | |
bytes.push(codePoint) | |
} else if (codePoint < 0x800) { | |
if ((units -= 2) < 0) break | |
bytes.push( | |
codePoint >> 0x6 | 0xC0, | |
codePoint & 0x3F | 0x80 | |
) | |
} else if (codePoint < 0x10000) { | |
if ((units -= 3) < 0) break | |
bytes.push( | |
codePoint >> 0xC | 0xE0, | |
codePoint >> 0x6 & 0x3F | 0x80, | |
codePoint & 0x3F | 0x80 | |
) | |
} else if (codePoint < 0x110000) { | |
if ((units -= 4) < 0) break | |
bytes.push( | |
codePoint >> 0x12 | 0xF0, | |
codePoint >> 0xC & 0x3F | 0x80, | |
codePoint >> 0x6 & 0x3F | 0x80, | |
codePoint & 0x3F | 0x80 | |
) | |
} else { | |
throw new Error('Invalid code point') | |
} | |
} | |
return bytes | |
} | |
function asciiToBytes (str) { | |
var byteArray = [] | |
for (var i = 0; i < str.length; i++) { | |
// Node's code seems to be doing this and not & 0x7F.. | |