/**
|
* @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 { categoricalCrossentropy as categoricalCrossentropyLoss, cosineProximity, meanAbsoluteError, meanAbsolutePercentageError, meanSquaredError, sparseCategoricalCrossentropy as sparseCategoricalCrossentropyLoss } from './losses';
|
import { binaryCrossentropy as lossBinaryCrossentropy } from './losses';
|
import { lossesMap } 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();
|
}
|
// 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWV0cmljcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3RmanMtbGF5ZXJzL3NyYy9tZXRyaWNzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7OztHQVFHO0FBRUg7O0dBRUc7QUFFSCxPQUFPLEtBQUssR0FBRyxNQUFNLHVCQUF1QixDQUFDO0FBQzdDLE9BQU8sRUFBUyxJQUFJLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUVuRCxPQUFPLEtBQUssQ0FBQyxNQUFNLHdCQUF3QixDQUFDO0FBQzVDLE9BQU8sRUFBQyxtQkFBbUIsRUFBRSxVQUFVLEVBQUMsTUFBTSxVQUFVLENBQUM7QUFDekQsT0FBTyxFQUFDLHVCQUF1QixJQUFJLDJCQUEyQixFQUFFLGVBQWUsRUFBRSxpQkFBaUIsRUFBRSwyQkFBMkIsRUFBRSxnQkFBZ0IsRUFBRSw2QkFBNkIsSUFBSSxpQ0FBaUMsRUFBQyxNQUFNLFVBQVUsQ0FBQztBQUN2TyxPQUFPLEVBQUMsa0JBQWtCLElBQUksc0JBQXNCLEVBQUMsTUFBTSxVQUFVLENBQUM7QUFDdEUsT0FBTyxFQUFDLFNBQVMsRUFBQyxNQUFNLFVBQVUsQ0FBQztBQUVuQyxPQUFPLEtBQUssSUFBSSxNQUFNLHVCQUF1QixDQUFDO0FBRTlDLE1BQU0sVUFBVSxjQUFjLENBQUMsS0FBYSxFQUFFLEtBQWE7SUFDekQsT0FBTyxJQUFJLENBQUMsR0FBRyxFQUFFO1FBQ2YsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsR0FBRyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQ25ELE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxTQUFTLENBQUMsRUFBRSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDNUUsT0FBTyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FB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LFVBQVUsSUFBSSxJQUFJLEVBQUU7UUFDL0QsT0FBTyxVQUFVLENBQUM7S0FDbkI7U0FBTTtRQUNMLE1BQU0sSUFBSSxVQUFVLENBQUMsa0JBQWtCLFVBQVUsRUFBRSxDQUFDLENBQUM7S0FDdEQ7QUFDSCxDQUFDO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFDSCxNQUFNLFVBQVUsbUJBQW1CLENBQUMsRUFBeUI7SUFDM0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEtBQUssSUFBSSxFQUFFLDBCQUEwQixFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ3pELElBQUksT0FBTyxFQUFFLEtBQUssUUFBUSxFQUFFO1FBQzFCLE9BQU8sRUFBRSxDQUFDO0tBQ1g7U0FBTTtRQUNMLElBQUksTUFBTSxDQUFDO1FBQ1gsS0FBSyxNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFO1lBQ3hDLElBQUksU0FBUyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsRUFBRTtnQkFDekIsTUFBTSxHQUFHLEdBQUcsQ0FBQztnQkFDYixNQUFNO2FBQ1A7U0FDRjtRQUNELElBQUksTUFBTSxLQUFLLFNBQVMsRUFBRTtZQUN4QixPQUFPLE1BQU0sQ0FBQztTQUNmO1FBQ0QsS0FBSyxNQUFNLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxFQUFFO1lBQ3pDLElBQUksVUFBVSxDQUFDLEdBQUcsQ0FBQyxLQUFLLEVBQUUsRUFBRTtnQkFDMUIsTUFBTSxHQUFHLEdBQUcsQ0FBQztnQkFDYixNQUFNO2FBQ1A7U0FDRjtRQUNELElBQUksTUFBTSxLQUFLLFNBQVMsRUFBRTtZQUN4QixPQUFPLE1BQU0sQ0FBQztTQUNmO1FBQ0QsT0FBUSxFQUFlLENBQUMsSUFBSSxDQUFDO0tBQzlCO0FBQ0gsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCAyMDE4IEdvb2dsZSBMTENcbiAqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGVcbiAqIGxpY2Vuc2UgdGhhdCBjYW4gYmUgZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBvciBhdFxuICogaHR0cHM6Ly9vcGVuc291cmNlLm9yZy9saWNlbnNlcy9NSVQuXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICovXG5cbi8qKlxuICogQnVpbHQtaW4gbWV0cmljcy5cbiAqL1xuXG5pbXBvcnQgKiBhcyB0ZmMgZnJvbSAnQHRlbnNvcmZsb3cvdGZqcy1jb3JlJztcbmltcG9ydCB7VGVuc29yLCB0aWR5fSBmcm9tICdAdGVuc29yZmxvdy90ZmpzLWNvcmUnO1xuXG5pbXBvcnQgKiBhcyBLIGZyb20gJy4vYmFja2VuZC90ZmpzX2JhY2tlbmQnO1xuaW1wb3J0IHtOb3RJbXBsZW1lbnRlZEVycm9yLCBWYWx1ZUVycm9yfSBmcm9tICcuL2Vycm9ycyc7XG5pbXBvcnQge2NhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5IGFzIGNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5TG9zcywgY29zaW5lUHJveGltaXR5LCBtZWFuQWJzb2x1dGVFcnJvciwgbWVhbkFic29sdXRlUGVyY2VudGFnZUVycm9yLCBtZWFuU3F1YXJlZEVycm9yLCBzcGFyc2VDYXRlZ29yaWNhbENyb3NzZW50cm9weSBhcyBzcGFyc2VDYXRlZ29yaWNhbENyb3NzZW50cm9weUxvc3N9IGZyb20gJy4vbG9zc2VzJztcbmltcG9ydCB7YmluYXJ5Q3Jvc3NlbnRyb3B5IGFzIGxvc3NCaW5hcnlDcm9zc2VudHJvcHl9IGZyb20gJy4vbG9zc2VzJztcbmltcG9ydCB7bG9zc2VzTWFwfSBmcm9tICcuL2xvc3Nlcyc7XG5pbXBvcnQge0xvc3NPck1ldHJpY0ZufSBmcm9tICcuL3R5cGVzJztcbmltcG9ydCAqIGFzIHV0aWwgZnJvbSAnLi91dGlscy9nZW5lcmljX3V0aWxzJztcblxuZXhwb3J0IGZ1bmN0aW9uIGJpbmFyeUFjY3VyYWN5KHlUcnVlOiBUZW5zb3IsIHlQcmVkOiBUZW5zb3IpOiBUZW5zb3Ige1xuICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgY29uc3QgdGhyZXNob2xkID0gdGZjLm11bCguNSwgdGZjLm9uZXNMaWtlKHlQcmVkKSk7XG4gICAgY29uc3QgeVByZWRUaHJlc2hvbGRlZCA9IEsuY2FzdCh0ZmMuZ3JlYXRlcih5UHJlZCwgdGhyZXNob2xkKSwgeVRydWUuZHR5cGUpO1xuICAgIHJldHVybiB0ZmMubWVhbih0ZmMuZXF1YWwoeVRydWUsIHlQcmVkVGhyZXNob2xkZWQpLCAtMSk7XG4gIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY2F0ZWdvcmljYWxBY2N1cmFjeSh5VHJ1ZTogVGVuc29yLCB5UHJlZDogVGVuc29yKTogVGVuc29yIHtcbiAgcmV0dXJuIHRpZHkoXG4gICAgICAoKSA9PiBLLmNhc3QoXG4gICAgICAgICAgdGZjLmVxdWFsKHRmYy5hcmdNYXgoeVRydWUsIC0xKSwgdGZjLmFyZ01heCh5UHJlZCwgLTEpKSwgJ2Zsb2F0MzInKSk7XG59XG5cbmZ1bmN0aW9uIHRydWVQb3NpdGl2ZXMoeVRydWU6IFRlbnNvciwgeVByZWQ6IFRlbnNvcik6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICByZXR1cm4gdGZjLmNhc3QoXG4gICAgICAgIHRmYy5zdW0odGZjLmxvZ2ljYWxBbmQodGZjLmVxdWFsKHlUcnVlLCAxKSwgdGZjLmVxdWFsKHlQcmVkLCAxKSkpLFxuICAgICAgICAnZmxvYXQzMicpO1xuICB9KTtcbn1cblxuZnVuY3Rpb24gZmFsc2VOZWdhdGl2ZXMoeVRydWU6IFRlbnNvciwgeVByZWQ6IFRlbnNvcik6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICByZXR1cm4gdGZjLmNhc3QoXG4gICAgICAgIHRmYy5zdW0odGZjLmxvZ2ljYWxBbmQodGZjLmVxdWFsKHlUcnVlLCAxKSwgdGZjLmVxdWFsKHlQcmVkLCAwKSkpLFxuICAgICAgICAnZmxvYXQzMicpO1xuICB9KTtcbn1cblxuZnVuY3Rpb24gZmFsc2VQb3NpdGl2ZXMoeVRydWU6IFRlbnNvciwgeVByZWQ6IFRlbnNvcik6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICByZXR1cm4gdGZjLmNhc3QoXG4gICAgICAgIHRmYy5zdW0odGZjLmxvZ2ljYWxBbmQodGZjLmVxdWFsKHlUcnVlLCAwKSwgdGZjLmVxdWFsKHlQcmVkLCAxKSkpLFxuICAgICAgICAnZmxvYXQzMicpO1xuICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHByZWNpc2lvbih5VHJ1ZTogVGVuc29yLCB5UHJlZDogVGVuc29yKTogVGVuc29yIHtcbiAgcmV0dXJuIHRpZHkoKCkgPT4ge1xuICAgIGNvbnN0IHRwID0gdHJ1ZVBvc2l0aXZlcyh5VHJ1ZSwgeVByZWQpO1xuICAgIGNvbnN0IGZwID0gZmFsc2VQb3NpdGl2ZXMoeVRydWUsIHlQcmVkKTtcblxuICAgIGNvbnN0IGRlbm9taW5hdG9yID0gdGZjLmFkZCh0cCwgZnApO1xuXG4gICAgcmV0dXJuIHRmYy5jYXN0KFxuICAgICAgICB0ZmMud2hlcmUodGZjLmdyZWF0ZXIoZGVub21pbmF0b3IsIDApLCB0ZmMuZGl2KHRwLCBkZW5vbWluYXRvciksIDApLFxuICAgICAgICAnZmxvYXQzMicpO1xuICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlY2FsbCh5VHJ1ZTogVGVuc29yLCB5UHJlZDogVGVuc29yKTogVGVuc29yIHtcbiAgcmV0dXJuIHRpZHkoKCkgPT4ge1xuICAgIGNvbnN0IHRwID0gdHJ1ZVBvc2l0aXZlcyh5VHJ1ZSwgeVByZWQpO1xuICAgIGNvbnN0IGZuID0gZmFsc2VOZWdhdGl2ZXMoeVRydWUsIHlQcmVkKTtcblxuICAgIGNvbnN0IGRlbm9taW5hdG9yID0gdGZjLmFkZCh0cCwgZm4pO1xuXG4gICAgcmV0dXJuIHRmYy5jYXN0KFxuICAgICAgICB0ZmMud2hlcmUodGZjLmdyZWF0ZXIoZGVub21pbmF0b3IsIDApLCB0ZmMuZGl2KHRwLCBkZW5vbWluYXRvciksIDApLFxuICAgICAgICAnZmxvYXQzMicpO1xuICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGJpbmFyeUNyb3NzZW50cm9weSh5VHJ1ZTogVGVuc29yLCB5UHJlZDogVGVuc29yKTogVGVuc29yIHtcbiAgcmV0dXJuIGxvc3NCaW5hcnlDcm9zc2VudHJvcHkoeVRydWUsIHlQcmVkKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNwYXJzZUNhdGVnb3JpY2FsQWNjdXJhY3koXG4gICAgeVRydWU6IFRlbnNvciwgeVByZWQ6IFRlbnNvcik6IFRlbnNvciB7XG4gIGlmICh5VHJ1ZS5yYW5rID09PSB5UHJlZC5yYW5rKSB7XG4gICAgeVRydWUgPSB0ZmMuc3F1ZWV6ZSh5VHJ1ZSwgW3lUcnVlLnJhbmsgLSAxXSk7XG4gIH1cbiAgeVByZWQgPSB0ZmMuYXJnTWF4KHlQcmVkLCAtMSk7XG4gIGlmICh5UHJlZC5kdHlwZSAhPT0geVRydWUuZHR5cGUpIHtcbiAgICB5UHJlZCA9IHRmYy5jYXN0KHlQcmVkLCB5VHJ1ZS5kdHlwZSk7XG4gIH1cbiAgcmV0dXJuIHRmYy5jYXN0KHRmYy5lcXVhbCh5VHJ1ZSwgeVByZWQpLCAnZmxvYXQzMicpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdG9wS0NhdGVnb3JpY2FsQWNjdXJhY3koeVRydWU6IFRlbnNvciwgeVByZWQ6IFRlbnNvcik6IFRlbnNvciB7XG4gIHRocm93IG5ldyBOb3RJbXBsZW1lbnRlZEVycm9yKCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzcGFyc2VUb3BLQ2F0ZWdvcmljYWxBY2N1cmFjeShcbiAgICB5VHJ1ZTogVGVuc29yLCB5UHJlZDogVGVuc29yKTogVGVuc29yIHtcbiAgdGhyb3cgbmV3IE5vdEltcGxlbWVudGVkRXJyb3IoKTtcbn1cblxuLy8gQWxpYXNlcy5cbmV4cG9ydCBjb25zdCBtc2UgPSBtZWFuU3F1YXJlZEVycm9yO1xuZXhwb3J0IGNvbnN0IE1TRSA9IG1lYW5TcXVhcmVkRXJyb3I7XG5leHBvcnQgY29uc3QgbWFlID0gbWVhbkFic29sdXRlRXJyb3I7XG5leHBvcnQgY29uc3QgTUFFID0gbWVhbkFic29sdXRlRXJyb3I7XG5leHBvcnQgY29uc3QgbWFwZSA9IG1lYW5BYnNvbHV0ZVBlcmNlbnRhZ2VFcnJvcjtcbmV4cG9ydCBjb25zdCBNQVBFID0gbWVhbkFic29sdXRlUGVyY2VudGFnZUVycm9yO1xuZXhwb3J0IGNvbnN0IGNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5ID0gY2F0ZWdvcmljYWxDcm9zc2VudHJvcHlMb3NzO1xuZXhwb3J0IGNvbnN0IGNvc2luZSA9IGNvc2luZVByb3hpbWl0eTtcbmV4cG9ydCBjb25zdCBzcGFyc2VDYXRlZ29yaWNhbENyb3NzZW50cm9weSA9IHNwYXJzZUNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5TG9zcztcblxuLy8gVE9ETyhjYWlzLCBuaWVsc2VuZSk6IEFkZCBzZXJpYWxpemUoKS5cblxuZXhwb3J0IGNvbnN0IG1ldHJpY3NNYXA6IHtbZnVuY3Rpb25OYW1lOiBzdHJpbmddOiBMb3NzT3JNZXRyaWNGbn0gPSB7XG4gIGJpbmFyeUFjY3VyYWN5LFxuICBjYXRlZ29yaWNhbEFjY3VyYWN5LFxuICBwcmVjaXNpb24sXG4gIGNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5LFxuICBzcGFyc2VDYXRlZ29yaWNhbENyb3NzZW50cm9weSxcbiAgbXNlLFxuICBNU0UsXG4gIG1hZSxcbiAgTUFFLFxuICBtYXBlLFxuICBNQVBFLFxuICBjb3NpbmVcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXQoaWRlbnRpZmllcjogc3RyaW5nfExvc3NPck1ldHJpY0ZuKTogTG9zc09yTWV0cmljRm4ge1xuICBpZiAodHlwZW9mIGlkZW50aWZpZXIgPT09ICdzdHJpbmcnICYmIGlkZW50aWZpZXIgaW4gbWV0cmljc01hcCkge1xuICAgIHJldHVybiBtZXRyaWNzTWFwW2lkZW50aWZpZXJdO1xuICB9IGVsc2UgaWYgKHR5cGVvZiBpZGVudGlmaWVyICE9PSAnc3RyaW5nJyAmJiBpZGVudGlmaWVyICE9IG51bGwpIHtcbiAgICByZXR1cm4gaWRlbnRpZmllcjtcbiAgfSBlbHNlIHtcbiAgICB0aHJvdyBuZXcgVmFsdWVFcnJvcihgVW5rbm93biBtZXRyaWMgJHtpZGVudGlmaWVyfWApO1xuICB9XG59XG5cbi8qKlxuICogR2V0IHRoZSBzaG9ydGN1dCBmdW5jdGlvbiBuYW1lLlxuICpcbiAqIElmIHRoZSBmbiBuYW1lIGlzIGEgc3RyaW5nLFxuICogICBkaXJlY3RseSByZXR1cm4gdGhlIHN0cmluZyBuYW1lLlxuICogSWYgdGhlIGZ1bmN0aW9uIGlzIGluY2x1ZGVkIGluIG1ldHJpY3NNYXAgb3IgbG9zc2VzTWFwLFxuICogICByZXR1cm4ga2V5IG9mIHRoZSBtYXAuXG4gKiAgIC0gSWYgdGhlIGZ1bmN0aW9uIHJlbGF0aXZlIHRvIG11bHRpcGxlIGtleXMsXG4gKiAgICAgcmV0dXJuIHRoZSBmaXJzdCBmb3VuZCBrZXkgYXMgdGhlIGZ1bmN0aW9uIG5hbWUuXG4gKiAgIC0gSWYgdGhlIGZ1bmN0aW9uIGV4aXN0cyBpbiBib3RoIGxvc3Nlc01hcCBhbmQgbWV0cmljc01hcCxcbiAqICAgICBzZWFyY2ggbG9zc2VzTWFwIGZpcnN0LlxuICogSWYgdGhlIGZ1bmN0aW9uIGlzIG5vdCBpbmNsdWRlZCBpbiBtZXRyaWNzTWFwIG9yIGxvc3Nlc01hcCxcbiAqICAgcmV0dXJuIHRoZSBmdW5jdGlvbiBuYW1lLlxuICpcbiAqIEBwYXJhbSBmbiBsb3NzIGZ1bmN0aW9uLCBtZXRyaWMgZnVuY3Rpb24sIG9yIHNob3J0IGN1dCBuYW1lLlxuICogQHJldHVybnMgTG9zcyBvciBNZXRyaWMgbmFtZSBpbiBzdHJpbmcuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRMb3NzT3JNZXRyaWNOYW1lKGZuOiBzdHJpbmd8TG9zc09yTWV0cmljRm4pOiBzdHJpbmcge1xuICB1dGlsLmFzc2VydChmbiAhPT0gbnVsbCwgYFVua25vd24gTG9zc09yTWV0cmljRm4gJHtmbn1gKTtcbiAgaWYgKHR5cGVvZiBmbiA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gZm47XG4gIH0gZWxzZSB7XG4gICAgbGV0IGZuTmFtZTtcbiAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhsb3NzZXNNYXApKSB7XG4gICAgICBpZiAobG9zc2VzTWFwW2tleV0gPT09IGZuKSB7XG4gICAgICAgIGZuTmFtZSA9IGtleTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChmbk5hbWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIGZuTmFtZTtcbiAgICB9XG4gICAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXMobWV0cmljc01hcCkpIHtcbiAgICAgIGlmIChtZXRyaWNzTWFwW2tleV0gPT09IGZuKSB7XG4gICAgICAgIGZuTmFtZSA9IGtleTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChmbk5hbWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIGZuTmFtZTtcbiAgICB9XG4gICAgcmV0dXJuIChmbiBhcyBGdW5jdGlvbikubmFtZTtcbiAgfVxufVxuIl19
|