/**
|
* @license
|
* Copyright 2018 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 * as tf from '../index';
|
import { ALL_ENVS, describeWithFlags } from '../jasmine_util';
|
import { expectArraysClose } from '../test_util';
|
import { Optimizer } from './optimizer';
|
import { SGDOptimizer } from './sgd_optimizer';
|
describeWithFlags('optimizer', ALL_ENVS, () => {
|
it('basic', async () => {
|
const initialTensors = tf.memory().numTensors;
|
const learningRate = .1;
|
const optimizer = tf.train.sgd(learningRate);
|
const x = tf.scalar(4).variable();
|
const bias = tf.scalar(1).variable();
|
const strayVariable = tf.scalar(-1).variable();
|
let numTensors = tf.memory().numTensors;
|
// tslint:disable-next-line: no-unnecessary-type-assertion
|
const f = () => x.square().add(bias);
|
let cost = optimizer.minimize(f, /* returnCost */ true);
|
// Cost should be the only additional arrays.
|
expect(tf.memory().numTensors).toBe(numTensors + 1);
|
// de/dx = 2x
|
const expectedX1 = -2 * 4 * learningRate + 4;
|
// de/db = 1
|
const expectedBias1 = -1 * learningRate + 1;
|
expectArraysClose(await x.data(), [expectedX1]);
|
expectArraysClose(await bias.data(), [expectedBias1]);
|
expectArraysClose(await cost.data(), [Math.pow(4, 2) + 1]);
|
// The stray variable should remain unchanged.
|
expectArraysClose(await strayVariable.data(), [-1]);
|
cost.dispose();
|
numTensors = tf.memory().numTensors;
|
cost = optimizer.minimize(f, /* returnCost */ false);
|
// There should be no new additional Tensors.
|
expect(tf.memory().numTensors).toBe(numTensors);
|
const expectedX2 = -2 * expectedX1 * learningRate + expectedX1;
|
const expectedBias2 = -learningRate + expectedBias1;
|
expectArraysClose(await x.data(), [expectedX2]);
|
expectArraysClose(await bias.data(), [expectedBias2]);
|
expect(cost).toBe(null);
|
// The stray variable should remain unchanged.
|
expectArraysClose(await strayVariable.data(), [-1]);
|
optimizer.dispose();
|
x.dispose();
|
bias.dispose();
|
strayVariable.dispose();
|
// The only additional tensors remaining are the arguments to variable().
|
expect(tf.memory().numTensors).toBe(initialTensors + 3);
|
});
|
it('varList array of all variables', async () => {
|
const learningRate = .1;
|
const optimizer = new SGDOptimizer(learningRate);
|
const x = tf.scalar(4).variable();
|
const bias = tf.scalar(1).variable();
|
const strayVariable = tf.scalar(-1).variable();
|
const varList = [x, bias];
|
// tslint:disable-next-line: no-unnecessary-type-assertion
|
const f = () => x.square().add(bias);
|
let cost = optimizer.minimize(f, /* returnCost */ true, varList);
|
// de/dx = 2x
|
const expectedX1 = -2 * 4 * learningRate + 4;
|
// de/db = 1
|
const expectedBias1 = -1 * learningRate + 1;
|
expectArraysClose(await x.data(), [expectedX1]);
|
expectArraysClose(await bias.data(), [expectedBias1]);
|
expectArraysClose(await cost.data(), [Math.pow(4, 2) + 1]);
|
// The stray variable should remain unchanged.
|
expectArraysClose(await strayVariable.data(), [-1]);
|
cost = optimizer.minimize(f, /* returnCost */ false, varList);
|
const expectedX2 = -2 * expectedX1 * learningRate + expectedX1;
|
const expectedBias2 = -learningRate + expectedBias1;
|
expectArraysClose(await x.data(), [expectedX2]);
|
expectArraysClose(await bias.data(), [expectedBias2]);
|
// The stray variable should remain unchanged.
|
expectArraysClose(await strayVariable.data(), [-1]);
|
expect(cost).toBe(null);
|
});
|
it('varList empty array of variables throws error', () => {
|
const learningRate = .1;
|
const optimizer = new SGDOptimizer(learningRate);
|
const x = tf.scalar(4).variable();
|
const bias = tf.scalar(1).variable();
|
// Stray variable.
|
tf.scalar(-1).variable();
|
const varList = [];
|
// tslint:disable-next-line: no-unnecessary-type-assertion
|
const f = () => x.square().add(bias);
|
expect(() => optimizer.minimize(f, /* returnCost */ true, varList))
|
.toThrowError();
|
});
|
it('varList subset of variables update', async () => {
|
const learningRate = .1;
|
const optimizer = new SGDOptimizer(learningRate);
|
const x = tf.scalar(4).variable();
|
const bias = tf.scalar(1).variable();
|
const strayVariable = tf.scalar(-1).variable();
|
const varList = [x];
|
// tslint:disable-next-line: no-unnecessary-type-assertion
|
const f = () => x.square().add(bias);
|
let cost = optimizer.minimize(f, /* returnCost */ true, varList);
|
// de/dx = 2x
|
const expectedValue1 = -2 * 4 * learningRate + 4;
|
expectArraysClose(await x.data(), [expectedValue1]);
|
// bias should remain unchanged.
|
expectArraysClose(await bias.data(), [1]);
|
expectArraysClose(await cost.data(), [Math.pow(4, 2) + 1]);
|
// The stray variable should remain unchanged.
|
expectArraysClose(await strayVariable.data(), [-1]);
|
cost = optimizer.minimize(f, /* returnCost */ false, varList);
|
const expectedValue2 = -2 * expectedValue1 * learningRate + expectedValue1;
|
expectArraysClose(await x.data(), [expectedValue2]);
|
// Bias still should remain unchanged.
|
expectArraysClose(await bias.data(), [1]);
|
expect(cost).toBe(null);
|
// The stray variable should remain unchanged.
|
expectArraysClose(await strayVariable.data(), [-1]);
|
});
|
it('only bias trainable', async () => {
|
const learningRate = .1;
|
const optimizer = new SGDOptimizer(learningRate);
|
const trainable = false;
|
const x = tf.scalar(4).variable(trainable);
|
const bias = tf.scalar(1).variable();
|
const strayVariable = tf.scalar(-1).variable();
|
// tslint:disable-next-line: no-unnecessary-type-assertion
|
const f = () => x.square().add(bias);
|
let cost = optimizer.minimize(f, /* returnCost */ true);
|
// x should not have been updated.
|
expectArraysClose(await x.data(), [4]);
|
// de/db = 1
|
const expectedBias1 = -1 * learningRate + 1;
|
expectArraysClose(await bias.data(), [expectedBias1]);
|
expectArraysClose(await cost.data(), [Math.pow(4, 2) + 1]);
|
// The stray variable should remain unchanged.
|
expectArraysClose(await strayVariable.data(), [-1]);
|
cost = optimizer.minimize(f, /* returnCost */ false);
|
// x should not have been updated.
|
expectArraysClose(await x.data(), [4]);
|
const expectedBias2 = -learningRate + expectedBias1;
|
expectArraysClose(await bias.data(), [expectedBias2]);
|
expect(cost).toBe(null);
|
// The stray variable should remain unchanged.
|
expectArraysClose(await strayVariable.data(), [-1]);
|
});
|
it('only bias trainable, only x in varList throws error', () => {
|
const learningRate = .1;
|
const optimizer = new SGDOptimizer(learningRate);
|
const trainable = false;
|
const x = tf.scalar(4).variable(trainable);
|
const bias = tf.scalar(1).variable();
|
// stray variable.
|
tf.scalar(-1).variable();
|
const varList = [x];
|
// tslint:disable-next-line: no-unnecessary-type-assertion
|
const f = () => x.square().add(bias);
|
expect(() => optimizer.minimize(f, /* returnCost */ true, varList))
|
.toThrowError();
|
});
|
it('instanceof Optimizer', () => {
|
const learningRate = .1;
|
const optimizer = new SGDOptimizer(learningRate);
|
expect(optimizer instanceof Optimizer).toBe(true);
|
});
|
it('throws error when f returns a non-scalar', () => {
|
const learningRate = .1;
|
const optimizer = new SGDOptimizer(learningRate);
|
const x = tf.tensor1d([1, 2]).variable();
|
const f = () => x.square();
|
// tslint:disable-next-line:no-any
|
expect(() => optimizer.minimize(f)).toThrowError();
|
});
|
});
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3B0aW1pemVyX3Rlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi90ZmpzLWNvcmUvc3JjL29wdGltaXplcnMvb3B0aW1pemVyX3Rlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBRUgsT0FBTyxLQUFLLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFDL0IsT0FBTyxFQUFDLFFBQVEsRUFBRSxpQkFBaUIsRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBRTVELE9BQU8sRUFBQyxpQkFBaUIsRUFBQyxNQUFNLGNBQWMsQ0FBQztBQUUvQyxPQUFPLEVBQUMsU0FBUyxFQUFDLE1BQU0sYUFBYSxDQUFDO0FBQ3RDLE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUU3QyxpQkFBaUIsQ0FBQyxXQUFXLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRTtJQUM1QyxFQUFFLENBQUMsT0FBTyxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQ3JCLE1BQU0sY0FBYyxHQUFHLEVBQUUsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxVQUFVLENBQUM7UUFDOUMsTUFBTSxZQUFZLEdBQUcsRUFBRSxDQUFDO1FBQ3hCLE1BQU0sU0FBUyxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBRTdDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDbEMsTUFBTSxJQUFJLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNyQyxNQUFNLGFBQWEsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUM7UUFFL0MsSUFBSSxVQUFVLEdBQUcsRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFD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OlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMTggR29vZ2xlIExMQy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqL1xuXG5pbXBvcnQgKiBhcyB0ZiBmcm9tICcuLi9pbmRleCc7XG5pbXBvcnQge0FMTF9FTlZTLCBkZXNjcmliZVdpdGhGbGFnc30gZnJvbSAnLi4vamFzbWluZV91dGlsJztcbmltcG9ydCB7VmFyaWFibGV9IGZyb20gJy4uL3RlbnNvcic7XG5pbXBvcnQge2V4cGVjdEFycmF5c0Nsb3NlfSBmcm9tICcuLi90ZXN0X3V0aWwnO1xuXG5pbXBvcnQge09wdGltaXplcn0gZnJvbSAnLi9vcHRpbWl6ZXInO1xuaW1wb3J0IHtTR0RPcHRpbWl6ZXJ9IGZyb20gJy4vc2dkX29wdGltaXplcic7XG5cbmRlc2NyaWJlV2l0aEZsYWdzKCdvcHRpbWl6ZXInLCBBTExfRU5WUywgKCkgPT4ge1xuICBpdCgnYmFzaWMnLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgaW5pdGlhbFRlbnNvcnMgPSB0Zi5tZW1vcnkoKS5udW1UZW5zb3JzO1xuICAgIGNvbnN0IGxlYXJuaW5nUmF0ZSA9IC4xO1xuICAgIGNvbnN0IG9wdGltaXplciA9IHRmLnRyYWluLnNnZChsZWFybmluZ1JhdGUpO1xuXG4gICAgY29uc3QgeCA9IHRmLnNjYWxhcig0KS52YXJpYWJsZSgpO1xuICAgIGNvbnN0IGJpYXMgPSB0Zi5zY2FsYXIoMSkudmFyaWFibGUoKTtcbiAgICBjb25zdCBzdHJheVZhcmlhYmxlID0gdGYuc2NhbGFyKC0xKS52YXJpYWJsZSgpO1xuXG4gICAgbGV0IG51bVRlbnNvcnMgPSB0Zi5tZW1vcnkoKS5udW1UZW5zb3JzO1xuXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOiBuby11bm5lY2Vzc2FyeS10eXBlLWFzc2VydGlvblxuICAgIGNvbnN0IGYgPSAoKSA9PiB4LnNxdWFyZSgpLmFkZChiaWFzKSBhcyB0Zi5TY2FsYXI7XG5cbiAgICBsZXQgY29zdCA9IG9wdGltaXplci5taW5pbWl6ZShmLCAvKiByZXR1cm5Db3N0ICovIHRydWUpO1xuXG4gICAgLy8gQ29zdCBzaG91bGQgYmUgdGhlIG9ubHkgYWRkaXRpb25hbCBhcnJheXMuXG4gICAgZXhwZWN0KHRmLm1lbW9yeSgpLm51bVRlbnNvcnMpLnRvQmUobnVtVGVuc29ycyArIDEpO1xuXG4gICAgLy8gZGUvZHggPSAyeFxuICAgIGNvbnN0IGV4cGVjdGVkWDEgPSAtMiAqIDQgKiBsZWFybmluZ1JhdGUgKyA0O1xuICAgIC8vIGRlL2RiID0gMVxuICAgIGNvbnN0IGV4cGVjdGVkQmlhczEgPSAtMSAqIGxlYXJuaW5nUmF0ZSArIDE7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgeC5kYXRhKCksIFtleHBlY3RlZFgxXSk7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgYmlhcy5kYXRhKCksIFtleHBlY3RlZEJpYXMxXSk7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgY29zdC5kYXRhKCksIFtNYXRoLnBvdyg0LCAyKSArIDFdKTtcbiAgICAvLyBUaGUgc3RyYXkgdmFyaWFibGUgc2hvdWxkIHJlbWFpbiB1bmNoYW5nZWQuXG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgc3RyYXlWYXJpYWJsZS5kYXRhKCksIFstMV0pO1xuXG4gICAgY29zdC5kaXNwb3NlKCk7XG4gICAgbnVtVGVuc29ycyA9IHRmLm1lbW9yeSgpLm51bVRlbnNvcnM7XG5cbiAgICBjb3N0ID0gb3B0aW1pemVyLm1pbmltaXplKGYsIC8qIHJldHVybkNvc3QgKi8gZmFsc2UpO1xuICAgIC8vIFRoZXJlIHNob3VsZCBiZSBubyBuZXcgYWRkaXRpb25hbCBUZW5zb3JzLlxuICAgIGV4cGVjdCh0Zi5tZW1vcnkoKS5udW1UZW5zb3JzKS50b0JlKG51bVRlbnNvcnMpO1xuXG4gICAgY29uc3QgZXhwZWN0ZWRYMiA9IC0yICogZXhwZWN0ZWRYMSAqIGxlYXJuaW5nUmF0ZSArIGV4cGVjdGVkWDE7XG4gICAgY29uc3QgZXhwZWN0ZWRCaWFzMiA9IC1sZWFybmluZ1JhdGUgKyBleHBlY3RlZEJpYXMxO1xuICAgIGV4cGVjdEFycmF5c0Nsb3NlKGF3YWl0IHguZGF0YSgpLCBbZXhwZWN0ZWRYMl0pO1xuICAgIGV4cGVjdEFycmF5c0Nsb3NlKGF3YWl0IGJpYXMuZGF0YSgpLCBbZXhwZWN0ZWRCaWFzMl0pO1xuICAgIGV4cGVjdChjb3N0KS50b0JlKG51bGwpO1xuICAgIC8vIFRoZSBzdHJheSB2YXJpYWJsZSBzaG91bGQgcmVtYWluIHVuY2hhbmdlZC5cbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCBzdHJheVZhcmlhYmxlLmRhdGEoKSwgWy0xXSk7XG5cbiAgICBvcHRpbWl6ZXIuZGlzcG9zZSgpO1xuICAgIHguZGlzcG9zZSgpO1xuICAgIGJpYXMuZGlzcG9zZSgpO1xuICAgIHN0cmF5VmFyaWFibGUuZGlzcG9zZSgpO1xuICAgIC8vIFRoZSBvbmx5IGFkZGl0aW9uYWwgdGVuc29ycyByZW1haW5pbmcgYXJlIHRoZSBhcmd1bWVudHMgdG8gdmFyaWFibGUoKS5cbiAgICBleHBlY3QodGYubWVtb3J5KCkubnVtVGVuc29ycykudG9CZShpbml0aWFsVGVuc29ycyArIDMpO1xuICB9KTtcblxuICBpdCgndmFyTGlzdCBhcnJheSBvZiBhbGwgdmFyaWFibGVzJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGxlYXJuaW5nUmF0ZSA9IC4xO1xuICAgIGNvbnN0IG9wdGltaXplciA9IG5ldyBTR0RPcHRpbWl6ZXIobGVhcm5pbmdSYXRlKTtcblxuICAgIGNvbnN0IHggPSB0Zi5zY2FsYXIoNCkudmFyaWFibGUoKTtcbiAgICBjb25zdCBiaWFzID0gdGYuc2NhbGFyKDEpLnZhcmlhYmxlKCk7XG4gICAgY29uc3Qgc3RyYXlWYXJpYWJsZSA9IHRmLnNjYWxhcigtMSkudmFyaWFibGUoKTtcbiAgICBjb25zdCB2YXJMaXN0ID0gW3gsIGJpYXNdO1xuXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOiBuby11bm5lY2Vzc2FyeS10eXBlLWFzc2VydGlvblxuICAgIGNvbnN0IGYgPSAoKSA9PiB4LnNxdWFyZSgpLmFkZChiaWFzKSBhcyB0Zi5TY2FsYXI7XG5cbiAgICBsZXQgY29zdCA9IG9wdGltaXplci5taW5pbWl6ZShmLCAvKiByZXR1cm5Db3N0ICovIHRydWUsIHZhckxpc3QpO1xuXG4gICAgLy8gZGUvZHggPSAyeFxuICAgIGNvbnN0IGV4cGVjdGVkWDEgPSAtMiAqIDQgKiBsZWFybmluZ1JhdGUgKyA0O1xuICAgIC8vIGRlL2RiID0gMVxuICAgIGNvbnN0IGV4cGVjdGVkQmlhczEgPSAtMSAqIGxlYXJuaW5nUmF0ZSArIDE7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgeC5kYXRhKCksIFtleHBlY3RlZFgxXSk7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgYmlhcy5kYXRhKCksIFtleHBlY3RlZEJpYXMxXSk7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgY29zdC5kYXRhKCksIFtNYXRoLnBvdyg0LCAyKSArIDFdKTtcbiAgICAvLyBUaGUgc3RyYXkgdmFyaWFibGUgc2hvdWxkIHJlbWFpbiB1bmNoYW5nZWQuXG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgc3RyYXlWYXJpYWJsZS5kYXRhKCksIFstMV0pO1xuXG4gICAgY29zdCA9IG9wdGltaXplci5taW5pbWl6ZShmLCAvKiByZXR1cm5Db3N0ICovIGZhbHNlLCB2YXJMaXN0KTtcblxuICAgIGNvbnN0IGV4cGVjdGVkWDIgPSAtMiAqIGV4cGVjdGVkWDEgKiBsZWFybmluZ1JhdGUgKyBleHBlY3RlZFgxO1xuICAgIGNvbnN0IGV4cGVjdGVkQmlhczIgPSAtbGVhcm5pbmdSYXRlICsgZXhwZWN0ZWRCaWFzMTtcbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCB4LmRhdGEoKSwgW2V4cGVjdGVkWDJdKTtcbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCBiaWFzLmRhdGEoKSwgW2V4cGVjdGVkQmlhczJdKTtcbiAgICAvLyBUaGUgc3RyYXkgdmFyaWFibGUgc2hvdWxkIHJlbWFpbiB1bmNoYW5nZWQuXG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgc3RyYXlWYXJpYWJsZS5kYXRhKCksIFstMV0pO1xuICAgIGV4cGVjdChjb3N0KS50b0JlKG51bGwpO1xuICB9KTtcblxuICBpdCgndmFyTGlzdCBlbXB0eSBhcnJheSBvZiB2YXJpYWJsZXMgdGhyb3dzIGVycm9yJywgKCkgPT4ge1xuICAgIGNvbnN0IGxlYXJuaW5nUmF0ZSA9IC4xO1xuICAgIGNvbnN0IG9wdGltaXplciA9IG5ldyBTR0RPcHRpbWl6ZXIobGVhcm5pbmdSYXRlKTtcblxuICAgIGNvbnN0IHggPSB0Zi5zY2FsYXIoNCkudmFyaWFibGUoKTtcbiAgICBjb25zdCBiaWFzID0gdGYuc2NhbGFyKDEpLnZhcmlhYmxlKCk7XG4gICAgLy8gU3RyYXkgdmFyaWFibGUuXG4gICAgdGYuc2NhbGFyKC0xKS52YXJpYWJsZSgpO1xuICAgIGNvbnN0IHZhckxpc3Q6IFZhcmlhYmxlW10gPSBbXTtcblxuICAgIC8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTogbm8tdW5uZWNlc3NhcnktdHlwZS1hc3NlcnRpb25cbiAgICBjb25zdCBmID0gKCkgPT4geC5zcXVhcmUoKS5hZGQoYmlhcykgYXMgdGYuU2NhbGFyO1xuXG4gICAgZXhwZWN0KCgpID0+IG9wdGltaXplci5taW5pbWl6ZShmLCAvKiByZXR1cm5Db3N0ICovIHRydWUsIHZhckxpc3QpKVxuICAgICAgICAudG9UaHJvd0Vycm9yKCk7XG4gIH0pO1xuXG4gIGl0KCd2YXJMaXN0IHN1YnNldCBvZiB2YXJpYWJsZXMgdXBkYXRlJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGxlYXJuaW5nUmF0ZSA9IC4xO1xuICAgIGNvbnN0IG9wdGltaXplciA9IG5ldyBTR0RPcHRpbWl6ZXIobGVhcm5pbmdSYXRlKTtcblxuICAgIGNvbnN0IHggPSB0Zi5zY2FsYXIoNCkudmFyaWFibGUoKTtcbiAgICBjb25zdCBiaWFzID0gdGYuc2NhbGFyKDEpLnZhcmlhYmxlKCk7XG4gICAgY29uc3Qgc3RyYXlWYXJpYWJsZSA9IHRmLnNjYWxhcigtMSkudmFyaWFibGUoKTtcbiAgICBjb25zdCB2YXJMaXN0ID0gW3hdO1xuXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOiBuby11bm5lY2Vzc2FyeS10eXBlLWFzc2VydGlvblxuICAgIGNvbnN0IGYgPSAoKSA9PiB4LnNxdWFyZSgpLmFkZChiaWFzKSBhcyB0Zi5TY2FsYXI7XG5cbiAgICBsZXQgY29zdCA9IG9wdGltaXplci5taW5pbWl6ZShmLCAvKiByZXR1cm5Db3N0ICovIHRydWUsIHZhckxpc3QpO1xuXG4gICAgLy8gZGUvZHggPSAyeFxuICAgIGNvbnN0IGV4cGVjdGVkVmFsdWUxID0gLTIgKiA0ICogbGVhcm5pbmdSYXRlICsgNDtcbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCB4LmRhdGEoKSwgW2V4cGVjdGVkVmFsdWUxXSk7XG4gICAgLy8gYmlhcyBzaG91bGQgcmVtYWluIHVuY2hhbmdlZC5cbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCBiaWFzLmRhdGEoKSwgWzFdKTtcbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCBjb3N0LmRhdGEoKSwgW01hdGgucG93KDQsIDIpICsgMV0pO1xuICAgIC8vIFRoZSBzdHJheSB2YXJpYWJsZSBzaG91bGQgcmVtYWluIHVuY2hhbmdlZC5cbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCBzdHJheVZhcmlhYmxlLmRhdGEoKSwgWy0xXSk7XG5cbiAgICBjb3N0ID0gb3B0aW1pemVyLm1pbmltaXplKGYsIC8qIHJldHVybkNvc3QgKi8gZmFsc2UsIHZhckxpc3QpO1xuXG4gICAgY29uc3QgZXhwZWN0ZWRWYWx1ZTIgPSAtMiAqIGV4cGVjdGVkVmFsdWUxICogbGVhcm5pbmdSYXRlICsgZXhwZWN0ZWRWYWx1ZTE7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgeC5kYXRhKCksIFtleHBlY3RlZFZhbHVlMl0pO1xuICAgIC8vIEJpYXMgc3RpbGwgc2hvdWxkIHJlbWFpbiB1bmNoYW5nZWQuXG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgYmlhcy5kYXRhKCksIFsxXSk7XG4gICAgZXhwZWN0KGNvc3QpLnRvQmUobnVsbCk7XG4gICAgLy8gVGhlIHN0cmF5IHZhcmlhYmxlIHNob3VsZCByZW1haW4gdW5jaGFuZ2VkLlxuICAgIGV4cGVjdEFycmF5c0Nsb3NlKGF3YWl0IHN0cmF5VmFyaWFibGUuZGF0YSgpLCBbLTFdKTtcbiAgfSk7XG5cbiAgaXQoJ29ubHkgYmlhcyB0cmFpbmFibGUnLCBhc3luYyAoKSA9PiB7XG4gICAgY29uc3QgbGVhcm5pbmdSYXRlID0gLjE7XG4gICAgY29uc3Qgb3B0aW1pemVyID0gbmV3IFNHRE9wdGltaXplcihsZWFybmluZ1JhdGUpO1xuXG4gICAgY29uc3QgdHJhaW5hYmxlID0gZmFsc2U7XG4gICAgY29uc3QgeCA9IHRmLnNjYWxhcig0KS52YXJpYWJsZSh0cmFpbmFibGUpO1xuICAgIGNvbnN0IGJpYXMgPSB0Zi5zY2FsYXIoMSkudmFyaWFibGUoKTtcbiAgICBjb25zdCBzdHJheVZhcmlhYmxlID0gdGYuc2NhbGFyKC0xKS52YXJpYWJsZSgpO1xuXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOiBuby11bm5lY2Vzc2FyeS10eXBlLWFzc2VydGlvblxuICAgIGNvbnN0IGYgPSAoKSA9PiB4LnNxdWFyZSgpLmFkZChiaWFzKSBhcyB0Zi5TY2FsYXI7XG5cbiAgICBsZXQgY29zdCA9IG9wdGltaXplci5taW5pbWl6ZShmLCAvKiByZXR1cm5Db3N0ICovIHRydWUpO1xuXG4gICAgLy8geCBzaG91bGQgbm90IGhhdmUgYmVlbiB1cGRhdGVkLlxuICAgIGV4cGVjdEFycmF5c0Nsb3NlKGF3YWl0IHguZGF0YSgpLCBbNF0pO1xuICAgIC8vIGRlL2RiID0gMVxuICAgIGNvbnN0IGV4cGVjdGVkQmlhczEgPSAtMSAqIGxlYXJuaW5nUmF0ZSArIDE7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgYmlhcy5kYXRhKCksIFtleHBlY3RlZEJpYXMxXSk7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgY29zdC5kYXRhKCksIFtNYXRoLnBvdyg0LCAyKSArIDFdKTtcbiAgICAvLyBUaGUgc3RyYXkgdmFyaWFibGUgc2hvdWxkIHJlbWFpbiB1bmNoYW5nZWQuXG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgc3RyYXlWYXJpYWJsZS5kYXRhKCksIFstMV0pO1xuXG4gICAgY29zdCA9IG9wdGltaXplci5taW5pbWl6ZShmLCAvKiByZXR1cm5Db3N0ICovIGZhbHNlKTtcblxuICAgIC8vIHggc2hvdWxkIG5vdCBoYXZlIGJlZW4gdXBkYXRlZC5cbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCB4LmRhdGEoKSwgWzRdKTtcbiAgICBjb25zdCBleHBlY3RlZEJpYXMyID0gLWxlYXJuaW5nUmF0ZSArIGV4cGVjdGVkQmlhczE7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgYmlhcy5kYXRhKCksIFtleHBlY3RlZEJpYXMyXSk7XG4gICAgZXhwZWN0KGNvc3QpLnRvQmUobnVsbCk7XG4gICAgLy8gVGhlIHN0cmF5IHZhcmlhYmxlIHNob3VsZCByZW1haW4gdW5jaGFuZ2VkLlxuICAgIGV4cGVjdEFycmF5c0Nsb3NlKGF3YWl0IHN0cmF5VmFyaWFibGUuZGF0YSgpLCBbLTFdKTtcbiAgfSk7XG5cbiAgaXQoJ29ubHkgYmlhcyB0cmFpbmFibGUsIG9ubHkgeCBpbiB2YXJMaXN0IHRocm93cyBlcnJvcicsICgpID0+IHtcbiAgICBjb25zdCBsZWFybmluZ1JhdGUgPSAuMTtcbiAgICBjb25zdCBvcHRpbWl6ZXIgPSBuZXcgU0dET3B0aW1pemVyKGxlYXJuaW5nUmF0ZSk7XG5cbiAgICBjb25zdCB0cmFpbmFibGUgPSBmYWxzZTtcbiAgICBjb25zdCB4ID0gdGYuc2NhbGFyKDQpLnZhcmlhYmxlKHRyYWluYWJsZSk7XG4gICAgY29uc3QgYmlhcyA9IHRmLnNjYWxhcigxKS52YXJpYWJsZSgpO1xuICAgIC8vIHN0cmF5IHZhcmlhYmxlLlxuICAgIHRmLnNjYWxhcigtMSkudmFyaWFibGUoKTtcbiAgICBjb25zdCB2YXJMaXN0ID0gW3hdO1xuXG4gICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOiBuby11bm5lY2Vzc2FyeS10eXBlLWFzc2VydGlvblxuICAgIGNvbnN0IGYgPSAoKSA9PiB4LnNxdWFyZSgpLmFkZChiaWFzKSBhcyB0Zi5TY2FsYXI7XG5cbiAgICBleHBlY3QoKCkgPT4gb3B0aW1pemVyLm1pbmltaXplKGYsIC8qIHJldHVybkNvc3QgKi8gdHJ1ZSwgdmFyTGlzdCkpXG4gICAgICAgIC50b1Rocm93RXJyb3IoKTtcbiAgfSk7XG5cbiAgaXQoJ2luc3RhbmNlb2YgT3B0aW1pemVyJywgKCkgPT4ge1xuICAgIGNvbnN0IGxlYXJuaW5nUmF0ZSA9IC4xO1xuICAgIGNvbnN0IG9wdGltaXplciA9IG5ldyBTR0RPcHRpbWl6ZXIobGVhcm5pbmdSYXRlKTtcblxuICAgIGV4cGVjdChvcHRpbWl6ZXIgaW5zdGFuY2VvZiBPcHRpbWl6ZXIpLnRvQmUodHJ1ZSk7XG4gIH0pO1xuXG4gIGl0KCd0aHJvd3MgZXJyb3Igd2hlbiBmIHJldHVybnMgYSBub24tc2NhbGFyJywgKCkgPT4ge1xuICAgIGNvbnN0IGxlYXJuaW5nUmF0ZSA9IC4xO1xuICAgIGNvbnN0IG9wdGltaXplciA9IG5ldyBTR0RPcHRpbWl6ZXIobGVhcm5pbmdSYXRlKTtcblxuICAgIGNvbnN0IHggPSB0Zi50ZW5zb3IxZChbMSwgMl0pLnZhcmlhYmxlKCk7XG4gICAgY29uc3QgZiA9ICgpID0+IHguc3F1YXJlKCk7XG5cbiAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tYW55XG4gICAgZXhwZWN0KCgpID0+IG9wdGltaXplci5taW5pbWl6ZShmIGFzIGFueSkpLnRvVGhyb3dFcnJvcigpO1xuICB9KTtcbn0pO1xuIl19
|