eff
Version:
An extensible effect monad based on the freer monad
131 lines (102 loc) • 17.6 kB
JavaScript
;
var _ava = _interopRequireDefault(require("ava"));
var _jsverify = _interopRequireDefault(require("jsverify"));
var _ramda = require("ramda");
var _eff = require("./eff");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Note: JSVerify does not appear to have a way to generate arbitrary arbitraries;
// this means that each arbitrary in JSVerify has to be of a certain type.
// For all of the tests below we are using arbitrary *numbers*, with the number
// type being chosen pseudo-randomly. There's no logic within the Eff core
// that treats the types of values differently, so this *shouldn't* have any
// significance. Of course, as soon as an edge case is found, we will have
// to revisit this approach.
// -----------------------------------------------------------------------------
// Setoid laws
// -----------------------------------------------------------------------------
(0, _ava.default)("Reflexivity (Pure)", function (t) {
// equals a a ≡ true
_jsverify.default.assert(_jsverify.default.forall("number", function (a) {
return (0, _eff.equals)((0, _eff.pure)(a))((0, _eff.pure)(a)) === true;
}));
t.pass();
});
(0, _ava.default)("Reflexivity (Impure)", function (t) {
// equals a a ≡ true
_jsverify.default.assert(_jsverify.default.forall("json", function (effect) {
return (0, _eff.equals)((0, _eff.send)(effect))((0, _eff.send)(effect)) === true;
}));
t.pass();
});
(0, _ava.default)("Symmetry (Pure)", function (t) {
// equals a b ≡ equals b a
_jsverify.default.assert(_jsverify.default.forall("number", "number", function (a, b) {
return (0, _eff.equals)((0, _eff.pure)(a))((0, _eff.pure)(b)) === (0, _eff.equals)((0, _eff.pure)(b))((0, _eff.pure)(a));
}));
t.pass();
});
(0, _ava.default)("Symmetry (Impure)", function (t) {
// equals a b ≡ equals b a
_jsverify.default.assert(_jsverify.default.forall("json", "json", function (a, b) {
return (0, _eff.equals)((0, _eff.send)(a))((0, _eff.send)(b)) === (0, _eff.equals)((0, _eff.send)(b))((0, _eff.send)(a));
}));
t.pass();
}); // TODO: should pass in the abritrary data with the constraint, rather than including the constraint in the test
(0, _ava.default)("Transitivity (Pure)", function (t) {
// if equals a b == true and equals b c == true, then equals a c == true
_jsverify.default.assert(_jsverify.default.forall("number", "number", "number", function (a, b, c) {
return (0, _eff.equals)((0, _eff.pure)(a))((0, _eff.pure)(b)) && (0, _eff.equals)((0, _eff.pure)(b))((0, _eff.pure)(c)) ? (0, _eff.equals)((0, _eff.pure)(a))((0, _eff.pure)(b)) : true;
}));
t.pass();
});
(0, _ava.default)("Transitivity (Impure)", function (t) {
// if equals a b == true and equals b c == true, then equals a c == true
_jsverify.default.assert(_jsverify.default.forall("json", "json", "json", function (a, b, c) {
return (0, _eff.equals)((0, _eff.send)(a))((0, _eff.send)(b)) && (0, _eff.equals)((0, _eff.send)(b))((0, _eff.send)(c)) ? (0, _eff.equals)((0, _eff.send)(a))((0, _eff.send)(b)) : true;
}));
t.pass();
}); // -----------------------------------------------------------------------------
// Functor Laws (https://wiki.haskell.org/Functor, https://github.com/fantasyland/fantasy-land#functor)
// -----------------------------------------------------------------------------
_ava.default.todo("Identity (map)"); // u.map(a => a) is equivalent to u
_ava.default.todo("Composition (map)"); // u.map(x => f(g(x))) is equivalent to u.map(g).map(f)
// -----------------------------------------------------------------------------
// Apply Laws (https://github.com/fantasyland/fantasy-land#apply)
// -----------------------------------------------------------------------------
_ava.default.todo("Composition (ap)"); // v.ap(u.ap(a.map(f => g => x => f(g(x))))) is equivalent to v.ap(u).ap(a)
// -----------------------------------------------------------------------------
// Applicative Laws (https://github.com/fantasyland/fantasy-land#applicative)
// -----------------------------------------------------------------------------
_ava.default.todo("Identity (ap)"); // v.ap(A.of(x => x)) is equivalent to v
_ava.default.todo("Homomorphism"); // A.of(x).ap(A.of(f)) is equivalent to A.of(f(x))
_ava.default.todo("Interchange"); // A.of(y).ap(u) is equivalent to u.ap(A.of(f => f(y)))
// -----------------------------------------------------------------------------
// Monad Laws (https://wiki.haskell.org/Monad_laws, https://github.com/fantasyland/fantasy-land#monad, https://github.com/fantasyland/fantasy-land#chain)
// -----------------------------------------------------------------------------
(0, _ava.default)("Left Identity", function (t) {
// return a >>= f ≡ f a
_jsverify.default.assert(_jsverify.default.forall("number", "number -> number", function (a, f) {
var f2 = (0, _ramda.pipe)(f, _eff.pure);
return (0, _eff.equals)((0, _eff.chain)(f2)((0, _eff.pure)(a)))(f2(a));
}));
t.pass();
});
(0, _ava.default)("Right Identity", function (t) {
// return m >>= return ≡ m
_jsverify.default.assert(_jsverify.default.forall("number", function (a) {
return (0, _eff.equals)((0, _eff.chain)(_eff.pure)((0, _eff.pure)(a)))((0, _eff.pure)(a));
}));
t.pass();
});
(0, _ava.default)("Associativity", function (t) {
// (m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)
_jsverify.default.assert(_jsverify.default.forall("number", "number -> number", "number -> number", function (a, f, g) {
var f2 = (0, _ramda.pipe)(f, _eff.pure);
var g2 = (0, _ramda.pipe)(g, _eff.pure);
return (0, _eff.equals)((0, _eff.chain)(g2)((0, _eff.chain)(f2)((0, _eff.pure)(a))))((0, _eff.chain)(function (x) {
return (0, _eff.chain)(g2)(f2(x));
})((0, _eff.pure)(a)));
}));
t.pass();
});
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NvdXJjZXMvZWZmLnRlc3QuanMiXSwibmFtZXMiOlsidCIsImpzdmVyaWZ5IiwiYXNzZXJ0IiwiZm9yYWxsIiwiYSIsInBhc3MiLCJlZmZlY3QiLCJiIiwiYyIsInRlc3QiLCJ0b2RvIiwiZiIsImYyIiwicHVyZSIsImciLCJnMiIsIngiXSwibWFwcGluZ3MiOiI7O0FBRUE7O0FBQ0E7O0FBQ0E7O0FBRUE7Ozs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBLGtCQUFLLG9CQUFMLEVBQTJCLFVBQUFBLENBQUMsRUFBSTtBQUMvQjtBQUVBQyxvQkFBU0MsTUFBVCxDQUNDRCxrQkFBU0UsTUFBVCxDQUFnQixRQUFoQixFQUEwQixVQUFBQyxDQUFDO0FBQUEsV0FBSSxpQkFBTyxlQUFLQSxDQUFMLENBQVAsRUFBZ0IsZUFBS0EsQ0FBTCxDQUFoQixNQUE2QixJQUFqQztBQUFBLEdBQTNCLENBREQ7O0FBR0FKLEVBQUFBLENBQUMsQ0FBQ0ssSUFBRjtBQUNBLENBUEQ7QUFTQSxrQkFBSyxzQkFBTCxFQUE2QixVQUFBTCxDQUFDLEVBQUk7QUFDakM7QUFFQUMsb0JBQVNDLE1BQVQsQ0FDQ0Qsa0JBQVNFLE1BQVQsQ0FDQyxNQURELEVBRUMsVUFBQUcsTUFBTTtBQUFBLFdBQUksaUJBQU8sZUFBS0EsTUFBTCxDQUFQLEVBQXFCLGVBQUtBLE1BQUwsQ0FBckIsTUFBdUMsSUFBM0M7QUFBQSxHQUZQLENBREQ7O0FBTUFOLEVBQUFBLENBQUMsQ0FBQ0ssSUFBRjtBQUNBLENBVkQ7QUFZQSxrQkFBSyxpQkFBTCxFQUF3QixVQUFBTCxDQUFDLEVBQUk7QUFDNUI7QUFFQUMsb0JBQVNDLE1BQVQsQ0FDQ0Qsa0JBQVNFLE1BQVQsQ0FDQyxRQURELEVBRUMsUUFGRCxFQUdDLFVBQUNDLENBQUQsRUFBSUcsQ0FBSjtBQUFBLFdBQVUsaUJBQU8sZUFBS0gsQ0FBTCxDQUFQLEVBQWdCLGVBQUtHLENBQUwsQ0FBaEIsTUFBNkIsaUJBQU8sZUFBS0EsQ0FBTCxDQUFQLEVBQWdCLGVBQUtILENBQUwsQ0FBaEIsQ0FBdkM7QUFBQSxHQUhELENBREQ7O0FBT0FKLEVBQUFBLENBQUMsQ0FBQ0ssSUFBRjtBQUNBLENBWEQ7QUFhQSxrQkFBSyxtQkFBTCxFQUEwQixVQUFBTCxDQUFDLEVBQUk7QUFDOUI7QUFFQUMsb0JBQVNDLE1BQVQsQ0FDQ0Qsa0JBQVNFLE1BQVQsQ0FDQyxNQURELEVBRUMsTUFGRCxFQUdDLFVBQUNDLENBQUQsRUFBSUcsQ0FBSjtBQUFBLFdBQVUsaUJBQU8sZUFBS0gsQ0FBTCxDQUFQLEVBQWdCLGVBQUtHLENBQUwsQ0FBaEIsTUFBNkIsaUJBQU8sZUFBS0EsQ0FBTCxDQUFQLEVBQWdCLGVBQUtILENBQUwsQ0FBaEIsQ0FBdkM7QUFBQSxHQUhELENBREQ7O0FBT0FKLEVBQUFBLENBQUMsQ0FBQ0ssSUFBRjtBQUNBLENBWEQsRSxDQWFBOztBQUNBLGtCQUFLLHFCQUFMLEVBQTRCLFVBQUFMLENBQUMsRUFBSTtBQUNoQztBQUVBQyxvQkFBU0MsTUFBVCxDQUNDRCxrQkFBU0UsTUFBVCxDQUFnQixRQUFoQixFQUEwQixRQUExQixFQUFvQyxRQUFwQyxFQUE4QyxVQUFDQyxDQUFELEVBQUlHLENBQUosRUFBT0MsQ0FBUDtBQUFBLFdBQzdDLGlCQUFPLGVBQUtKLENBQUwsQ0FBUCxFQUFnQixlQUFLRyxDQUFMLENBQWhCLEtBQTRCLGlCQUFPLGVBQUtBLENBQUwsQ0FBUCxFQUFnQixlQUFLQyxDQUFMLENBQWhCLENBQTVCLEdBQ0csaUJBQU8sZUFBS0osQ0FBTCxDQUFQLEVBQWdCLGVBQUtHLENBQUwsQ0FBaEIsQ0FESCxHQUVHLElBSDBDO0FBQUEsR0FBOUMsQ0FERDs7QUFPQVAsRUFBQUEsQ0FBQyxDQUFDSyxJQUFGO0FBQ0EsQ0FYRDtBQWFBLGtCQUFLLHVCQUFMLEVBQThCLFVBQUFMLENBQUMsRUFBSTtBQUNsQztBQUVBQyxvQkFBU0MsTUFBVCxDQUNDRCxrQkFBU0UsTUFBVCxDQUFnQixNQUFoQixFQUF3QixNQUF4QixFQUFnQyxNQUFoQyxFQUF3QyxVQUFDQyxDQUFELEVBQUlHLENBQUosRUFBT0MsQ0FBUDtBQUFBLFdBQ3ZDLGlCQUFPLGVBQUtKLENBQUwsQ0FBUCxFQUFnQixlQUFLRyxDQUFMLENBQWhCLEtBQTRCLGlCQUFPLGVBQUtBLENBQUwsQ0FBUCxFQUFnQixlQUFLQyxDQUFMLENBQWhCLENBQTVCLEdBQ0csaUJBQU8sZUFBS0osQ0FBTCxDQUFQLEVBQWdCLGVBQUtHLENBQUwsQ0FBaEIsQ0FESCxHQUVHLElBSG9DO0FBQUEsR0FBeEMsQ0FERDs7QUFPQVAsRUFBQUEsQ0FBQyxDQUFDSyxJQUFGO0FBQ0EsQ0FYRCxFLENBYUE7QUFDQTtBQUNBOztBQUVBSSxhQUFLQyxJQUFMLENBQVUsZ0JBQVYsRSxDQUE2Qjs7O0FBRTdCRCxhQUFLQyxJQUFMLENBQVUsbUJBQVYsRSxDQUFnQztBQUVoQztBQUNBO0FBQ0E7OztBQUVBRCxhQUFLQyxJQUFMLENBQVUsa0JBQVYsRSxDQUErQjtBQUUvQjtBQUNBO0FBQ0E7OztBQUVBRCxhQUFLQyxJQUFMLENBQVUsZUFBVixFLENBQTRCOzs7QUFFNUJELGFBQUtDLElBQUwsQ0FBVSxjQUFWLEUsQ0FBMkI7OztBQUUzQkQsYUFBS0MsSUFBTCxDQUFVLGFBQVYsRSxDQUEwQjtBQUUxQjtBQUNBO0FBQ0E7OztBQUVBLGtCQUFLLGVBQUwsRUFBc0IsVUFBQVYsQ0FBQyxFQUFJO0FBQzFCO0FBRUFDLG9CQUFTQyxNQUFULENBQ0NELGtCQUFTRSxNQUFULENBQWdCLFFBQWhCLEVBQTBCLGtCQUExQixFQUE4QyxVQUFDQyxDQUFELEVBQUlPLENBQUosRUFBVTtBQUN2RCxRQUFNQyxFQUFFLEdBQUcsaUJBQ1ZELENBRFUsRUFFVkUsU0FGVSxDQUFYO0FBS0EsV0FBTyxpQkFBTyxnQkFBTUQsRUFBTixFQUFVLGVBQUtSLENBQUwsQ0FBVixDQUFQLEVBQTJCUSxFQUFFLENBQUNSLENBQUQsQ0FBN0IsQ0FBUDtBQUNBLEdBUEQsQ0FERDs7QUFVQUosRUFBQUEsQ0FBQyxDQUFDSyxJQUFGO0FBQ0EsQ0FkRDtBQWdCQSxrQkFBSyxnQkFBTCxFQUF1QixVQUFBTCxDQUFDLEVBQUk7QUFDM0I7QUFFQUMsb0JBQVNDLE1BQVQsQ0FDQ0Qsa0JBQVNFLE1BQVQsQ0FBZ0IsUUFBaEIsRUFBMEIsVUFBQUMsQ0FBQztBQUFBLFdBQUksaUJBQU8sZ0JBQU1TLFNBQU4sRUFBWSxlQUFLVCxDQUFMLENBQVosQ0FBUCxFQUE2QixlQUFLQSxDQUFMLENBQTdCLENBQUo7QUFBQSxHQUEzQixDQUREOztBQUdBSixFQUFBQSxDQUFDLENBQUNLLElBQUY7QUFDQSxDQVBEO0FBU0Esa0JBQUssZUFBTCxFQUFzQixVQUFBTCxDQUFDLEVBQUk7QUFDMUI7QUFFQUMsb0JBQVNDLE1BQVQsQ0FDQ0Qsa0JBQVNFLE1BQVQsQ0FDQyxRQURELEVBRUMsa0JBRkQsRUFHQyxrQkFIRCxFQUlDLFVBQUNDLENBQUQsRUFBSU8sQ0FBSixFQUFPRyxDQUFQLEVBQWE7QUFDWixRQUFNRixFQUFFLEdBQUcsaUJBQ1ZELENBRFUsRUFFVkUsU0FGVSxDQUFYO0FBS0EsUUFBTUUsRUFBRSxHQUFHLGlCQUNWRCxDQURVLEVBRVZELFNBRlUsQ0FBWDtBQUtBLFdBQU8saUJBQU8sZ0JBQU1FLEVBQU4sRUFBVSxnQkFBTUgsRUFBTixFQUFVLGVBQUtSLENBQUwsQ0FBVixDQUFWLENBQVAsRUFDTixnQkFBTSxVQUFBWSxDQUFDO0FBQUEsYUFBSSxnQkFBTUQsRUFBTixFQUFVSCxFQUFFLENBQUNJLENBQUQsQ0FBWixDQUFKO0FBQUEsS0FBUCxFQUE2QixlQUFLWixDQUFMLENBQTdCLENBRE0sQ0FBUDtBQUdBLEdBbEJGLENBREQ7O0FBc0JBSixFQUFBQSxDQUFDLENBQUNLLElBQUY7QUFDQSxDQTFCRCIsInNvdXJjZXNDb250ZW50IjpbIi8qIEBmbG93ICovXG5cbmltcG9ydCB0ZXN0IGZyb20gXCJhdmFcIjtcbmltcG9ydCBqc3ZlcmlmeSBmcm9tIFwianN2ZXJpZnlcIjtcbmltcG9ydCB7IHBpcGUgfSBmcm9tIFwicmFtZGFcIjtcblxuaW1wb3J0IHsgY2hhaW4sIGVxdWFscywgcHVyZSwgc2VuZCB9IGZyb20gXCIuL2VmZlwiO1xuXG4vLyBOb3RlOiBKU1ZlcmlmeSBkb2VzIG5vdCBhcHBlYXIgdG8gaGF2ZSBhIHdheSB0byBnZW5lcmF0ZSBhcmJpdHJhcnkgYXJiaXRyYXJpZXM7XG4vLyAgICAgICB0aGlzIG1lYW5zIHRoYXQgZWFjaCBhcmJpdHJhcnkgaW4gSlNWZXJpZnkgaGFzIHRvIGJlIG9mIGEgY2VydGFpbiB0eXBlLlxuLy8gICAgICAgRm9yIGFsbCBvZiB0aGUgdGVzdHMgYmVsb3cgd2UgYXJlIHVzaW5nIGFyYml0cmFyeSAqbnVtYmVycyosIHdpdGggdGhlIG51bWJlclxuLy8gICAgICAgdHlwZSBiZWluZyBjaG9zZW4gcHNldWRvLXJhbmRvbWx5LiBUaGVyZSdzIG5vIGxvZ2ljIHdpdGhpbiB0aGUgRWZmIGNvcmVcbi8vICAgICAgIHRoYXQgdHJlYXRzIHRoZSB0eXBlcyBvZiB2YWx1ZXMgZGlmZmVyZW50bHksIHNvIHRoaXMgKnNob3VsZG4ndCogaGF2ZSBhbnlcbi8vICAgICAgIHNpZ25pZmljYW5jZS4gT2YgY291cnNlLCBhcyBzb29uIGFzIGFuIGVkZ2UgY2FzZSBpcyBmb3VuZCwgd2Ugd2lsbCBoYXZlXG4vLyAgICAgICB0byByZXZpc2l0IHRoaXMgYXBwcm9hY2guXG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBTZXRvaWQgbGF3c1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxudGVzdChcIlJlZmxleGl2aXR5IChQdXJlKVwiLCB0ID0+IHtcblx0Ly8gZXF1YWxzIGEgYSDiiaEgdHJ1ZVxuXG5cdGpzdmVyaWZ5LmFzc2VydChcblx0XHRqc3ZlcmlmeS5mb3JhbGwoXCJudW1iZXJcIiwgYSA9PiBlcXVhbHMocHVyZShhKSkocHVyZShhKSkgPT09IHRydWUpLFxuXHQpO1xuXHR0LnBhc3MoKTtcbn0pO1xuXG50ZXN0KFwiUmVmbGV4aXZpdHkgKEltcHVyZSlcIiwgdCA9PiB7XG5cdC8vIGVxdWFscyBhIGEg4omhIHRydWVcblxuXHRqc3ZlcmlmeS5hc3NlcnQoXG5cdFx0anN2ZXJpZnkuZm9yYWxsKFxuXHRcdFx0XCJqc29uXCIsXG5cdFx0XHRlZmZlY3QgPT4gZXF1YWxzKHNlbmQoZWZmZWN0KSkoc2VuZChlZmZlY3QpKSA9PT0gdHJ1ZSxcblx0XHQpLFxuXHQpO1xuXHR0LnBhc3MoKTtcbn0pO1xuXG50ZXN0KFwiU3ltbWV0cnkgKFB1cmUpXCIsIHQgPT4ge1xuXHQvLyBlcXVhbHMgYSBiIOKJoSBlcXVhbHMgYiBhXG5cblx0anN2ZXJpZnkuYXNzZXJ0KFxuXHRcdGpzdmVyaWZ5LmZvcmFsbChcblx0XHRcdFwibnVtYmVyXCIsXG5cdFx0XHRcIm51bWJlclwiLFxuXHRcdFx0KGEsIGIpID0+IGVxdWFscyhwdXJlKGEpKShwdXJlKGIpKSA9PT0gZXF1YWxzKHB1cmUoYikpKHB1cmUoYSkpLFxuXHRcdCksXG5cdCk7XG5cdHQucGFzcygpO1xufSk7XG5cbnRlc3QoXCJTeW1tZXRyeSAoSW1wdXJlKVwiLCB0ID0+IHtcblx0Ly8gZXF1YWxzIGEgYiDiiaEgZXF1YWxzIGIgYVxuXG5cdGpzdmVyaWZ5LmFzc2VydChcblx0XHRqc3ZlcmlmeS5mb3JhbGwoXG5cdFx0XHRcImpzb25cIixcblx0XHRcdFwianNvblwiLFxuXHRcdFx0KGEsIGIpID0+IGVxdWFscyhzZW5kKGEpKShzZW5kKGIpKSA9PT0gZXF1YWxzKHNlbmQoYikpKHNlbmQoYSkpLFxuXHRcdCksXG5cdCk7XG5cdHQucGFzcygpO1xufSk7XG5cbi8vIFRPRE86IHNob3VsZCBwYXNzIGluIHRoZSBhYnJpdHJhcnkgZGF0YSB3aXRoIHRoZSBjb25zdHJhaW50LCByYXRoZXIgdGhhbiBpbmNsdWRpbmcgdGhlIGNvbnN0cmFpbnQgaW4gdGhlIHRlc3RcbnRlc3QoXCJUcmFuc2l0aXZpdHkgKFB1cmUpXCIsIHQgPT4ge1xuXHQvLyBpZiBlcXVhbHMgYSBiID09IHRydWUgYW5kIGVxdWFscyBiIGMgPT0gdHJ1ZSwgdGhlbiBlcXVhbHMgYSBjID09IHRydWVcblxuXHRqc3ZlcmlmeS5hc3NlcnQoXG5cdFx0anN2ZXJpZnkuZm9yYWxsKFwibnVtYmVyXCIsIFwibnVtYmVyXCIsIFwibnVtYmVyXCIsIChhLCBiLCBjKSA9PlxuXHRcdFx0ZXF1YWxzKHB1cmUoYSkpKHB1cmUoYikpICYmIGVxdWFscyhwdXJlKGIpKShwdXJlKGMpKVxuXHRcdFx0XHQ/IGVxdWFscyhwdXJlKGEpKShwdXJlKGIpKVxuXHRcdFx0XHQ6IHRydWUsXG5cdFx0KSxcblx0KTtcblx0dC5wYXNzKCk7XG59KTtcblxudGVzdChcIlRyYW5zaXRpdml0eSAoSW1wdXJlKVwiLCB0ID0+IHtcblx0Ly8gaWYgZXF1YWxzIGEgYiA9PSB0cnVlIGFuZCBlcXVhbHMgYiBjID09IHRydWUsIHRoZW4gZXF1YWxzIGEgYyA9PSB0cnVlXG5cblx0anN2ZXJpZnkuYXNzZXJ0KFxuXHRcdGpzdmVyaWZ5LmZvcmFsbChcImpzb25cIiwgXCJqc29uXCIsIFwianNvblwiLCAoYSwgYiwgYykgPT5cblx0XHRcdGVxdWFscyhzZW5kKGEpKShzZW5kKGIpKSAmJiBlcXVhbHMoc2VuZChiKSkoc2VuZChjKSlcblx0XHRcdFx0PyBlcXVhbHMoc2VuZChhKSkoc2VuZChiKSlcblx0XHRcdFx0OiB0cnVlLFxuXHRcdCksXG5cdCk7XG5cdHQucGFzcygpO1xufSk7XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBGdW5jdG9yIExhd3MgKGh0dHBzOi8vd2lraS5oYXNrZWxsLm9yZy9GdW5jdG9yLCBodHRwczovL2dpdGh1Yi5jb20vZmFudGFzeWxhbmQvZmFudGFzeS1sYW5kI2Z1bmN0b3IpXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG50ZXN0LnRvZG8oXCJJZGVudGl0eSAobWFwKVwiKTsgLy8gdS5tYXAoYSA9PiBhKSBpcyBlcXVpdmFsZW50IHRvIHVcblxudGVzdC50b2RvKFwiQ29tcG9zaXRpb24gKG1hcClcIik7IC8vIHUubWFwKHggPT4gZihnKHgpKSkgaXMgZXF1aXZhbGVudCB0byB1Lm1hcChnKS5tYXAoZilcblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIEFwcGx5IExhd3MgKGh0dHBzOi8vZ2l0aHViLmNvbS9mYW50YXN5bGFuZC9mYW50YXN5LWxhbmQjYXBwbHkpXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG50ZXN0LnRvZG8oXCJDb21wb3NpdGlvbiAoYXApXCIpOyAvLyB2LmFwKHUuYXAoYS5tYXAoZiA9PiBnID0+IHggPT4gZihnKHgpKSkpKSBpcyBlcXVpdmFsZW50IHRvIHYuYXAodSkuYXAoYSlcblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIEFwcGxpY2F0aXZlIExhd3MgKGh0dHBzOi8vZ2l0aHViLmNvbS9mYW50YXN5bGFuZC9mYW50YXN5LWxhbmQjYXBwbGljYXRpdmUpXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG50ZXN0LnRvZG8oXCJJZGVudGl0eSAoYXApXCIpOyAvLyB2LmFwKEEub2YoeCA9PiB4KSkgaXMgZXF1aXZhbGVudCB0byB2XG5cbnRlc3QudG9kbyhcIkhvbW9tb3JwaGlzbVwiKTsgLy8gQS5vZih4KS5hcChBLm9mKGYpKSBpcyBlcXVpdmFsZW50IHRvIEEub2YoZih4KSlcblxudGVzdC50b2RvKFwiSW50ZXJjaGFuZ2VcIik7IC8vIEEub2YoeSkuYXAodSkgaXMgZXF1aXZhbGVudCB0byB1LmFwKEEub2YoZiA9PiBmKHkpKSlcblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIE1vbmFkIExhd3MgKGh0dHBzOi8vd2lraS5oYXNrZWxsLm9yZy9Nb25hZF9sYXdzLCBodHRwczovL2dpdGh1Yi5jb20vZmFudGFzeWxhbmQvZmFudGFzeS1sYW5kI21vbmFkLCBodHRwczovL2dpdGh1Yi5jb20vZmFudGFzeWxhbmQvZmFudGFzeS1sYW5kI2NoYWluKVxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxudGVzdChcIkxlZnQgSWRlbnRpdHlcIiwgdCA9PiB7XG5cdC8vIHJldHVybiBhID4+PSBmIOKJoSBmIGFcblxuXHRqc3ZlcmlmeS5hc3NlcnQoXG5cdFx0anN2ZXJpZnkuZm9yYWxsKFwibnVtYmVyXCIsIFwibnVtYmVyIC0+IG51bWJlclwiLCAoYSwgZikgPT4ge1xuXHRcdFx0Y29uc3QgZjIgPSBwaXBlKFxuXHRcdFx0XHRmLFxuXHRcdFx0XHRwdXJlLFxuXHRcdFx0KTtcblxuXHRcdFx0cmV0dXJuIGVxdWFscyhjaGFpbihmMikocHVyZShhKSkpKGYyKGEpKTtcblx0XHR9KSxcblx0KTtcblx0dC5wYXNzKCk7XG59KTtcblxudGVzdChcIlJpZ2h0IElkZW50aXR5XCIsIHQgPT4ge1xuXHQvLyByZXR1cm4gbSA+Pj0gcmV0dXJuIOKJoSBtXG5cblx0anN2ZXJpZnkuYXNzZXJ0KFxuXHRcdGpzdmVyaWZ5LmZvcmFsbChcIm51bWJlclwiLCBhID0+IGVxdWFscyhjaGFpbihwdXJlKShwdXJlKGEpKSkocHVyZShhKSkpLFxuXHQpO1xuXHR0LnBhc3MoKTtcbn0pO1xuXG50ZXN0KFwiQXNzb2NpYXRpdml0eVwiLCB0ID0+IHtcblx0Ly8gKG0gPj49IGYpID4+PSBnIOKJoSBtID4+PSAoXFx4IC0+IGYgeCA+Pj0gZylcblxuXHRqc3ZlcmlmeS5hc3NlcnQoXG5cdFx0anN2ZXJpZnkuZm9yYWxsKFxuXHRcdFx0XCJudW1iZXJcIixcblx0XHRcdFwibnVtYmVyIC0+IG51bWJlclwiLFxuXHRcdFx0XCJudW1iZXIgLT4gbnVtYmVyXCIsXG5cdFx0XHQoYSwgZiwgZykgPT4ge1xuXHRcdFx0XHRjb25zdCBmMiA9IHBpcGUoXG5cdFx0XHRcdFx0Zixcblx0XHRcdFx0XHRwdXJlLFxuXHRcdFx0XHQpO1xuXG5cdFx0XHRcdGNvbnN0IGcyID0gcGlwZShcblx0XHRcdFx0XHRnLFxuXHRcdFx0XHRcdHB1cmUsXG5cdFx0XHRcdCk7XG5cblx0XHRcdFx0cmV0dXJuIGVxdWFscyhjaGFpbihnMikoY2hhaW4oZjIpKHB1cmUoYSkpKSkoXG5cdFx0XHRcdFx0Y2hhaW4oeCA9PiBjaGFpbihnMikoZjIoeCkpKShwdXJlKGEpKSxcblx0XHRcdFx0KTtcblx0XHRcdH0sXG5cdFx0KSxcblx0KTtcblx0dC5wYXNzKCk7XG59KTtcbiJdfQ==