UNPKG

eff

Version:

An extensible effect monad based on the freer monad

131 lines (102 loc) 17.6 kB
"use strict"; 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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NvdXJjZXMvZWZmLnRlc3QuanMiXSwibmFtZXMiOlsidCIsImpzdmVyaWZ5IiwiYXNzZXJ0IiwiZm9yYWxsIiwiYSIsInBhc3MiLCJlZmZlY3QiLCJiIiwiYyIsInRlc3QiLCJ0b2RvIiwiZiIsImYyIiwicHVyZSIsImciLCJnMiIsIngiXSwibWFwcGluZ3MiOiI7O0FBRUE7O0FBQ0E7O0FBQ0E7O0FBRUE7Ozs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUVBO0FBQ0E7QUFDQTtBQUVBLGtCQUFLLG9CQUFMLEVBQTJCLFVBQUFBLENBQUMsRUFBSTtBQUMvQjtBQUVBQyxvQkFBU0MsTUFBVCxDQUNDRCxrQkFBU0UsTUFBVCxDQUFnQixRQUFoQixFQUEwQixVQUFBQyxDQUFDO0FBQUEsV0FBSSxpQkFBTyxlQUFLQSxDQUFMLENBQVAsRUFBZ0IsZUFBS0EsQ0FBTCxDQUFoQixNQUE2QixJQUFqQztBQUFBLEdBQTNCLENBREQ7O0FBR0FKLEVBQUFBLENBQUMsQ0FBQ0ssSUFBRjtBQUNBLENBUEQ7QUFTQSxrQkFBSyxzQkFBTCxFQUE2QixVQUFBTCxDQUFDLEVBQUk7QUFDakM7QUFFQUMsb0JBQVNDLE1BQVQsQ0FDQ0Qsa0JBQVNFLE1BQVQsQ0FDQyxNQURELEVBRUMsVUFBQUcsTUFBTTtBQUFBLFdBQUksaUJBQU8sZUFBS0EsTUFBTCxDQUFQLEVBQXFCLGVBQUtBLE1BQUwsQ0FBckIsTUFBdUMsSUFBM0M7QUFBQSxHQUZQLENBREQ7O0FBTUFOLEVBQUFBLENBQUMsQ0FBQ0ssSUFBRjtBQUNBLENBVkQ7QUFZQSxrQkFBSyxpQkFBTCxFQUF3QixVQUFBTCxDQUFDLEVBQUk7QUFDNUI7QUFFQUMsb0JBQVNDLE1BQVQsQ0FDQ0Qsa0JBQVNFLE1BQVQsQ0FDQyxRQURELEVBRUMsUUFGRCxFQUdDLFVBQUNDLENBQUQsRUFBSUcsQ0FBSjtBQUFBLFdBQVUsaUJBQU8sZUFBS0gsQ0FBTCxDQUFQLEVBQWdCLGVBQUtHLENBQUwsQ0FBaEIsTUFB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QUFGO0FBQ0EsQ0FkRDtBQWdCQSxrQkFBSyxnQkFBTCxFQUF1QixVQUFBTCxDQUFDLEVBQUk7QUFDM0I7QUFFQUMsb0JBQVNDLE1BQVQsQ0FDQ0Qsa0JBQVNFLE1BQVQsQ0FBZ0IsUUFBaEIsRUFBMEIsVUFBQUMsQ0FBQztBQUFBLFdBQUksaUJBQU8sZ0JBQU1TLFNBQU4sRUFBWSxlQUFLVCxDQUFMLENBQVosQ0FBUCxFQUE2QixlQUFLQSxDQUFMLENBQTdCLENBQUo7QUFBQSxHQUEzQixDQUREOztBQUdBSixFQUFBQSxDQUFDLENBQUNLLElBQUY7QUFDQSxDQVBEO0FBU0Esa0JBQUssZUFBTCxFQUFzQixVQUFBTCxDQUFDLEVBQUk7QUFDMUI7QUFFQUMsb0JBQVNDLE1BQVQsQ0FDQ0Qsa0JBQVNFLE1BQVQsQ0FDQyxRQURELEVBRUMsa0JBRkQsRUFHQyxrQkFIRCxFQUlDLFVBQUNDLENBQUQsRUFBSU8sQ0FBSixFQUFPRyxDQUFQLEVBQWE7QUFDWixRQUFNRixFQUFFLEdBQUcsaUJBQ1ZELENBRFUsRUFFVkUsU0FGVSxDQUFYO0FBS0EsUUFBTUUsRUFBRSxHQUFHLGlCQUNWRCxDQURVLEVBRVZELFNBRlUsQ0FBWDtBQUtBLFdBQU8saUJBQU8sZ0JBQU1FLEVBQU4sRUFBVSxnQkFBTUgsRUFBTixFQUFVLGVBQUtSLENBQUwsQ0FBVixDQUFWLENBQVAsRUFDTixnQkFBTSxVQUFBWSxDQUFDO0FBQUEsYUFBSSxnQkFBTUQsRUFBTixFQUFVSCxFQUFFLENBQUNJLENBQUQsQ0FBWixDQUFKO0FBQUEsS0FBUCxFQUE2QixlQUFLWixDQUFMLENBQTdCLENBRE0sQ0FBUDtBQUdBLEdBbEJGLENBREQ7O0FBc0JBSixFQUFBQSxDQUFDLENBQUNLLElBQUY7QUFDQSxDQTFCRCIsInNvdXJjZXNDb250ZW50IjpbIi8qIEBmbG93ICovXG5cbmltcG9ydCB0ZXN0IGZyb20gXCJhdmFcIjtcbmltcG9ydCBqc3ZlcmlmeSBmcm9tIFwianN2ZXJpZnlcIjtcbmltcG9ydCB7IHBpcGUgfSBmcm9tIFwicmFtZGFcIjtcblxuaW1wb3J0IHsgY2hhaW4sIGVxdWFscywgcHVyZSwgc2VuZCB9IGZyb20gXCIuL2VmZlwiO1xuXG4vLyBOb3RlOiBKU1ZlcmlmeSBkb2VzIG5vdCBhcHBlYXIgdG8gaGF2ZSBhIHdheSB0byBnZW5lcmF0ZSBhcmJpdHJhcnkgYXJiaXRyYXJpZXM7XG4vLyAgICAgICB0aGlzIG1lYW5zIHRoYXQgZWFjaCBhcmJpdHJhcnkgaW4gSlNWZXJpZnkgaGFzIHRvIGJlIG9mIGEgY2VydGFpbiB0eXBlLlxuLy8gICAgICAgRm9yIGFsbCBvZiB0aGUgdGVzdHMgYmVsb3cgd2UgYXJlIHVzaW5nIGFyYml0cmFyeSAqbnVtYmVycyosIHdpdGggdGhlIG51bWJlclxuLy8gICAgICAgdHlwZSBiZWluZyBjaG9zZW4gcHNldWRvLXJhbmRvbWx5LiBUaGVyZSdzIG5vIGxvZ2ljIHdpdGhpbiB0aGUgRWZmIGNvcmVcbi8vICAgICAgIHRoYXQgdHJlYXRzIHRoZSB0eXBlcyBvZiB2YWx1ZXMgZGlmZmVyZW50bHksIHNvIHRoaXMgKnNob3VsZG4ndCogaGF2ZSBhbnlcbi8vICAgICAgIHNpZ25pZmljYW5jZS4gT2YgY291cnNlLCBhcyBzb29uIGFzIGFuIGVkZ2UgY2FzZSBpcyBmb3VuZCwgd2Ugd2lsbCBoYXZlXG4vLyAgICAgICB0byByZXZpc2l0IHRoaXMgYXBwcm9hY2guXG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBTZXRvaWQgbGF3c1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxudGVzdChcIlJlZmxleGl2aXR5IChQdXJlKVwiLCB0ID0+IHtcblx0Ly8gZXF1YWxzIGEgYSDiiaEgdHJ1ZVxuXG5cdGpzdmVyaWZ5LmFzc2VydChcblx0XHRqc3ZlcmlmeS5mb3JhbGwoXCJudW1iZXJcIiwgYSA9PiBlcXVhbHMocHVyZShhKSkocHVyZShhKSkgPT09IHRydWUpLFxuXHQpO1xuXHR0LnBhc3MoKTtcbn0pO1xuXG50ZXN0KFwiUmVmbGV4aXZpdHkgKEltcHVyZSlcIiwgdCA9PiB7XG5cdC8vIGVxdWFscyBhIGEg4omhIHRydWVcblxuXHRqc3ZlcmlmeS5hc3NlcnQoXG5cdFx0anN2ZXJpZnkuZm9yYWxsKFxuXHRcdFx0XCJqc29uXCIsXG5cdFx0XHRlZmZlY3QgPT4gZXF1YWxzKHNlbmQoZWZmZWN0KSkoc2VuZChlZmZlY3QpKSA9PT0gdHJ1ZSxcblx0XHQpLFxuXHQpO1xuXHR0LnBhc3MoKTtcbn0pO1xuXG50ZXN0KFwiU3ltbWV0cnkgKFB1cmUpXCIsIHQgPT4ge1xuXHQvLyBlcXVhbHMgYSBiIOKJoSBlcXVhbHMgYiBhXG5cblx0anN2ZXJpZnkuYXNzZXJ0KFxuXHRcdGpzdmVyaWZ5LmZvcmFsbChcblx0XHRcdFwibnVtYmVyXCIsXG5cdFx0XHRcIm51bWJlclwiLFxuXHRcdFx0KGEsIGIpID0+IGVxdWFscyhwdXJlKGEpKShwdXJlKGIpKSA9PT0gZXF1YWxzKHB1cmUoYikpKHB1cmUoYSkpLFxuXHRcdCksXG5cdCk7XG5cdHQucGFzcygpO1xufSk7XG5cbnRlc3QoXCJTeW1tZXRyeSAoSW1wdXJlKVwiLCB0ID0+IHtcblx0Ly8gZXF1YWxzIGEgYiDiiaEgZXF1YWxzIGIgYVxuXG5cdGpzdmVyaWZ5LmFzc2VydChcblx0XHRqc3ZlcmlmeS5mb3JhbGwoXG5cdFx0XHRcImpzb25cIixcblx0XHRcdFwianNvblwiLFxuXHRcdFx0KGEsIGIpID0+IGVxdWFscyhzZW5kKGEpKShzZW5kKGIpKSA9PT0gZXF1YWxzKHNlbmQoYikpKHNlbmQoYSkpLFxuXHRcdCksXG5cdCk7XG5cdHQucGFzcygpO1xufSk7XG5cbi8vIFRPRE86IHNob3VsZCBwYXNzIGluIHRoZSBhYnJpdHJhcnkgZGF0YSB3aXRoIHRoZSBjb25zdHJhaW50LCByYXRoZXIgdGhhbiBpbmNsdWRpbmcgdGhlIGNvbnN0cmFpbnQgaW4gdGhlIHRlc3RcbnRlc3QoXCJUcmFuc2l0aXZpdHkgKFB1cmUpXCIsIHQgPT4ge1xuXHQvLyBpZiBlcXVhbHMgYSBiID09IHRydWUgYW5kIGVxdWFscyBiIGMgPT0gdHJ1ZSwgdGhlbiBlcXVhbHMgYSBjID09IHRydWVcblxuXHRqc3ZlcmlmeS5hc3NlcnQoXG5cdFx0anN2ZXJpZnkuZm9yYWxsKFwibnVtYmVyXCIsIFwibnVtYmVyXCIsIFwibnVtYmVyXCIsIChhLCBiLCBjKSA9PlxuXHRcdFx0ZXF1YWxzKHB1cmUoYSkpKHB1cmUoYikpICYmIGVxdWFscyhwdXJlKGIpKShwdXJlKGMpKVxuXHRcdFx0XHQ/IGVxdWFscyhwdXJlKGEpKShwdXJlKGIpKVxuXHRcdFx0XHQ6IHRydWUsXG5cdFx0KSxcblx0KTtcblx0dC5wYXNzKCk7XG59KTtcblxudGVzdChcIlRyYW5zaXRpdml0eSAoSW1wdXJlKVwiLCB0ID0+IHtcblx0Ly8gaWYgZXF1YWxzIGEgYiA9PSB0cnVlIGFuZCBlcXVhbHMgYiBjID09IHRydWUsIHRoZW4gZXF1YWxzIGEgYyA9PSB0cnVlXG5cblx0anN2ZXJpZnkuYXNzZXJ0KFxuXHRcdGpzdmVyaWZ5LmZvcmFsbChcImpzb25cIiwgXCJqc29uXCIsIFwianNvblwiLCAoYSwgYiwgYykgPT5cblx0XHRcdGVxdWFscyhzZW5kKGEpKShzZW5kKGIpKSAmJiBlcXVhbHMoc2VuZChiKSkoc2VuZChjKSlcblx0XHRcdFx0PyBlcXVhbHMoc2VuZChhKSkoc2VuZChiKSlcblx0XHRcdFx0OiB0cnVlLFxuXHRcdCksXG5cdCk7XG5cdHQucGFzcygpO1xufSk7XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBGdW5jdG9yIExhd3MgKGh0dHBzOi8vd2lraS5oYXNrZWxsLm9yZy9GdW5jdG9yLCBodHRwczovL2dpdGh1Yi5jb20vZmFudGFzeWxhbmQvZmFudGFzeS1sYW5kI2Z1bmN0b3IpXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG50ZXN0LnRvZG8oXCJJZGVudGl0eSAobWFwKVwiKTsgLy8gdS5tYXAoYSA9PiBhKSBpcyBlcXVpdmFsZW50IHRvIHVcblxudGVzdC50b2RvKFwiQ29tcG9zaXRpb24gKG1hcClcIik7IC8vIHUubWFwKHggPT4gZihnKHgpKSkgaXMgZXF1aXZhbGVudCB0byB1Lm1hcChnKS5tYXAoZilcblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIEFwcGx5IExhd3MgKGh0dHBzOi8vZ2l0aHViLmNvbS9mYW50YXN5bGFuZC9mYW50YXN5LWxhbmQjYXBwbHkpXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG50ZXN0LnRvZG8oXCJDb21wb3NpdGlvbiAoYXApXCIpOyAvLyB2LmFwKHUuYXAoYS5tYXAoZiA9PiBnID0+IHggPT4gZihnKHgpKSkpKSBpcyBlcXVpdmFsZW50IHRvIHYuYXAodSkuYXAoYSlcblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIEFwcGxpY2F0aXZlIExhd3MgKGh0dHBzOi8vZ2l0aHViLmNvbS9mYW50YXN5bGFuZC9mYW50YXN5LWxhbmQjYXBwbGljYXRpdmUpXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG50ZXN0LnRvZG8oXCJJZGVudGl0eSAoYXApXCIpOyAvLyB2LmFwKEEub2YoeCA9PiB4KSkgaXMgZXF1aXZhbGVudCB0byB2XG5cbnRlc3QudG9kbyhcIkhvbW9tb3JwaGlzbVwiKTsgLy8gQS5vZih4KS5hcChBLm9mKGYpKSBpcyBlcXVpdmFsZW50IHRvIEEub2YoZih4KSlcblxudGVzdC50b2RvKFwiSW50ZXJjaGFuZ2VcIik7IC8vIEEub2YoeSkuYXAodSkgaXMgZXF1aXZhbGVudCB0byB1LmFwKEEub2YoZiA9PiBmKHkpKSlcblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIE1vbmFkIExhd3MgKGh0dHBzOi8vd2lraS5oYXNrZWxsLm9yZy9Nb25hZF9sYXdzLCBodHRwczovL2dpdGh1Yi5jb20vZmFudGFzeWxhbmQvZmFudGFzeS1sYW5kI21vbmFkLCBodHRwczovL2dpdGh1Yi5jb20vZmFudGFzeWxhbmQvZmFudGFzeS1sYW5kI2NoYWluKVxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxudGVzdChcIkxlZnQgSWRlbnRpdHlcIiwgdCA9PiB7XG5cdC8vIHJldHVybiBhID4+PSBmIOKJoSBmIGFcblxuXHRqc3ZlcmlmeS5hc3NlcnQoXG5cdFx0anN2ZXJpZnkuZm9yYWxsKFwibnVtYmVyXCIsIFwibnVtYmVyIC0+IG51bWJlclwiLCAoYSwgZikgPT4ge1xuXHRcdFx0Y29uc3QgZjIgPSBwaXBlKFxuXHRcdFx0XHRmLFxuXHRcdFx0XHRwdXJlLFxuXHRcdFx0KTtcblxuXHRcdFx0cmV0dXJuIGVxdWFscyhjaGFpbihmMikocHVyZShhKSkpKGYyKGEpKTtcblx0XHR9KSxcblx0KTtcblx0dC5wYXNzKCk7XG59KTtcblxudGVzdChcIlJpZ2h0IElkZW50aXR5XCIsIHQgPT4ge1xuXHQvLyByZXR1cm4gbSA+Pj0gcmV0dXJuIOKJoSBtXG5cblx0anN2ZXJpZnkuYXNzZXJ0KFxuXHRcdGpzdmVyaWZ5LmZvcmFsbChcIm51bWJlclwiLCBhID0+IGVxdWFscyhjaGFpbihwdXJlKShwdXJlKGEpKSkocHVyZShhKSkpLFxuXHQpO1xuXHR0LnBhc3MoKTtcbn0pO1xuXG50ZXN0KFwiQXNzb2NpYXRpdml0eVwiLCB0ID0+IHtcblx0Ly8gKG0gPj49IGYpID4+PSBnIOKJoSBtID4+PSAoXFx4IC0+IGYgeCA+Pj0gZylcblxuXHRqc3ZlcmlmeS5hc3NlcnQoXG5cdFx0anN2ZXJpZnkuZm9yYWxsKFxuXHRcdFx0XCJudW1iZXJcIixcblx0XHRcdFwibnVtYmVyIC0+IG51bWJlclwiLFxuXHRcdFx0XCJudW1iZXIgLT4gbnVtYmVyXCIsXG5cdFx0XHQoYSwgZiwgZykgPT4ge1xuXHRcdFx0XHRjb25zdCBmMiA9IHBpcGUoXG5cdFx0XHRcdFx0Zixcblx0XHRcdFx0XHRwdXJlLFxuXHRcdFx0XHQpO1xuXG5cdFx0XHRcdGNvbnN0IGcyID0gcGlwZShcblx0XHRcdFx0XHRnLFxuXHRcdFx0XHRcdHB1cmUsXG5cdFx0XHRcdCk7XG5cblx0XHRcdFx0cmV0dXJuIGVxdWFscyhjaGFpbihnMikoY2hhaW4oZjIpKHB1cmUoYSkpKSkoXG5cdFx0XHRcdFx0Y2hhaW4oeCA9PiBjaGFpbihnMikoZjIoeCkpKShwdXJlKGEpKSxcblx0XHRcdFx0KTtcblx0XHRcdH0sXG5cdFx0KSxcblx0KTtcblx0dC5wYXNzKCk7XG59KTtcbiJdfQ==