/**
|
* @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 * as tf from './index';
|
import { ALL_ENVS, describeWithFlags } from './jasmine_util';
|
import { expectArraysClose } from './test_util';
|
describeWithFlags('kernel_registry', ALL_ENVS, (testEnv) => {
|
afterEach(async () => {
|
// Revert backend mutation.
|
await tf.setBackend(testEnv.backendName);
|
});
|
it('register a kernel and call it', () => {
|
// Make sure the backend is loaded. Perhaps tf.getBackend
|
// should call tf.backend to make sure the backend is loaded?
|
expect(tf.backend()).toBeDefined();
|
let called = false;
|
tf.registerKernel({
|
kernelName: 'MyKernel',
|
backendName: tf.getBackend(),
|
kernelFunc: ({ inputs, attrs }) => {
|
expect(attrs.a).toBe(5);
|
expect(inputs.x.shape).toEqual([2, 2]);
|
expect(inputs.x.dtype).toBe('float32');
|
called = true;
|
return { dtype: 'float32', shape: [3, 3], dataId: {} };
|
}
|
});
|
const inputs = { x: tf.zeros([2, 2]) };
|
const attrs = { a: 5 };
|
const res = tf.engine().runKernel('MyKernel', inputs, attrs);
|
expect(called).toBe(true);
|
expect(res.dtype).toBe('float32');
|
expect(res.shape).toEqual([3, 3]);
|
tf.unregisterKernel('MyKernel', tf.getBackend());
|
});
|
it('errors when running non-existent kernel', () => {
|
const inputs = {};
|
const attrs = {};
|
expect(() => tf.engine().runKernel('DoesNotExist', inputs, attrs))
|
.toThrowError();
|
});
|
// TODO (yassogba) double registration happens now because a backend might be
|
// imported more than once (e.g. by a top level package and a dependent
|
// package). We may want to remove this test long-term but skip it for
|
// now.
|
// tslint:disable-next-line: ban
|
xit('errors when registering the same kernel twice', () => {
|
tf.registerBackend('backend1', () => {
|
return {
|
id: 1,
|
dispose: () => null,
|
disposeData: (dataId) => null,
|
numDataIds: () => 0
|
};
|
});
|
tf.registerKernel({
|
kernelName: 'MyKernel',
|
backendName: 'backend1',
|
kernelFunc: () => {
|
return null;
|
}
|
});
|
expect(() => tf.registerKernel({
|
kernelName: 'MyKernel',
|
backendName: 'backend1',
|
kernelFunc: () => {
|
return null;
|
}
|
})).toThrowError();
|
tf.unregisterKernel('MyKernel', 'backend1');
|
tf.removeBackend('backend1');
|
});
|
it('register same kernel on two different backends', async () => {
|
tf.registerBackend('backend1', () => {
|
return {
|
id: 1,
|
dispose: () => null,
|
disposeData: (dataId) => true,
|
numDataIds: () => 0
|
};
|
});
|
tf.registerBackend('backend2', () => {
|
return {
|
id: 2,
|
dispose: () => null,
|
disposeData: (dataId) => null,
|
numDataIds: () => 0
|
};
|
});
|
let lastStorageId = -1;
|
const kernelFunc = ({ backend }) => {
|
lastStorageId = backend.id;
|
return { dataId: {}, shape: [], dtype: 'float32' };
|
};
|
tf.registerKernel({ kernelName: 'MyKernel', backendName: 'backend1', kernelFunc });
|
tf.registerKernel({ kernelName: 'MyKernel', backendName: 'backend2', kernelFunc });
|
// No kernel has been executed yet.
|
expect(lastStorageId).toBe(-1);
|
// Kernel was executed on the first backend.
|
await tf.setBackend('backend1');
|
tf.engine().runKernel('MyKernel', {}, {});
|
expect(lastStorageId).toBe(1);
|
// Kernel was executed on the second backend.
|
await tf.setBackend('backend2');
|
tf.engine().runKernel('MyKernel', {}, {});
|
expect(lastStorageId).toBe(2);
|
tf.removeBackend('backend1');
|
tf.removeBackend('backend2');
|
tf.unregisterKernel('MyKernel', 'backend1');
|
tf.unregisterKernel('MyKernel', 'backend2');
|
});
|
it('register kernel with setup and dispose functions', async () => {
|
const backendName = 'custom-backend';
|
const kernelName = 'MyKernel';
|
const customBackend = {
|
dispose: () => null,
|
disposeData: (dataId) => true,
|
numDataIds: () => 0
|
};
|
tf.registerBackend(backendName, () => customBackend);
|
const kernelFunc = () => {
|
return { dataId: {}, shape: [], dtype: 'float32' };
|
};
|
let setupCalled = false;
|
const setupFunc = (backend) => {
|
expect(backend).toBe(customBackend);
|
setupCalled = true;
|
};
|
let disposeCalled = false;
|
const disposeFunc = (backend) => {
|
expect(backend).toBe(customBackend);
|
disposeCalled = true;
|
};
|
tf.registerKernel({ kernelName, backendName, kernelFunc, setupFunc, disposeFunc });
|
expect(setupCalled).toBe(false);
|
expect(disposeCalled).toBe(false);
|
await tf.setBackend(backendName);
|
expect(setupCalled).toBe(true);
|
expect(disposeCalled).toBe(false);
|
// Kernel was executed on the first backend.
|
tf.engine().runKernel(kernelName, {}, {});
|
tf.removeBackend(backendName);
|
expect(setupCalled).toBe(true);
|
expect(disposeCalled).toBe(true);
|
tf.unregisterKernel(kernelName, backendName);
|
});
|
});
|
describeWithFlags('gradient registry', ALL_ENVS, () => {
|
it('register a kernel with gradient and call it', async () => {
|
let kernelWasCalled = false;
|
let gradientWasCalled = false;
|
const kernelName = 'MyKernel';
|
const x = tf.zeros([2, 2]);
|
tf.registerKernel({
|
kernelName,
|
backendName: tf.getBackend(),
|
kernelFunc: () => {
|
kernelWasCalled = true;
|
return { dtype: 'float32', shape: [3, 3], dataId: {} };
|
}
|
});
|
tf.registerGradient({
|
kernelName,
|
inputsToSave: ['x'],
|
gradFunc: (dy, saved) => {
|
// Make sure saved input (x) was passed to the gradient function.
|
expect(saved[0].dataId).toEqual(x.dataId);
|
// Make sure dy matches the shape of the output.
|
expect(dy.shape).toEqual([3, 3]);
|
gradientWasCalled = true;
|
return { x: () => tf.fill([2, 2], 3) };
|
},
|
});
|
const gradFunc = tf.grad(x => tf.engine().runKernel(kernelName, { x }, {} /* attrs */));
|
const dx = gradFunc(x);
|
expect(kernelWasCalled).toBe(true);
|
expect(gradientWasCalled).toBe(true);
|
expect(dx.dtype).toBe('float32');
|
expect(dx.shape).toEqual([2, 2]);
|
expectArraysClose(await dx.data(), [3, 3, 3, 3]);
|
tf.unregisterKernel(kernelName, tf.getBackend());
|
tf.unregisterGradient(kernelName);
|
});
|
it('register a kernel with gradient that specifies outputsToSave and call it', async () => {
|
let kernelWasCalled = false;
|
let gradientWasCalled = false;
|
const kernelName = 'MyKernel';
|
const tensor = tf.zeros([3, 3], 'float32');
|
const forwardReturnDataId = tensor.dataId;
|
tf.registerKernel({
|
kernelName,
|
backendName: tf.getBackend(),
|
kernelFunc: () => {
|
kernelWasCalled = true;
|
return {
|
dtype: tensor.dtype,
|
shape: tensor.shape,
|
dataId: forwardReturnDataId
|
};
|
}
|
});
|
tf.registerGradient({
|
kernelName,
|
outputsToSave: [true],
|
gradFunc: (dy, saved) => {
|
// Make sure saved output was passed to the gradient function.
|
expect(saved[0].dataId).toEqual(forwardReturnDataId);
|
// Make sure dy matches the shape of the output.
|
expect(dy.shape).toEqual([3, 3]);
|
gradientWasCalled = true;
|
return { x: () => tf.fill([2, 2], 3) };
|
},
|
});
|
const gradFunc = tf.grad(x => tf.engine().runKernel(kernelName, { x }, {} /* attrs */));
|
const x = tf.zeros([2, 2]);
|
const dx = gradFunc(x);
|
expect(kernelWasCalled).toBe(true);
|
expect(gradientWasCalled).toBe(true);
|
expect(dx.dtype).toBe('float32');
|
expect(dx.shape).toEqual([2, 2]);
|
tf.unregisterKernel(kernelName, tf.getBackend());
|
tf.unregisterGradient(kernelName);
|
});
|
it('register a kernel with array inputs and saveAllInputs true', async () => {
|
let kernelWasCalled = false;
|
let gradientWasCalled = false;
|
const kernelName = 'MyKernel';
|
const x = [tf.zeros([2, 2]), tf.zeros([2, 2])];
|
const forwardReturnDataId = {};
|
tf.registerKernel({
|
kernelName,
|
backendName: tf.getBackend(),
|
kernelFunc: () => {
|
kernelWasCalled = true;
|
return { dtype: 'float32', shape: [3, 3], dataId: forwardReturnDataId };
|
}
|
});
|
tf.registerGradient({
|
kernelName,
|
saveAllInputs: true,
|
gradFunc: (dy, saved) => {
|
// Make sure saved input (x) was passed to the gradient function.
|
const [$x0, $x1] = x;
|
expect(saved.length).toEqual(x.length);
|
expect($x0.dataId).toEqual(x[0].dataId);
|
expect($x1.dataId).toEqual(x[1].dataId);
|
gradientWasCalled = true;
|
return { 0: () => tf.fill([2, 2], 3), 1: () => tf.fill([2, 2], 3) };
|
}
|
});
|
// Inputs as array.
|
const z = (...x) =>
|
// tslint:disable-next-line: no-unnecessary-type-assertion
|
tf.engine().runKernel(kernelName, x, {} /* attrs */);
|
const gradFunc = tf.grads(z);
|
const dx = gradFunc(x);
|
expect(kernelWasCalled).toBe(true);
|
expect(gradientWasCalled).toBe(true);
|
expect(dx.length).toEqual(2);
|
expect(dx[0].dtype).toBe('float32');
|
expect(dx[0].shape).toEqual([2, 2]);
|
expect(dx[1].dtype).toBe('float32');
|
expect(dx[1].shape).toEqual([2, 2]);
|
expectArraysClose(await dx[0].data(), [3, 3, 3, 3]);
|
expectArraysClose(await dx[1].data(), [3, 3, 3, 3]);
|
tf.unregisterKernel(kernelName, tf.getBackend());
|
tf.unregisterGradient(kernelName);
|
});
|
it('register a kernel with map inputs and saveAllInputs true should throw ' +
|
'error', async () => {
|
const kernelName = 'MyKernel';
|
const x0 = tf.zeros([2, 2]);
|
const x1 = tf.zeros([2, 2]);
|
const forwardReturnDataId = {};
|
tf.registerKernel({
|
kernelName,
|
backendName: tf.getBackend(),
|
kernelFunc: () => {
|
return {
|
dtype: 'float32',
|
shape: [3, 3],
|
dataId: forwardReturnDataId
|
};
|
}
|
});
|
tf.registerGradient({
|
kernelName,
|
saveAllInputs: true,
|
gradFunc: (dy, saved) => {
|
// Make sure saved input (x) was passed to the gradient function.
|
const [$x0, $x1] = saved;
|
expect($x0.dataId).toEqual(x0.dataId);
|
expect($x1.dataId).toEqual(x1.dataId);
|
return { x0: () => tf.fill([2, 2], 3), x1: () => tf.fill([2, 2], 3) };
|
}
|
});
|
// Inputs as map.
|
const z = (x0, x1) =>
|
// tslint:disable-next-line: no-unnecessary-type-assertion
|
tf.engine().runKernel(kernelName, { x0, x1 }, {} /* attrs */);
|
const gradFunc = tf.grads(z);
|
expect(() => gradFunc([x0, x1]))
|
.toThrowError(/saveAllInputs is true, expected inputs to be an array/);
|
tf.unregisterKernel(kernelName, tf.getBackend());
|
tf.unregisterGradient(kernelName);
|
});
|
it('errors when running non-existent gradient', () => {
|
const kernelName = 'MyKernel';
|
const x = tf.zeros([2, 2]);
|
tf.registerKernel({
|
kernelName,
|
backendName: tf.getBackend(),
|
kernelFunc: () => ({ dtype: 'float32', shape: [3, 3], dataId: {} })
|
});
|
const gradFunc = tf.grad(x => tf.engine().runKernel(kernelName, { x }, {} /* attrs */));
|
expect(() => gradFunc(x))
|
.toThrowError(/gradient function not found for MyKernel/);
|
tf.unregisterKernel(kernelName, tf.getBackend());
|
});
|
// tslint:disable-next-line: ban
|
xit('warning when registering the same gradient twice', () => {
|
const kernelName = 'MyKernel';
|
tf.registerGradient({ kernelName, gradFunc: () => null });
|
spyOn(console, 'warn').and.callFake((msg) => {
|
expect(msg).toBe('Overriding the gradient for \'MyKernel\'');
|
});
|
tf.registerGradient({ kernelName, gradFunc: () => null });
|
tf.unregisterGradient(kernelName);
|
});
|
});
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia2VybmVsX3JlZ2lzdHJ5X3Rlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi90ZmpzLWNvcmUvc3JjL2tlcm5lbF9yZWdpc3RyeV90ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUVILE9BQU8sS0FBSyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBRTlCLE9BQU8sRUFBQyxRQUFRLEVBQUUsaUJBQWlCLEVBQVUsTUFBTSxnQkFBZ0IsQ0FBQztBQUdwRSxPQUFPLEVBQUMsaUJBQWlCLEVBQUMsTUFBTSxhQUFhLENBQUM7QUFFOUMsaUJBQWlCLENBQUMsaUJBQWlCLEVBQUUsUUFBUSxFQUFFLENBQUMsT0FBZ0IsRUFBRSxFQUFFO0lBQ2xFLFNBQVMsQ0FBQyxLQUFLLElBQUksRUFBRTtRQUNuQiwyQkFBMkI7UUFDM0IsTUFBTSxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUMzQyxDQUFDLENBQUMsQ0FBQztJQUVILEVBQUUsQ0FBQywrQkFBK0IsRUFBRSxHQUFHLEVBQUU7UUFDdkMseURBQXlEO1FBQ3pELDZEQUE2RDtRQUM3RCxNQUFNLENBQUMsRUFBRSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDbkMsSUFBSSxNQUFNLEdBQUcsS0FBSyxDQUFDO1FBQ25CLEVBQUUsQ0FBQyxjQUFjLENBQUM7WUFDaEIsVUFBVSxFQUFFLFVBQVU7WUFDdEIsV0FBVyxFQUFFLEVBQUUsQ0FBQyxVQUFVLEVBQUU7WUFDNUIsVUFBVSxFQUFFLENBQUMsRUFBQyxNQUFNLEVBQUUsS0FBSyxFQUFDLEVBQUUsRUFBRTtnQkFDOUIsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ3hCLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxD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Q0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUMsU0FBUyxDQUFDLFVBQVUsRUFBRSxFQUFDLENBQUMsRUFBQyxFQUFFLEVBQUUsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO1FBQ3pFLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7YUFDcEIsWUFBWSxDQUFDLDBDQUEwQyxDQUFDLENBQUM7UUFFOUQsRUFBRSxDQUFDLGdCQUFnQixDQUFDLFVBQVUsRUFBRSxFQUFFLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztJQUNuRCxDQUFDLENBQUMsQ0FBQztJQUVILGdDQUFnQztJQUNoQyxHQUFHLENBQUMsa0RBQWtELEVBQUUsR0FBRyxFQUFFO1FBQzNELE1BQU0sVUFBVSxHQUFHLFVBQVUsQ0FBQztRQUM5QixFQUFFLENBQUMsZ0JBQWdCLENBQUMsRUFBQyxVQUFVLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksRUFBQyxDQUFDLENBQUM7UUFDeEQsS0FBSyxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsR0FBVyxFQUFFLEVBQUU7WUFDbEQsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQywwQ0FBMEMsQ0FBQyxDQUFDO1FBQy9ELENBQUMsQ0FBQyxDQUFDO1FBQ0gsRUFBRSxDQUFDLGdCQUFnQixDQUFDLEVBQUMsVUFBVSxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLEVBQUMsQ0FBQyxDQUFDO1FBQ3hELEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUNwQyxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMTkgR29vZ2xlIExMQy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4gKiB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4gKiBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAqXG4gKiBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAqXG4gKiBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4gKiBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4gKiBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAqIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbiAqIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqL1xuXG5pbXBvcnQgKiBhcyB0ZiBmcm9tICcuL2luZGV4JztcbmltcG9ydCB7S2VybmVsQmFja2VuZH0gZnJvbSAnLi9pbmRleCc7XG5pbXBvcnQge0FMTF9FTlZTLCBkZXNjcmliZVdpdGhGbGFncywgVGVzdEVudn0gZnJvbSAnLi9qYXNtaW5lX3V0aWwnO1xuaW1wb3J0IHsgS2VybmVsRnVuYyB9IGZyb20gJy4va2VybmVsX3JlZ2lzdHJ5JztcbmltcG9ydCB7IFRlbnNvckluZm8gfSBmcm9tICcuL3RlbnNvcl9pbmZvJztcbmltcG9ydCB7ZXhwZWN0QXJyYXlzQ2xvc2V9IGZyb20gJy4vdGVzdF91dGlsJztcblxuZGVzY3JpYmVXaXRoRmxhZ3MoJ2tlcm5lbF9yZWdpc3RyeScsIEFMTF9FTlZTLCAodGVzdEVudjogVGVzdEVudikgPT4ge1xuICBhZnRlckVhY2goYXN5bmMgKCkgPT4ge1xuICAgIC8vIFJldmVydCBiYWNrZW5kIG11dGF0aW9uLlxuICAgIGF3YWl0IHRmLnNldEJhY2tlbmQodGVzdEVudi5iYWNrZW5kTmFtZSk7XG4gIH0pO1xuXG4gIGl0KCdyZWdpc3RlciBhIGtlcm5lbCBhbmQgY2FsbCBpdCcsICgpID0+IHtcbiAgICAvLyBNYWtlIHN1cmUgdGhlIGJhY2tlbmQgaXMgbG9hZGVkLiBQZXJoYXBzIHRmLmdldEJhY2tlbmRcbiAgICAvLyBzaG91bGQgY2FsbCB0Zi5iYWNrZW5kIHRvIG1ha2Ugc3VyZSB0aGUgYmFja2VuZCBpcyBsb2FkZWQ/XG4gICAgZXhwZWN0KHRmLmJhY2tlbmQoKSkudG9CZURlZmluZWQoKTtcbiAgICBsZXQgY2FsbGVkID0gZmFsc2U7XG4gICAgdGYucmVnaXN0ZXJLZXJuZWwoe1xuICAgICAga2VybmVsTmFtZTogJ015S2VybmVsJyxcbiAgICAgIGJhY2tlbmROYW1lOiB0Zi5nZXRCYWNrZW5kKCksXG4gICAgICBrZXJuZWxGdW5jOiAoe2lucHV0cywgYXR0cnN9KSA9PiB7XG4gICAgICAgIGV4cGVjdChhdHRycy5hKS50b0JlKDUpO1xuICAgICAgICBleHBlY3QoaW5wdXRzLnguc2hhcGUpLnRvRXF1YWwoWzIsIDJdKTtcbiAgICAgICAgZXhwZWN0KGlucHV0cy54LmR0eXBlKS50b0JlKCdmbG9hdDMyJyk7XG4gICAgICAgIGNhbGxlZCA9IHRydWU7XG4gICAgICAgIHJldHVybiB7ZHR5cGU6ICdmbG9hdDMyJywgc2hhcGU6IFszLCAzXSwgZGF0YUlkOiB7fX07XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBjb25zdCBpbnB1dHMgPSB7eDogdGYuemVyb3MoWzIsIDJdKX07XG4gICAgY29uc3QgYXR0cnMgPSB7YTogNX07XG4gICAgY29uc3QgcmVzID0gdGYuZW5naW5lKCkucnVuS2VybmVsKCdNeUtlcm5lbCcsIGlucHV0cywgYXR0cnMpIGFzIFRlbnNvckluZm87XG5cbiAgICBleHBlY3QoY2FsbGVkKS50b0JlKHRydWUpO1xuICAgIGV4cGVjdChyZXMuZHR5cGUpLnRvQmUoJ2Zsb2F0MzInKTtcbiAgICBleHBlY3QocmVzLnNoYXBlKS50b0VxdWFsKFszLCAzXSk7XG5cbiAgICB0Zi51bnJlZ2lzdGVyS2VybmVsKCdNeUtlcm5lbCcsIHRmLmdldEJhY2tlbmQoKSk7XG4gIH0pO1xuXG4gIGl0KCdlcnJvcnMgd2hlbiBydW5uaW5nIG5vbi1leGlzdGVudCBrZXJuZWwnLCAoKSA9PiB7XG4gICAgY29uc3QgaW5wdXRzID0ge307XG4gICAgY29uc3QgYXR0cnMgPSB7fTtcbiAgICBleHBlY3QoKCkgPT4gdGYuZW5naW5lKCkucnVuS2VybmVsKCdEb2VzTm90RXhpc3QnLCBpbnB1dHMsIGF0dHJzKSlcbiAgICAgICAgLnRvVGhyb3dFcnJvcigpO1xuICB9KTtcblxuICAvLyBUT0RPICh5YXNzb2diYSkgZG91YmxlIHJlZ2lzdHJhdGlvbiBoYXBwZW5zIG5vdyBiZWNhdXNlIGEgYmFja2VuZCBtaWdodCBiZVxuICAvLyBpbXBvcnRlZCBtb3JlIHRoYW4gb25jZSAoZS5nLiBieSBhIHRvcCBsZXZlbCBwYWNrYWdlIGFuZCBhIGRlcGVuZGVudFxuICAvLyBwYWNrYWdlKS4gV2UgbWF5IHdhbnQgdG8gcmVtb3ZlIHRoaXMgdGVzdCBsb25nLXRlcm0gYnV0IHNraXAgaXQgZm9yXG4gIC8vIG5vdy5cbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOiBiYW5cbiAgeGl0KCdlcnJvcnMgd2hlbiByZWdpc3RlcmluZyB0aGUgc2FtZSBrZXJuZWwgdHdpY2UnLCAoKSA9PiB7XG4gICAgaW50ZXJmYWNlIFRlc3RCYWNrZW5kIGV4dGVuZHMgS2VybmVsQmFja2VuZCB7XG4gICAgICBpZDogbnVtYmVyO1xuICAgIH1cbiAgICB0Zi5yZWdpc3RlckJhY2tlbmQoJ2JhY2tlbmQxJywgKCkgPT4ge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgaWQ6IDEsXG4gICAgICAgIGRpc3Bvc2U6ICgpID0+IG51bGwsXG4gICAgICAgIGRpc3Bvc2VEYXRhOiAoZGF0YUlkOiB7fSkgPT4gbnVsbCxcbiAgICAgICAgbnVtRGF0YUlkczogKCkgPT4gMFxuICAgICAgfSBhcyBUZXN0QmFja2VuZDtcbiAgICB9KTtcblxuICAgIHRmLnJlZ2lzdGVyS2VybmVsKHtcbiAgICAgIGtlcm5lbE5hbWU6ICdNeUtlcm5lbCcsXG4gICAgICBiYWNrZW5kTmFtZTogJ2JhY2tlbmQxJyxcbiAgICAgIGtlcm5lbEZ1bmM6ICgpID0+IHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgfSk7XG4gICAgZXhwZWN0KCgpID0+IHRmLnJlZ2lzdGVyS2VybmVsKHtcbiAgICAgIGtlcm5lbE5hbWU6ICdNeUtlcm5lbCcsXG4gICAgICBiYWNrZW5kTmFtZTogJ2JhY2tlbmQxJyxcbiAgICAgIGtlcm5lbEZ1bmM6ICgpID0+IHtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG4gICAgfSkpLnRvVGhyb3dFcnJvcigpO1xuXG4gICAgdGYudW5yZWdpc3Rlcktlcm5lbCgnTXlLZXJuZWwnLCAnYmFja2VuZDEnKTtcbiAgICB0Zi5yZW1vdmVCYWNrZW5kKCdiYWNrZW5kMScpO1xuICB9KTtcblxuICBpdCgncmVnaXN0ZXIgc2FtZSBrZXJuZWwgb24gdHdvIGRpZmZlcmVudCBiYWNrZW5kcycsIGFzeW5jICgpID0+IHtcbiAgICBpbnRlcmZhY2UgVGVzdEJhY2tlbmQgZXh0ZW5kcyBLZXJuZWxCYWNrZW5kIHtcbiAgICAgIGlkOiBudW1iZXI7XG4gICAgfVxuICAgIHRmLnJlZ2lzdGVyQmFja2VuZCgnYmFja2VuZDEnLCAoKSA9PiB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBpZDogMSxcbiAgICAgICAgZGlzcG9zZTogKCkgPT4gbnVsbCxcbiAgICAgICAgZGlzcG9zZURhdGE6IChkYXRhSWQ6IHt9KSA9PiB0cnVlLFxuICAgICAgICBudW1EYXRhSWRzOiAoKSA9PiAwXG4gICAgICB9IGFzIFRlc3RCYWNrZW5kO1xuICAgIH0pO1xuICAgIHRmLnJlZ2lzdGVyQmFja2VuZCgnYmFja2VuZDInLCAoKSA9PiB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBpZDogMixcbiAgICAgICAgZGlzcG9zZTogKCkgPT4gbnVsbCxcbiAgICAgICAgZGlzcG9zZURhdGE6IChkYXRhSWQ6IHt9KSA9PiBudWxsLFxuICAgICAgICBudW1EYXRhSWRzOiAoKSA9PiAwXG4gICAgICB9IGFzIFRlc3RCYWNrZW5kO1xuICAgIH0pO1xuXG4gICAgbGV0IGxhc3RTdG9yYWdlSWQgPSAtMTtcbiAgICBjb25zdCBrZXJuZWxGdW5jOiBLZXJuZWxGdW5jID0gKHtiYWNrZW5kfSkgPT4ge1xuICAgICAgbGFzdFN0b3JhZ2VJZCA9IChiYWNrZW5kIGFzIFRlc3RCYWNrZW5kKS5pZDtcbiAgICAgIHJldHVybiB7ZGF0YUlkOiB7fSwgc2hhcGU6IFtdLCBkdHlwZTogJ2Zsb2F0MzInfTtcbiAgICB9O1xuICAgIHRmLnJlZ2lzdGVyS2VybmVsKFxuICAgICAgICB7a2VybmVsTmFtZTogJ015S2VybmVsJywgYmFja2VuZE5hbWU6ICdiYWNrZW5kMScsIGtlcm5lbEZ1bmN9KTtcbiAgICB0Zi5yZWdpc3Rlcktlcm5lbChcbiAgICAgICAge2tlcm5lbE5hbWU6ICdNeUtlcm5lbCcsIGJhY2tlbmROYW1lOiAnYmFja2VuZDInLCBrZXJuZWxGdW5jfSk7XG5cbiAgICAvLyBObyBrZXJuZWwgaGFzIGJlZW4gZXhlY3V0ZWQgeWV0LlxuICAgIGV4cGVjdChsYXN0U3RvcmFnZUlkKS50b0JlKC0xKTtcblxuICAgIC8vIEtlcm5lbCB3YXMgZXhlY3V0ZWQgb24gdGhlIGZpcnN0IGJhY2tlbmQuXG4gICAgYXdhaXQgdGYuc2V0QmFja2VuZCgnYmFja2VuZDEnKTtcbiAgICB0Zi5lbmdpbmUoKS5ydW5LZXJuZWwoJ015S2VybmVsJywge30sIHt9KTtcbiAgICBleHBlY3QobGFzdFN0b3JhZ2VJZCkudG9CZSgxKTtcblxuICAgIC8vIEtlcm5lbCB3YXMgZXhlY3V0ZWQgb24gdGhlIHNlY29uZCBiYWNrZW5kLlxuICAgIGF3YWl0IHRmLnNldEJhY2tlbmQoJ2JhY2tlbmQyJyk7XG4gICAgdGYuZW5naW5lKCkucnVuS2VybmVsKCdNeUtlcm5lbCcsIHt9LCB7fSk7XG4gICAgZXhwZWN0KGxhc3RTdG9yYWdlSWQpLnRvQmUoMik7XG5cbiAgICB0Zi5yZW1vdmVCYWNrZW5kKCdiYWNrZW5kMScpO1xuICAgIHRmLnJlbW92ZUJhY2tlbmQoJ2JhY2tlbmQyJyk7XG4gICAgdGYudW5yZWdpc3Rlcktlcm5lbCgnTXlLZXJuZWwnLCAnYmFja2VuZDEnKTtcbiAgICB0Zi51bnJlZ2lzdGVyS2VybmVsKCdNeUtlcm5lbCcsICdiYWNrZW5kMicpO1xuICB9KTtcblxuICBpdCgncmVnaXN0ZXIga2VybmVsIHdpdGggc2V0dXAgYW5kIGRpc3Bvc2UgZnVuY3Rpb25zJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGJhY2tlbmROYW1lID0gJ2N1c3RvbS1iYWNrZW5kJztcbiAgICBjb25zdCBrZXJuZWxOYW1lID0gJ015S2VybmVsJztcbiAgICBpbnRlcmZhY2UgVGVzdEJhY2tlbmQgZXh0ZW5kcyBLZXJuZWxCYWNrZW5kIHt9XG4gICAgY29uc3QgY3VzdG9tQmFja2VuZCA9IHtcbiAgICAgIGRpc3Bvc2U6ICgpID0+IG51bGwsXG4gICAgICBkaXNwb3NlRGF0YTogKGRhdGFJZDoge30pID0+IHRydWUsXG4gICAgICBudW1EYXRhSWRzOiAoKSA9PiAwXG4gICAgfSBhcyBUZXN0QmFja2VuZDtcbiAgICB0Zi5yZWdpc3RlckJhY2tlbmQoYmFja2VuZE5hbWUsICgpID0+IGN1c3RvbUJhY2tlbmQpO1xuXG4gICAgY29uc3Qga2VybmVsRnVuYzogS2VybmVsRnVuYyA9ICgpID0+IHtcbiAgICAgIHJldHVybiB7ZGF0YUlkOiB7fSwgc2hhcGU6IFtdLCBkdHlwZTogJ2Zsb2F0MzInfTtcbiAgICB9O1xuICAgIGxldCBzZXR1cENhbGxlZCA9IGZhbHNlO1xuICAgIGNvbnN0IHNldHVwRnVuYyA9IChiYWNrZW5kOiBLZXJuZWxCYWNrZW5kKSA9PiB7XG4gICAgICBleHBlY3QoYmFja2VuZCkudG9CZShjdXN0b21CYWNrZW5kKTtcbiAgICAgIHNldHVwQ2FsbGVkID0gdHJ1ZTtcbiAgICB9O1xuICAgIGxldCBkaXNwb3NlQ2FsbGVkID0gZmFsc2U7XG4gICAgY29uc3QgZGlzcG9zZUZ1bmMgPSAoYmFja2VuZDogS2VybmVsQmFja2VuZCkgPT4ge1xuICAgICAgZXhwZWN0KGJhY2tlbmQpLnRvQmUoY3VzdG9tQmFja2VuZCk7XG4gICAgICBkaXNwb3NlQ2FsbGVkID0gdHJ1ZTtcbiAgICB9O1xuICAgIHRmLnJlZ2lzdGVyS2VybmVsKFxuICAgICAgICB7a2VybmVsTmFtZSwgYmFja2VuZE5hbWUsIGtlcm5lbEZ1bmMsIHNldHVwRnVuYywgZGlzcG9zZUZ1bmN9KTtcblxuICAgIGV4cGVjdChzZXR1cENhbGxlZCkudG9CZShmYWxzZSk7XG4gICAgZXhwZWN0KGRpc3Bvc2VDYWxsZWQpLnRvQmUoZmFsc2UpO1xuXG4gICAgYXdhaXQgdGYuc2V0QmFja2VuZChiYWNrZW5kTmFtZSk7XG4gICAgZXhwZWN0KHNldHVwQ2FsbGVkKS50b0JlKHRydWUpO1xuICAgIGV4cGVjdChkaXNwb3NlQ2FsbGVkKS50b0JlKGZhbHNlKTtcblxuICAgIC8vIEtlcm5lbCB3YXMgZXhlY3V0ZWQgb24gdGhlIGZpcnN0IGJhY2tlbmQuXG4gICAgdGYuZW5naW5lKCkucnVuS2VybmVsKGtlcm5lbE5hbWUsIHt9LCB7fSk7XG5cbiAgICB0Zi5yZW1vdmVCYWNrZW5kKGJhY2tlbmROYW1lKTtcbiAgICBleHBlY3Qoc2V0dXBDYWxsZWQpLnRvQmUodHJ1ZSk7XG4gICAgZXhwZWN0KGRpc3Bvc2VDYWxsZWQpLnRvQmUodHJ1ZSk7XG5cbiAgICB0Zi51bnJlZ2lzdGVyS2VybmVsKGtlcm5lbE5hbWUsIGJhY2tlbmROYW1lKTtcbiAgfSk7XG59KTtcblxuZGVzY3JpYmVXaXRoRmxhZ3MoJ2dyYWRpZW50IHJlZ2lzdHJ5JywgQUxMX0VOVlMsICgpID0+IHtcbiAgaXQoJ3JlZ2lzdGVyIGEga2VybmVsIHdpdGggZ3JhZGllbnQgYW5kIGNhbGwgaXQnLCBhc3luYyAoKSA9PiB7XG4gICAgbGV0IGtlcm5lbFdhc0NhbGxlZCA9IGZhbHNlO1xuICAgIGxldCBncmFkaWVudFdhc0NhbGxlZCA9IGZhbHNlO1xuICAgIGNvbnN0IGtlcm5lbE5hbWUgPSAnTXlLZXJuZWwnO1xuICAgIGNvbnN0IHggPSB0Zi56ZXJvcyhbMiwgMl0pO1xuXG4gICAgdGYucmVnaXN0ZXJLZXJuZWwoe1xuICAgICAga2VybmVsTmFtZSxcbiAgICAgIGJhY2tlbmROYW1lOiB0Zi5nZXRCYWNrZW5kKCksXG4gICAgICBrZXJuZWxGdW5jOiAoKSA9PiB7XG4gICAgICAgIGtlcm5lbFdhc0NhbGxlZCA9IHRydWU7XG4gICAgICAgIHJldHVybiB7ZHR5cGU6ICdmbG9hdDMyJywgc2hhcGU6IFszLCAzXSwgZGF0YUlkOiB7fX07XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICB0Zi5yZWdpc3RlckdyYWRpZW50KHtcbiAgICAgIGtlcm5lbE5hbWUsXG4gICAgICBpbnB1dHNUb1NhdmU6IFsneCddLFxuICAgICAgZ3JhZEZ1bmM6IChkeTogdGYuVGVuc29yLCBzYXZlZCkgPT4ge1xuICAgICAgICAvLyBNYWtlIHN1cmUgc2F2ZWQgaW5wdXQgKHgpIHdhcyBwYXNzZWQgdG8gdGhlIGdyYWRpZW50IGZ1bmN0aW9uLlxuICAgICAgICBleHBlY3Qoc2F2ZWRbMF0uZGF0YUlkKS50b0VxdWFsKHguZGF0YUlkKTtcbiAgICAgICAgLy8gTWFrZSBzdXJlIGR5IG1hdGNoZXMgdGhlIHNoYXBlIG9mIHRoZSBvdXRwdXQuXG4gICAgICAgIGV4cGVjdChkeS5zaGFwZSkudG9FcXVhbChbMywgM10pO1xuICAgICAgICBncmFkaWVudFdhc0NhbGxlZCA9IHRydWU7XG4gICAgICAgIHJldHVybiB7eDogKCkgPT4gdGYuZmlsbChbMiwgMl0sIDMpfTtcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBjb25zdCBncmFkRnVuYyA9XG4gICAgICAgIHRmLmdyYWQoeCA9PiB0Zi5lbmdpbmUoKS5ydW5LZXJuZWwoa2VybmVsTmFtZSwge3h9LCB7fSAvKiBhdHRycyAqLykpO1xuICAgIGNvbnN0IGR4ID0gZ3JhZEZ1bmMoeCk7XG4gICAgZXhwZWN0KGtlcm5lbFdhc0NhbGxlZCkudG9CZSh0cnVlKTtcbiAgICBleHBlY3QoZ3JhZGllbnRXYXNDYWxsZWQpLnRvQmUodHJ1ZSk7XG4gICAgZXhwZWN0KGR4LmR0eXBlKS50b0JlKCdmbG9hdDMyJyk7XG4gICAgZXhwZWN0KGR4LnNoYXBlKS50b0VxdWFsKFsyLCAyXSk7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgZHguZGF0YSgpLCBbMywgMywgMywgM10pO1xuICAgIHRmLnVucmVnaXN0ZXJLZXJuZWwoa2VybmVsTmFtZSwgdGYuZ2V0QmFja2VuZCgpKTtcbiAgICB0Zi51bnJlZ2lzdGVyR3JhZGllbnQoa2VybmVsTmFtZSk7XG4gIH0pO1xuXG4gIGl0KCdyZWdpc3RlciBhIGtlcm5lbCB3aXRoIGdyYWRpZW50IHRoYXQgc3BlY2lmaWVzIG91dHB1dHNUb1NhdmUgYW5kIGNhbGwgaXQnLFxuICAgICBhc3luYyAoKSA9PiB7XG4gICAgICAgbGV0IGtlcm5lbFdhc0NhbGxlZCA9IGZhbHNlO1xuICAgICAgIGxldCBncmFkaWVudFdhc0NhbGxlZCA9IGZhbHNlO1xuICAgICAgIGNvbnN0IGtlcm5lbE5hbWUgPSAnTXlLZXJuZWwnO1xuXG4gICAgICAgY29uc3QgdGVuc29yID0gdGYuemVyb3MoWzMsIDNdLCAnZmxvYXQzMicpO1xuICAgICAgIGNvbnN0IGZvcndhcmRSZXR1cm5EYXRhSWQgPSB0ZW5zb3IuZGF0YUlkO1xuICAgICAgIHRmLnJlZ2lzdGVyS2VybmVsKHtcbiAgICAgICAgIGtlcm5lbE5hbWUsXG4gICAgICAgICBiYWNrZW5kTmFtZTogdGYuZ2V0QmFja2VuZCgpLFxuICAgICAgICAga2VybmVsRnVuYzogKCkgPT4ge1xuICAgICAgICAgICBrZXJuZWxXYXNDYWxsZWQgPSB0cnVlO1xuICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgIGR0eXBlOiB0ZW5zb3IuZHR5cGUsXG4gICAgICAgICAgICAgc2hhcGU6IHRlbnNvci5zaGFwZSxcbiAgICAgICAgICAgICBkYXRhSWQ6IGZvcndhcmRSZXR1cm5EYXRhSWRcbiAgICAgICAgICAgfTtcbiAgICAgICAgIH1cbiAgICAgICB9KTtcblxuICAgICAgIHRmLnJlZ2lzdGVyR3JhZGllbnQoe1xuICAgICAgICAga2VybmVsTmFtZSxcbiAgICAgICAgIG91dHB1dHNUb1NhdmU6IFt0cnVlXSxcbiAgICAgICAgIGdyYWRGdW5jOiAoZHk6IHRmLlRlbnNvciwgc2F2ZWQpID0+IHtcbiAgICAgICAgICAgLy8gTWFrZSBzdXJlIHNhdmVkIG91dHB1dCB3YXMgcGFzc2VkIHRvIHRoZSBncmFkaWVudCBmdW5jdGlvbi5cbiAgICAgICAgICAgZXhwZWN0KHNhdmVkWzBdLmRhdGFJZCkudG9FcXVhbChmb3J3YXJkUmV0dXJuRGF0YUlkKTtcbiAgICAgICAgICAgLy8gTWFrZSBzdXJlIGR5IG1hdGNoZXMgdGhlIHNoYXBlIG9mIHRoZSBvdXRwdXQuXG4gICAgICAgICAgIGV4cGVjdChkeS5zaGFwZSkudG9FcXVhbChbMywgM10pO1xuICAgICAgICAgICBncmFkaWVudFdhc0NhbGxlZCA9IHRydWU7XG4gICAgICAgICAgIHJldHVybiB7eDogKCkgPT4gdGYuZmlsbChbMiwgMl0sIDMpfTtcbiAgICAgICAgIH0sXG4gICAgICAgfSk7XG5cbiAgICAgICBjb25zdCBncmFkRnVuYyA9IHRmLmdyYWQoXG4gICAgICAgICAgIHggPT4gdGYuZW5naW5lKCkucnVuS2VybmVsKFxuICAgICAgICAgICAgICAga2VybmVsTmFtZSwge3h9LCB7fSAvKiBhdHRycyAqL1xuICAgICAgICAgICAgICAgKSk7XG4gICAgICAgY29uc3QgeCA9IHRmLnplcm9zKFsyLCAyXSk7XG4gICAgICAgY29uc3QgZHggPSBncmFkRnVuYyh4KTtcbiAgICAgICBleHBlY3Qoa2VybmVsV2FzQ2FsbGVkKS50b0JlKHRydWUpO1xuICAgICAgIGV4cGVjdChncmFkaWVudFdhc0NhbGxlZCkudG9CZSh0cnVlKTtcbiAgICAgICBleHBlY3QoZHguZHR5cGUpLnRvQmUoJ2Zsb2F0MzInKTtcbiAgICAgICBleHBlY3QoZHguc2hhcGUpLnRvRXF1YWwoWzIsIDJdKTtcbiAgICAgICB0Zi51bnJlZ2lzdGVyS2VybmVsKGtlcm5lbE5hbWUsIHRmLmdldEJhY2tlbmQoKSk7XG4gICAgICAgdGYudW5yZWdpc3RlckdyYWRpZW50KGtlcm5lbE5hbWUpO1xuICAgICB9KTtcblxuICBpdCgncmVnaXN0ZXIgYSBrZXJuZWwgd2l0aCBhcnJheSBpbnB1dHMgYW5kIHNhdmVBbGxJbnB1dHMgdHJ1ZScsIGFzeW5jICgpID0+IHtcbiAgICBsZXQga2VybmVsV2FzQ2FsbGVkID0gZmFsc2U7XG4gICAgbGV0IGdyYWRpZW50V2FzQ2FsbGVkID0gZmFsc2U7XG4gICAgY29uc3Qga2VybmVsTmFtZSA9ICdNeUtlcm5lbCc7XG4gICAgY29uc3QgeCA9IFt0Zi56ZXJvcyhbMiwgMl0pLCB0Zi56ZXJvcyhbMiwgMl0pXTtcblxuICAgIGNvbnN0IGZvcndhcmRSZXR1cm5EYXRhSWQgPSB7fTtcbiAgICB0Zi5yZWdpc3Rlcktlcm5lbCh7XG4gICAgICBrZXJuZWxOYW1lLFxuICAgICAgYmFja2VuZE5hbWU6IHRmLmdldEJhY2tlbmQoKSxcbiAgICAgIGtlcm5lbEZ1bmM6ICgpID0+IHtcbiAgICAgICAga2VybmVsV2FzQ2FsbGVkID0gdHJ1ZTtcbiAgICAgICAgcmV0dXJuIHtkdHlwZTogJ2Zsb2F0MzInLCBzaGFwZTogWzMsIDNdLCBkYXRhSWQ6IGZvcndhcmRSZXR1cm5EYXRhSWR9O1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGYucmVnaXN0ZXJHcmFkaWVudCh7XG4gICAgICBrZXJuZWxOYW1lLFxuICAgICAgc2F2ZUFsbElucHV0czogdHJ1ZSxcbiAgICAgIGdyYWRGdW5jOiAoZHk6IHRmLlRlbnNvciwgc2F2ZWQpID0+IHtcbiAgICAgICAgLy8gTWFrZSBzdXJlIHNhdmVkIGlucHV0ICh4KSB3YXMgcGFzc2VkIHRvIHRoZSBncmFkaWVudCBmdW5jdGlvbi5cbiAgICAgICAgY29uc3QgWyR4MCwgJHgxXSA9IHg7XG4gICAgICAgIGV4cGVjdChzYXZlZC5sZW5ndGgpLnRvRXF1YWwoeC5sZW5ndGgpO1xuICAgICAgICBleHBlY3QoJHgwLmRhdGFJZCkudG9FcXVhbCh4WzBdLmRhdGFJZCk7XG4gICAgICAgIGV4cGVjdCgkeDEuZGF0YUlkKS50b0VxdWFsKHhbMV0uZGF0YUlkKTtcbiAgICAgICAgZ3JhZGllbnRXYXNDYWxsZWQgPSB0cnVlO1xuICAgICAgICByZXR1cm4gezA6ICgpID0+IHRmLmZpbGwoWzIsIDJdLCAzKSwgMTogKCkgPT4gdGYuZmlsbChbMiwgMl0sIDMpfTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIElucHV0cyBhcyBhcnJheS5cbiAgICBjb25zdCB6ID0gKC4uLng6IHRmLlRlbnNvcltdKSA9PlxuICAgICAgICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6IG5vLXVubmVjZXNzYXJ5LXR5cGUtYXNzZXJ0aW9uXG4gICAgICAgIHRmLmVuZ2luZSgpLnJ1bktlcm5lbChcbiAgICAgICAgICAgIGtlcm5lbE5hbWUsIHggYXMgdW5rbm93biBhcyB0Zi5OYW1lZFRlbnNvck1hcCwge30gLyogYXR0cnMgKi8pIGFzXG4gICAgICAgIHRmLlRlbnNvcjtcbiAgICBjb25zdCBncmFkRnVuYyA9IHRmLmdyYWRzKHopO1xuICAgIGNvbnN0IGR4ID0gZ3JhZEZ1bmMoeCk7XG4gICAgZXhwZWN0KGtlcm5lbFdhc0NhbGxlZCkudG9CZSh0cnVlKTtcbiAgICBleHBlY3QoZ3JhZGllbnRXYXNDYWxsZWQpLnRvQmUodHJ1ZSk7XG4gICAgZXhwZWN0KGR4Lmxlbmd0aCkudG9FcXVhbCgyKTtcbiAgICBleHBlY3QoZHhbMF0uZHR5cGUpLnRvQmUoJ2Zsb2F0MzInKTtcbiAgICBleHBlY3QoZHhbMF0uc2hhcGUpLnRvRXF1YWwoWzIsIDJdKTtcbiAgICBleHBlY3QoZHhbMV0uZHR5cGUpLnRvQmUoJ2Zsb2F0MzInKTtcbiAgICBleHBlY3QoZHhbMV0uc2hhcGUpLnRvRXF1YWwoWzIsIDJdKTtcbiAgICBleHBlY3RBcnJheXNDbG9zZShhd2FpdCBkeFswXS5kYXRhKCksIFszLCAzLCAzLCAzXSk7XG4gICAgZXhwZWN0QXJyYXlzQ2xvc2UoYXdhaXQgZHhbMV0uZGF0YSgpLCBbMywgMywgMywgM10pO1xuICAgIHRmLnVucmVnaXN0ZXJLZXJuZWwoa2VybmVsTmFtZSwgdGYuZ2V0QmFja2VuZCgpKTtcbiAgICB0Zi51bnJlZ2lzdGVyR3JhZGllbnQoa2VybmVsTmFtZSk7XG4gIH0pO1xuXG4gIGl0KCdyZWdpc3RlciBhIGtlcm5lbCB3aXRoIG1hcCBpbnB1dHMgYW5kIHNhdmVBbGxJbnB1dHMgdHJ1ZSBzaG91bGQgdGhyb3cgJyArXG4gICAgICAgICAnZXJyb3InLFxuICAgICBhc3luYyAoKSA9PiB7XG4gICAgICAgY29uc3Qga2VybmVsTmFtZSA9ICdNeUtlcm5lbCc7XG4gICAgICAgY29uc3QgeDAgPSB0Zi56ZXJvcyhbMiwgMl0pO1xuICAgICAgIGNvbnN0IHgxID0gdGYuemVyb3MoWzIsIDJdKTtcblxuICAgICAgIGNvbnN0IGZvcndhcmRSZXR1cm5EYXRhSWQgPSB7fTtcbiAgICAgICB0Zi5yZWdpc3Rlcktlcm5lbCh7XG4gICAgICAgICBrZXJuZWxOYW1lLFxuICAgICAgICAgYmFja2VuZE5hbWU6IHRmLmdldEJhY2tlbmQoKSxcbiAgICAgICAgIGtlcm5lbEZ1bmM6ICgpID0+IHtcbiAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICBkdHlwZTogJ2Zsb2F0MzInLFxuICAgICAgICAgICAgIHNoYXBlOiBbMywgM10sXG4gICAgICAgICAgICAgZGF0YUlkOiBmb3J3YXJkUmV0dXJuRGF0YUlkXG4gICAgICAgICAgIH07XG4gICAgICAgICB9XG4gICAgICAgfSk7XG5cbiAgICAgICB0Zi5yZWdpc3RlckdyYWRpZW50KHtcbiAgICAgICAgIGtlcm5lbE5hbWUsXG4gICAgICAgICBzYXZlQWxsSW5wdXRzOiB0cnVlLFxuICAgICAgICAgZ3JhZEZ1bmM6IChkeTogdGYuVGVuc29yLCBzYXZlZCkgPT4ge1xuICAgICAgICAgICAvLyBNYWtlIHN1cmUgc2F2ZWQgaW5wdXQgKHgpIHdhcyBwYXNzZWQgdG8gdGhlIGdyYWRpZW50IGZ1bmN0aW9uLlxuICAgICAgICAgICBjb25zdCBbJHgwLCAkeDFdID0gc2F2ZWQ7XG4gICAgICAgICAgIGV4cGVjdCgkeDAuZGF0YUlkKS50b0VxdWFsKHgwLmRhdGFJZCk7XG4gICAgICAgICAgIGV4cGVjdCgkeDEuZGF0YUlkKS50b0VxdWFsKHgxLmRhdGFJZCk7XG4gICAgICAgICAgIHJldHVybiB7eDA6ICgpID0+IHRmLmZpbGwoWzIsIDJdLCAzKSwgeDE6ICgpID0+IHRmLmZpbGwoWzIsIDJdLCAzKX07XG4gICAgICAgICB9XG4gICAgICAgfSk7XG5cbiAgICAgICAvLyBJbnB1dHMgYXMgbWFwLlxuICAgICAgIGNvbnN0IHogPSAoeDA6IHRmLlRlbnNvciwgeDE6IHRmLlRlbnNvcikgPT5cbiAgICAgICAgICAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOiBuby11bm5lY2Vzc2FyeS10eXBlLWFzc2VydGlvblxuICAgICAgICAgICB0Zi5lbmdpbmUoKS5ydW5LZXJuZWwoa2VybmVsTmFtZSwge3gwLCB4MX0sIHt9IC8qIGF0dHJzICovKSBhc1xuICAgICAgICAgICB0Zi5UZW5zb3I7XG4gICAgICAgY29uc3QgZ3JhZEZ1bmMgPSB0Zi5ncmFkcyh6KTtcbiAgICAgICBleHBlY3QoKCkgPT4gZ3JhZEZ1bmMoW3gwLCB4MV0pKVxuICAgICAgICAgICAudG9UaHJvd0Vycm9yKFxuICAgICAgICAgICAgICAgL3NhdmVBbGxJbnB1dHMgaXMgdHJ1ZSwgZXhwZWN0ZWQgaW5wdXRzIHRvIGJlIGFuIGFycmF5Lyk7XG4gICAgICAgdGYudW5yZWdpc3Rlcktlcm5lbChrZXJuZWxOYW1lLCB0Zi5nZXRCYWNrZW5kKCkpO1xuICAgICAgIHRmLnVucmVnaXN0ZXJHcmFkaWVudChrZXJuZWxOYW1lKTtcbiAgICAgfSk7XG5cbiAgaXQoJ2Vycm9ycyB3aGVuIHJ1bm5pbmcgbm9uLWV4aXN0ZW50IGdyYWRpZW50JywgKCkgPT4ge1xuICAgIGNvbnN0IGtlcm5lbE5hbWUgPSAnTXlLZXJuZWwnO1xuICAgIGNvbnN0IHggPSB0Zi56ZXJvcyhbMiwgMl0pO1xuXG4gICAgdGYucmVnaXN0ZXJLZXJuZWwoe1xuICAgICAga2VybmVsTmFtZSxcbiAgICAgIGJhY2tlbmROYW1lOiB0Zi5nZXRCYWNrZW5kKCksXG4gICAgICBrZXJuZWxGdW5jOiAoKSA9PiAoe2R0eXBlOiAnZmxvYXQzMicsIHNoYXBlOiBbMywgM10sIGRhdGFJZDoge319KVxuICAgIH0pO1xuXG4gICAgY29uc3QgZ3JhZEZ1bmMgPVxuICAgICAgICB0Zi5ncmFkKHggPT4gdGYuZW5naW5lKCkucnVuS2VybmVsKGtlcm5lbE5hbWUsIHt4fSwge30gLyogYXR0cnMgKi8pKTtcbiAgICBleHBlY3QoKCkgPT4gZ3JhZEZ1bmMoeCkpXG4gICAgICAgIC50b1Rocm93RXJyb3IoL2dyYWRpZW50IGZ1bmN0aW9uIG5vdCBmb3VuZCBmb3IgTXlLZXJuZWwvKTtcblxuICAgIHRmLnVucmVnaXN0ZXJLZXJuZWwoa2VybmVsTmFtZSwgdGYuZ2V0QmFja2VuZCgpKTtcbiAgfSk7XG5cbiAgLy8gdHNsaW50OmRpc2FibGUtbmV4dC1saW5lOiBiYW5cbiAgeGl0KCd3YXJuaW5nIHdoZW4gcmVnaXN0ZXJpbmcgdGhlIHNhbWUgZ3JhZGllbnQgdHdpY2UnLCAoKSA9PiB7XG4gICAgY29uc3Qga2VybmVsTmFtZSA9ICdNeUtlcm5lbCc7XG4gICAgdGYucmVnaXN0ZXJHcmFkaWVudCh7a2VybmVsTmFtZSwgZ3JhZEZ1bmM6ICgpID0+IG51bGx9KTtcbiAgICBzcHlPbihjb25zb2xlLCAnd2FybicpLmFuZC5jYWxsRmFrZSgobXNnOiBzdHJpbmcpID0+IHtcbiAgICAgIGV4cGVjdChtc2cpLnRvQmUoJ092ZXJyaWRpbmcgdGhlIGdyYWRpZW50IGZvciBcXCdNeUtlcm5lbFxcJycpO1xuICAgIH0pO1xuICAgIHRmLnJlZ2lzdGVyR3JhZGllbnQoe2tlcm5lbE5hbWUsIGdyYWRGdW5jOiAoKSA9PiBudWxsfSk7XG4gICAgdGYudW5yZWdpc3RlckdyYWRpZW50KGtlcm5lbE5hbWUpO1xuICB9KTtcbn0pO1xuIl19
|