@tensorflow/tfjs-layers
Version:
TensorFlow layers API in JavaScript
167 lines • 21.7 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.
* =============================================================================
*/
/**
* Built-in metrics.
*/
import * as tfc from '@tensorflow/tfjs-core';
import { tidy } from '@tensorflow/tfjs-core';
import * as K from './backend/tfjs_backend';
import { NotImplementedError, ValueError } from './errors';
import { binaryCrossentropy as lossBinaryCrossentropy, categoricalCrossentropy as categoricalCrossentropyLoss, cosineProximity, lossesMap, meanAbsoluteError, meanAbsolutePercentageError, meanSquaredError, sparseCategoricalCrossentropy as sparseCategoricalCrossentropyLoss } from './losses';
import * as util from './utils/generic_utils';
export function binaryAccuracy(yTrue, yPred) {
return tidy(() => {
const threshold = tfc.mul(.5, tfc.onesLike(yPred));
const yPredThresholded = K.cast(tfc.greater(yPred, threshold), yTrue.dtype);
return tfc.mean(tfc.equal(yTrue, yPredThresholded), -1);
});
}
export function categoricalAccuracy(yTrue, yPred) {
return tidy(() => K.cast(tfc.equal(tfc.argMax(yTrue, -1), tfc.argMax(yPred, -1)), 'float32'));
}
function truePositives(yTrue, yPred) {
return tidy(() => {
return tfc.cast(tfc.sum(tfc.logicalAnd(tfc.equal(yTrue, 1), tfc.equal(yPred, 1))), 'float32');
});
}
function falseNegatives(yTrue, yPred) {
return tidy(() => {
return tfc.cast(tfc.sum(tfc.logicalAnd(tfc.equal(yTrue, 1), tfc.equal(yPred, 0))), 'float32');
});
}
function falsePositives(yTrue, yPred) {
return tidy(() => {
return tfc.cast(tfc.sum(tfc.logicalAnd(tfc.equal(yTrue, 0), tfc.equal(yPred, 1))), 'float32');
});
}
export function precision(yTrue, yPred) {
return tidy(() => {
const tp = truePositives(yTrue, yPred);
const fp = falsePositives(yTrue, yPred);
const denominator = tfc.add(tp, fp);
return tfc.cast(tfc.where(tfc.greater(denominator, 0), tfc.div(tp, denominator), 0), 'float32');
});
}
export function recall(yTrue, yPred) {
return tidy(() => {
const tp = truePositives(yTrue, yPred);
const fn = falseNegatives(yTrue, yPred);
const denominator = tfc.add(tp, fn);
return tfc.cast(tfc.where(tfc.greater(denominator, 0), tfc.div(tp, denominator), 0), 'float32');
});
}
export function binaryCrossentropy(yTrue, yPred) {
return lossBinaryCrossentropy(yTrue, yPred);
}
export function sparseCategoricalAccuracy(yTrue, yPred) {
if (yTrue.rank === yPred.rank) {
yTrue = tfc.squeeze(yTrue, [yTrue.rank - 1]);
}
yPred = tfc.argMax(yPred, -1);
if (yPred.dtype !== yTrue.dtype) {
yPred = tfc.cast(yPred, yTrue.dtype);
}
return tfc.cast(tfc.equal(yTrue, yPred), 'float32');
}
export function topKCategoricalAccuracy(yTrue, yPred) {
throw new NotImplementedError();
}
export function sparseTopKCategoricalAccuracy(yTrue, yPred) {
throw new NotImplementedError();
}
export function r2Score(yTrue, yPred) {
return tidy(() => {
const sumSquaresResiduals = yTrue.sub(yPred).square().sum();
const sumSquares = yTrue.sub(yTrue.mean()).square().sum();
return tfc.scalar(1).sub(sumSquaresResiduals.div(sumSquares));
});
}
// Aliases.
export const mse = meanSquaredError;
export const MSE = meanSquaredError;
export const mae = meanAbsoluteError;
export const MAE = meanAbsoluteError;
export const mape = meanAbsolutePercentageError;
export const MAPE = meanAbsolutePercentageError;
export const categoricalCrossentropy = categoricalCrossentropyLoss;
export const cosine = cosineProximity;
export const sparseCategoricalCrossentropy = sparseCategoricalCrossentropyLoss;
// TODO(cais, nielsene): Add serialize().
export const metricsMap = {
binaryAccuracy,
categoricalAccuracy,
precision,
categoricalCrossentropy,
sparseCategoricalCrossentropy,
mse,
MSE,
mae,
MAE,
mape,
MAPE,
cosine
};
export function get(identifier) {
if (typeof identifier === 'string' && identifier in metricsMap) {
return metricsMap[identifier];
}
else if (typeof identifier !== 'string' && identifier != null) {
return identifier;
}
else {
throw new ValueError(`Unknown metric ${identifier}`);
}
}
/**
* Get the shortcut function name.
*
* If the fn name is a string,
* directly return the string name.
* If the function is included in metricsMap or lossesMap,
* return key of the map.
* - If the function relative to multiple keys,
* return the first found key as the function name.
* - If the function exists in both lossesMap and metricsMap,
* search lossesMap first.
* If the function is not included in metricsMap or lossesMap,
* return the function name.
*
* @param fn loss function, metric function, or short cut name.
* @returns Loss or Metric name in string.
*/
export function getLossOrMetricName(fn) {
util.assert(fn !== null, `Unknown LossOrMetricFn ${fn}`);
if (typeof fn === 'string') {
return fn;
}
else {
let fnName;
for (const key of Object.keys(lossesMap)) {
if (lossesMap[key] === fn) {
fnName = key;
break;
}
}
if (fnName !== undefined) {
return fnName;
}
for (const key of Object.keys(metricsMap)) {
if (metricsMap[key] === fn) {
fnName = key;
break;
}
}
if (fnName !== undefined) {
return fnName;
}
return fn.name;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWV0cmljcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3RmanMtbGF5ZXJzL3NyYy9tZXRyaWNzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7OztHQVFHO0FBRUg7O0dBRUc7QUFFSCxPQUFPLEtBQUssR0FBRyxNQUFNLHVCQUF1QixDQUFDO0FBQzdDLE9BQU8sRUFBUyxJQUFJLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUVuRCxPQUFPLEtBQUssQ0FBQyxNQUFNLHdCQUF3QixDQUFDO0FBQzVDLE9BQU8sRUFBQyxtQkFBbUIsRUFBRSxVQUFVLEVBQUMsTUFBTSxVQUFVLENBQUM7QUFDekQsT0FBTyxFQUFDLGtCQUFrQixJQUFJLHNCQUFzQixFQUFFLHVCQUF1QixJQUFJLDJCQUEyQixFQUFFLGVBQWUsRUFBRSxTQUFTLEVBQUUsaUJBQWlCLEVBQUUsMkJBQTJCLEVBQUUsZ0JBQWdCLEVBQUUsNkJBQTZCLElBQUksaUNBQWlDLEVBQUMsTUFBTSxVQUFVLENBQUM7QUFFaFMsT0FBTyxLQUFLLElBQUksTUFBTSx1QkFBdUIsQ0FBQztBQUU5QyxNQUFNLFVBQVUsY0FBYyxDQUFDLEtBQWEsRUFBRSxLQUFhO0lBQ3pELE9BQU8sSUFBSSxDQUFDLEdBQUcsRUFBRTtRQUNmLE1BQU0sU0FBUyxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUNuRCxNQUFNLGdCQUFnQixHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzVFLE9BQU8sR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxnQkFBZ0IsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDMUQsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsTUFBTSxVQUFVLG1CQUFtQixDQUFDLEtBQWEsRUFBRSxLQUFhO0lBQzlELE9BQU8sSUFBSSxDQUNQLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQ1IsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDO0FBQy9FLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FBQyxLQUFhLEVBQUUsS0FBYTtJQUNqRCxPQUFPLElBQUksQ0FBQyxHQUFHLEVBQUU7UUFDZixPQUFPLEdBQUcsQ0FBQyxJQUFJLENBQ1gsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFDakUsU0FBUyxDQUFDLENBQUM7SUFDakIsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsU0FBUyxjQUFjLENBQUMsS0FBYSxFQUFFLEtBQWE7SUFDbEQsT0FBTyxJQUFJLENBQUMsR0FBRyxFQUFFO1FBQ2YsT0FBTyxHQUFHLENBQUMsSUFBSSxDQUNYLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQ2pFLFNBQVMsQ0FBQyxDQUFDO0lBQ2pCLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELFNBQVMsY0FBYyxDQUFDLEtBQWEsRUFBRSxLQUFhO0lBQ2xELE9BQU8sSUFBSSxDQUFDLEdBQUcsRUFBRTtRQUNmLE9BQU8sR0FBRyxDQUFDLElBQUksQ0FDWCxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUNqRSxTQUFTLENBQUMsQ0FBQztJQUNqQixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRCxNQUFNLFVBQVUsU0FBUyxDQUFDLEtBQWEsRUFBRSxLQUFhO0lBQ3BELE9BQU8sSUFBSSxDQUFDLEdBQUcsRUFBRTtRQUNmLE1BQU0sRUFBRSxHQUFHLGFBQWEsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDdkMsTUFBTSxFQUFFLEdBQUcsY0FBYyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztRQUV4QyxNQUFNLFdBQVcsR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVwQyxPQUFPLEdBQUcsQ0FBQyxJQUFJLENBQ1gsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsRUFBRSxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxXQUFXLENBQUMsRUFBRSxDQUFDLENBQUMsRUFDbkUsU0FBUyxDQUFDLENBQUM7SUFDakIsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsTUFBTSxVQUFVLE1BQU0sQ0FBQyxLQUFhLEVBQUUsS0FBYTtJQUNqRCxPQUFPLElBQUksQ0FBQyxHQUFHLEVBQUU7UUFDZixNQUFNLEVBQUUsR0FBRyxhQUFhLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3ZDLE1BQU0sRUFBRSxHQUFHLGNBQWMsQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFFeEMsTUFBTSxXQUFXLEdBQUcsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7UUFFcEMsT0FBTyxHQUFHLENBQUMsSUFBSSxDQUNYLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsV0FBVyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQ25FLFNBQVMsQ0FBQyxDQUFDO0lBQ2pCLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELE1BQU0sVUFBVSxrQkFBa0IsQ0FBQyxLQUFhLEVBQUUsS0FBYTtJQUM3RCxPQUFPLHNCQUFzQixDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQztBQUM5QyxDQUFDO0FBRUQsTUFBTSxVQUFVLHlCQUF5QixDQUNyQyxLQUFhLEVBQUUsS0FBYTtJQUM5QixJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssS0FBSyxDQUFDLElBQUksRUFBRTtRQUM3QixLQUFLLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7S0FDOUM7SUFDRCxLQUFLLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM5QixJQUFJLEtBQUssQ0FBQyxLQUFLLEtBQUssS0FBSyxDQUFDLEtBQUssRUFBRTtRQUMvQixLQUFLLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO0tBQ3RDO0lBQ0QsT0FBTyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxFQUFFLFNBQVMsQ0FBQyxDQUFDO0FBQ3RELENBQUM7QUFFRCxNQUFNLFVBQVUsdUJBQXVCLENBQUMsS0FBYSxFQUFFLEtBQWE7SUFDbEUsTUFBTSxJQUFJLG1CQUFtQixFQUFFLENBQUM7QUFDbEMsQ0FBQztBQUVELE1BQU0sVUFBVSw2QkFBNkIsQ0FDekMsS0FBYSxFQUFFLEtBQWE7SUFDOUIsTUFBTSxJQUFJLG1CQUFtQixFQUFFLENBQUM7QUFDbEMsQ0FBQztBQUVELE1BQU0sVUFBVSxPQUFPLENBQUMsS0FBYSxFQUFFLEtBQWE7SUFDbEQsT0FBTyxJQUFJLENBQUMsR0FBRyxFQUFFO1FBQ2YsTUFBTSxtQkFBbUIsR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQzVELE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDMUQsT0FBTyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxtQkFBbUIsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztJQUNoRSxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRCxXQUFXO0FBQ1gsTUFBTSxDQUFDLE1BQU0sR0FBRyxHQUFHLGdCQUFnQixDQUFDO0FBQ3BDLE1BQU0sQ0FBQyxNQUFNLEdBQUcsR0FBRyxnQkFBZ0IsQ0FBQztBQUNwQyxNQUFNLENBQUMsTUFBTSxHQUFHLEdBQUcsaUJBQWlCLENBQUM7QUFDckMsTUFBTSxDQUFDLE1BQU0sR0FBRyxHQUFHLGlCQUFpQixDQUFDO0FBQ3JDLE1BQU0sQ0FBQyxNQUFNLElBQUksR0FBRywyQkFBMkIsQ0FBQztBQUNoRCxNQUFNLENBQUMsTUFBTSxJQUFJLEdBQUcsMkJBQTJCLENBQUM7QUFDaEQsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsMkJBQTJCLENBQUM7QUFDbkUsTUFBTSxDQUFDLE1BQU0sTUFBTSxHQUFHLGVBQWUsQ0FBQztBQUN0QyxNQUFNLENBQUMsTUFBTSw2QkFBNkIsR0FBRyxpQ0FBaUMsQ0FBQztBQUUvRSx5Q0FBeUM7QUFFekMsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUE2QztJQUNsRSxjQUFjO0lBQ2QsbUJBQW1CO0lBQ25CLFNBQVM7SUFDVCx1QkFBdUI7SUFDdkIsNkJBQTZCO0lBQzdCLEdBQUc7SUFDSCxHQUFHO0lBQ0gsR0FBRztJQUNILEdBQUc7SUFDSCxJQUFJO0lBQ0osSUFBSTtJQUNKLE1BQU07Q0FDUCxDQUFDO0FBRUYsTUFBTSxVQUFVLEdBQUcsQ0FBQyxVQUFpQztJQUNuRCxJQUFJLE9BQU8sVUFBVSxLQUFLLFFBQVEsSUFBSSxVQUFVLElBQUksVUFBVSxFQUFFO1FBQzlELE9BQU8sVUFBVSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0tBQy9CO1NBQU0sSUFBSSxPQUFPLFVBQVUsS0FBSyxRQUFRLElBQUksVUFBVSxJQUFJLElBQUksRUFBRTtRQUMvRCxPQUFPLFVBQVUsQ0FBQztLQUNuQjtTQUFNO1FBQ0wsTUFBTSxJQUFJLFVBQVUsQ0FBQyxrQkFBa0IsVUFBVSxFQUFFLENBQUMsQ0FBQztLQUN0RDtBQUNILENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRztBQUNILE1BQU0sVUFBVSxtQkFBbUIsQ0FBQyxFQUF5QjtJQUMzRCxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsS0FBSyxJQUFJLEVBQUUsMEJBQTBCLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDekQsSUFBSSxPQUFPLEVBQUUsS0FBSyxRQUFRLEVBQUU7UUFDMUIsT0FBTyxFQUFFLENBQUM7S0FDWDtTQUFNO1FBQ0wsSUFBSSxNQUFNLENBQUM7UUFDWCxLQUFLLE1BQU0sR0FBRyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUU7WUFDeEMsSUFBSSxTQUFTLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxFQUFFO2dCQUN6QixNQUFNLEdBQUcsR0FBRyxDQUFDO2dCQUNiLE1BQU07YUFDUDtTQUNGO1FBQ0QsSUFBSSxNQUFNLEtBQUssU0FBUyxFQUFFO1lBQ3hCLE9BQU8sTUFBTSxDQUFDO1NBQ2Y7UUFDRCxLQUFLLE1BQU0sR0FBRyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUU7WUFDekMsSUFBSSxVQUFVLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxFQUFFO2dCQUMxQixNQUFNLEdBQUcsR0FBRyxDQUFDO2dCQUNiLE1BQU07YUFDUDtTQUNGO1FBQ0QsSUFBSSxNQUFNLEtBQUssU0FBUyxFQUFFO1lBQ3hCLE9BQU8sTUFBTSxDQUFDO1NBQ2Y7UUFDRCxPQUFRLEVBQWUsQ0FBQyxJQUFJLENBQUM7S0FDOUI7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMTggR29vZ2xlIExMQ1xuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZVxuICogbGljZW5zZSB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIG9yIGF0XG4gKiBodHRwczovL29wZW5zb3VyY2Uub3JnL2xpY2Vuc2VzL01JVC5cbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKi9cblxuLyoqXG4gKiBCdWlsdC1pbiBtZXRyaWNzLlxuICovXG5cbmltcG9ydCAqIGFzIHRmYyBmcm9tICdAdGVuc29yZmxvdy90ZmpzLWNvcmUnO1xuaW1wb3J0IHtUZW5zb3IsIHRpZHl9IGZyb20gJ0B0ZW5zb3JmbG93L3RmanMtY29yZSc7XG5cbmltcG9ydCAqIGFzIEsgZnJvbSAnLi9iYWNrZW5kL3RmanNfYmFja2VuZCc7XG5pbXBvcnQge05vdEltcGxlbWVudGVkRXJyb3IsIFZhbHVlRXJyb3J9IGZyb20gJy4vZXJyb3JzJztcbmltcG9ydCB7YmluYXJ5Q3Jvc3NlbnRyb3B5IGFzIGxvc3NCaW5hcnlDcm9zc2VudHJvcHksIGNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5IGFzIGNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5TG9zcywgY29zaW5lUHJveGltaXR5LCBsb3NzZXNNYXAsIG1lYW5BYnNvbHV0ZUVycm9yLCBtZWFuQWJzb2x1dGVQZXJjZW50YWdlRXJyb3IsIG1lYW5TcXVhcmVkRXJyb3IsIHNwYXJzZUNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5IGFzIHNwYXJzZUNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5TG9zc30gZnJvbSAnLi9sb3NzZXMnO1xuaW1wb3J0IHtMb3NzT3JNZXRyaWNGbn0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgKiBhcyB1dGlsIGZyb20gJy4vdXRpbHMvZ2VuZXJpY191dGlscyc7XG5cbmV4cG9ydCBmdW5jdGlvbiBiaW5hcnlBY2N1cmFjeSh5VHJ1ZTogVGVuc29yLCB5UHJlZDogVGVuc29yKTogVGVuc29yIHtcbiAgcmV0dXJuIHRpZHkoKCkgPT4ge1xuICAgIGNvbnN0IHRocmVzaG9sZCA9IHRmYy5tdWwoLjUsIHRmYy5vbmVzTGlrZSh5UHJlZCkpO1xuICAgIGNvbnN0IHlQcmVkVGhyZXNob2xkZWQgPSBLLmNhc3QodGZjLmdyZWF0ZXIoeVByZWQsIHRocmVzaG9sZCksIHlUcnVlLmR0eXBlKTtcbiAgICByZXR1cm4gdGZjLm1lYW4odGZjLmVxdWFsKHlUcnVlLCB5UHJlZFRocmVzaG9sZGVkKSwgLTEpO1xuICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNhdGVnb3JpY2FsQWNjdXJhY3koeVRydWU6IFRlbnNvciwgeVByZWQ6IFRlbnNvcik6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KFxuICAgICAgKCkgPT4gSy5jYXN0KFxuICAgICAgICAgIHRmYy5lcXVhbCh0ZmMuYXJnTWF4KHlUcnVlLCAtMSksIHRmYy5hcmdNYXgoeVByZWQsIC0xKSksICdmbG9hdDMyJykpO1xufVxuXG5mdW5jdGlvbiB0cnVlUG9zaXRpdmVzKHlUcnVlOiBUZW5zb3IsIHlQcmVkOiBUZW5zb3IpOiBUZW5zb3Ige1xuICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgcmV0dXJuIHRmYy5jYXN0KFxuICAgICAgICB0ZmMuc3VtKHRmYy5sb2dpY2FsQW5kKHRmYy5lcXVhbCh5VHJ1ZSwgMSksIHRmYy5lcXVhbCh5UHJlZCwgMSkpKSxcbiAgICAgICAgJ2Zsb2F0MzInKTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGZhbHNlTmVnYXRpdmVzKHlUcnVlOiBUZW5zb3IsIHlQcmVkOiBUZW5zb3IpOiBUZW5zb3Ige1xuICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgcmV0dXJuIHRmYy5jYXN0KFxuICAgICAgICB0ZmMuc3VtKHRmYy5sb2dpY2FsQW5kKHRmYy5lcXVhbCh5VHJ1ZSwgMSksIHRmYy5lcXVhbCh5UHJlZCwgMCkpKSxcbiAgICAgICAgJ2Zsb2F0MzInKTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGZhbHNlUG9zaXRpdmVzKHlUcnVlOiBUZW5zb3IsIHlQcmVkOiBUZW5zb3IpOiBUZW5zb3Ige1xuICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgcmV0dXJuIHRmYy5jYXN0KFxuICAgICAgICB0ZmMuc3VtKHRmYy5sb2dpY2FsQW5kKHRmYy5lcXVhbCh5VHJ1ZSwgMCksIHRmYy5lcXVhbCh5UHJlZCwgMSkpKSxcbiAgICAgICAgJ2Zsb2F0MzInKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwcmVjaXNpb24oeVRydWU6IFRlbnNvciwgeVByZWQ6IFRlbnNvcik6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICBjb25zdCB0cCA9IHRydWVQb3NpdGl2ZXMoeVRydWUsIHlQcmVkKTtcbiAgICBjb25zdCBmcCA9IGZhbHNlUG9zaXRpdmVzKHlUcnVlLCB5UHJlZCk7XG5cbiAgICBjb25zdCBkZW5vbWluYXRvciA9IHRmYy5hZGQodHAsIGZwKTtcblxuICAgIHJldHVybiB0ZmMuY2FzdChcbiAgICAgICAgdGZjLndoZXJlKHRmYy5ncmVhdGVyKGRlbm9taW5hdG9yLCAwKSwgdGZjLmRpdih0cCwgZGVub21pbmF0b3IpLCAwKSxcbiAgICAgICAgJ2Zsb2F0MzInKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWNhbGwoeVRydWU6IFRlbnNvciwgeVByZWQ6IFRlbnNvcik6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICBjb25zdCB0cCA9IHRydWVQb3NpdGl2ZXMoeVRydWUsIHlQcmVkKTtcbiAgICBjb25zdCBmbiA9IGZhbHNlTmVnYXRpdmVzKHlUcnVlLCB5UHJlZCk7XG5cbiAgICBjb25zdCBkZW5vbWluYXRvciA9IHRmYy5hZGQodHAsIGZuKTtcblxuICAgIHJldHVybiB0ZmMuY2FzdChcbiAgICAgICAgdGZjLndoZXJlKHRmYy5ncmVhdGVyKGRlbm9taW5hdG9yLCAwKSwgdGZjLmRpdih0cCwgZGVub21pbmF0b3IpLCAwKSxcbiAgICAgICAgJ2Zsb2F0MzInKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBiaW5hcnlDcm9zc2VudHJvcHkoeVRydWU6IFRlbnNvciwgeVByZWQ6IFRlbnNvcik6IFRlbnNvciB7XG4gIHJldHVybiBsb3NzQmluYXJ5Q3Jvc3NlbnRyb3B5KHlUcnVlLCB5UHJlZCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzcGFyc2VDYXRlZ29yaWNhbEFjY3VyYWN5KFxuICAgIHlUcnVlOiBUZW5zb3IsIHlQcmVkOiBUZW5zb3IpOiBUZW5zb3Ige1xuICBpZiAoeVRydWUucmFuayA9PT0geVByZWQucmFuaykge1xuICAgIHlUcnVlID0gdGZjLnNxdWVlemUoeVRydWUsIFt5VHJ1ZS5yYW5rIC0gMV0pO1xuICB9XG4gIHlQcmVkID0gdGZjLmFyZ01heCh5UHJlZCwgLTEpO1xuICBpZiAoeVByZWQuZHR5cGUgIT09IHlUcnVlLmR0eXBlKSB7XG4gICAgeVByZWQgPSB0ZmMuY2FzdCh5UHJlZCwgeVRydWUuZHR5cGUpO1xuICB9XG4gIHJldHVybiB0ZmMuY2FzdCh0ZmMuZXF1YWwoeVRydWUsIHlQcmVkKSwgJ2Zsb2F0MzInKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHRvcEtDYXRlZ29yaWNhbEFjY3VyYWN5KHlUcnVlOiBUZW5zb3IsIHlQcmVkOiBUZW5zb3IpOiBUZW5zb3Ige1xuICB0aHJvdyBuZXcgTm90SW1wbGVtZW50ZWRFcnJvcigpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc3BhcnNlVG9wS0NhdGVnb3JpY2FsQWNjdXJhY3koXG4gICAgeVRydWU6IFRlbnNvciwgeVByZWQ6IFRlbnNvcik6IFRlbnNvciB7XG4gIHRocm93IG5ldyBOb3RJbXBsZW1lbnRlZEVycm9yKCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByMlNjb3JlKHlUcnVlOiBUZW5zb3IsIHlQcmVkOiBUZW5zb3IpOiBUZW5zb3Ige1xuICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgY29uc3Qgc3VtU3F1YXJlc1Jlc2lkdWFscyA9IHlUcnVlLnN1Yih5UHJlZCkuc3F1YXJlKCkuc3VtKCk7XG4gICAgY29uc3Qgc3VtU3F1YXJlcyA9IHlUcnVlLnN1Yih5VHJ1ZS5tZWFuKCkpLnNxdWFyZSgpLnN1bSgpO1xuICAgIHJldHVybiB0ZmMuc2NhbGFyKDEpLnN1YihzdW1TcXVhcmVzUmVzaWR1YWxzLmRpdihzdW1TcXVhcmVzKSk7XG4gIH0pO1xufVxuXG4vLyBBbGlhc2VzLlxuZXhwb3J0IGNvbnN0IG1zZSA9IG1lYW5TcXVhcmVkRXJyb3I7XG5leHBvcnQgY29uc3QgTVNFID0gbWVhblNxdWFyZWRFcnJvcjtcbmV4cG9ydCBjb25zdCBtYWUgPSBtZWFuQWJzb2x1dGVFcnJvcjtcbmV4cG9ydCBjb25zdCBNQUUgPSBtZWFuQWJzb2x1dGVFcnJvcjtcbmV4cG9ydCBjb25zdCBtYXBlID0gbWVhbkFic29sdXRlUGVyY2VudGFnZUVycm9yO1xuZXhwb3J0IGNvbnN0IE1BUEUgPSBtZWFuQWJzb2x1dGVQZXJjZW50YWdlRXJyb3I7XG5leHBvcnQgY29uc3QgY2F0ZWdvcmljYWxDcm9zc2VudHJvcHkgPSBjYXRlZ29yaWNhbENyb3NzZW50cm9weUxvc3M7XG5leHBvcnQgY29uc3QgY29zaW5lID0gY29zaW5lUHJveGltaXR5O1xuZXhwb3J0IGNvbnN0IHNwYXJzZUNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5ID0gc3BhcnNlQ2F0ZWdvcmljYWxDcm9zc2VudHJvcHlMb3NzO1xuXG4vLyBUT0RPKGNhaXMsIG5pZWxzZW5lKTogQWRkIHNlcmlhbGl6ZSgpLlxuXG5leHBvcnQgY29uc3QgbWV0cmljc01hcDoge1tmdW5jdGlvbk5hbWU6IHN0cmluZ106IExvc3NPck1ldHJpY0ZufSA9IHtcbiAgYmluYXJ5QWNjdXJhY3ksXG4gIGNhdGVnb3JpY2FsQWNjdXJhY3ksXG4gIHByZWNpc2lvbixcbiAgY2F0ZWdvcmljYWxDcm9zc2VudHJvcHksXG4gIHNwYXJzZUNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5LFxuICBtc2UsXG4gIE1TRSxcbiAgbWFlLFxuICBNQUUsXG4gIG1hcGUsXG4gIE1BUEUsXG4gIGNvc2luZVxufTtcblxuZXhwb3J0IGZ1bmN0aW9uIGdldChpZGVudGlmaWVyOiBzdHJpbmd8TG9zc09yTWV0cmljRm4pOiBMb3NzT3JNZXRyaWNGbiB7XG4gIGlmICh0eXBlb2YgaWRlbnRpZmllciA9PT0gJ3N0cmluZycgJiYgaWRlbnRpZmllciBpbiBtZXRyaWNzTWFwKSB7XG4gICAgcmV0dXJuIG1ldHJpY3NNYXBbaWRlbnRpZmllcl07XG4gIH0gZWxzZSBpZiAodHlwZW9mIGlkZW50aWZpZXIgIT09ICdzdHJpbmcnICYmIGlkZW50aWZpZXIgIT0gbnVsbCkge1xuICAgIHJldHVybiBpZGVudGlmaWVyO1xuICB9IGVsc2Uge1xuICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKGBVbmtub3duIG1ldHJpYyAke2lkZW50aWZpZXJ9YCk7XG4gIH1cbn1cblxuLyoqXG4gKiBHZXQgdGhlIHNob3J0Y3V0IGZ1bmN0aW9uIG5hbWUuXG4gKlxuICogSWYgdGhlIGZuIG5hbWUgaXMgYSBzdHJpbmcsXG4gKiAgIGRpcmVjdGx5IHJldHVybiB0aGUgc3RyaW5nIG5hbWUuXG4gKiBJZiB0aGUgZnVuY3Rpb24gaXMgaW5jbHVkZWQgaW4gbWV0cmljc01hcCBvciBsb3NzZXNNYXAsXG4gKiAgIHJldHVybiBrZXkgb2YgdGhlIG1hcC5cbiAqICAgLSBJZiB0aGUgZnVuY3Rpb24gcmVsYXRpdmUgdG8gbXVsdGlwbGUga2V5cyxcbiAqICAgICByZXR1cm4gdGhlIGZpcnN0IGZvdW5kIGtleSBhcyB0aGUgZnVuY3Rpb24gbmFtZS5cbiAqICAgLSBJZiB0aGUgZnVuY3Rpb24gZXhpc3RzIGluIGJvdGggbG9zc2VzTWFwIGFuZCBtZXRyaWNzTWFwLFxuICogICAgIHNlYXJjaCBsb3NzZXNNYXAgZmlyc3QuXG4gKiBJZiB0aGUgZnVuY3Rpb24gaXMgbm90IGluY2x1ZGVkIGluIG1ldHJpY3NNYXAgb3IgbG9zc2VzTWFwLFxuICogICByZXR1cm4gdGhlIGZ1bmN0aW9uIG5hbWUuXG4gKlxuICogQHBhcmFtIGZuIGxvc3MgZnVuY3Rpb24sIG1ldHJpYyBmdW5jdGlvbiwgb3Igc2hvcnQgY3V0IG5hbWUuXG4gKiBAcmV0dXJucyBMb3NzIG9yIE1ldHJpYyBuYW1lIGluIHN0cmluZy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExvc3NPck1ldHJpY05hbWUoZm46IHN0cmluZ3xMb3NzT3JNZXRyaWNGbik6IHN0cmluZyB7XG4gIHV0aWwuYXNzZXJ0KGZuICE9PSBudWxsLCBgVW5rbm93biBMb3NzT3JNZXRyaWNGbiAke2ZufWApO1xuICBpZiAodHlwZW9mIGZuID09PSAnc3RyaW5nJykge1xuICAgIHJldHVybiBmbjtcbiAgfSBlbHNlIHtcbiAgICBsZXQgZm5OYW1lO1xuICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKGxvc3Nlc01hcCkpIHtcbiAgICAgIGlmIChsb3NzZXNNYXBba2V5XSA9PT0gZm4pIHtcbiAgICAgICAgZm5OYW1lID0ga2V5O1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGZuTmFtZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gZm5OYW1lO1xuICAgIH1cbiAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhtZXRyaWNzTWFwKSkge1xuICAgICAgaWYgKG1ldHJpY3NNYXBba2V5XSA9PT0gZm4pIHtcbiAgICAgICAgZm5OYW1lID0ga2V5O1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGZuTmFtZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gZm5OYW1lO1xuICAgIH1cbiAgICByZXR1cm4gKGZuIGFzIEZ1bmN0aW9uKS5uYW1lO1xuICB9XG59XG4iXX0=