Skip to content

Instantly share code, notes, and snippets.

@graue
Created July 25, 2014 18:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save graue/6ed6230a616bd920a674 to your computer and use it in GitHub Desktop.
Save graue/6ed6230a616bd920a674 to your computer and use it in GitHub Desktop.
Gentest bundle for browsers
(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){
window.gentest = require('./index');
},{"./index":2}],2:[function(require,module,exports){
exports.run = require('./lib/run');
exports.sample = require('./lib/sample');
exports.types = require('./lib/types');
var errors = require('./lib/errors');
exports.FailureError = errors.FailureError;
exports.GentestError = errors.GentestError;
},{"./lib/errors":3,"./lib/run":4,"./lib/sample":5,"./lib/types":6}],3:[function(require,module,exports){
// Remove library code from the provided stack trace.
// This is a bit voodoo since the precise contents of the stack trace
// string vary by browser vendor.
//
// Example: We want to keep the first line and every line starting from
// "at Context.<anonymous>" (note that it's in a different project),
// but elide lines 2-6 in between.
//
// Error: property (anonymous function) failed to hold
// at FailureError.Error (<anonymous>)
// at FailureError.GentestError (/home/sf/code/immutable/node_modules/gentest/lib/errors.js:22:41)
// at new FailureError (/home/sf/code/immutable/node_modules/gentest/lib/errors.js:32:38)
// at _run (/home/sf/code/immutable/node_modules/gentest/lib/run.js:59:15)
// at Object.run (/home/sf/code/immutable/node_modules/gentest/lib/run.js:37:10)
// at Context.<anonymous> (/home/sf/code/immutable/test/index.js:44:20)
// [... more lines not shown ...]
//
// TODO: Test to make sure this does reasonable things in browsers
// as well as Node.
//
function cleanupStack(str, errorName) {
if (typeof str !== 'string') return str;
var isLibraryCode = function(line) {
return line.match(/\/gentest\//) ||
line.match(/at( new)? (\w+)Error/);
};
var lines = str.split(/\n/);
var i = 1;
while (i < lines.length && isLibraryCode(lines[i])) {
i++;
}
return [lines[0]].concat(lines.slice(i)).join('\n');
}
var ErrorSubclass = function ErrorSubclass() {};
ErrorSubclass.prototype = Error.prototype;
var GentestError = function GentestError() {
if (!this instanceof GentestError) {
throw new TypeError('GentestError must be called via new');
}
var tmp = Error.prototype.constructor.apply(this, arguments);
if (tmp.stack) {
this.stack = cleanupStack(tmp.stack).replace(/^Error/, 'GentestError');
}
if (tmp.message) {
this.message = tmp.message;
}
this.name = 'GentestError';
return this;
};
GentestError.prototype = new ErrorSubclass();
GentestError.prototype.constructor = GentestError;
var FailureError = function FailureError() {
GentestError.prototype.constructor.apply(this, arguments);
if (this.stack) {
this.stack = this.stack.replace(/^GentestError/, 'FailureError');
}
this.name = 'FailureError';
};
FailureError.prototype = new GentestError();
FailureError.prototype.constructor = FailureError;
exports.GentestError = GentestError;
exports.FailureError = FailureError;
},{}],4:[function(require,module,exports){
var PRNG = require('burtleprng');
var errors = require('./errors');
// TODO: add a maxSize parameter somehow.
// Returns true if all tests passed.
function run(func, numTests, seed) {
// Mess with arguments. Varargs are generators,
// and numTests and seed are optional so may also be
// generators.
// (However, numTests must be provided if seed is.)
var generators = [].slice.call(arguments, 3);
var defaultSeed = Date.now();
if (typeof seed === 'function') {
generators.unshift(seed);
seed = defaultSeed;
} else if (typeof seed === 'undefined') {
seed = defaultSeed;
} else if (typeof seed !== 'number') {
throw new TypeError('seed must be a number');
}
seed &= 0xffffffff;
var DEFAULT_NUM_TESTS = 100;
if (typeof numTests === 'function') {
generators.unshift(numTests);
numTests = DEFAULT_NUM_TESTS;
} else if (typeof numTests === 'undefined') {
// This suggests your tests use no generators at all,
// which seems an unlikely case, but whatever.
numTests = DEFAULT_NUM_TESTS;
} else if (typeof numTests !== 'number' || numTests < 1) {
throw new TypeError('numTests must be a positive number');
}
numTests >>>= 0;
return _run(func, numTests, seed, generators);
}
function _run(func, numTests, seed, gens) {
var prng = new PRNG(seed);
for (var x = 0; x < numTests; x++) {
var size = Math.floor(x/2) + 1;
var values = gens.map(function(gen) {
return gen(prng, size);
});
if (!func.apply(null, values)) {
var msg = 'property ' + (func.name ? func.name + ' ' : '') +
'violated';
var e = new errors.FailureError(msg);
e.testCase = values;
e.property = func.name;
throw e;
}
}
return true;
}
module.exports = run;
},{"./errors":3,"burtleprng":7}],5:[function(require,module,exports){
var PRNG = require('burtleprng');
var DEFAULT_COUNT = 10;
// TODO: should this have a size parameter? Should gentest.run be modified
// to use this routine instead of doing its own sampling?
function sample(gen, count) {
if (arguments.length < 2) {
count = DEFAULT_COUNT;
}
var rng = new PRNG(Date.now() & 0xffffffff);
var results = new Array(count);
for (var i = 0; i < count; i++) {
results[i] = gen(rng, Math.floor(i/2) + 1);
}
return results;
}
module.exports = sample;
},{"burtleprng":7}],6:[function(require,module,exports){
var errors = require('./errors');
// Using the given PRNG, picks an int from low to high, inclusive.
function choose(prng, low, high) {
return Math.floor(prng.float() * (high - low + 1) + low);
}
var t = {};
t.number = function(rng, size) {
return rng.float() * size*2 - size;
};
t.number.nonNegative = function(rng, size) {
return rng.float() * size;
};
t.suchThat = function(pred, gen, maxTries) {
if (arguments.length < 3) maxTries = 10;
return function(rng, size) {
var triesLeft = maxTries;
var val;
do {
val = gen(rng, size);
if (pred(val)) {
return val;
}
} while(--triesLeft > 0);
throw new errors.GentestError('suchThat: could not find a suitable value');
};
};
function isNonzero(x) {
return x !== 0;
}
t.number.nonZero = t.suchThat(isNonzero, t.number);
t.number.positive = t.suchThat(isNonzero, t.number.nonNegative);
t.int = function(rng, size) {
return choose(rng, -size, size);
};
t.int.nonNegative = function(rng, size) {
return choose(rng, 0, size);
};
t.int.nonZero = t.suchThat(isNonzero, t.int);
t.int.positive = function(rng, size) {
return choose(rng, 1, size + 1);
};
// FIXME: This should eventually generate non-ASCII characters, I guess.
t.char = function(rng, _) {
return String.fromCharCode(choose(rng, 32, 126));
};
t.arrayOf = function(elemGen) {
return function(rng, size) {
var len = t.int.nonNegative(rng, size);
var array = new Array(len);
for (var i = 0; i < len; i++) {
array[i] = elemGen(rng, size);
}
return array;
};
};
t.fmap = function(fun, gen) {
return function(rng, size) {
return fun(gen(rng, size));
};
};
t.string = t.fmap(function(chars) {
return chars.join('');
}, t.arrayOf(t.char));
function constantly(x) {
return function(_, _) {
return x;
};
}
t.oneOf = function(gens) {
return function(rng, size) {
var which = choose(rng, 0, gens.length-1);
return gens[which](rng, size);
};
};
t.elements = function(elems) {
return t.oneOf(elems.map(constantly));
};
t.bool = t.elements([false, true]);
t.shape = function(obj) {
return function(rng, size) {
var out = {};
Object.keys(obj).forEach(function(key) {
out[key] = obj[key](rng, size);
});
return out;
};
};
module.exports = t;
},{"./errors":3}],7:[function(require,module,exports){
function BurtlePRNG(seed) {
seed >>>= 0;
var ctx = this.ctx = new Array(4);
ctx[0] = 0xf1ea5eed;
ctx[1] = ctx[2] = ctx[3] = seed;
for (var i = 0; i < 20; i++) {
this.next();
}
return this;
}
function rot(x, k) {
return (x << k) | (x >> (32-k));
}
BurtlePRNG.prototype.next = function() {
var ctx = this.ctx;
var e = (ctx[0] - rot(ctx[1], 27))>>>0;
ctx[0] = (ctx[1] ^ rot(ctx[2], 17))>>>0;
ctx[1] = (ctx[2] + ctx[3])>>>0;
ctx[2] = (ctx[3] + e)>>>0;
ctx[3] = (e + ctx[0])>>>0;
return ctx[3];
};
BurtlePRNG.prototype['float'] = function() {
return this.next() / 4294967296.0;
};
if (typeof module === 'object') {
module.exports = BurtlePRNG;
}
},{}]},{},[1])
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9ob21lL3NmLy5udm0vdjAuMTAuMjgvbGliL25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCIvaG9tZS9zZi9jb2RlL2dlbnRlc3QvYnJvd3Nlci5qcyIsIi9ob21lL3NmL2NvZGUvZ2VudGVzdC9pbmRleC5qcyIsIi9ob21lL3NmL2NvZGUvZ2VudGVzdC9saWIvZXJyb3JzLmpzIiwiL2hvbWUvc2YvY29kZS9nZW50ZXN0L2xpYi9ydW4uanMiLCIvaG9tZS9zZi9jb2RlL2dlbnRlc3QvbGliL3NhbXBsZS5qcyIsIi9ob21lL3NmL2NvZGUvZ2VudGVzdC9saWIvdHlwZXMuanMiLCIvaG9tZS9zZi9jb2RlL2dlbnRlc3Qvbm9kZV9tb2R1bGVzL2J1cnRsZXBybmcvQnVydGxlUFJORy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7O0FDREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwid2luZG93LmdlbnRlc3QgPSByZXF1aXJlKCcuL2luZGV4Jyk7XG4iLCJleHBvcnRzLnJ1biA9IHJlcXVpcmUoJy4vbGliL3J1bicpO1xuZXhwb3J0cy5zYW1wbGUgPSByZXF1aXJlKCcuL2xpYi9zYW1wbGUnKTtcbmV4cG9ydHMudHlwZXMgPSByZXF1aXJlKCcuL2xpYi90eXBlcycpO1xuXG52YXIgZXJyb3JzID0gcmVxdWlyZSgnLi9saWIvZXJyb3JzJyk7XG5leHBvcnRzLkZhaWx1cmVFcnJvciA9IGVycm9ycy5GYWlsdXJlRXJyb3I7XG5leHBvcnRzLkdlbnRlc3RFcnJvciA9IGVycm9ycy5HZW50ZXN0RXJyb3I7XG4iLCIvLyBSZW1vdmUgbGlicmFyeSBjb2RlIGZyb20gdGhlIHByb3ZpZGVkIHN0YWNrIHRyYWNlLlxuLy8gVGhpcyBpcyBhIGJpdCB2b29kb28gc2luY2UgdGhlIHByZWNpc2UgY29udGVudHMgb2YgdGhlIHN0YWNrIHRyYWNlXG4vLyBzdHJpbmcgdmFyeSBieSBicm93c2VyIHZlbmRvci5cbi8vXG4vLyBFeGFtcGxlOiBXZSB3YW50IHRvIGtlZXAgdGhlIGZpcnN0IGxpbmUgYW5kIGV2ZXJ5IGxpbmUgc3RhcnRpbmcgZnJvbVxuLy8gXCJhdCBDb250ZXh0Ljxhbm9ueW1vdXM+XCIgKG5vdGUgdGhhdCBpdCdzIGluIGEgZGlmZmVyZW50IHByb2plY3QpLFxuLy8gYnV0IGVsaWRlIGxpbmVzIDItNiBpbiBiZXR3ZWVuLlxuLy9cbi8vIEVycm9yOiBwcm9wZXJ0eSAoYW5vbnltb3VzIGZ1bmN0aW9uKSBmYWlsZWQgdG8gaG9sZFxuLy8gICAgIGF0IEZhaWx1cmVFcnJvci5FcnJvciAoPGFub255bW91cz4pXG4vLyAgICAgYXQgRmFpbHVyZUVycm9yLkdlbnRlc3RFcnJvciAoL2hvbWUvc2YvY29kZS9pbW11dGFibGUvbm9kZV9tb2R1bGVzL2dlbnRlc3QvbGliL2Vycm9ycy5qczoyMjo0MSlcbi8vICAgICBhdCBuZXcgRmFpbHVyZUVycm9yICgvaG9tZS9zZi9jb2RlL2ltbXV0YWJsZS9ub2RlX21vZHVsZXMvZ2VudGVzdC9saWIvZXJyb3JzLmpzOjMyOjM4KVxuLy8gICAgIGF0IF9ydW4gKC9ob21lL3NmL2NvZGUvaW1tdXRhYmxlL25vZGVfbW9kdWxlcy9nZW50ZXN0L2xpYi9ydW4uanM6NTk6MTUpXG4vLyAgICAgYXQgT2JqZWN0LnJ1biAoL2hvbWUvc2YvY29kZS9pbW11dGFibGUvbm9kZV9tb2R1bGVzL2dlbnRlc3QvbGliL3J1bi5qczozNzoxMClcbi8vICAgICBhdCBDb250ZXh0Ljxhbm9ueW1vdXM+ICgvaG9tZS9zZi9jb2RlL2ltbXV0YWJsZS90ZXN0L2luZGV4LmpzOjQ0OjIwKVxuLy8gICAgIFsuLi4gbW9yZSBsaW5lcyBub3Qgc2hvd24gLi4uXVxuLy9cbi8vIFRPRE86IFRlc3QgdG8gbWFrZSBzdXJlIHRoaXMgZG9lcyByZWFzb25hYmxlIHRoaW5ncyBpbiBicm93c2Vyc1xuLy8gYXMgd2VsbCBhcyBOb2RlLlxuLy9cbmZ1bmN0aW9uIGNsZWFudXBTdGFjayhzdHIsIGVycm9yTmFtZSkge1xuICBpZiAodHlwZW9mIHN0ciAhPT0gJ3N0cmluZycpIHJldHVybiBzdHI7XG5cbiAgdmFyIGlzTGlicmFyeUNvZGUgPSBmdW5jdGlvbihsaW5lKSB7XG4gICAgcmV0dXJuIGxpbmUubWF0Y2goL1xcL2dlbnRlc3RcXC8vKSB8fFxuICAgICAgICAgICBsaW5lLm1hdGNoKC9hdCggbmV3KT8gKFxcdyspRXJyb3IvKTtcbiAgfTtcblxuICB2YXIgbGluZXMgPSBzdHIuc3BsaXQoL1xcbi8pO1xuICB2YXIgaSA9IDE7XG4gIHdoaWxlIChpIDwgbGluZXMubGVuZ3RoICYmIGlzTGlicmFyeUNvZGUobGluZXNbaV0pKSB7XG4gICAgaSsrO1xuICB9XG4gIHJldHVybiBbbGluZXNbMF1dLmNvbmNhdChsaW5lcy5zbGljZShpKSkuam9pbignXFxuJyk7XG59XG5cbnZhciBFcnJvclN1YmNsYXNzID0gZnVuY3Rpb24gRXJyb3JTdWJjbGFzcygpIHt9O1xuRXJyb3JTdWJjbGFzcy5wcm90b3R5cGUgPSBFcnJvci5wcm90b3R5cGU7XG5cbnZhciBHZW50ZXN0RXJyb3IgPSBmdW5jdGlvbiBHZW50ZXN0RXJyb3IoKSB7XG4gIGlmICghdGhpcyBpbnN0YW5jZW9mIEdlbnRlc3RFcnJvcikge1xuICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0dlbnRlc3RFcnJvciBtdXN0IGJlIGNhbGxlZCB2aWEgbmV3Jyk7XG4gIH1cbiAgdmFyIHRtcCA9IEVycm9yLnByb3RvdHlwZS5jb25zdHJ1Y3Rvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICBpZiAodG1wLnN0YWNrKSB7XG4gICAgdGhpcy5zdGFjayA9IGNsZWFudXBTdGFjayh0bXAuc3RhY2spLnJlcGxhY2UoL15FcnJvci8sICdHZW50ZXN0RXJyb3InKTtcbiAgfVxuICBpZiAodG1wLm1lc3NhZ2UpIHtcbiAgICB0aGlzLm1lc3NhZ2UgPSB0bXAubWVzc2FnZTtcbiAgfVxuICB0aGlzLm5hbWUgPSAnR2VudGVzdEVycm9yJztcbiAgcmV0dXJuIHRoaXM7XG59O1xuR2VudGVzdEVycm9yLnByb3RvdHlwZSA9IG5ldyBFcnJvclN1YmNsYXNzKCk7XG5HZW50ZXN0RXJyb3IucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gR2VudGVzdEVycm9yO1xuXG52YXIgRmFpbHVyZUVycm9yID0gZnVuY3Rpb24gRmFpbHVyZUVycm9yKCkge1xuICBHZW50ZXN0RXJyb3IucHJvdG90eXBlLmNvbnN0cnVjdG9yLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gIGlmICh0aGlzLnN0YWNrKSB7XG4gICAgdGhpcy5zdGFjayA9IHRoaXMuc3RhY2sucmVwbGFjZSgvXkdlbnRlc3RFcnJvci8sICdGYWlsdXJlRXJyb3InKTtcbiAgfVxuICB0aGlzLm5hbWUgPSAnRmFpbHVyZUVycm9yJztcbn07XG5GYWlsdXJlRXJyb3IucHJvdG90eXBlID0gbmV3IEdlbnRlc3RFcnJvcigpO1xuRmFpbHVyZUVycm9yLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IEZhaWx1cmVFcnJvcjtcblxuZXhwb3J0cy5HZW50ZXN0RXJyb3IgPSBHZW50ZXN0RXJyb3I7XG5leHBvcnRzLkZhaWx1cmVFcnJvciA9IEZhaWx1cmVFcnJvcjtcbiIsInZhciBQUk5HID0gcmVxdWlyZSgnYnVydGxlcHJuZycpO1xudmFyIGVycm9ycyA9IHJlcXVpcmUoJy4vZXJyb3JzJyk7XG5cbi8vIFRPRE86IGFkZCBhIG1heFNpemUgcGFyYW1ldGVyIHNvbWVob3cuXG4vLyBSZXR1cm5zIHRydWUgaWYgYWxsIHRlc3RzIHBhc3NlZC5cbmZ1bmN0aW9uIHJ1bihmdW5jLCBudW1UZXN0cywgc2VlZCkge1xuICAvLyBNZXNzIHdpdGggYXJndW1lbnRzLiBWYXJhcmdzIGFyZSBnZW5lcmF0b3JzLFxuICAvLyBhbmQgbnVtVGVzdHMgYW5kIHNlZWQgYXJlIG9wdGlvbmFsIHNvIG1heSBhbHNvIGJlXG4gIC8vIGdlbmVyYXRvcnMuXG4gIC8vIChIb3dldmVyLCBudW1UZXN0cyBtdXN0IGJlIHByb3ZpZGVkIGlmIHNlZWQgaXMuKVxuICB2YXIgZ2VuZXJhdG9ycyA9IFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAzKTtcblxuICB2YXIgZGVmYXVsdFNlZWQgPSBEYXRlLm5vdygpO1xuICBpZiAodHlwZW9mIHNlZWQgPT09ICdmdW5jdGlvbicpIHtcbiAgICBnZW5lcmF0b3JzLnVuc2hpZnQoc2VlZCk7XG4gICAgc2VlZCA9IGRlZmF1bHRTZWVkO1xuICB9IGVsc2UgaWYgKHR5cGVvZiBzZWVkID09PSAndW5kZWZpbmVkJykge1xuICAgIHNlZWQgPSBkZWZhdWx0U2VlZDtcbiAgfSBlbHNlIGlmICh0eXBlb2Ygc2VlZCAhPT0gJ251bWJlcicpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdzZWVkIG11c3QgYmUgYSBudW1iZXInKTtcbiAgfVxuICBzZWVkICY9IDB4ZmZmZmZmZmY7XG5cbiAgdmFyIERFRkFVTFRfTlVNX1RFU1RTID0gMTAwO1xuICBpZiAodHlwZW9mIG51bVRlc3RzID09PSAnZnVuY3Rpb24nKSB7XG4gICAgZ2VuZXJhdG9ycy51bnNoaWZ0KG51bVRlc3RzKTtcbiAgICBudW1UZXN0cyA9IERFRkFVTFRfTlVNX1RFU1RTO1xuICB9IGVsc2UgaWYgKHR5cGVvZiBudW1UZXN0cyA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAvLyBUaGlzIHN1Z2dlc3RzIHlvdXIgdGVzdHMgdXNlIG5vIGdlbmVyYXRvcnMgYXQgYWxsLFxuICAgIC8vIHdoaWNoIHNlZW1zIGFuIHVubGlrZWx5IGNhc2UsIGJ1dCB3aGF0ZXZlci5cbiAgICBudW1UZXN0cyA9IERFRkFVTFRfTlVNX1RFU1RTO1xuICB9IGVsc2UgaWYgKHR5cGVvZiBudW1UZXN0cyAhPT0gJ251bWJlcicgfHwgbnVtVGVzdHMgPCAxKSB7XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcignbnVtVGVzdHMgbXVzdCBiZSBhIHBvc2l0aXZlIG51bWJlcicpO1xuICB9XG4gIG51bVRlc3RzID4+Pj0gMDtcblxuICByZXR1cm4gX3J1bihmdW5jLCBudW1UZXN0cywgc2VlZCwgZ2VuZXJhdG9ycyk7XG59XG5cbmZ1bmN0aW9uIF9ydW4oZnVuYywgbnVtVGVzdHMsIHNlZWQsIGdlbnMpIHtcbiAgdmFyIHBybmcgPSBuZXcgUFJORyhzZWVkKTtcblxuICBmb3IgKHZhciB4ID0gMDsgeCA8IG51bVRlc3RzOyB4KyspIHtcbiAgICB2YXIgc2l6ZSA9IE1hdGguZmxvb3IoeC8yKSArIDE7XG4gICAgdmFyIHZhbHVlcyA9IGdlbnMubWFwKGZ1bmN0aW9uKGdlbikge1xuICAgICAgcmV0dXJuIGdlbihwcm5nLCBzaXplKTtcbiAgICB9KTtcbiAgICBpZiAoIWZ1bmMuYXBwbHkobnVsbCwgdmFsdWVzKSkge1xuICAgICAgdmFyIG1zZyA9ICdwcm9wZXJ0eSAnICsgKGZ1bmMubmFtZSA/IGZ1bmMubmFtZSArICcgJyA6ICcnKSArXG4gICAgICAgICAgICAgICAgJ3Zpb2xhdGVkJztcbiAgICAgIHZhciBlID0gbmV3IGVycm9ycy5GYWlsdXJlRXJyb3IobXNnKTtcbiAgICAgIGUudGVzdENhc2UgPSB2YWx1ZXM7XG4gICAgICBlLnByb3BlcnR5ID0gZnVuYy5uYW1lO1xuICAgICAgdGhyb3cgZTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBydW47XG4iLCJ2YXIgUFJORyA9IHJlcXVpcmUoJ2J1cnRsZXBybmcnKTtcblxudmFyIERFRkFVTFRfQ09VTlQgPSAxMDtcblxuLy8gVE9ETzogc2hvdWxkIHRoaXMgaGF2ZSBhIHNpemUgcGFyYW1ldGVyPyBTaG91bGQgZ2VudGVzdC5ydW4gYmUgbW9kaWZpZWRcbi8vIHRvIHVzZSB0aGlzIHJvdXRpbmUgaW5zdGVhZCBvZiBkb2luZyBpdHMgb3duIHNhbXBsaW5nP1xuZnVuY3Rpb24gc2FtcGxlKGdlbiwgY291bnQpIHtcbiAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPCAyKSB7XG4gICAgY291bnQgPSBERUZBVUxUX0NPVU5UO1xuICB9XG5cbiAgdmFyIHJuZyA9IG5ldyBQUk5HKERhdGUubm93KCkgJiAweGZmZmZmZmZmKTtcbiAgdmFyIHJlc3VsdHMgPSBuZXcgQXJyYXkoY291bnQpO1xuICBmb3IgKHZhciBpID0gMDsgaSA8IGNvdW50OyBpKyspIHtcbiAgICByZXN1bHRzW2ldID0gZ2VuKHJuZywgTWF0aC5mbG9vcihpLzIpICsgMSk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdHM7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gc2FtcGxlO1xuIiwidmFyIGVycm9ycyA9IHJlcXVpcmUoJy4vZXJyb3JzJyk7XG5cbi8vIFVzaW5nIHRoZSBnaXZlbiBQUk5HLCBwaWNrcyBhbiBpbnQgZnJvbSBsb3cgdG8gaGlnaCwgaW5jbHVzaXZlLlxuZnVuY3Rpb24gY2hvb3NlKHBybmcsIGxvdywgaGlnaCkge1xuICByZXR1cm4gTWF0aC5mbG9vcihwcm5nLmZsb2F0KCkgKiAoaGlnaCAtIGxvdyArIDEpICsgbG93KTtcbn1cblxudmFyIHQgPSB7fTtcblxudC5udW1iZXIgPSBmdW5jdGlvbihybmcsIHNpemUpIHtcbiAgcmV0dXJuIHJuZy5mbG9hdCgpICogc2l6ZSoyIC0gc2l6ZTtcbn07XG5cbnQubnVtYmVyLm5vbk5lZ2F0aXZlID0gZnVuY3Rpb24ocm5nLCBzaXplKSB7XG4gIHJldHVybiBybmcuZmxvYXQoKSAqIHNpemU7XG59O1xuXG50LnN1Y2hUaGF0ID0gZnVuY3Rpb24ocHJlZCwgZ2VuLCBtYXhUcmllcykge1xuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA8IDMpIG1heFRyaWVzID0gMTA7XG5cbiAgcmV0dXJuIGZ1bmN0aW9uKHJuZywgc2l6ZSkge1xuICAgIHZhciB0cmllc0xlZnQgPSBtYXhUcmllcztcbiAgICB2YXIgdmFsO1xuICAgIGRvIHtcbiAgICAgIHZhbCA9IGdlbihybmcsIHNpemUpO1xuICAgICAgaWYgKHByZWQodmFsKSkge1xuICAgICAgICByZXR1cm4gdmFsO1xuICAgICAgfVxuICAgIH0gd2hpbGUoLS10cmllc0xlZnQgPiAwKTtcbiAgICB0aHJvdyBuZXcgZXJyb3JzLkdlbnRlc3RFcnJvcignc3VjaFRoYXQ6IGNvdWxkIG5vdCBmaW5kIGEgc3VpdGFibGUgdmFsdWUnKTtcbiAgfTtcbn07XG5cbmZ1bmN0aW9uIGlzTm9uemVybyh4KSB7XG4gIHJldHVybiB4ICE9PSAwO1xufVxuXG50Lm51bWJlci5ub25aZXJvID0gdC5zdWNoVGhhdChpc05vbnplcm8sIHQubnVtYmVyKTtcbnQubnVtYmVyLnBvc2l0aXZlID0gdC5zdWNoVGhhdChpc05vbnplcm8sIHQubnVtYmVyLm5vbk5lZ2F0aXZlKTtcblxudC5pbnQgPSBmdW5jdGlvbihybmcsIHNpemUpIHtcbiAgcmV0dXJuIGNob29zZShybmcsIC1zaXplLCBzaXplKTtcbn07XG5cbnQuaW50Lm5vbk5lZ2F0aXZlID0gZnVuY3Rpb24ocm5nLCBzaXplKSB7XG4gIHJldHVybiBjaG9vc2Uocm5nLCAwLCBzaXplKTtcbn07XG5cbnQuaW50Lm5vblplcm8gPSB0LnN1Y2hUaGF0KGlzTm9uemVybywgdC5pbnQpO1xuXG50LmludC5wb3NpdGl2ZSA9IGZ1bmN0aW9uKHJuZywgc2l6ZSkge1xuICByZXR1cm4gY2hvb3NlKHJuZywgMSwgc2l6ZSArIDEpO1xufTtcblxuLy8gRklYTUU6IFRoaXMgc2hvdWxkIGV2ZW50dWFsbHkgZ2VuZXJhdGUgbm9uLUFTQ0lJIGNoYXJhY3RlcnMsIEkgZ3Vlc3MuXG50LmNoYXIgPSBmdW5jdGlvbihybmcsIF8pIHtcbiAgcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUoY2hvb3NlKHJuZywgMzIsIDEyNikpO1xufTtcblxudC5hcnJheU9mID0gZnVuY3Rpb24oZWxlbUdlbikge1xuICByZXR1cm4gZnVuY3Rpb24ocm5nLCBzaXplKSB7XG4gICAgdmFyIGxlbiA9IHQuaW50Lm5vbk5lZ2F0aXZlKHJuZywgc2l6ZSk7XG4gICAgdmFyIGFycmF5ID0gbmV3IEFycmF5KGxlbik7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW47IGkrKykge1xuICAgICAgYXJyYXlbaV0gPSBlbGVtR2VuKHJuZywgc2l6ZSk7XG4gICAgfVxuICAgIHJldHVybiBhcnJheTtcbiAgfTtcbn07XG5cbnQuZm1hcCA9IGZ1bmN0aW9uKGZ1biwgZ2VuKSB7XG4gIHJldHVybiBmdW5jdGlvbihybmcsIHNpemUpIHtcbiAgICByZXR1cm4gZnVuKGdlbihybmcsIHNpemUpKTtcbiAgfTtcbn07XG5cbnQuc3RyaW5nID0gdC5mbWFwKGZ1bmN0aW9uKGNoYXJzKSB7XG4gIHJldHVybiBjaGFycy5qb2luKCcnKTtcbn0sIHQuYXJyYXlPZih0LmNoYXIpKTtcblxuZnVuY3Rpb24gY29uc3RhbnRseSh4KSB7XG4gIHJldHVybiBmdW5jdGlvbihfLCBfKSB7XG4gICAgcmV0dXJuIHg7XG4gIH07XG59XG5cbnQub25lT2YgPSBmdW5jdGlvbihnZW5zKSB7XG4gIHJldHVybiBmdW5jdGlvbihybmcsIHNpemUpIHtcbiAgICB2YXIgd2hpY2ggPSBjaG9vc2Uocm5nLCAwLCBnZW5zLmxlbmd0aC0xKTtcbiAgICByZXR1cm4gZ2Vuc1t3aGljaF0ocm5nLCBzaXplKTtcbiAgfTtcbn07XG5cbnQuZWxlbWVudHMgPSBmdW5jdGlvbihlbGVtcykge1xuICByZXR1cm4gdC5vbmVPZihlbGVtcy5tYXAoY29uc3RhbnRseSkpO1xufTtcblxudC5ib29sID0gdC5lbGVtZW50cyhbZmFsc2UsIHRydWVdKTtcblxudC5zaGFwZSA9IGZ1bmN0aW9uKG9iaikge1xuICByZXR1cm4gZnVuY3Rpb24ocm5nLCBzaXplKSB7XG4gICAgdmFyIG91dCA9IHt9O1xuICAgIE9iamVjdC5rZXlzKG9iaikuZm9yRWFjaChmdW5jdGlvbihrZXkpIHtcbiAgICAgIG91dFtrZXldID0gb2JqW2tleV0ocm5nLCBzaXplKTtcbiAgICB9KTtcbiAgICByZXR1cm4gb3V0O1xuICB9O1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSB0O1xuIiwiZnVuY3Rpb24gQnVydGxlUFJORyhzZWVkKSB7XG4gIHNlZWQgPj4+PSAwO1xuICB2YXIgY3R4ID0gdGhpcy5jdHggPSBuZXcgQXJyYXkoNCk7XG4gIGN0eFswXSA9IDB4ZjFlYTVlZWQ7XG4gIGN0eFsxXSA9IGN0eFsyXSA9IGN0eFszXSA9IHNlZWQ7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgMjA7IGkrKykge1xuICAgIHRoaXMubmV4dCgpO1xuICB9XG4gIHJldHVybiB0aGlzO1xufVxuXG5mdW5jdGlvbiByb3QoeCwgaykge1xuICByZXR1cm4gKHggPDwgaykgfCAoeCA+PiAoMzItaykpO1xufVxuXG5CdXJ0bGVQUk5HLnByb3RvdHlwZS5uZXh0ID0gZnVuY3Rpb24oKSB7XG4gIHZhciBjdHggPSB0aGlzLmN0eDtcbiAgdmFyIGUgPSAgICAgICAgICAgKGN0eFswXSAtIHJvdChjdHhbMV0sIDI3KSk+Pj4wO1xuICBjdHhbMF0gPSAoY3R4WzFdIF4gcm90KGN0eFsyXSwgMTcpKT4+PjA7XG4gIGN0eFsxXSA9IChjdHhbMl0gKyBjdHhbM10pPj4+MDtcbiAgY3R4WzJdID0gKGN0eFszXSArIGUpPj4+MDtcbiAgY3R4WzNdID0gKGUgICAgICArIGN0eFswXSk+Pj4wO1xuICByZXR1cm4gY3R4WzNdO1xufTtcblxuQnVydGxlUFJORy5wcm90b3R5cGVbJ2Zsb2F0J10gPSBmdW5jdGlvbigpIHtcbiAgcmV0dXJuIHRoaXMubmV4dCgpIC8gNDI5NDk2NzI5Ni4wO1xufTtcblxuaWYgKHR5cGVvZiBtb2R1bGUgPT09ICdvYmplY3QnKSB7XG4gIG1vZHVsZS5leHBvcnRzID0gQnVydGxlUFJORztcbn1cbiJdfQ==
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment