@tensorflow/tfjs-layers
Version:
TensorFlow layers API in JavaScript
253 lines • 34.9 kB
JavaScript
/**
* @license
* Copyright 2018 Google LLC
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
* =============================================================================
*/
/**
* Advanced activation layers.
*/
import { add, cast, clipByValue, elu, exp, greater, leakyRelu, logSumExp, mul, ones, prelu, relu, scalar, serialization, sub, tidy } from '@tensorflow/tfjs-core';
import { Softmax as softmaxActivation } from '../activations';
import { getConstraint, serializeConstraint } from '../constraints';
import { InputSpec, Layer } from '../engine/topology';
import { NotImplementedError, ValueError } from '../errors';
import { getInitializer, serializeInitializer } from '../initializers';
import { getRegularizer, serializeRegularizer } from '../regularizers';
import { getExactlyOneShape, getExactlyOneTensor } from '../utils/types_utils';
class ReLU extends Layer {
constructor(args) {
super(args == null ? {} : args);
this.supportsMasking = true;
if (args != null) {
this.maxValue = args.maxValue;
}
}
call(inputs, kwargs) {
inputs = getExactlyOneTensor(inputs);
let output = relu(inputs);
if (this.maxValue != null) {
output = clipByValue(output, 0, this.maxValue);
}
return output;
}
computeOutputShape(inputShape) {
return inputShape;
}
getConfig() {
const config = { maxValue: this.maxValue };
const baseConfig = super.getConfig();
Object.assign(config, baseConfig);
return config;
}
}
/** @nocollapse */
ReLU.className = 'ReLU';
export { ReLU };
serialization.registerClass(ReLU);
class LeakyReLU extends Layer {
constructor(args) {
super(args == null ? {} : args);
this.DEFAULT_ALPHA = 0.3;
if (args == null) {
args = {};
}
this.alpha = args.alpha == null ? this.DEFAULT_ALPHA : args.alpha;
}
call(inputs, kwargs) {
const x = getExactlyOneTensor(inputs);
return leakyRelu(x, this.alpha);
}
computeOutputShape(inputShape) {
return inputShape;
}
getConfig() {
const config = { alpha: this.alpha };
const baseConfig = super.getConfig();
Object.assign(config, baseConfig);
return config;
}
}
/** @nocollapse */
LeakyReLU.className = 'LeakyReLU';
export { LeakyReLU };
serialization.registerClass(LeakyReLU);
class PReLU extends Layer {
constructor(args) {
super(args == null ? {} : args);
this.DEFAULT_ALPHA_INITIALIZER = 'zeros';
if (args == null) {
args = {};
}
this.supportsMasking = true;
this.alphaInitializer =
getInitializer(args.alphaInitializer || this.DEFAULT_ALPHA_INITIALIZER);
this.alphaRegularizer = getRegularizer(args.alphaRegularizer);
this.alphaConstraint = getConstraint(args.alphaConstraint);
if (args.sharedAxes == null) {
this.sharedAxes = null;
}
else if (Array.isArray(args.sharedAxes)) {
this.sharedAxes = args.sharedAxes;
}
else if (typeof args.sharedAxes === 'number') {
this.sharedAxes = [args.sharedAxes];
}
else {
throw new ValueError(`Expected sharedAxes to be a number or an array of numbers, ` +
`but got ${args.sharedAxes}`);
}
}
build(inputShape) {
inputShape = getExactlyOneShape(inputShape);
const paramShape = inputShape.slice(1);
if (this.sharedAxes != null) {
for (const i of this.sharedAxes) {
paramShape[i - 1] = 1;
}
}
this.alpha = this.addWeight('alpha', paramShape, 'float32', this.alphaInitializer, this.alphaRegularizer, true, this.alphaConstraint);
// Set input spec.
const axes = {};
if (this.sharedAxes != null) {
for (let i = 1; i < inputShape.length; ++i) {
axes[i] = inputShape[i];
}
}
this.inputSpec = [new InputSpec({
ndim: inputShape.length,
axes,
})];
this.built = true;
}
call(inputs, kwargs) {
inputs = getExactlyOneTensor(inputs);
return prelu(inputs, this.alpha.read());
}
getConfig() {
const config = {
alphaInitializer: serializeInitializer(this.alphaInitializer),
alphaRegularizer: serializeRegularizer(this.alphaRegularizer),
alphaConstraint: serializeConstraint(this.alphaConstraint),
sharedAxes: this.sharedAxes
};
const baseConfig = super.getConfig();
Object.assign(config, baseConfig);
return config;
}
}
/** @nocollapse */
PReLU.className = 'PReLU';
export { PReLU };
serialization.registerClass(PReLU);
class ELU extends Layer {
constructor(args) {
super(args == null ? {} : args);
this.DEFAULT_ALPHA = 1.0;
if (args == null) {
args = {};
}
if (args.alpha != null && args.alpha !== this.DEFAULT_ALPHA) {
throw new NotImplementedError(`Non-default alpha value (${args.alpha}) is not supported by the ` +
`ELU layer yet.`);
}
this.alpha = args.alpha == null ? this.DEFAULT_ALPHA : args.alpha;
}
call(inputs, kwargs) {
const x = getExactlyOneTensor(inputs);
return elu(x);
}
computeOutputShape(inputShape) {
return inputShape;
}
getConfig() {
const config = { alpha: this.alpha };
const baseConfig = super.getConfig();
Object.assign(config, baseConfig);
return config;
}
}
/** @nocollapse */
ELU.className = 'ELU';
export { ELU };
serialization.registerClass(ELU);
class ThresholdedReLU extends Layer {
constructor(args) {
super(args == null ? {} : args);
this.DEFAULT_THETA = 1.0;
if (args == null) {
args = {};
}
this.theta = args.theta == null ? this.DEFAULT_THETA : args.theta;
}
call(inputs, kwargs) {
const x = getExactlyOneTensor(inputs);
return mul(x, cast(greater(x, this.theta), 'float32'));
}
computeOutputShape(inputShape) {
return inputShape;
}
getConfig() {
const config = { theta: this.theta };
const baseConfig = super.getConfig();
Object.assign(config, baseConfig);
return config;
}
}
/** @nocollapse */
ThresholdedReLU.className = 'ThresholdedReLU';
export { ThresholdedReLU };
serialization.registerClass(ThresholdedReLU);
class Softmax extends Layer {
constructor(args) {
super(args == null ? {} : args);
this.DEFAULT_AXIS = 1.0;
if (args == null) {
args = {};
}
this.softmax = new softmaxActivation().apply;
this.axis = args.axis == null ? this.DEFAULT_AXIS : args.axis;
}
call(inputs, kwargs) {
// TODO(pforderique): Add tests for when `this.axis` is a number[].
return tidy(() => {
let x = getExactlyOneTensor(inputs);
const mask = kwargs['mask'];
if (mask != null) {
// Since mask is 1.0 for positions we want to keep and 0.0 for masked
// positions, this operation will create a tensor which is 0.0 for
// positions we want to attend and -1e.9 for masked positions.
const adder = mul(sub(ones(x.shape), cast(mask, x.dtype)), scalar(-1e9));
// Since we are adding it to the raw scores before the softmax, this
// is effectively the same as removing these entirely.
x = add(x, adder);
}
if (this.axis instanceof Array) {
if (this.axis.length > 1) {
return exp(sub(x, logSumExp(x, this.axis, true)));
}
else {
return this.softmax(x, this.axis[0]);
}
}
return this.softmax(x, this.axis);
});
}
computeOutputShape(inputShape) {
return inputShape;
}
getConfig() {
const config = { axis: this.axis };
const baseConfig = super.getConfig();
Object.assign(config, baseConfig);
return config;
}
}
/** @nocollapse */
Softmax.className = 'Softmax';
export { Softmax };
serialization.registerClass(Softmax);
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWR2YW5jZWRfYWN0aXZhdGlvbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi90ZmpzLWxheWVycy9zcmMvbGF5ZXJzL2FkdmFuY2VkX2FjdGl2YXRpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7OztHQVFHO0FBRUg7O0dBRUc7QUFFSCxPQUFPLEVBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLGFBQWEsRUFBRSxHQUFHLEVBQVUsSUFBSSxFQUFDLE1BQU0sdUJBQXVCLENBQUM7QUFFeEssT0FBTyxFQUFDLE9BQU8sSUFBSSxpQkFBaUIsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQzVELE9BQU8sRUFBYSxhQUFhLEVBQUUsbUJBQW1CLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5RSxPQUFPLEVBQUMsU0FBUyxFQUFFLEtBQUssRUFBWSxNQUFNLG9CQUFvQixDQUFDO0FBQy9ELE9BQU8sRUFBQyxtQkFBbUIsRUFBRSxVQUFVLEVBQUMsTUFBTSxXQUFXLENBQUM7QUFDMUQsT0FBTyxFQUFDLGNBQWMsRUFBc0Msb0JBQW9CLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUV6RyxPQUFPLEVBQUMsY0FBYyxFQUFlLG9CQUFvQixFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFFbEYsT0FBTyxFQUFDLGtCQUFrQixFQUFFLG1CQUFtQixFQUFDLE1BQU0sc0JBQXNCLENBQUM7QUFVN0UsTUFBYSxJQUFLLFNBQVEsS0FBSztJQUs3QixZQUFZLElBQW9CO1FBQzlCLEtBQUssQ0FBQyxJQUFJLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2hDLElB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QyxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxVQUFVLENBQUMsQ0FBQztRQUNsQyxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDOztBQW5ERCxrQkFBa0I7QUFDWCxpQkFBUyxHQUFHLFNBQVMsQUFBWixDQUFhO1NBRmxCLE9BQU87QUFzRHBCLGFBQWEsQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgMjAxOCBHb29nbGUgTExDXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlXG4gKiBsaWNlbnNlIHRoYXQgY2FuIGJlIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgb3IgYXRcbiAqIGh0dHBzOi8vb3BlbnNvdXJjZS5vcmcvbGljZW5zZXMvTUlULlxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqL1xuXG4vKipcbiAqICBBZHZhbmNlZCBhY3RpdmF0aW9uIGxheWVycy5cbiAqL1xuXG5pbXBvcnQge2FkZCwgY2FzdCwgY2xpcEJ5VmFsdWUsIGVsdSwgZXhwLCBncmVhdGVyLCBsZWFreVJlbHUsIGxvZ1N1bUV4cCwgbXVsLCBvbmVzLCBwcmVsdSwgcmVsdSwgc2NhbGFyLCBzZXJpYWxpemF0aW9uLCBzdWIsIFRlbnNvciwgdGlkeX0gZnJvbSAnQHRlbnNvcmZsb3cvdGZqcy1jb3JlJztcblxuaW1wb3J0IHtTb2Z0bWF4IGFzIHNvZnRtYXhBY3RpdmF0aW9ufSBmcm9tICcuLi9hY3RpdmF0aW9ucyc7XG5pbXBvcnQge0NvbnN0cmFpbnQsIGdldENvbnN0cmFpbnQsIHNlcmlhbGl6ZUNvbnN0cmFpbnR9IGZyb20gJy4uL2NvbnN0cmFpbnRzJztcbmltcG9ydCB7SW5wdXRTcGVjLCBMYXllciwgTGF5ZXJBcmdzfSBmcm9tICcuLi9lbmdpbmUvdG9wb2xvZ3knO1xuaW1wb3J0IHtOb3RJbXBsZW1lbnRlZEVycm9yLCBWYWx1ZUVycm9yfSBmcm9tICcuLi9lcnJvcnMnO1xuaW1wb3J0IHtnZXRJbml0aWFsaXplciwgSW5pdGlhbGl6ZXIsIEluaXRpYWxpemVySWRlbnRpZmllciwgc2VyaWFsaXplSW5pdGlhbGl6ZXJ9IGZyb20gJy4uL2luaXRpYWxpemVycyc7XG5pbXBvcnQge1NoYXBlfSBmcm9tICcuLi9rZXJhc19mb3JtYXQvY29tbW9uJztcbmltcG9ydCB7Z2V0UmVndWxhcml6ZXIsIFJlZ3VsYXJpemVyLCBzZXJpYWxpemVSZWd1bGFyaXplcn0gZnJvbSAnLi4vcmVndWxhcml6ZXJzJztcbmltcG9ydCB7S3dhcmdzfSBmcm9tICcuLi90eXBlcyc7XG5pbXBvcnQge2dldEV4YWN0bHlPbmVTaGFwZSwgZ2V0RXhhY3RseU9uZVRlbnNvcn0gZnJvbSAnLi4vdXRpbHMvdHlwZXNfdXRpbHMnO1xuaW1wb3J0IHtMYXllclZhcmlhYmxlfSBmcm9tICcuLi92YXJpYWJsZXMnO1xuXG5leHBvcnQgZGVjbGFyZSBpbnRlcmZhY2UgUmVMVUxheWVyQXJncyBleHRlbmRzIExheWVyQXJncyB7XG4gIC8qKlxuICAgKiBGbG9hdCwgdGhlIG1heGltdW0gb3V0cHV0IHZhbHVlLlxuICAgKi9cbiAgbWF4VmFsdWU/OiBudW1iZXI7XG59XG5cbmV4cG9ydCBjbGFzcyBSZUxVIGV4dGVuZHMgTGF5ZXIge1xuICAvKiogQG5vY29sbGFwc2UgKi9cbiAgc3RhdGljIGNsYXNzTmFtZSA9ICdSZUxVJztcbiAgbWF4VmFsdWU6IG51bWJlcjtcblxuICBjb25zdHJ1Y3RvcihhcmdzPzogUmVMVUxheWVyQXJncykge1xuICAgIHN1cGVyKGFyZ3MgPT0gbnVsbCA/IHt9IDogYXJncyk7XG4gICAgdGhpcy5zdXBwb3J0c01hc2tpbmcgPSB0cnVlO1xuICAgIGlmIChhcmdzICE9IG51bGwpIHtcbiAgICAgIHRoaXMubWF4VmFsdWUgPSBhcmdzLm1heFZhbHVlO1xuICAgIH1cbiAgfVxuXG4gIG92ZXJyaWRlIGNhbGwoaW5wdXRzOiBUZW5zb3J8VGVuc29yW10sIGt3YXJnczogS3dhcmdzKTogVGVuc29yfFRlbnNvcltdIHtcbiAgICBpbnB1dHMgPSBnZXRFeGFjdGx5T25lVGVuc29yKGlucHV0cyk7XG4gICAgbGV0IG91dHB1dCA9IHJlbHUoaW5wdXRzKTtcbiAgICBpZiAodGhpcy5tYXhWYWx1ZSAhPSBudWxsKSB7XG4gICAgICBvdXRwdXQgPSBjbGlwQnlWYWx1ZShvdXRwdXQsIDAsIHRoaXMubWF4VmFsdWUpO1xuICAgIH1cbiAgICByZXR1cm4gb3V0cHV0O1xuICB9XG5cbiAgb3ZlcnJpZGUgY29tcHV0ZU91dHB1dFNoYXBlKGlucHV0U2hhcGU6IFNoYXBlfFNoYXBlW10pOiBTaGFwZXxTaGFwZVtdIHtcbiAgICByZXR1cm4gaW5wdXRTaGFwZTtcbiAgfVxuXG4gIG92ZXJyaWRlIGdldENvbmZpZygpOiBzZXJpYWxpemF0aW9uLkNvbmZpZ0RpY3Qge1xuICAgIGNvbnN0IGNvbmZpZzogc2VyaWFsaXphdGlvbi5Db25maWdEaWN0ID0ge21heFZhbHVlOiB0aGlzLm1heFZhbHVlfTtcbiAgICBjb25zdCBiYXNlQ29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgT2JqZWN0LmFzc2lnbihjb25maWcsIGJhc2VDb25maWcpO1xuICAgIHJldHVybiBjb25maWc7XG4gIH1cbn1cbnNlcmlhbGl6YXRpb24ucmVnaXN0ZXJDbGFzcyhSZUxVKTtcblxuZXhwb3J0IGRlY2xhcmUgaW50ZXJmYWNlIExlYWt5UmVMVUxheWVyQXJncyBleHRlbmRzIExheWVyQXJncyB7XG4gIC8qKlxuICAgKiBGbG9hdCBgPj0gMGAuIE5lZ2F0aXZlIHNsb3BlIGNvZWZmaWNpZW50LiBEZWZhdWx0cyB0byBgMC4zYC5cbiAgICovXG4gIGFscGhhPzogbnVtYmVyO1xufVxuXG5leHBvcnQgY2xhc3MgTGVha3lSZUxVIGV4dGVuZHMgTGF5ZXIge1xuICAvKiogQG5vY29sbGFwc2UgKi9cbiAgc3RhdGljIGNsYXNzTmFtZSA9ICdMZWFreVJlTFUnO1xuICByZWFkb25seSBhbHBoYTogbnVtYmVyO1xuXG4gIHJlYWRvbmx5IERFRkFVTFRfQUxQSEEgPSAwLjM7XG5cbiAgY29uc3RydWN0b3IoYXJncz86IExlYWt5UmVMVUxheWVyQXJncykge1xuICAgIHN1cGVyKGFyZ3MgPT0gbnVsbCA/IHt9IDogYXJncyk7XG4gICAgaWYgKGFyZ3MgPT0gbnVsbCkge1xuICAgICAgYXJncyA9IHt9O1xuICAgIH1cbiAgICB0aGlzLmFscGhhID0gYXJncy5hbHBoYSA9PSBudWxsID8gdGhpcy5ERUZBVUxUX0FMUEhBIDogYXJncy5hbHBoYTtcbiAgfVxuXG4gIG92ZXJyaWRlIGNhbGwoaW5wdXRzOiBUZW5zb3J8VGVuc29yW10sIGt3YXJnczogS3dhcmdzKTogVGVuc29yfFRlbnNvcltdIHtcbiAgICBjb25zdCB4ID0gZ2V0RXhhY3RseU9uZVRlbnNvcihpbnB1dHMpO1xuICAgIHJldHVybiBsZWFreVJlbHUoeCwgdGhpcy5hbHBoYSk7XG4gIH1cblxuICBvdmVycmlkZSBjb21wdXRlT3V0cHV0U2hhcGUoaW5wdXRTaGFwZTogU2hhcGV8U2hhcGVbXSk6IFNoYXBlfFNoYXBlW10ge1xuICAgIHJldHVybiBpbnB1dFNoYXBlO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnOiBzZXJpYWxpemF0aW9uLkNvbmZpZ0RpY3QgPSB7YWxwaGE6IHRoaXMuYWxwaGF9O1xuICAgIGNvbnN0IGJhc2VDb25maWcgPSBzdXBlci5nZXRDb25maWcoKTtcbiAgICBPYmplY3QuYXNzaWduKGNvbmZpZywgYmFzZUNvbmZpZyk7XG4gICAgcmV0dXJuIGNvbmZpZztcbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKExlYWt5UmVMVSk7XG5cbmV4cG9ydCBkZWNsYXJlIGludGVyZmFjZSBQUmVMVUxheWVyQXJncyBleHRlbmRzIExheWVyQXJncyB7XG4gIC8qKlxuICAgKiBJbml0aWFsaXplciBmb3IgdGhlIGxlYXJuYWJsZSBhbHBoYS5cbiAgICovXG4gIGFscGhhSW5pdGlhbGl6ZXI/OiBJbml0aWFsaXplcnxJbml0aWFsaXplcklkZW50aWZpZXI7XG5cbiAgLyoqXG4gICAqIFJlZ3VsYXJpemVyIGZvciB0aGUgbGVhcm5hYmxlIGFscGhhLlxuICAgKi9cbiAgYWxwaGFSZWd1bGFyaXplcj86IFJlZ3VsYXJpemVyO1xuXG4gIC8qKlxuICAgKiBDb25zdHJhaW50IGZvciB0aGUgbGVhcm5hYmxlIGFscGhhLlxuICAgKi9cbiAgYWxwaGFDb25zdHJhaW50PzogQ29uc3RyYWludDtcblxuICAvKipcbiAgICogVGhlIGF4ZXMgYWxvbmcgd2hpY2ggdG8gc2hhcmUgbGVhcm5hYmxlIHBhcmFtZXRlcnMgZm9yIHRoZSBhY3RpdmF0aW9uXG4gICAqIGZ1bmN0aW9uLiBGb3IgZXhhbXBsZSwgaWYgdGhlIGluY29taW5nIGZlYXR1cmUgbWFwcyBhcmUgZnJvbSBhIDJEXG4gICAqIGNvbnZvbHV0aW9uIHdpdGggb3V0cHV0IHNoYXBlIGBbbnVtRXhhbXBsZXMsIGhlaWdodCwgd2lkdGgsIGNoYW5uZWxzXWAsXG4gICAqIGFuZCB5b3Ugd2lzaCB0byBzaGFyZSBwYXJhbWV0ZXJzIGFjcm9zcyBzcGFjZSAoaGVpZ2h0IGFuZCB3aWR0aCkgc28gdGhhdFxuICAgKiBlYWNoIGZpbHRlciBjaGFubmVscyBoYXMgb25seSBvbmUgc2V0IG9mIHBhcmFtZXRlcnMsIHNldFxuICAgKiBgc2hhcmVkX2F4ZXM6IFsxLCAyXWAuXG4gICAqL1xuICBzaGFyZWRBeGVzPzogbnVtYmVyfG51bWJlcltdO1xufVxuXG5leHBvcnQgY2xhc3MgUFJlTFUgZXh0ZW5kcyBMYXllciB7XG4gIC8qKiBAbm9jb2xsYXBzZSAqL1xuICBzdGF0aWMgY2xhc3NOYW1lID0gJ1BSZUxVJztcbiAgcHJpdmF0ZSByZWFkb25seSBhbHBoYUluaXRpYWxpemVyOiBJbml0aWFsaXplcjtcbiAgcHJpdmF0ZSByZWFkb25seSBhbHBoYVJlZ3VsYXJpemVyOiBSZWd1bGFyaXplcjtcbiAgcHJpdmF0ZSByZWFkb25seSBhbHBoYUNvbnN0cmFpbnQ6IENvbnN0cmFpbnQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgc2hhcmVkQXhlczogbnVtYmVyW107XG4gIHByaXZhdGUgYWxwaGE6IExheWVyVmFyaWFibGU7XG5cbiAgcmVhZG9ubHkgREVGQVVMVF9BTFBIQV9JTklUSUFMSVpFUjogSW5pdGlhbGl6ZXJJZGVudGlmaWVyID0gJ3plcm9zJztcblxuICBjb25zdHJ1Y3RvcihhcmdzPzogUFJlTFVMYXllckFyZ3MpIHtcbiAgICBzdXBlcihhcmdzID09IG51bGwgPyB7fSA6IGFyZ3MpO1xuICAgIGlmIChhcmdzID09IG51bGwpIHtcbiAgICAgIGFyZ3MgPSB7fTtcbiAgICB9XG5cbiAgICB0aGlzLnN1cHBvcnRzTWFza2luZyA9IHRydWU7XG4gICAgdGhpcy5hbHBoYUluaXRpYWxpemVyID1cbiAgICAgICAgZ2V0SW5pdGlhbGl6ZXIoYXJncy5hbHBoYUluaXRpYWxpemVyIHx8IHRoaXMuREVGQVVMVF9BTFBIQV9JTklUSUFMSVpFUik7XG4gICAgdGhpcy5hbHBoYVJlZ3VsYXJpemVyID0gZ2V0UmVndWxhcml6ZXIoYXJncy5hbHBoYVJlZ3VsYXJpemVyKTtcbiAgICB0aGlzLmFscGhhQ29uc3RyYWludCA9IGdldENvbnN0cmFpbnQoYXJncy5hbHBoYUNvbnN0cmFpbnQpO1xuICAgIGlmIChhcmdzLnNoYXJlZEF4ZXMgPT0gbnVsbCkge1xuICAgICAgdGhpcy5zaGFyZWRBeGVzID0gbnVsbDtcbiAgICB9IGVsc2UgaWYgKEFycmF5LmlzQXJyYXkoYXJncy5zaGFyZWRBeGVzKSkge1xuICAgICAgdGhpcy5zaGFyZWRBeGVzID0gYXJncy5zaGFyZWRBeGVzO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIGFyZ3Muc2hhcmVkQXhlcyA9PT0gJ251bWJlcicpIHtcbiAgICAgIHRoaXMuc2hhcmVkQXhlcyA9IFthcmdzLnNoYXJlZEF4ZXNdO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihcbiAgICAgICAgICBgRXhwZWN0ZWQgc2hhcmVkQXhlcyB0byBiZSBhIG51bWJlciBvciBhbiBhcnJheSBvZiBudW1iZXJzLCBgICtcbiAgICAgICAgICBgYnV0IGdvdCAke2FyZ3Muc2hhcmVkQXhlc31gKTtcbiAgICB9XG4gIH1cblxuICBvdmVycmlkZSBidWlsZChpbnB1dFNoYXBlOiBTaGFwZXxTaGFwZVtdKSB7XG4gICAgaW5wdXRTaGFwZSA9IGdldEV4YWN0bHlPbmVTaGFwZShpbnB1dFNoYXBlKTtcbiAgICBjb25zdCBwYXJhbVNoYXBlOiBTaGFwZSA9IGlucHV0U2hhcGUuc2xpY2UoMSk7XG4gICAgaWYgKHRoaXMuc2hhcmVkQXhlcyAhPSBudWxsKSB7XG4gICAgICBmb3IgKGNvbnN0IGkgb2YgdGhpcy5zaGFyZWRBeGVzKSB7XG4gICAgICAgIHBhcmFtU2hhcGVbaSAtIDFdID0gMTtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5hbHBoYSA9IHRoaXMuYWRkV2VpZ2h0KFxuICAgICAgICAnYWxwaGEnLCBwYXJhbVNoYXBlLCAnZmxvYXQzMicsIHRoaXMuYWxwaGFJbml0aWFsaXplcixcbiAgICAgICAgdGhpcy5hbHBoYVJlZ3VsYXJpemVyLCB0cnVlLCB0aGlzLmFscGhhQ29uc3RyYWludCk7XG4gICAgLy8gU2V0IGlucHV0IHNwZWMuXG4gICAgY29uc3QgYXhlczoge1theGlzOiBudW1iZXJdOiBudW1iZXJ9ID0ge307XG4gICAgaWYgKHRoaXMuc2hhcmVkQXhlcyAhPSBudWxsKSB7XG4gICAgICBmb3IgKGxldCBpID0gMTsgaSA8IGlucHV0U2hhcGUubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgYXhlc1tpXSA9IGlucHV0U2hhcGVbaV07XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMuaW5wdXRTcGVjID0gW25ldyBJbnB1dFNwZWMoe1xuICAgICAgbmRpbTogaW5wdXRTaGFwZS5sZW5ndGgsXG4gICAgICBheGVzLFxuICAgIH0pXTtcbiAgICB0aGlzLmJ1aWx0ID0gdHJ1ZTtcbiAgfVxuXG4gIG92ZXJyaWRlIGNhbGwoaW5wdXRzOiBUZW5zb3J8VGVuc29yW10sIGt3YXJnczogS3dhcmdzKTogVGVuc29yfFRlbnNvcltdIHtcbiAgICBpbnB1dHMgPSBnZXRFeGFjdGx5T25lVGVuc29yKGlucHV0cyk7XG4gICAgcmV0dXJuIHByZWx1KGlucHV0cywgdGhpcy5hbHBoYS5yZWFkKCkpO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgY29uc3QgY29uZmlnOiBzZXJpYWxpemF0aW9uLkNvbmZpZ0RpY3QgPSB7XG4gICAgICBhbHBoYUluaXRpYWxpemVyOiBzZXJpYWxpemVJbml0aWFsaXplcih0aGlzLmFscGhhSW5pdGlhbGl6ZXIpLFxuICAgICAgYWxwaGFSZWd1bGFyaXplcjogc2VyaWFsaXplUmVndWxhcml6ZXIodGhpcy5hbHBoYVJlZ3VsYXJpemVyKSxcbiAgICAgIGFscGhhQ29uc3RyYWludDogc2VyaWFsaXplQ29uc3RyYWludCh0aGlzLmFscGhhQ29uc3RyYWludCksXG4gICAgICBzaGFyZWRBeGVzOiB0aGlzLnNoYXJlZEF4ZXNcbiAgICB9O1xuICAgIGNvbnN0IGJhc2VDb25maWcgPSBzdXBlci5nZXRDb25maWcoKTtcbiAgICBPYmplY3QuYXNzaWduKGNvbmZpZywgYmFzZUNvbmZpZyk7XG4gICAgcmV0dXJuIGNvbmZpZztcbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKFBSZUxVKTtcblxuZXhwb3J0IGRlY2xhcmUgaW50ZXJmYWNlIEVMVUxheWVyQXJncyBleHRlbmRzIExheWVyQXJncyB7XG4gIC8qKlxuICAgKiBGbG9hdCBgPj0gMGAuIE5lZ2F0aXZlIHNsb3BlIGNvZWZmaWNpZW50LiBEZWZhdWx0cyB0byBgMS4wYC5cbiAgICovXG4gIGFscGhhPzogbnVtYmVyO1xufVxuXG5leHBvcnQgY2xhc3MgRUxVIGV4dGVuZHMgTGF5ZXIge1xuICAvKiogQG5vY29sbGFwc2UgKi9cbiAgc3RhdGljIGNsYXNzTmFtZSA9ICdFTFUnO1xuICByZWFkb25seSBhbHBoYTogbnVtYmVyO1xuXG4gIHJlYWRvbmx5IERFRkFVTFRfQUxQSEEgPSAxLjA7XG5cbiAgY29uc3RydWN0b3IoYXJncz86IEVMVUxheWVyQXJncykge1xuICAgIHN1cGVyKGFyZ3MgPT0gbnVsbCA/IHt9IDogYXJncyk7XG4gICAgaWYgKGFyZ3MgPT0gbnVsbCkge1xuICAgICAgYXJncyA9IHt9O1xuICAgIH1cblxuICAgIGlmIChhcmdzLmFscGhhICE9IG51bGwgJiYgYXJncy5hbHBoYSAhPT0gdGhpcy5ERUZBVUxUX0FMUEhBKSB7XG4gICAgICB0aHJvdyBuZXcgTm90SW1wbGVtZW50ZWRFcnJvcihcbiAgICAgICAgICBgTm9uLWRlZmF1bHQgYWxwaGEgdmFsdWUgKCR7YXJncy5hbHBoYX0pIGlzIG5vdCBzdXBwb3J0ZWQgYnkgdGhlIGAgK1xuICAgICAgICAgIGBFTFUgbGF5ZXIgeWV0LmApO1xuICAgIH1cblxuICAgIHRoaXMuYWxwaGEgPSBhcmdzLmFscGhhID09IG51bGwgPyB0aGlzLkRFRkFVTFRfQUxQSEEgOiBhcmdzLmFscGhhO1xuICB9XG5cbiAgb3ZlcnJpZGUgY2FsbChpbnB1dHM6IFRlbnNvcnxUZW5zb3JbXSwga3dhcmdzOiBLd2FyZ3MpOiBUZW5zb3J8VGVuc29yW10ge1xuICAgIGNvbnN0IHggPSBnZXRFeGFjdGx5T25lVGVuc29yKGlucHV0cyk7XG4gICAgcmV0dXJuIGVsdSh4KTtcbiAgfVxuXG4gIG92ZXJyaWRlIGNvbXB1dGVPdXRwdXRTaGFwZShpbnB1dFNoYXBlOiBTaGFwZXxTaGFwZVtdKTogU2hhcGV8U2hhcGVbXSB7XG4gICAgcmV0dXJuIGlucHV0U2hhcGU7XG4gIH1cblxuICBvdmVycmlkZSBnZXRDb25maWcoKTogc2VyaWFsaXphdGlvbi5Db25maWdEaWN0IHtcbiAgICBjb25zdCBjb25maWc6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCA9IHthbHBoYTogdGhpcy5hbHBoYX07XG4gICAgY29uc3QgYmFzZUNvbmZpZyA9IHN1cGVyLmdldENvbmZpZygpO1xuICAgIE9iamVjdC5hc3NpZ24oY29uZmlnLCBiYXNlQ29uZmlnKTtcbiAgICByZXR1cm4gY29uZmlnO1xuICB9XG59XG5zZXJpYWxpemF0aW9uLnJlZ2lzdGVyQ2xhc3MoRUxVKTtcblxuZXhwb3J0IGRlY2xhcmUgaW50ZXJmYWNlIFRocmVzaG9sZGVkUmVMVUxheWVyQXJncyBleHRlbmRzIExheWVyQXJncyB7XG4gIC8qKlxuICAgKiBGbG9hdCA+PSAwLiBUaHJlc2hvbGQgbG9jYXRpb24gb2YgYWN0aXZhdGlvbi5cbiAgICovXG4gIHRoZXRhPzogbnVtYmVyO1xufVxuXG5leHBvcnQgY2xhc3MgVGhyZXNob2xkZWRSZUxVIGV4dGVuZHMgTGF5ZXIge1xuICAvKiogQG5vY29sbGFwc2UgKi9cbiAgc3RhdGljIGNsYXNzTmFtZSA9ICdUaHJlc2hvbGRlZFJlTFUnO1xuICByZWFkb25seSB0aGV0YTogbnVtYmVyO1xuXG4gIHJlYWRvbmx5IERFRkFVTFRfVEhFVEEgPSAxLjA7XG5cbiAgY29uc3RydWN0b3IoYXJncz86IFRocmVzaG9sZGVkUmVMVUxheWVyQXJncykge1xuICAgIHN1cGVyKGFyZ3MgPT0gbnVsbCA/IHt9IDogYXJncyk7XG4gICAgaWYgKGFyZ3MgPT0gbnVsbCkge1xuICAgICAgYXJncyA9IHt9O1xuICAgIH1cblxuICAgIHRoaXMudGhldGEgPSBhcmdzLnRoZXRhID09IG51bGwgPyB0aGlzLkRFRkFVTFRfVEhFVEEgOiBhcmdzLnRoZXRhO1xuICB9XG5cbiAgb3ZlcnJpZGUgY2FsbChpbnB1dHM6IFRlbnNvcnxUZW5zb3JbXSwga3dhcmdzOiBLd2FyZ3MpOiBUZW5zb3J8VGVuc29yW10ge1xuICAgIGNvbnN0IHggPSBnZXRFeGFjdGx5T25lVGVuc29yKGlucHV0cyk7XG4gICAgcmV0dXJuIG11bCh4LCBjYXN0KGdyZWF0ZXIoeCwgdGhpcy50aGV0YSksICdmbG9hdDMyJykpO1xuICB9XG5cbiAgb3ZlcnJpZGUgY29tcHV0ZU91dHB1dFNoYXBlKGlucHV0U2hhcGU6IFNoYXBlfFNoYXBlW10pOiBTaGFwZXxTaGFwZVtdIHtcbiAgICByZXR1cm4gaW5wdXRTaGFwZTtcbiAgfVxuXG4gIG92ZXJyaWRlIGdldENvbmZpZygpOiBzZXJpYWxpemF0aW9uLkNvbmZpZ0RpY3Qge1xuICAgIGNvbnN0IGNvbmZpZzogc2VyaWFsaXphdGlvbi5Db25maWdEaWN0ID0ge3RoZXRhOiB0aGlzLnRoZXRhfTtcbiAgICBjb25zdCBiYXNlQ29uZmlnID0gc3VwZXIuZ2V0Q29uZmlnKCk7XG4gICAgT2JqZWN0LmFzc2lnbihjb25maWcsIGJhc2VDb25maWcpO1xuICAgIHJldHVybiBjb25maWc7XG4gIH1cbn1cbnNlcmlhbGl6YXRpb24ucmVnaXN0ZXJDbGFzcyhUaHJlc2hvbGRlZFJlTFUpO1xuXG5leHBvcnQgZGVjbGFyZSBpbnRlcmZhY2UgU29mdG1heExheWVyQXJncyBleHRlbmRzIExheWVyQXJncyB7XG4gIC8qKlxuICAgKiBJbnRlZ2VyLCBheGlzIGFsb25nIHdoaWNoIHRoZSBzb2Z0bWF4IG5vcm1hbGl6YXRpb24gaXMgYXBwbGllZC5cbiAgICogRGVmYXVsdHMgdG8gYC0xYCAoaS5lLiwgdGhlIGxhc3QgYXhpcykuXG4gICAqL1xuICBheGlzPzogbnVtYmVyfG51bWJlcltdO1xufVxuXG5leHBvcnQgY2xhc3MgU29mdG1heCBleHRlbmRzIExheWVyIHtcbiAgLyoqIEBub2NvbGxhcHNlICovXG4gIHN0YXRpYyBjbGFzc05hbWUgPSAnU29mdG1heCc7XG4gIHJlYWRvbmx5IGF4aXM6IG51bWJlcnxudW1iZXJbXTtcbiAgcmVhZG9ubHkgc29mdG1heDogKHQ6IFRlbnNvciwgYT86IG51bWJlcikgPT4gVGVuc29yO1xuICByZWFkb25seSBERUZBVUxUX0FYSVMgPSAxLjA7XG5cbiAgY29uc3RydWN0b3IoYXJncz86IFNvZnRtYXhMYXllckFyZ3MpIHtcbiAgICBzdXBlcihhcmdzID09IG51bGwgPyB7fSA6IGFyZ3MpO1xuICAgIGlmIChhcmdzID09IG51bGwpIHtcbiAgICAgIGFyZ3MgPSB7fTtcbiAgICB9XG4gICAgdGhpcy5zb2Z0bWF4ID0gbmV3IHNvZnRtYXhBY3RpdmF0aW9uKCkuYXBwbHk7XG4gICAgdGhpcy5heGlzID0gYXJncy5heGlzID09IG51bGwgPyB0aGlzLkRFRkFVTFRfQVhJUyA6IGFyZ3MuYXhpcztcbiAgfVxuXG4gIG92ZXJyaWRlIGNhbGwoaW5wdXRzOiBUZW5zb3J8VGVuc29yW10sIGt3YXJnczogS3dhcmdzKTogVGVuc29yfFRlbnNvcltdIHtcbiAgICAvLyBUT0RPKHBmb3JkZXJpcXVlKTogQWRkIHRlc3RzIGZvciB3aGVuIGB0aGlzLmF4aXNgIGlzIGEgbnVtYmVyW10uXG4gICAgcmV0dXJuIHRpZHkoKCkgPT4ge1xuICAgICAgbGV0IHggPSBnZXRFeGFjdGx5T25lVGVuc29yKGlucHV0cyk7XG4gICAgICBjb25zdCBtYXNrID0ga3dhcmdzWydtYXNrJ10gYXMgVGVuc29yO1xuICAgICAgaWYgKG1hc2sgIT0gbnVsbCkge1xuICAgICAgICAvLyBTaW5jZSBtYXNrIGlzIDEuMCBmb3IgcG9zaXRpb25zIHdlIHdhbnQgdG8ga2VlcCBhbmQgMC4wIGZvciBtYXNrZWRcbiAgICAgICAgLy8gcG9zaXRpb25zLCB0aGlzIG9wZXJhdGlvbiB3aWxsIGNyZWF0ZSBhIHRlbnNvciB3aGljaCBpcyAwLjAgZm9yXG4gICAgICAgIC8vIHBvc2l0aW9ucyB3ZSB3YW50IHRvIGF0dGVuZCBhbmQgLTFlLjkgZm9yIG1hc2tlZCBwb3NpdGlvbnMuXG4gICAgICAgIGNvbnN0IGFkZGVyID1cbiAgICAgICAgICBtdWwoc3ViKG9uZXMoeC5zaGFwZSksIGNhc3QobWFzaywgeC5kdHlwZSkpLCBzY2FsYXIoLTFlOSkpO1xuXG4gICAgICAgIC8vIFNpbmNlIHdlIGFyZSBhZGRpbmcgaXQgdG8gdGhlIHJhdyBzY29yZXMgYmVmb3JlIHRoZSBzb2Z0bWF4LCB0aGlzXG4gICAgICAgIC8vIGlzIGVmZmVjdGl2ZWx5IHRoZSBzYW1lIGFzIHJlbW92aW5nIHRoZXNlIGVudGlyZWx5LlxuICAgICAgICB4ID0gYWRkKHgsIGFkZGVyKTtcbiAgICAgIH1cbiAgICAgIGlmICh0aGlzLmF4aXMgaW5zdGFuY2VvZiBBcnJheSkge1xuICAgICAgICBpZiAodGhpcy5heGlzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICByZXR1cm4gZXhwKHN1Yih4LCBsb2dTdW1FeHAoeCwgdGhpcy5heGlzLCB0cnVlKSkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiB0aGlzLnNvZnRtYXgoeCwgdGhpcy5heGlzWzBdKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXMuc29mdG1heCh4LCB0aGlzLmF4aXMpO1xuICAgIH0pO1xuICB9XG5cbiAgb3ZlcnJpZGUgY29tcHV0ZU91dHB1dFNoYXBlKGlucHV0U2hhcGU6IFNoYXBlfFNoYXBlW10pOiBTaGFwZXxTaGFwZVtdIHtcbiAgICByZXR1cm4gaW5wdXRTaGFwZTtcbiAgfVxuXG4gIG92ZXJyaWRlIGdldENvbmZpZygpOiBzZXJpYWxpemF0aW9uLkNvbmZpZ0RpY3Qge1xuICAgIGNvbnN0IGNvbmZpZzogc2VyaWFsaXphdGlvbi5Db25maWdEaWN0ID0ge2F4aXM6IHRoaXMuYXhpc307XG4gICAgY29uc3QgYmFzZUNvbmZpZyA9IHN1cGVyLmdldENvbmZpZygpO1xuICAgIE9iamVjdC5hc3NpZ24oY29uZmlnLCBiYXNlQ29uZmlnKTtcbiAgICByZXR1cm4gY29uZmlnO1xuICB9XG59XG5zZXJpYWxpemF0aW9uLnJlZ2lzdGVyQ2xhc3MoU29mdG1heCk7XG4iXX0=