@tensorflow/tfjs-layers
Version:
TensorFlow layers API in JavaScript
151 lines • 21.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.
* =============================================================================
*/
/* Original source: keras/contraints.py */
import * as tfc from '@tensorflow/tfjs-core';
import { serialization, tidy } from '@tensorflow/tfjs-core';
import { epsilon } from './backend/common';
import { deserializeKerasObject, serializeKerasObject } from './utils/generic_utils';
/**
* Helper function used by many of the Constraints to find the L2Norms.
*/
function calcL2Norms(w, axis) {
return tidy(() => tfc.sqrt(tfc.sum(tfc.mul(w, w), axis, true)));
}
/**
* Base class for functions that impose constraints on weight values
*
* @doc {
* heading: 'Constraints',
* subheading: 'Classes',
* namespace: 'constraints'
* }
*/
export class Constraint extends serialization.Serializable {
getConfig() {
return {};
}
}
class MaxNorm extends Constraint {
constructor(args) {
super();
this.defaultMaxValue = 2;
this.defaultAxis = 0;
this.maxValue =
args.maxValue != null ? args.maxValue : this.defaultMaxValue;
this.axis = args.axis != null ? args.axis : this.defaultAxis;
}
apply(w) {
return tidy(() => {
const norms = calcL2Norms(w, this.axis);
const desired = tfc.clipByValue(norms, 0, this.maxValue);
return tfc.mul(w, tfc.div(desired, tfc.add(epsilon(), norms)));
});
}
getConfig() {
return { maxValue: this.maxValue, axis: this.axis };
}
}
/** @nocollapse */
MaxNorm.className = 'MaxNorm';
export { MaxNorm };
serialization.registerClass(MaxNorm);
class UnitNorm extends Constraint {
constructor(args) {
super();
this.defaultAxis = 0;
this.axis = args.axis != null ? args.axis : this.defaultAxis;
}
apply(w) {
return tidy(() => tfc.div(w, tfc.add(epsilon(), calcL2Norms(w, this.axis))));
}
getConfig() {
return { axis: this.axis };
}
}
/** @nocollapse */
UnitNorm.className = 'UnitNorm';
export { UnitNorm };
serialization.registerClass(UnitNorm);
class NonNeg extends Constraint {
apply(w) {
return tfc.relu(w);
}
}
/** @nocollapse */
NonNeg.className = 'NonNeg';
export { NonNeg };
serialization.registerClass(NonNeg);
class MinMaxNorm extends Constraint {
constructor(args) {
super();
this.defaultMinValue = 0.0;
this.defaultMaxValue = 1.0;
this.defaultRate = 1.0;
this.defaultAxis = 0;
this.minValue =
args.minValue != null ? args.minValue : this.defaultMinValue;
this.maxValue =
args.maxValue != null ? args.maxValue : this.defaultMaxValue;
this.rate = args.rate != null ? args.rate : this.defaultRate;
this.axis = args.axis != null ? args.axis : this.defaultAxis;
}
apply(w) {
return tidy(() => {
const norms = calcL2Norms(w, this.axis);
const desired = tfc.add(tfc.mul(this.rate, tfc.clipByValue(norms, this.minValue, this.maxValue)), tfc.mul(1.0 - this.rate, norms));
return tfc.mul(w, tfc.div(desired, tfc.add(epsilon(), norms)));
});
}
getConfig() {
return {
minValue: this.minValue,
maxValue: this.maxValue,
rate: this.rate,
axis: this.axis
};
}
}
/** @nocollapse */
MinMaxNorm.className = 'MinMaxNorm';
export { MinMaxNorm };
serialization.registerClass(MinMaxNorm);
// Maps the JavaScript-like identifier keys to the corresponding registry
// symbols.
export const CONSTRAINT_IDENTIFIER_REGISTRY_SYMBOL_MAP = {
'maxNorm': 'MaxNorm',
'minMaxNorm': 'MinMaxNorm',
'nonNeg': 'NonNeg',
'unitNorm': 'UnitNorm'
};
export function serializeConstraint(constraint) {
return serializeKerasObject(constraint);
}
export function deserializeConstraint(config, customObjects = {}) {
return deserializeKerasObject(config, serialization.SerializationMap.getMap().classNameMap, customObjects, 'constraint');
}
export function getConstraint(identifier) {
if (identifier == null) {
return null;
}
if (typeof identifier === 'string') {
const className = identifier in CONSTRAINT_IDENTIFIER_REGISTRY_SYMBOL_MAP ?
CONSTRAINT_IDENTIFIER_REGISTRY_SYMBOL_MAP[identifier] :
identifier;
const config = { className, config: {} };
return deserializeConstraint(config);
}
else if (identifier instanceof Constraint) {
return identifier;
}
else {
return deserializeConstraint(identifier);
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RyYWludHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi90ZmpzLWxheWVycy9zcmMvY29uc3RyYWludHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7O0dBUUc7QUFFSCwwQ0FBMEM7QUFFMUMsT0FBTyxLQUFLLEdBQUcsTUFBTSx1QkFBdUIsQ0FBQztBQUM3QyxPQUFPLEVBQUMsYUFBYSxFQUFVLElBQUksRUFBQyxNQUFNLHVCQUF1QixDQUFDO0FBQ2xFLE9BQU8sRUFBQyxPQUFPLEVBQUMsTUFBTSxrQkFBa0IsQ0FBQztBQUN6QyxPQUFPLEVBQUMsc0JBQXNCLEVBQUUsb0JBQW9CLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUVuRjs7R0FFRztBQUNILFNBQVMsV0FBVyxDQUFDLENBQVMsRUFBRSxJQUFZO0lBQzFDLE9BQU8sSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ2xFLENBQUM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sT0FBZ0IsVUFBVyxTQUFRLGFBQWEsQ0FBQyxZQUFZO0lBR2pFLFNBQVM7UUFDUCxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7Q0FDRjtBQXdCRCxNQUFhLE9BQVEsU0FBUSxVQUFVO0lBUXJDLFlBQVksSUFBaUI7UUFDM0IsS0FBSyxFQUFFLENBQUM7UUFKTyxvQkFBZSxHQUFHLENBQUMsQ0FBQztRQUNwQixnQkFBVyxHQUFHLENBQUMsQ0FBQztRQUkvQixJQUFJLENBQUMsUUFBUTtZQUNULElBQUksQ0FBQyxRQUFRLElBQUksSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsZUFB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LE1BQU0sQ0FBQyxDQUFDO0tBQ3RDO1NBQU0sSUFBSSxVQUFVLFlBQVksVUFBVSxFQUFFO1FBQzNDLE9BQU8sVUFBVSxDQUFDO0tBQ25CO1NBQU07UUFDTCxPQUFPLHFCQUFxQixDQUFDLFVBQVUsQ0FBQyxDQUFDO0tBQzFDO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCAyMDE4IEdvb2dsZSBMTENcbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGVcbiAqIGxpY2Vuc2UgdGhhdCBjYW4gYmUgZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBvciBhdFxuICogaHR0cHM6Ly9vcGVuc291cmNlLm9yZy9saWNlbnNlcy9NSVQuXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICovXG5cbi8qIE9yaWdpbmFsIHNvdXJjZToga2VyYXMvY29udHJhaW50cy5weSAqL1xuXG5pbXBvcnQgKiBhcyB0ZmMgZnJvbSAnQHRlbnNvcmZsb3cvdGZqcy1jb3JlJztcbmltcG9ydCB7c2VyaWFsaXphdGlvbiwgVGVuc29yLCB0aWR5fSBmcm9tICdAdGVuc29yZmxvdy90ZmpzLWNvcmUnO1xuaW1wb3J0IHtlcHNpbG9ufSBmcm9tICcuL2JhY2tlbmQvY29tbW9uJztcbmltcG9ydCB7ZGVzZXJpYWxpemVLZXJhc09iamVjdCwgc2VyaWFsaXplS2VyYXNPYmplY3R9IGZyb20gJy4vdXRpbHMvZ2VuZXJpY191dGlscyc7XG5cbi8qKlxuICogSGVscGVyIGZ1bmN0aW9uIHVzZWQgYnkgbWFueSBvZiB0aGUgQ29uc3RyYWludHMgdG8gZmluZCB0aGUgTDJOb3Jtcy5cbiAqL1xuZnVuY3Rpb24gY2FsY0wyTm9ybXModzogVGVuc29yLCBheGlzOiBudW1iZXIpOiBUZW5zb3Ige1xuICByZXR1cm4gdGlkeSgoKSA9PiB0ZmMuc3FydCh0ZmMuc3VtKHRmYy5tdWwodywgdyksIGF4aXMsIHRydWUpKSk7XG59XG5cbi8qKlxuICogQmFzZSBjbGFzcyBmb3IgZnVuY3Rpb25zIHRoYXQgaW1wb3NlIGNvbnN0cmFpbnRzIG9uIHdlaWdodCB2YWx1ZXNcbiAqXG4gKiBAZG9jIHtcbiAqICAgaGVhZGluZzogJ0NvbnN0cmFpbnRzJyxcbiAqICAgc3ViaGVhZGluZzogJ0NsYXNzZXMnLFxuICogICBuYW1lc3BhY2U6ICdjb25zdHJhaW50cydcbiAqIH1cbiAqL1xuZXhwb3J0IGFic3RyYWN0IGNsYXNzIENvbnN0cmFpbnQgZXh0ZW5kcyBzZXJpYWxpemF0aW9uLlNlcmlhbGl6YWJsZSB7XG4gIC8qIFBvcnRpbmcgbm90ZTogd2FzIF9fY2FsbF9fLCBhcHBseSBjaG9zZW4gdG8gbWF0Y2ggb3RoZXIgc2ltaWxhciBjaG9pY2VzICovXG4gIGFic3RyYWN0IGFwcGx5KHc6IFRlbnNvcik6IFRlbnNvcjtcbiAgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgcmV0dXJuIHt9O1xuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWF4Tm9ybUFyZ3Mge1xuICAvKipcbiAgICogTWF4aW11bSBub3JtIGZvciBpbmNvbWluZyB3ZWlnaHRzXG4gICAqL1xuICBtYXhWYWx1ZT86IG51bWJlcjtcbiAgLyoqXG4gICAqIEF4aXMgYWxvbmcgd2hpY2ggdG8gY2FsY3VsYXRlIG5vcm1zLlxuICAgKlxuICAgKiAgRm9yIGluc3RhbmNlLCBpbiBhIGBEZW5zZWAgbGF5ZXIgdGhlIHdlaWdodCBtYXRyaXhcbiAgICogIGhhcyBzaGFwZSBgW2lucHV0RGltLCBvdXRwdXREaW1dYCxcbiAgICogIHNldCBgYXhpc2AgdG8gYDBgIHRvIGNvbnN0cmFpbiBlYWNoIHdlaWdodCB2ZWN0b3JcbiAgICogIG9mIGxlbmd0aCBgW2lucHV0RGltLF1gLlxuICAgKiAgSW4gYSBgQ29udjJEYCBsYXllciB3aXRoIGBkYXRhRm9ybWF0PVwiY2hhbm5lbHNfbGFzdFwiYCxcbiAgICogIHRoZSB3ZWlnaHQgdGVuc29yIGhhcyBzaGFwZVxuICAgKiAgYFtyb3dzLCBjb2xzLCBpbnB1dERlcHRoLCBvdXRwdXREZXB0aF1gLFxuICAgKiAgc2V0IGBheGlzYCB0byBgWzAsIDEsIDJdYFxuICAgKiAgdG8gY29uc3RyYWluIHRoZSB3ZWlnaHRzIG9mIGVhY2ggZmlsdGVyIHRlbnNvciBvZiBzaXplXG4gICAqICBgW3Jvd3MsIGNvbHMsIGlucHV0RGVwdGhdYC5cbiAgICovXG4gIGF4aXM/OiBudW1iZXI7XG59XG5cbmV4cG9ydCBjbGFzcyBNYXhOb3JtIGV4dGVuZHMgQ29uc3RyYWludCB7XG4gIC8qKiBAbm9jb2xsYXBzZSAqL1xuICBzdGF0aWMgcmVhZG9ubHkgY2xhc3NOYW1lID0gJ01heE5vcm0nO1xuICBwcml2YXRlIG1heFZhbHVlOiBudW1iZXI7XG4gIHByaXZhdGUgYXhpczogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IGRlZmF1bHRNYXhWYWx1ZSA9IDI7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGVmYXVsdEF4aXMgPSAwO1xuXG4gIGNvbnN0cnVjdG9yKGFyZ3M6IE1heE5vcm1BcmdzKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLm1heFZhbHVlID1cbiAgICAgICAgYXJncy5tYXhWYWx1ZSAhPSBudWxsID8gYXJncy5tYXhWYWx1ZSA6IHRoaXMuZGVmYXVsdE1heFZhbHVlO1xuICAgIHRoaXMuYXhpcyA9IGFyZ3MuYXhpcyAhPSBudWxsID8gYXJncy5heGlzIDogdGhpcy5kZWZhdWx0QXhpcztcbiAgfVxuXG4gIGFwcGx5KHc6IFRlbnNvcik6IFRlbnNvciB7XG4gICAgcmV0dXJuIHRpZHkoKCkgPT4ge1xuICAgICAgY29uc3Qgbm9ybXMgPSBjYWxjTDJOb3Jtcyh3LCB0aGlzLmF4aXMpO1xuICAgICAgY29uc3QgZGVzaXJlZCA9IHRmYy5jbGlwQnlWYWx1ZShub3JtcywgMCwgdGhpcy5tYXhWYWx1ZSk7XG4gICAgICByZXR1cm4gdGZjLm11bCh3LCB0ZmMuZGl2KGRlc2lyZWQsIHRmYy5hZGQoZXBzaWxvbigpLCBub3JtcykpKTtcbiAgICB9KTtcbiAgfVxuXG4gIG92ZXJyaWRlIGdldENvbmZpZygpOiBzZXJpYWxpemF0aW9uLkNvbmZpZ0RpY3Qge1xuICAgIHJldHVybiB7bWF4VmFsdWU6IHRoaXMubWF4VmFsdWUsIGF4aXM6IHRoaXMuYXhpc307XG4gIH1cbn1cbnNlcmlhbGl6YXRpb24ucmVnaXN0ZXJDbGFzcyhNYXhOb3JtKTtcblxuZXhwb3J0IGludGVyZmFjZSBVbml0Tm9ybUFyZ3Mge1xuICAvKipcbiAgICogQXhpcyBhbG9uZyB3aGljaCB0byBjYWxjdWxhdGUgbm9ybXMuXG4gICAqXG4gICAqIEZvciBpbnN0YW5jZSwgaW4gYSBgRGVuc2VgIGxheWVyIHRoZSB3ZWlnaHQgbWF0cml4XG4gICAqIGhhcyBzaGFwZSBgW2lucHV0RGltLCBvdXRwdXREaW1dYCxcbiAgICogc2V0IGBheGlzYCB0byBgMGAgdG8gY29uc3RyYWluIGVhY2ggd2VpZ2h0IHZlY3RvclxuICAgKiBvZiBsZW5ndGggYFtpbnB1dERpbSxdYC5cbiAgICogSW4gYSBgQ29udjJEYCBsYXllciB3aXRoIGBkYXRhRm9ybWF0PVwiY2hhbm5lbHNfbGFzdFwiYCxcbiAgICogdGhlIHdlaWdodCB0ZW5zb3IgaGFzIHNoYXBlXG4gICAqIGBbcm93cywgY29scywgaW5wdXREZXB0aCwgb3V0cHV0RGVwdGhdYCxcbiAgICogc2V0IGBheGlzYCB0byBgWzAsIDEsIDJdYFxuICAgKiB0byBjb25zdHJhaW4gdGhlIHdlaWdodHMgb2YgZWFjaCBmaWx0ZXIgdGVuc29yIG9mIHNpemVcbiAgICogYFtyb3dzLCBjb2xzLCBpbnB1dERlcHRoXWAuXG4gICAqL1xuICBheGlzPzogbnVtYmVyO1xufVxuXG5leHBvcnQgY2xhc3MgVW5pdE5vcm0gZXh0ZW5kcyBDb25zdHJhaW50IHtcbiAgLyoqIEBub2NvbGxhcHNlICovXG4gIHN0YXRpYyByZWFkb25seSBjbGFzc05hbWUgPSAnVW5pdE5vcm0nO1xuICBwcml2YXRlIGF4aXM6IG51bWJlcjtcbiAgcHJpdmF0ZSByZWFkb25seSBkZWZhdWx0QXhpcyA9IDA7XG4gIGNvbnN0cnVjdG9yKGFyZ3M6IFVuaXROb3JtQXJncykge1xuICAgIHN1cGVyKCk7XG4gICAgdGhpcy5heGlzID0gYXJncy5heGlzICE9IG51bGwgPyBhcmdzLmF4aXMgOiB0aGlzLmRlZmF1bHRBeGlzO1xuICB9XG5cbiAgYXBwbHkodzogVGVuc29yKTogVGVuc29yIHtcbiAgICByZXR1cm4gdGlkeShcbiAgICAgICAgKCkgPT4gdGZjLmRpdih3LCB0ZmMuYWRkKGVwc2lsb24oKSwgY2FsY0wyTm9ybXModywgdGhpcy5heGlzKSkpKTtcbiAgfVxuXG4gIG92ZXJyaWRlIGdldENvbmZpZygpOiBzZXJpYWxpemF0aW9uLkNvbmZpZ0RpY3Qge1xuICAgIHJldHVybiB7YXhpczogdGhpcy5heGlzfTtcbiAgfVxufVxuc2VyaWFsaXphdGlvbi5yZWdpc3RlckNsYXNzKFVuaXROb3JtKTtcblxuZXhwb3J0IGNsYXNzIE5vbk5lZyBleHRlbmRzIENvbnN0cmFpbnQge1xuICAvKiogQG5vY29sbGFwc2UgKi9cbiAgc3RhdGljIHJlYWRvbmx5IGNsYXNzTmFtZSA9ICdOb25OZWcnO1xuXG4gIGFwcGx5KHc6IFRlbnNvcik6IFRlbnNvciB7XG4gICAgcmV0dXJuIHRmYy5yZWx1KHcpO1xuICB9XG59XG5zZXJpYWxpemF0aW9uLnJlZ2lzdGVyQ2xhc3MoTm9uTmVnKTtcblxuZXhwb3J0IGludGVyZmFjZSBNaW5NYXhOb3JtQXJncyB7XG4gIC8qKlxuICAgKiBNaW5pbXVtIG5vcm0gZm9yIGluY29taW5nIHdlaWdodHNcbiAgICovXG4gIG1pblZhbHVlPzogbnVtYmVyO1xuICAvKipcbiAgICogTWF4aW11bSBub3JtIGZvciBpbmNvbWluZyB3ZWlnaHRzXG4gICAqL1xuICBtYXhWYWx1ZT86IG51bWJlcjtcbiAgLyoqXG4gICAqIEF4aXMgYWxvbmcgd2hpY2ggdG8gY2FsY3VsYXRlIG5vcm1zLlxuICAgKiBGb3IgaW5zdGFuY2UsIGluIGEgYERlbnNlYCBsYXllciB0aGUgd2VpZ2h0IG1hdHJpeFxuICAgKiBoYXMgc2hhcGUgYFtpbnB1dERpbSwgb3V0cHV0RGltXWAsXG4gICAqIHNldCBgYXhpc2AgdG8gYDBgIHRvIGNvbnN0cmFpbiBlYWNoIHdlaWdodCB2ZWN0b3JcbiAgICogb2YgbGVuZ3RoIGBbaW5wdXREaW0sXWAuXG4gICAqIEluIGEgYENvbnYyRGAgbGF5ZXIgd2l0aCBgZGF0YUZvcm1hdD1cImNoYW5uZWxzX2xhc3RcImAsXG4gICAqIHRoZSB3ZWlnaHQgdGVuc29yIGhhcyBzaGFwZVxuICAgKiBgW3Jvd3MsIGNvbHMsIGlucHV0RGVwdGgsIG91dHB1dERlcHRoXWAsXG4gICAqIHNldCBgYXhpc2AgdG8gYFswLCAxLCAyXWBcbiAgICogdG8gY29uc3RyYWluIHRoZSB3ZWlnaHRzIG9mIGVhY2ggZmlsdGVyIHRlbnNvciBvZiBzaXplXG4gICAqIGBbcm93cywgY29scywgaW5wdXREZXB0aF1gLlxuICAgKi9cbiAgYXhpcz86IG51bWJlcjtcbiAgLyoqXG4gICAqIFJhdGUgZm9yIGVuZm9yY2luZyB0aGUgY29uc3RyYWludDogd2VpZ2h0cyB3aWxsIGJlIHJlc2NhbGVkIHRvIHlpZWxkOlxuICAgKiBgKDEgLSByYXRlKSAqIG5vcm0gKyByYXRlICogbm9ybS5jbGlwKG1pblZhbHVlLCBtYXhWYWx1ZSlgLlxuICAgKiBFZmZlY3RpdmVseSwgdGhpcyBtZWFucyB0aGF0IHJhdGU9MS4wIHN0YW5kcyBmb3Igc3RyaWN0XG4gICAqIGVuZm9yY2VtZW50IG9mIHRoZSBjb25zdHJhaW50LCB3aGlsZSByYXRlPDEuMCBtZWFucyB0aGF0XG4gICAqIHdlaWdodHMgd2lsbCBiZSByZXNjYWxlZCBhdCBlYWNoIHN0ZXAgdG8gc2xvd2x5IG1vdmVcbiAgICogdG93YXJkcyBhIHZhbHVlIGluc2lkZSB0aGUgZGVzaXJlZCBpbnRlcnZhbC5cbiAgICovXG4gIHJhdGU/OiBudW1iZXI7XG59XG5cbmV4cG9ydCBjbGFzcyBNaW5NYXhOb3JtIGV4dGVuZHMgQ29uc3RyYWludCB7XG4gIC8qKiBAbm9jb2xsYXBzZSAqL1xuICBzdGF0aWMgcmVhZG9ubHkgY2xhc3NOYW1lID0gJ01pbk1heE5vcm0nO1xuICBwcml2YXRlIG1pblZhbHVlOiBudW1iZXI7XG4gIHByaXZhdGUgbWF4VmFsdWU6IG51bWJlcjtcbiAgcHJpdmF0ZSByYXRlOiBudW1iZXI7XG4gIHByaXZhdGUgYXhpczogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IGRlZmF1bHRNaW5WYWx1ZSA9IDAuMDtcbiAgcHJpdmF0ZSByZWFkb25seSBkZWZhdWx0TWF4VmFsdWUgPSAxLjA7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGVmYXVsdFJhdGUgPSAxLjA7XG4gIHByaXZhdGUgcmVhZG9ubHkgZGVmYXVsdEF4aXMgPSAwO1xuXG4gIGNvbnN0cnVjdG9yKGFyZ3M6IE1pbk1heE5vcm1BcmdzKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLm1pblZhbHVlID1cbiAgICAgICAgYXJncy5taW5WYWx1ZSAhPSBudWxsID8gYXJncy5taW5WYWx1ZSA6IHRoaXMuZGVmYXVsdE1pblZhbHVlO1xuICAgIHRoaXMubWF4VmFsdWUgPVxuICAgICAgICBhcmdzLm1heFZhbHVlICE9IG51bGwgPyBhcmdzLm1heFZhbHVlIDogdGhpcy5kZWZhdWx0TWF4VmFsdWU7XG4gICAgdGhpcy5yYXRlID0gYXJncy5yYXRlICE9IG51bGwgPyBhcmdzLnJhdGUgOiB0aGlzLmRlZmF1bHRSYXRlO1xuICAgIHRoaXMuYXhpcyA9IGFyZ3MuYXhpcyAhPSBudWxsID8gYXJncy5heGlzIDogdGhpcy5kZWZhdWx0QXhpcztcbiAgfVxuXG4gIGFwcGx5KHc6IFRlbnNvcik6IFRlbnNvciB7XG4gICAgcmV0dXJuIHRpZHkoKCkgPT4ge1xuICAgICAgY29uc3Qgbm9ybXMgPSBjYWxjTDJOb3Jtcyh3LCB0aGlzLmF4aXMpO1xuICAgICAgY29uc3QgZGVzaXJlZCA9IHRmYy5hZGQoXG4gICAgICAgICAgdGZjLm11bChcbiAgICAgICAgICAgICAgdGhpcy5yYXRlLCB0ZmMuY2xpcEJ5VmFsdWUobm9ybXMsIHRoaXMubWluVmFsdWUsIHRoaXMubWF4VmFsdWUpKSxcbiAgICAgICAgICB0ZmMubXVsKDEuMCAtIHRoaXMucmF0ZSwgbm9ybXMpKTtcbiAgICAgIHJldHVybiB0ZmMubXVsKHcsIHRmYy5kaXYoZGVzaXJlZCwgdGZjLmFkZChlcHNpbG9uKCksIG5vcm1zKSkpO1xuICAgIH0pO1xuICB9XG5cbiAgb3ZlcnJpZGUgZ2V0Q29uZmlnKCk6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG1pblZhbHVlOiB0aGlzLm1pblZhbHVlLFxuICAgICAgbWF4VmFsdWU6IHRoaXMubWF4VmFsdWUsXG4gICAgICByYXRlOiB0aGlzLnJhdGUsXG4gICAgICBheGlzOiB0aGlzLmF4aXNcbiAgICB9O1xuICB9XG59XG5zZXJpYWxpemF0aW9uLnJlZ2lzdGVyQ2xhc3MoTWluTWF4Tm9ybSk7XG5cbi8qKiBAZG9jaW5saW5lICovXG5leHBvcnQgdHlwZSBDb25zdHJhaW50SWRlbnRpZmllciA9XG4gICAgJ21heE5vcm0nfCdtaW5NYXhOb3JtJ3wnbm9uTmVnJ3wndW5pdE5vcm0nfHN0cmluZztcblxuLy8gTWFwcyB0aGUgSmF2YVNjcmlwdC1saWtlIGlkZW50aWZpZXIga2V5cyB0byB0aGUgY29ycmVzcG9uZGluZyByZWdpc3RyeVxuLy8gc3ltYm9scy5cbmV4cG9ydCBjb25zdCBDT05TVFJBSU5UX0lERU5USUZJRVJfUkVHSVNUUllfU1lNQk9MX01BUDpcbiAgICB7W2lkZW50aWZpZXIgaW4gQ29uc3RyYWludElkZW50aWZpZXJdOiBzdHJpbmd9ID0ge1xuICAgICAgJ21heE5vcm0nOiAnTWF4Tm9ybScsXG4gICAgICAnbWluTWF4Tm9ybSc6ICdNaW5NYXhOb3JtJyxcbiAgICAgICdub25OZWcnOiAnTm9uTmVnJyxcbiAgICAgICd1bml0Tm9ybSc6ICdVbml0Tm9ybSdcbiAgICB9O1xuXG5leHBvcnQgZnVuY3Rpb24gc2VyaWFsaXplQ29uc3RyYWludChjb25zdHJhaW50OiBDb25zdHJhaW50KTpcbiAgICBzZXJpYWxpemF0aW9uLkNvbmZpZ0RpY3RWYWx1ZSB7XG4gIHJldHVybiBzZXJpYWxpemVLZXJhc09iamVjdChjb25zdHJhaW50KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRlc2VyaWFsaXplQ29uc3RyYWludChcbiAgICBjb25maWc6IHNlcmlhbGl6YXRpb24uQ29uZmlnRGljdCxcbiAgICBjdXN0b21PYmplY3RzOiBzZXJpYWxpemF0aW9uLkNvbmZpZ0RpY3QgPSB7fSk6IENvbnN0cmFpbnQge1xuICByZXR1cm4gZGVzZXJpYWxpemVLZXJhc09iamVjdChcbiAgICAgIGNvbmZpZywgc2VyaWFsaXphdGlvbi5TZXJpYWxpemF0aW9uTWFwLmdldE1hcCgpLmNsYXNzTmFtZU1hcCxcbiAgICAgIGN1c3RvbU9iamVjdHMsICdjb25zdHJhaW50Jyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRDb25zdHJhaW50KGlkZW50aWZpZXI6IENvbnN0cmFpbnRJZGVudGlmaWVyfFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWFsaXphdGlvbi5Db25maWdEaWN0fENvbnN0cmFpbnQpOiBDb25zdHJhaW50IHtcbiAgaWYgKGlkZW50aWZpZXIgPT0gbnVsbCkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIGlmICh0eXBlb2YgaWRlbnRpZmllciA9PT0gJ3N0cmluZycpIHtcbiAgICBjb25zdCBjbGFzc05hbWUgPSBpZGVudGlmaWVyIGluIENPTlNUUkFJTlRfSURFTlRJRklFUl9SRUdJU1RSWV9TWU1CT0xfTUFQID9cbiAgICAgICAgQ09OU1RSQUlOVF9JREVOVElGSUVSX1JFR0lTVFJZX1NZTUJPTF9NQVBbaWRlbnRpZmllcl0gOlxuICAgICAgICBpZGVudGlmaWVyO1xuICAgIGNvbnN0IGNvbmZpZyA9IHtjbGFzc05hbWUsIGNvbmZpZzoge319O1xuICAgIHJldHVybiBkZXNlcmlhbGl6ZUNvbnN0cmFpbnQoY29uZmlnKTtcbiAgfSBlbHNlIGlmIChpZGVudGlmaWVyIGluc3RhbmNlb2YgQ29uc3RyYWludCkge1xuICAgIHJldHVybiBpZGVudGlmaWVyO1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBkZXNlcmlhbGl6ZUNvbnN0cmFpbnQoaWRlbnRpZmllcik7XG4gIH1cbn1cbiJdfQ==