gx
chenyc
2025-06-12 7b72ac13a83764a662159d4a49b7fffb90476ecb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
/**
 * @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