/** * @license * Copyright 2019 Google LLC. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============================================================================= */ import { ENGINE } from './engine'; import * as tf from './index'; import { ALL_ENVS, describeWithFlags } from './jasmine_util'; import { expectArraysClose } from './test_util'; describeWithFlags('gradients', ALL_ENVS, () => { it('matmul + relu', async () => { const a = tf.tensor2d([-1, 2, -3, 10, -20, 30], [2, 3]); const b = tf.tensor2d([2, -3, 4, -1, 2, -3], [3, 2]); const [da, db] = tf.grads((a, b) => { // m = dot(a, b) // y = relu(m) // e = sum(y) const m = tf.matMul(a, b); const y = tf.relu(m); return tf.sum(y); })([a, b]); // de/dy = 1 // dy/dm = step(m) // de/dm = de/dy * dy/dm = step(m) const dedm = tf.step(tf.matMul(a, b)); // de/da = dot(de/dy, bT) expect(da.shape).toEqual(a.shape); let transposeA = false; let transposeB = true; expectArraysClose(await da.data(), await tf.matMul(dedm, b, transposeA, transposeB).data()); // de/db = dot(aT, de/dy) expect(db.shape).toEqual(b.shape); transposeA = true; transposeB = false; expectArraysClose(await db.data(), await tf.matMul(a, dedm, transposeA, transposeB).data()); }); it('grad(f)', async () => { const grad = tf.grad(x => x.square()); const result = grad(tf.tensor1d([.1, .2])); expectArraysClose(await result.data(), [.2, .4]); }); it('calling grad(f) twice works', async () => { const grad = tf.grad(x => x.square()); const result = grad(tf.tensor1d([.1, .2])); const result2 = grad(tf.tensor1d([.1, .4])); expectArraysClose(await result.data(), [.2, .4]); expectArraysClose(await result2.data(), [.2, .8]); }); it('grad(f): throwing an error during forward pass', () => { const grad = tf.grad(x => { throw new Error('failed forward pass'); }); expect(() => grad(tf.zeros([]))).toThrowError(); expect(ENGINE.isTapeOn()).toBe(false); }); it('grad(f): throwing an error during backwards pass', () => { const customOp = tf.customGrad((x) => { return { value: x, gradFunc: () => { throw new Error('failed backward pass'); } }; }); const grad = tf.grad(x => customOp(x)); expect(() => grad(tf.zeros([]))).toThrowError(); expect(ENGINE.isTapeOn()).toBe(false); }); it('grads(f)', async () => { const grads = tf.grads(x => x.square()); const result = grads([tf.tensor1d([.1, .2])]); expectArraysClose(await result[0].data(), [.2, .4]); }); it('calling grads(f) twice works', async () => { const grads = tf.grads(x => x.square()); const result = grads([tf.tensor1d([.1, .2])]); const result2 = grads([tf.tensor1d([.1, .4])]); expectArraysClose(await result[0].data(), [.2, .4]); expectArraysClose(await result2[0].data(), [.2, .8]); }); it('works with reshape', async () => { const a = tf.tensor2d([1, 2, 3, 4], [2, 2]); const exponent = tf.tensor1d([2, 2, 2, 2], 'int32'); const da = tf.grad(a => { const b = a.flatten(); const m = tf.pow(b, exponent); return tf.sum(m); })(a); expect(da.shape).toEqual([2, 2]); expectArraysClose(await da.data(), [2, 4, 6, 8]); }); it('reshape outside tf.grads() throws error', () => { const a = tf.tensor2d([1, 2, 3, 4], [2, 2]); const b = a.flatten(); const exponent = tf.tensor1d([2, 2, 2, 2], 'int32'); const f = () => { tf.grads((a, b) => { const m = tf.pow(b, exponent); return tf.sum(m); })([a, b]); }; expect(f).toThrowError(); }); it('does not error if irrelevant (pruned) ops are missing grads', async () => { const a = tf.tensor1d([true, true], 'bool'); const b = tf.tensor1d([false, true], 'bool'); const da = tf.grad(a => { // Logical has no gradients, but it is irrelevant. a.logicalAnd(b); return a.sum(); })(a); expectArraysClose(await da.data(), [1, 1]); }); it('errors if relevant ops are missing grads', () => { const a = tf.tensor1d([true, true], 'bool'); const b = tf.tensor1d([false, true], 'bool'); const dfda = tf.grad(a => { // Logical has no gradients, but it's relevant to the output. return a.logicalAnd(b); }); expect(() => dfda(a)).toThrowError(); }); it('works with asType', async () => { const a = tf.tensor2d([1, 2, 3, 4], [2, 2], 'int32'); const exponent = tf.tensor2d([2, 2, 2, 2], [2, 2], 'int32'); const da = tf.grad(a => { const b = a.toFloat(); const m = tf.pow(b, exponent); return tf.sum(m); })(a); expect(da.shape).toEqual([2, 2]); expect(da.dtype).toEqual('float32'); expectArraysClose(await da.data(), [2, 4, 6, 8]); }); it('asType outside of tf.grads() throws error', () => { const a = tf.tensor2d([1, 2, 3, 4], [2, 2], 'int32'); const b = a.toFloat(); const exponent = tf.tensor2d([2, 2, 2, 2], [2, 2], 'int32'); const f = () => { tf.grad(a => { const m = tf.pow(b, exponent); return tf.sum(m); })(a); }; expect(f).toThrowError(); }); it('saves tensors from the forward pass as expected', () => { const x = tf.scalar(1).variable(); const optimizer = tf.train.sgd(0.1); optimizer.minimize(() => { const y = x.square(); const z = y.square(); y.dispose(); return z; }); }); it('custom ops do not leak', () => { const before = tf.memory().numTensors; const x = tf.softmax([1, 2, 3, 4]); x.dispose(); const now = tf.memory().numTensors; expect(now).toBe(before); }); }); describeWithFlags('valueAndGradients', ALL_ENVS, () => { it('matmul + relu', async () => { const a = tf.tensor2d([-1, 2, -3, 10, -20, 30], [2, 3]); const b = tf.tensor2d([2, -3, 4, -1, 2, -3], [3, 2]); const { value, grads } = tf.valueAndGrads((a, b) => { // m = dot(a, b) // y = relu(m) // e = sum(y) const m = tf.matMul(a, b); const y = tf.relu(m); return tf.sum(y); })([a, b]); expectArraysClose(await value.data(), 10); // de/dy = 1 // dy/dm = step(m) // de/dm = de/dy * dy/dm = step(m) const dedm = tf.step(tf.matMul(a, b)); const [da, db] = grads; // de/da = dot(de/dy, bT) let transposeA = false; let transposeB = true; expectArraysClose(await da.data(), await tf.matMul(dedm, b, transposeA, transposeB).data()); // de/db = dot(aT, de/dy) transposeA = true; transposeB = false; expectArraysClose(await db.data(), await tf.matMul(a, dedm, transposeA, transposeB).data()); }); it('matmul + relu + inner tidy', async () => { const a = tf.tensor2d([-1, 2, -3, 10, -20, 30], [2, 3]); const b = tf.tensor2d([2, -3, 4, -1, 2, -3], [3, 2]); const { value, grads } = tf.valueAndGrads((a, b) => { // m = dot(a, b) // y = relu(m) // e = sum(y) const m = tf.matMul(a, b); return tf.tidy(() => { const y = tf.relu(m); return tf.sum(y); }); })([a, b]); expectArraysClose(await value.data(), 10); // de/dy = 1 // dy/dm = step(m) // de/dm = de/dy * dy/dm = step(m) const dedm = tf.step(tf.matMul(a, b)); const [da, db] = grads; // de/da = dot(de/dy, bT) let transposeA = false; let transposeB = true; expectArraysClose(await da.data(), await tf.matMul(dedm, b, transposeA, transposeB).data()); // de/db = dot(aT, de/dy) transposeA = true; transposeB = false; expectArraysClose(await db.data(), await tf.matMul(a, dedm, transposeA, transposeB).data()); }); }); describeWithFlags('higher-order gradients', ALL_ENVS, () => { it('grad(grad(f))', async () => { const x = tf.tensor1d([.1, .2]); const before = tf.memory().numTensors; const gradgrad = tf.grad(tf.grad(x => x.mul(x).mul(x))); const result = gradgrad(x); expect(tf.memory().numTensors).toBe(before + 1); expectArraysClose(await result.data(), [.6, 1.2]); }); it('grad(grad(x^2))', async () => { const x = tf.scalar(3); const gradgrad = tf.grad(tf.grad(x => x.square())); const result = gradgrad(x); // grad(grad(x^2)) = grad(2x) = 2 expectArraysClose(await result.data(), [2]); }); it('grads(grads(f))', async () => { const grads = tf.grads(x => x.mul(x).mul(x)); const gradsgrads = tf.grads(x => grads([x])[0]); const result = gradsgrads([tf.tensor1d([.1, .2])]); expectArraysClose(await result[0].data(), [.6, 1.2]); }); }); describeWithFlags('customGradient', ALL_ENVS, () => { it('basic', async () => { const a = tf.scalar(3); const b = tf.scalar(2, 'int32'); const dy = tf.scalar(4); const customPow = tf.customGrad((a) => { const value = tf.pow(a, b); const gradFunc = (dy) => dy.mul(tf.scalar(0.1)); return { value, gradFunc }; }); const { value, grad } = tf.valueAndGrad(a => customPow(a))(a, dy); expect(value.shape).toEqual(a.shape); expectArraysClose(await value.data(), [9]); expect(grad.shape).toEqual(a.shape); expectArraysClose(await grad.data(), [.4]); }); it('second order derivative through customGradient', async () => { const a = tf.scalar(3); const b = tf.scalar(2, 'int32'); const dy = tf.scalar(5); const customPow = tf.customGrad((a, save) => { const value = tf.pow(a, b); save([a]); const gradFunc = (dy, saved) => { const [a] = saved; return dy.mul(a); }; return { value, gradFunc }; }); const dda = tf.grad(tf.grad(a => customPow(a)))(a, dy); expect(dda.shape).toEqual(a.shape); // First order: dy * a. Second order: dy. expectArraysClose(await dda.data(), await dy.data()); }); it('calling gradient of custom op twice works', async () => { const customOp = tf.customGrad((x, save) => { // Override gradient of our custom x ^ 2 op to be dy * abs(x); save([x]); return { value: x.square(), gradFunc: (dy, saved) => { const [x] = saved; return dy.mul(x.abs()); } }; }); const x = tf.tensor1d([-1, -2, 3]); const grad = tf.grad(x => customOp(x)); expectArraysClose(await grad(x).data(), [1, 2, 3]); expectArraysClose(await grad(x).data(), [1, 2, 3]); }); }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JhZGllbnRzX3Rlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi90ZmpzLWNvcmUvc3JjL2dyYWRpZW50c190ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUVILE9BQU8sRUFBQyxNQUFNLEVBQUMsTUFBTSxVQUFVLENBQUM7QUFDaEMsT0FBTyxLQUFLLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDOUIsT0FBTyxFQUFDLFFBQVEsRUFBRSxpQkFBaUIsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBRTNELE9BQU8sRUFBQyxpQkFBaUIsRUFBQyxNQUFNLGFBQWEsQ0FBQztBQUU5QyxpQkFBaUIsQ0FBQyxXQUFXLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRTtJQUM1QyxFQUFFLENBQUMsZUFBZSxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQzdCLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDeEQsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUVyRCxNQUFNLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFjLEVBQUUsQ0FBYyxFQUFFLEVBQUU7WUFDM0QsZ0JBQWdCO1lBQ2hCLGNBQWM7WUFDZCxhQUFhO1lBQ2IsTUFBTSxDQUFDLEdBQUcsRUFBRSxD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QyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIlxuLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMTkgR29vZ2xlIExMQy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqL1xuXG5pbXBvcnQge0VOR0lORX0gZnJvbSAnLi9lbmdpbmUnO1xuaW1wb3J0ICogYXMgdGYgZnJvbSAnLi9pbmRleCc7XG5pbXBvcnQge0FMTF9FTlZTLCBkZXNjcmliZVdpdGhGbGFnc30gZnJvbSAnLi9qYXNtaW5lX3V0aWwnO1xuaW1wb3J0IHtUZW5zb3J9IGZyb20gJy4vdGVuc29yJztcbmltcG9ydCB7ZXhwZWN0QXJyYXlzQ2xvc2V9IGZyb20gJy4vdGVzdF91dGlsJztcblxuZGVzY3JpYmVXaXRoRmxhZ3MoJ2dyYWRpZW50cycsIEFMTF9FTlZTLCAoKSA9PiB7XG4gIGl0KCdtYXRtdWwgKyByZWx1JywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGEgPSB0Zi50ZW5zb3IyZChbLTEsIDIsIC0zLCAxMCwgLTIwLCAzMF0sIFsyLCAzXSk7XG4gICAgY29uc3QgYiA9IHRmLnRlbnNvcjJkKFsyLCAtMywgNCwgLTEsIDIsIC0zXSwgWzMsIDJdKTtcblxuICAgIGNvbnN0IFtkYSwgZGJdID0gdGYuZ3JhZHMoKGE6IHRmLlRlbnNvcjJELCBiOiB0Zi5UZW5zb3IyRCkgPT4ge1xuICAgICAgLy8gbSA9IGRvdChhLCBiKVxuICAgICAgLy8geSA9IHJlbHUobSlcbiAgICAgIC8vIGUgPSBzdW0oeSlcbiAgICAgIGNvbnN0IG0gPSB0Zi5tYXRNdWwoYSwgYik7XG4gICAgICBjb25zdCB5ID0gdGYucmVsdShtKTtcbiAgICAgIHJldHVybiB0Zi5zdW0oeSk7XG4gICAgfSkoW2EsIGJdKTtcblxuICAgIC8vIGRlL2R5ID0gMVxuICAgIC8vIGR5L2RtID0gc3RlcChtKVxuICAgIC8vIGRlL2RtID0gZGUvZHkgKiBkeS9kbSA9IHN0ZXAobSlcbiAgICBjb25zdCBkZWRtID0gdGYuc3RlcCh0Zi5tYXRNdWwoYSwgYikpO1xuXG4gICAgLy8gZGUvZGEgPSBkb3QoZGUvZHksIGJUKVxuICAgIGV4cGVjdChkYS5zaGFwZSkudG9FcXVhbChhLnNoYXBlKTtcbiAgICBsZXQgdHJhbnNwb3NlQSA9IGZhbHNlO1xuICAgIGxldCB0cmFuc3Bvc2VCID0gdHJ1ZTtcbiAgICBleHBlY3RBcnJheXNDbG9zZShcbiAgICAgICAgYXdhaXQgZGEuZGF0YSgpLFxuICAgICAgICBhd2FpdCB0Zi5tYXRNdWwoZGVkbSwgYiwgdHJhbnNwb3NlQSwgdHJhbnNwb3NlQikuZGF0YSgpKTtcblxuICAgIC8vIGRlL2RiID0gZG90KGFULCBkZS9keSlcbiAgICBleHBlY3QoZGIuc2hhcGUpLnRvRXF1YWwoYi5zaGFwZSk7XG4gICAgdHJhbnNwb3NlQSA9IHRydWU7XG4gICAgdHJhbnNwb3NlQiA9IGZhbHNlO1xuICAgIGV4cGVjdEFycmF5c0Nsb3NlKFxuICAgICAgICBhd2FpdCBkYi5kYXRhKCksXG4gICAgICAgIGF3YWl0IHRmLm1hdE11bChhLCBkZWRtLCB0cmFuc3Bvc2VBLCB0cmFuc3Bvc2VCKS5kYXRhKCkpO1xuICB9KTtcblxuICBpdCgnZ3JhZChmKScsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBncmFkID0gdGYuZ3JhZCh4ID0+IHguc3F1YXJlKCkpO1xuICAgIGNvbnN0IHJlc3VsdCA9IGdyYWQodGYudGVuc29yMWQoWy4xLCAuMl0pKTtcbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCByZXN1bHQuZGF0YSgpLCBbLjIsIC40XSk7XG4gIH0pO1xuXG4gIGl0KCdjYWxsaW5nIGdyYWQoZikgdHdpY2Ugd29ya3MnLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgZ3JhZCA9IHRmLmdyYWQoeCA9PiB4LnNxdWFyZSgpKTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGdyYWQodGYudGVuc29yMWQoWy4xLCAuMl0pKTtcbiAgICBjb25zdCByZXN1bHQyID0gZ3JhZCh0Zi50ZW5zb3IxZChbLjEsIC40XSkpO1xuICAgIGV4cGVjdEFycmF5c0Nsb3NlKGF3YWl0IHJlc3VsdC5kYXRhKCksIFsuMiwgLjRdKTtcbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCByZXN1bHQyLmRhdGEoKSwgWy4yLCAuOF0pO1xuICB9KTtcblxuICBpdCgnZ3JhZChmKTogdGhyb3dpbmcgYW4gZXJyb3IgZHVyaW5nIGZvcndhcmQgcGFzcycsICgpID0+IHtcbiAgICBjb25zdCBncmFkID0gdGYuZ3JhZCh4ID0+IHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignZmFpbGVkIGZvcndhcmQgcGFzcycpO1xuICAgIH0pO1xuICAgIGV4cGVjdCgoKSA9PiBncmFkKHRmLnplcm9zKFtdKSkpLnRvVGhyb3dFcnJvcigpO1xuICAgIGV4cGVjdChFTkdJTkUuaXNUYXBlT24oKSkudG9CZShmYWxzZSk7XG4gIH0pO1xuXG4gIGl0KCdncmFkKGYpOiB0aHJvd2luZyBhbiBlcnJvciBkdXJpbmcgYmFja3dhcmRzIHBhc3MnLCAoKSA9PiB7XG4gICAgY29uc3QgY3VzdG9tT3AgPSB0Zi5jdXN0b21HcmFkKCh4OiB0Zi5UZW5zb3IpID0+IHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHZhbHVlOiB4LFxuICAgICAgICBncmFkRnVuYzogKCkgPT4ge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignZmFpbGVkIGJhY2t3YXJkIHBhc3MnKTtcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICB9KTtcbiAgICBjb25zdCBncmFkID0gdGYuZ3JhZCh4ID0+IGN1c3RvbU9wKHgpKTtcbiAgICBleHBlY3QoKCkgPT4gZ3JhZCh0Zi56ZXJvcyhbXSkpKS50b1Rocm93RXJyb3IoKTtcbiAgICBleHBlY3QoRU5HSU5FLmlzVGFwZU9uKCkpLnRvQmUoZmFsc2UpO1xuICB9KTtcblxuICBpdCgnZ3JhZHMoZiknLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgZ3JhZHMgPSB0Zi5ncmFkcyh4ID0+IHguc3F1YXJlKCkpO1xuICAgIGNvbnN0IHJlc3VsdCA9IGdyYWRzKFt0Zi50ZW5zb3IxZChbLjEsIC4yXSldKTtcbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCByZXN1bHRbMF0uZGF0YSgpLCBbLjIsIC40XSk7XG4gIH0pO1xuXG4gIGl0KCdjYWxsaW5nIGdyYWRzKGYpIHR3aWNlIHdvcmtzJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGdyYWRzID0gdGYuZ3JhZHMoeCA9PiB4LnNxdWFyZSgpKTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGdyYWRzKFt0Zi50ZW5zb3IxZChbLjEsIC4yXSldKTtcbiAgICBjb25zdCByZXN1bHQyID0gZ3JhZHMoW3RmLnRlbnNvcjFkKFsuMSwgLjRdKV0pO1xuICAgIGV4cGVjdEFycmF5c0Nsb3NlKGF3YWl0IHJlc3VsdFswXS5kYXRhKCksIFsuMiwgLjRdKTtcbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCByZXN1bHQyWzBdLmRhdGEoKSwgWy4yLCAuOF0pO1xuICB9KTtcblxuICBpdCgnd29ya3Mgd2l0aCByZXNoYXBlJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGEgPSB0Zi50ZW5zb3IyZChbMSwgMiwgMywgNF0sIFsyLCAyXSk7XG4gICAgY29uc3QgZXhwb25lbnQgPSB0Zi50ZW5zb3IxZChbMiwgMiwgMiwgMl0sICdpbnQzMicpO1xuXG4gICAgY29uc3QgZGEgPSB0Zi5ncmFkKGEgPT4ge1xuICAgICAgY29uc3QgYiA9IGEuZmxhdHRlbigpO1xuICAgICAgY29uc3QgbSA9IHRmLnBvdyhiLCBleHBvbmVudCk7XG4gICAgICByZXR1cm4gdGYuc3VtKG0pO1xuICAgIH0pKGEpO1xuXG4gICAgZXhwZWN0KGRhLnNoYXBlKS50b0VxdWFsKFsyLCAyXSk7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgZGEuZGF0YSgpLCBbMiwgNCwgNiwgOF0pO1xuICB9KTtcblxuICBpdCgncmVzaGFwZSBvdXRzaWRlIHRmLmdyYWRzKCkgdGhyb3dzIGVycm9yJywgKCkgPT4ge1xuICAgIGNvbnN0IGEgPSB0Zi50ZW5zb3IyZChbMSwgMiwgMywgNF0sIFsyLCAyXSk7XG4gICAgY29uc3QgYiA9IGEuZmxhdHRlbigpO1xuICAgIGNvbnN0IGV4cG9uZW50ID0gdGYudGVuc29yMWQoWzIsIDIsIDIsIDJdLCAnaW50MzInKTtcblxuICAgIGNvbnN0IGYgPSAoKSA9PiB7XG4gICAgICB0Zi5ncmFkcygoYSwgYikgPT4ge1xuICAgICAgICBjb25zdCBtID0gdGYucG93KGIsIGV4cG9uZW50KTtcbiAgICAgICAgcmV0dXJuIHRmLnN1bShtKTtcbiAgICAgIH0pKFthLCBiXSk7XG4gICAgfTtcbiAgICBleHBlY3QoZikudG9UaHJvd0Vycm9yKCk7XG4gIH0pO1xuXG4gIGl0KCdkb2VzIG5vdCBlcnJvciBpZiBpcnJlbGV2YW50IChwcnVuZWQpIG9wcyBhcmUgbWlzc2luZyBncmFkcycsXG4gICAgIGFzeW5jICgpID0+IHtcbiAgICAgICBjb25zdCBhID0gdGYudGVuc29yMWQoW3RydWUsIHRydWVdLCAnYm9vbCcpO1xuICAgICAgIGNvbnN0IGIgPSB0Zi50ZW5zb3IxZChbZmFsc2UsIHRydWVdLCAnYm9vbCcpO1xuICAgICAgIGNvbnN0IGRhID0gdGYuZ3JhZChhID0+IHtcbiAgICAgICAgIC8vIExvZ2ljYWwgaGFzIG5vIGdyYWRpZW50cywgYnV0IGl0IGlzIGlycmVsZXZhbnQuXG4gICAgICAgICBhLmxvZ2ljYWxBbmQoYik7XG4gICAgICAgICByZXR1cm4gYS5zdW0oKTtcbiAgICAgICB9KShhKTtcbiAgICAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCBkYS5kYXRhKCksIFsxLCAxXSk7XG4gICAgIH0pO1xuXG4gIGl0KCdlcnJvcnMgaWYgcmVsZXZhbnQgb3BzIGFyZSBtaXNzaW5nIGdyYWRzJywgKCkgPT4ge1xuICAgIGNvbnN0IGEgPSB0Zi50ZW5zb3IxZChbdHJ1ZSwgdHJ1ZV0sICdib29sJyk7XG4gICAgY29uc3QgYiA9IHRmLnRlbnNvcjFkKFtmYWxzZSwgdHJ1ZV0sICdib29sJyk7XG4gICAgY29uc3QgZGZkYSA9IHRmLmdyYWQoYSA9PiB7XG4gICAgICAvLyBMb2dpY2FsIGhhcyBubyBncmFkaWVudHMsIGJ1dCBpdCdzIHJlbGV2YW50IHRvIHRoZSBvdXRwdXQuXG4gICAgICByZXR1cm4gYS5sb2dpY2FsQW5kKGIpO1xuICAgIH0pO1xuICAgIGV4cGVjdCgoKSA9PiBkZmRhKGEpKS50b1Rocm93RXJyb3IoKTtcbiAgfSk7XG5cbiAgaXQoJ3dvcmtzIHdpdGggYXNUeXBlJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGEgPSB0Zi50ZW5zb3IyZChbMSwgMiwgMywgNF0sIFsyLCAyXSwgJ2ludDMyJyk7XG4gICAgY29uc3QgZXhwb25lbnQgPSB0Zi50ZW5zb3IyZChbMiwgMiwgMiwgMl0sIFsyLCAyXSwgJ2ludDMyJyk7XG5cbiAgICBjb25zdCBkYSA9IHRmLmdyYWQoYSA9PiB7XG4gICAgICBjb25zdCBiID0gYS50b0Zsb2F0KCk7XG4gICAgICBjb25zdCBtID0gdGYucG93KGIsIGV4cG9uZW50KTtcbiAgICAgIHJldHVybiB0Zi5zdW0obSk7XG4gICAgfSkoYSk7XG5cbiAgICBleHBlY3QoZGEuc2hhcGUpLnRvRXF1YWwoWzIsIDJdKTtcbiAgICBleHBlY3QoZGEuZHR5cGUpLnRvRXF1YWwoJ2Zsb2F0MzInKTtcbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCBkYS5kYXRhKCksIFsyLCA0LCA2LCA4XSk7XG4gIH0pO1xuXG4gIGl0KCdhc1R5cGUgb3V0c2lkZSBvZiB0Zi5ncmFkcygpIHRocm93cyBlcnJvcicsICgpID0+IHtcbiAgICBjb25zdCBhID0gdGYudGVuc29yMmQoWzEsIDIsIDMsIDRdLCBbMiwgMl0sICdpbnQzMicpO1xuICAgIGNvbnN0IGIgPSBhLnRvRmxvYXQoKTtcbiAgICBjb25zdCBleHBvbmVudCA9IHRmLnRlbnNvcjJkKFsyLCAyLCAyLCAyXSwgWzIsIDJdLCAnaW50MzInKTtcblxuICAgIGNvbnN0IGYgPSAoKSA9PiB7XG4gICAgICB0Zi5ncmFkKGEgPT4ge1xuICAgICAgICBjb25zdCBtID0gdGYucG93KGIsIGV4cG9uZW50KTtcbiAgICAgICAgcmV0dXJuIHRmLnN1bShtKTtcbiAgICAgIH0pKGEpO1xuICAgIH07XG4gICAgZXhwZWN0KGYpLnRvVGhyb3dFcnJvcigpO1xuICB9KTtcblxuICBpdCgnc2F2ZXMgdGVuc29ycyBmcm9tIHRoZSBmb3J3YXJkIHBhc3MgYXMgZXhwZWN0ZWQnLCAoKSA9PiB7XG4gICAgY29uc3QgeCA9IHRmLnNjYWxhcigxKS52YXJpYWJsZSgpO1xuICAgIGNvbnN0IG9wdGltaXplciA9IHRmLnRyYWluLnNnZCgwLjEpO1xuICAgIG9wdGltaXplci5taW5pbWl6ZSgoKSA9PiB7XG4gICAgICBjb25zdCB5ID0geC5zcXVhcmUoKTtcbiAgICAgIGNvbnN0IHogPSB5LnNxdWFyZSgpO1xuICAgICAgeS5kaXNwb3NlKCk7XG4gICAgICByZXR1cm4gejtcbiAgICB9KTtcbiAgfSk7XG5cbiAgaXQoJ2N1c3RvbSBvcHMgZG8gbm90IGxlYWsnLCAoKSA9PiB7XG4gICAgY29uc3QgYmVmb3JlID0gdGYubWVtb3J5KCkubnVtVGVuc29ycztcbiAgICBjb25zdCB4ID0gdGYuc29mdG1heChbMSwgMiwgMywgNF0pO1xuICAgIHguZGlzcG9zZSgpO1xuICAgIGNvbnN0IG5vdyA9IHRmLm1lbW9yeSgpLm51bVRlbnNvcnM7XG4gICAgZXhwZWN0KG5vdykudG9CZShiZWZvcmUpO1xuICB9KTtcbn0pO1xuXG5kZXNjcmliZVdpdGhGbGFncygndmFsdWVBbmRHcmFkaWVudHMnLCBBTExfRU5WUywgKCkgPT4ge1xuICBpdCgnbWF0bXVsICsgcmVsdScsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBhID0gdGYudGVuc29yMmQoWy0xLCAyLCAtMywgMTAsIC0yMCwgMzBdLCBbMiwgM10pO1xuICAgIGNvbnN0IGIgPSB0Zi50ZW5zb3IyZChbMiwgLTMsIDQsIC0xLCAyLCAtM10sIFszLCAyXSk7XG5cbiAgICBjb25zdCB7dmFsdWUsIGdyYWRzfSA9XG4gICAgICAgIHRmLnZhbHVlQW5kR3JhZHMoKGE6IHRmLlRlbnNvcjJELCBiOiB0Zi5UZW5zb3IyRCkgPT4ge1xuICAgICAgICAgIC8vIG0gPSBkb3QoYSwgYilcbiAgICAgICAgICAvLyB5ID0gcmVsdShtKVxuICAgICAgICAgIC8vIGUgPSBzdW0oeSlcbiAgICAgICAgICBjb25zdCBtID0gdGYubWF0TXVsKGEsIGIpO1xuICAgICAgICAgIGNvbnN0IHkgPSB0Zi5yZWx1KG0pO1xuICAgICAgICAgIHJldHVybiB0Zi5zdW0oeSk7XG4gICAgICAgIH0pKFthLCBiXSk7XG5cbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCB2YWx1ZS5kYXRhKCksIDEwKTtcblxuICAgIC8vIGRlL2R5ID0gMVxuICAgIC8vIGR5L2RtID0gc3RlcChtKVxuICAgIC8vIGRlL2RtID0gZGUvZHkgKiBkeS9kbSA9IHN0ZXAobSlcbiAgICBjb25zdCBkZWRtID0gdGYuc3RlcCh0Zi5tYXRNdWwoYSwgYikpO1xuXG4gICAgY29uc3QgW2RhLCBkYl0gPSBncmFkcztcbiAgICAvLyBkZS9kYSA9IGRvdChkZS9keSwgYlQpXG4gICAgbGV0IHRyYW5zcG9zZUEgPSBmYWxzZTtcbiAgICBsZXQgdHJhbnNwb3NlQiA9IHRydWU7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoXG4gICAgICAgIGF3YWl0IGRhLmRhdGEoKSxcbiAgICAgICAgYXdhaXQgdGYubWF0TXVsKGRlZG0sIGIsIHRyYW5zcG9zZUEsIHRyYW5zcG9zZUIpLmRhdGEoKSk7XG5cbiAgICAvLyBkZS9kYiA9IGRvdChhVCwgZGUvZHkpXG4gICAgdHJhbnNwb3NlQSA9IHRydWU7XG4gICAgdHJhbnNwb3NlQiA9IGZhbHNlO1xuICAgIGV4cGVjdEFycmF5c0Nsb3NlKFxuICAgICAgICBhd2FpdCBkYi5kYXRhKCksXG4gICAgICAgIGF3YWl0IHRmLm1hdE11bChhLCBkZWRtLCB0cmFuc3Bvc2VBLCB0cmFuc3Bvc2VCKS5kYXRhKCkpO1xuICB9KTtcblxuICBpdCgnbWF0bXVsICsgcmVsdSArIGlubmVyIHRpZHknLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgYSA9IHRmLnRlbnNvcjJkKFstMSwgMiwgLTMsIDEwLCAtMjAsIDMwXSwgWzIsIDNdKTtcbiAgICBjb25zdCBiID0gdGYudGVuc29yMmQoWzIsIC0zLCA0LCAtMSwgMiwgLTNdLCBbMywgMl0pO1xuXG4gICAgY29uc3Qge3ZhbHVlLCBncmFkc30gPVxuICAgICAgICB0Zi52YWx1ZUFuZEdyYWRzKChhOiB0Zi5UZW5zb3IyRCwgYjogdGYuVGVuc29yMkQpID0+IHtcbiAgICAgICAgICAvLyBtID0gZG90KGEsIGIpXG4gICAgICAgICAgLy8geSA9IHJlbHUobSlcbiAgICAgICAgICAvLyBlID0gc3VtKHkpXG4gICAgICAgICAgY29uc3QgbSA9IHRmLm1hdE11bChhLCBiKTtcbiAgICAgICAgICByZXR1cm4gdGYudGlkeSgoKSA9PiB7XG4gICAgICAgICAgICBjb25zdCB5ID0gdGYucmVsdShtKTtcbiAgICAgICAgICAgIHJldHVybiB0Zi5zdW0oeSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pKFthLCBiXSk7XG5cbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCB2YWx1ZS5kYXRhKCksIDEwKTtcblxuICAgIC8vIGRlL2R5ID0gMVxuICAgIC8vIGR5L2RtID0gc3RlcChtKVxuICAgIC8vIGRlL2RtID0gZGUvZHkgKiBkeS9kbSA9IHN0ZXAobSlcbiAgICBjb25zdCBkZWRtID0gdGYuc3RlcCh0Zi5tYXRNdWwoYSwgYikpO1xuXG4gICAgY29uc3QgW2RhLCBkYl0gPSBncmFkcztcbiAgICAvLyBkZS9kYSA9IGRvdChkZS9keSwgYlQpXG4gICAgbGV0IHRyYW5zcG9zZUEgPSBmYWxzZTtcbiAgICBsZXQgdHJhbnNwb3NlQiA9IHRydWU7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoXG4gICAgICAgIGF3YWl0IGRhLmRhdGEoKSxcbiAgICAgICAgYXdhaXQgdGYubWF0TXVsKGRlZG0sIGIsIHRyYW5zcG9zZUEsIHRyYW5zcG9zZUIpLmRhdGEoKSk7XG5cbiAgICAvLyBkZS9kYiA9IGRvdChhVCwgZGUvZHkpXG4gICAgdHJhbnNwb3NlQSA9IHRydWU7XG4gICAgdHJhbnNwb3NlQiA9IGZhbHNlO1xuICAgIGV4cGVjdEFycmF5c0Nsb3NlKFxuICAgICAgICBhd2FpdCBkYi5kYXRhKCksXG4gICAgICAgIGF3YWl0IHRmLm1hdE11bChhLCBkZWRtLCB0cmFuc3Bvc2VBLCB0cmFuc3Bvc2VCKS5kYXRhKCkpO1xuICB9KTtcbn0pO1xuXG5kZXNjcmliZVdpdGhGbGFncygnaGlnaGVyLW9yZGVyIGdyYWRpZW50cycsIEFMTF9FTlZTLCAoKSA9PiB7XG4gIGl0KCdncmFkKGdyYWQoZikpJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IHggPSB0Zi50ZW5zb3IxZChbLjEsIC4yXSk7XG4gICAgY29uc3QgYmVmb3JlID0gdGYubWVtb3J5KCkubnVtVGVuc29ycztcbiAgICBjb25zdCBncmFkZ3JhZCA9IHRmLmdyYWQodGYuZ3JhZCh4ID0+IHgubXVsKHgpLm11bCh4KSkpO1xuICAgIGNvbnN0IHJlc3VsdCA9IGdyYWRncmFkKHgpO1xuICAgIGV4cGVjdCh0Zi5tZW1vcnkoKS5udW1UZW5zb3JzKS50b0JlKGJlZm9yZSArIDEpO1xuICAgIGV4cGVjdEFycmF5c0Nsb3NlKGF3YWl0IHJlc3VsdC5kYXRhKCksIFsuNiwgMS4yXSk7XG4gIH0pO1xuXG4gIGl0KCdncmFkKGdyYWQoeF4yKSknLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgeCA9IHRmLnNjYWxhcigzKTtcbiAgICBjb25zdCBncmFkZ3JhZCA9IHRmLmdyYWQodGYuZ3JhZCh4ID0+IHguc3F1YXJlKCkpKTtcbiAgICBjb25zdCByZXN1bHQgPSBncmFkZ3JhZCh4KTtcbiAgICAvLyBncmFkKGdyYWQoeF4yKSkgPSBncmFkKDJ4KSA9IDJcbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCByZXN1bHQuZGF0YSgpLCBbMl0pO1xuICB9KTtcblxuICBpdCgnZ3JhZHMoZ3JhZHMoZikpJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGdyYWRzID0gdGYuZ3JhZHMoeCA9PiB4Lm11bCh4KS5tdWwoeCkpO1xuICAgIGNvbnN0IGdyYWRzZ3JhZHMgPSB0Zi5ncmFkcyh4ID0+IGdyYWRzKFt4XSlbMF0pO1xuICAgIGNvbnN0IHJlc3VsdCA9IGdyYWRzZ3JhZHMoW3RmLnRlbnNvcjFkKFsuMSwgLjJdKV0pO1xuICAgIGV4cGVjdEFycmF5c0Nsb3NlKGF3YWl0IHJlc3VsdFswXS5kYXRhKCksIFsuNiwgMS4yXSk7XG4gIH0pO1xufSk7XG5cbmRlc2NyaWJlV2l0aEZsYWdzKCdjdXN0b21HcmFkaWVudCcsIEFMTF9FTlZTLCAoKSA9PiB7XG4gIGl0KCdiYXNpYycsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBhID0gdGYuc2NhbGFyKDMpO1xuICAgIGNvbnN0IGIgPSB0Zi5zY2FsYXIoMiwgJ2ludDMyJyk7XG4gICAgY29uc3QgZHkgPSB0Zi5zY2FsYXIoNCk7XG5cbiAgICBjb25zdCBjdXN0b21Qb3cgPSB0Zi5jdXN0b21HcmFkKChhOiB0Zi5UZW5zb3IpID0+IHtcbiAgICAgIGNvbnN0IHZhbHVlID0gdGYucG93KGEsIGIpO1xuICAgICAgY29uc3QgZ3JhZEZ1bmMgPSAoZHk6IHRmLlRlbnNvcikgPT4gZHkubXVsKHRmLnNjYWxhcigwLjEpKTtcbiAgICAgIHJldHVybiB7dmFsdWUsIGdyYWRGdW5jfTtcbiAgICB9KTtcblxuICAgIGNvbnN0IHt2YWx1ZSwgZ3JhZH0gPSB0Zi52YWx1ZUFuZEdyYWQoYSA9PiBjdXN0b21Qb3coYSkpKGEsIGR5KTtcbiAgICBleHBlY3QodmFsdWUuc2hhcGUpLnRvRXF1YWwoYS5zaGFwZSk7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgdmFsdWUuZGF0YSgpLCBbOV0pO1xuICAgIGV4cGVjdChncmFkLnNoYXBlKS50b0VxdWFsKGEuc2hhcGUpO1xuICAgIGV4cGVjdEFycmF5c0Nsb3NlKGF3YWl0IGdyYWQuZGF0YSgpLCBbLjRdKTtcbiAgfSk7XG5cbiAgaXQoJ3NlY29uZCBvcmRlciBkZXJpdmF0aXZlIHRocm91Z2ggY3VzdG9tR3JhZGllbnQnLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgYSA9IHRmLnNjYWxhcigzKTtcbiAgICBjb25zdCBiID0gdGYuc2NhbGFyKDIsICdpbnQzMicpO1xuXG4gICAgY29uc3QgZHkgPSB0Zi5zY2FsYXIoNSk7XG5cbiAgICBjb25zdCBjdXN0b21Qb3cgPSB0Zi5jdXN0b21HcmFkKChhOiB0Zi5UZW5zb3IsIHNhdmU6IHRmLkdyYWRTYXZlRnVuYykgPT4ge1xuICAgICAgY29uc3QgdmFsdWUgPSB0Zi5wb3coYSwgYik7XG4gICAgICBzYXZlKFthXSk7XG4gICAgICBjb25zdCBncmFkRnVuYyA9IChkeTogdGYuVGVuc29yLCBzYXZlZDogVGVuc29yW10pID0+IHtcbiAgICAgICAgY29uc3QgW2FdID0gc2F2ZWQ7XG4gICAgICAgIHJldHVybiBkeS5tdWwoYSk7XG4gICAgICB9O1xuICAgICAgcmV0dXJuIHt2YWx1ZSwgZ3JhZEZ1bmN9O1xuICAgIH0pO1xuXG4gICAgY29uc3QgZGRhID0gdGYuZ3JhZCh0Zi5ncmFkKGEgPT4gY3VzdG9tUG93KGEpKSkoYSwgZHkpO1xuICAgIGV4cGVjdChkZGEuc2hhcGUpLnRvRXF1YWwoYS5zaGFwZSk7XG5cbiAgICAvLyBGaXJzdCBvcmRlcjogZHkgKiBhLiBTZWNvbmQgb3JkZXI6IGR5LlxuICAgIGV4cGVjdEFycmF5c0Nsb3NlKGF3YWl0IGRkYS5kYXRhKCksIGF3YWl0IGR5LmRhdGEoKSk7XG4gIH0pO1xuXG4gIGl0KCdjYWxsaW5nIGdyYWRpZW50IG9mIGN1c3RvbSBvcCB0d2ljZSB3b3JrcycsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBjdXN0b21PcCA9IHRmLmN1c3RvbUdyYWQoKHg6IHRmLlRlbnNvciwgc2F2ZTogdGYuR3JhZFNhdmVGdW5jKSA9PiB7XG4gICAgICAvLyBPdmVycmlkZSBncmFkaWVudCBvZiBvdXIgY3VzdG9tIHggXiAyIG9wIHRvIGJlIGR5ICogYWJzKHgpO1xuICAgICAgc2F2ZShbeF0pO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdmFsdWU6IHguc3F1YXJlKCksXG4gICAgICAgIGdyYWRGdW5jOiAoZHksIHNhdmVkOiBUZW5zb3JbXSkgPT4ge1xuICAgICAgICAgIGNvbnN0IFt4XSA9IHNhdmVkO1xuICAgICAgICAgIHJldHVybiBkeS5tdWwoeC5hYnMoKSk7XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgfSk7XG4gICAgY29uc3QgeCA9IHRmLnRlbnNvcjFkKFstMSwgLTIsIDNdKTtcbiAgICBjb25zdCBncmFkID0gdGYuZ3JhZCh4ID0+IGN1c3RvbU9wKHgpKTtcblxuICAgIGV4cGVjdEFycmF5c0Nsb3NlKGF3YWl0IGdyYWQoeCkuZGF0YSgpLCBbMSwgMiwgM10pO1xuICAgIGV4cGVjdEFycmF5c0Nsb3NlKGF3YWl0IGdyYWQoeCkuZGF0YSgpLCBbMSwgMiwgM10pO1xuICB9KTtcbn0pO1xuIl19