UNPKG

@tensorflow/tfjs-layers

Version:

TensorFlow layers API in JavaScript

167 lines 21.7 kB
/** * @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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWV0cmljcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3RmanMtbGF5ZXJzL3NyYy9tZXRyaWNzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7OztHQVFHO0FBRUg7O0dBRUc7QUFFSCxPQUFPLEtBQUssR0FBRyxNQUFNLHVCQUF1QixDQUFDO0FBQzdDLE9BQU8sRUFBUyxJQUFJLEVBQUMsTUFBTSx1QkFBdUIsQ0FBQztBQUVuRCxPQUFPLEtBQUssQ0FBQyxNQUFNLHdCQUF3QixDQUFDO0FBQzVDLE9BQU8sRUFBQyxtQkFBbUIsRUFBRSxVQUFVLEVBQUMsTUFBTSxVQUFVLENBQUM7QUFDekQsT0FBTyxFQUFDLGtCQUFrQixJQUFJLHNCQUFzQixFQUFFLHVCQUF1QixJQUFJLDJCQUEyQixFQUFFLGVBQWUsRUFBRSxTQUFTLEVBQUUsaUJBQWlCLEVBQUUsMkJBQTJCLEVBQUUsZ0JBQWdCLEVBQUUsNkJBQTZCLElBQUksaUNBQWlDLEVBQUMsTUFBTSxVQUFVLENBQUM7QUFFaFMsT0FBTyxLQUFLLElBQUksTUFBTSx1QkFBdUIsQ0FBQztBQUU5QyxNQUFNLFVBQVUsY0FBYyxDQUFDLEtBQWEsRUFBRSxLQUFhO0lBQ3pELE9BQU8sSUFBSSxDQUFDLEdBQUcsRUFBRTtRQUNmLE1BQU0sU0FBUyxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLEdBQUcsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUNuRCxNQUFNLGdCQUFnQixHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzVFLE9BQU8sR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxnQkFBZ0IsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFD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LE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUU7WUFDekMsSUFBSSxVQUFVLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxFQUFFO2dCQUMxQixNQUFNLEdBQUcsR0FBRyxDQUFDO2dCQUNiLE1BQU07YUFDUDtTQUNGO1FBQ0QsSUFBSSxNQUFNLEtBQUssU0FBUyxFQUFFO1lBQ3hCLE9BQU8sTUFBTSxDQUFDO1NBQ2Y7UUFDRCxPQUFRLEVBQWUsQ0FBQyxJQUFJLENBQUM7S0FDOUI7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMTggR29vZ2xlIExMQ1xuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZVxuICogbGljZW5zZSB0aGF0IGNhbiBiZSBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIG9yIGF0XG4gKiBodHRwczovL29wZW5zb3VyY2Uub3JnL2xpY2Vuc2VzL01JVC5cbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKi9cblxuLyoqXG4gKiBCdWlsdC1pbiBtZXRyaWNzLlxuICovXG5cbmltcG9ydCAqIGFzIHRmYyBmcm9tICdAdGVuc29yZmxvdy90ZmpzLWNvcmUnO1xuaW1wb3J0IHtUZW5zb3IsIHRpZHl9IGZyb20gJ0B0ZW5zb3JmbG93L3RmanMtY29yZSc7XG5cbmltcG9ydCAqIGFzIEsgZnJvbSAnLi9iYWNrZW5kL3RmanNfYmFja2VuZCc7XG5pbXBvcnQge05vdEltcGxlbWVudGVkRXJyb3IsIFZhbHVlRXJyb3J9IGZyb20gJy4vZXJyb3JzJztcbmltcG9ydCB7YmluYXJ5Q3Jvc3NlbnRyb3B5IGFzIGxvc3NCaW5hcnlDcm9zc2VudHJvcHksIGNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5IGFzIGNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5TG9zcywgY29zaW5lUHJveGltaXR5LCBsb3NzZXNNYXAsIG1lYW5BYnNvbHV0ZUVycm9yLCBtZWFuQWJzb2x1dGVQZXJjZW50YWdlRXJyb3IsIG1lYW5TcXVhcmVkRXJyb3IsIHNwYXJzZUNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5IGFzIHNwYXJzZUNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5TG9zc30gZnJvbSAnLi9sb3NzZXMnO1xuaW1wb3J0IHtMb3NzT3JNZXRyaWNGbn0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgKiBhcyB1dGlsIGZyb20gJy4vdXRpbHMvZ2VuZXJpY191dGlscyc7XG5cbmV4cG9ydCBmdW5jdGlvbiBiaW5hcnlBY2N1cmFjeSh5VHJ1ZTogVGVuc29yLCB5UHJlZDogVGVuc29yKTogVGVuc29yIHtcbiAgcmV0dXJuIHRpZHkoKCkgPT4ge1xuICAgIGNvbnN0IHRocmVzaG9sZCA9IHRmYy5tdWwoLjUsIHRmYy5vbmVzTGlrZSh5UHJlZCkpO1xuICAgIGNvbnN0IHlQcmVkVGhyZXNob2xkZWQgPSBLLmNhc3QodGZjLmdyZWF0ZXIoeVByZWQsIHRocmVzaG9sZCksIHlUcnVlLmR0eXBlKTtcbiAgICByZXR1cm4gdGZjLm1lYW4odGZjLmVxdWFsKHlUcnVlLCB5UHJlZFRocmVzaG9sZGVkKSwgLTEpO1xuICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNhdGVnb3JpY2FsQWNjdXJhY3koeVRydWU6IFRlbnNvciwgeVByZWQ6IFRlbnNvcik6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KFxuICAgICAgKCkgPT4gSy5jYXN0KFxuICAgICAgICAgIHRmYy5lcXVhbCh0ZmMuYXJnTWF4KHlUcnVlLCAtMSksIHRmYy5hcmdNYXgoeVByZWQsIC0xKSksICdmbG9hdDMyJykpO1xufVxuXG5mdW5jdGlvbiB0cnVlUG9zaXRpdmVzKHlUcnVlOiBUZW5zb3IsIHlQcmVkOiBUZW5zb3IpOiBUZW5zb3Ige1xuICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgcmV0dXJuIHRmYy5jYXN0KFxuICAgICAgICB0ZmMuc3VtKHRmYy5sb2dpY2FsQW5kKHRmYy5lcXVhbCh5VHJ1ZSwgMSksIHRmYy5lcXVhbCh5UHJlZCwgMSkpKSxcbiAgICAgICAgJ2Zsb2F0MzInKTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGZhbHNlTmVnYXRpdmVzKHlUcnVlOiBUZW5zb3IsIHlQcmVkOiBUZW5zb3IpOiBUZW5zb3Ige1xuICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgcmV0dXJuIHRmYy5jYXN0KFxuICAgICAgICB0ZmMuc3VtKHRmYy5sb2dpY2FsQW5kKHRmYy5lcXVhbCh5VHJ1ZSwgMSksIHRmYy5lcXVhbCh5UHJlZCwgMCkpKSxcbiAgICAgICAgJ2Zsb2F0MzInKTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGZhbHNlUG9zaXRpdmVzKHlUcnVlOiBUZW5zb3IsIHlQcmVkOiBUZW5zb3IpOiBUZW5zb3Ige1xuICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgcmV0dXJuIHRmYy5jYXN0KFxuICAgICAgICB0ZmMuc3VtKHRmYy5sb2dpY2FsQW5kKHRmYy5lcXVhbCh5VHJ1ZSwgMCksIHRmYy5lcXVhbCh5UHJlZCwgMSkpKSxcbiAgICAgICAgJ2Zsb2F0MzInKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBwcmVjaXNpb24oeVRydWU6IFRlbnNvciwgeVByZWQ6IFRlbnNvcik6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICBjb25zdCB0cCA9IHRydWVQb3NpdGl2ZXMoeVRydWUsIHlQcmVkKTtcbiAgICBjb25zdCBmcCA9IGZhbHNlUG9zaXRpdmVzKHlUcnVlLCB5UHJlZCk7XG5cbiAgICBjb25zdCBkZW5vbWluYXRvciA9IHRmYy5hZGQodHAsIGZwKTtcblxuICAgIHJldHVybiB0ZmMuY2FzdChcbiAgICAgICAgdGZjLndoZXJlKHRmYy5ncmVhdGVyKGRlbm9taW5hdG9yLCAwKSwgdGZjLmRpdih0cCwgZGVub21pbmF0b3IpLCAwKSxcbiAgICAgICAgJ2Zsb2F0MzInKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWNhbGwoeVRydWU6IFRlbnNvciwgeVByZWQ6IFRlbnNvcik6IFRlbnNvciB7XG4gIHJldHVybiB0aWR5KCgpID0+IHtcbiAgICBjb25zdCB0cCA9IHRydWVQb3NpdGl2ZXMoeVRydWUsIHlQcmVkKTtcbiAgICBjb25zdCBmbiA9IGZhbHNlTmVnYXRpdmVzKHlUcnVlLCB5UHJlZCk7XG5cbiAgICBjb25zdCBkZW5vbWluYXRvciA9IHRmYy5hZGQodHAsIGZuKTtcblxuICAgIHJldHVybiB0ZmMuY2FzdChcbiAgICAgICAgdGZjLndoZXJlKHRmYy5ncmVhdGVyKGRlbm9taW5hdG9yLCAwKSwgdGZjLmRpdih0cCwgZGVub21pbmF0b3IpLCAwKSxcbiAgICAgICAgJ2Zsb2F0MzInKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBiaW5hcnlDcm9zc2VudHJvcHkoeVRydWU6IFRlbnNvciwgeVByZWQ6IFRlbnNvcik6IFRlbnNvciB7XG4gIHJldHVybiBsb3NzQmluYXJ5Q3Jvc3NlbnRyb3B5KHlUcnVlLCB5UHJlZCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzcGFyc2VDYXRlZ29yaWNhbEFjY3VyYWN5KFxuICAgIHlUcnVlOiBUZW5zb3IsIHlQcmVkOiBUZW5zb3IpOiBUZW5zb3Ige1xuICBpZiAoeVRydWUucmFuayA9PT0geVByZWQucmFuaykge1xuICAgIHlUcnVlID0gdGZjLnNxdWVlemUoeVRydWUsIFt5VHJ1ZS5yYW5rIC0gMV0pO1xuICB9XG4gIHlQcmVkID0gdGZjLmFyZ01heCh5UHJlZCwgLTEpO1xuICBpZiAoeVByZWQuZHR5cGUgIT09IHlUcnVlLmR0eXBlKSB7XG4gICAgeVByZWQgPSB0ZmMuY2FzdCh5UHJlZCwgeVRydWUuZHR5cGUpO1xuICB9XG4gIHJldHVybiB0ZmMuY2FzdCh0ZmMuZXF1YWwoeVRydWUsIHlQcmVkKSwgJ2Zsb2F0MzInKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHRvcEtDYXRlZ29yaWNhbEFjY3VyYWN5KHlUcnVlOiBUZW5zb3IsIHlQcmVkOiBUZW5zb3IpOiBUZW5zb3Ige1xuICB0aHJvdyBuZXcgTm90SW1wbGVtZW50ZWRFcnJvcigpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc3BhcnNlVG9wS0NhdGVnb3JpY2FsQWNjdXJhY3koXG4gICAgeVRydWU6IFRlbnNvciwgeVByZWQ6IFRlbnNvcik6IFRlbnNvciB7XG4gIHRocm93IG5ldyBOb3RJbXBsZW1lbnRlZEVycm9yKCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByMlNjb3JlKHlUcnVlOiBUZW5zb3IsIHlQcmVkOiBUZW5zb3IpOiBUZW5zb3Ige1xuICByZXR1cm4gdGlkeSgoKSA9PiB7XG4gICAgY29uc3Qgc3VtU3F1YXJlc1Jlc2lkdWFscyA9IHlUcnVlLnN1Yih5UHJlZCkuc3F1YXJlKCkuc3VtKCk7XG4gICAgY29uc3Qgc3VtU3F1YXJlcyA9IHlUcnVlLnN1Yih5VHJ1ZS5tZWFuKCkpLnNxdWFyZSgpLnN1bSgpO1xuICAgIHJldHVybiB0ZmMuc2NhbGFyKDEpLnN1YihzdW1TcXVhcmVzUmVzaWR1YWxzLmRpdihzdW1TcXVhcmVzKSk7XG4gIH0pO1xufVxuXG4vLyBBbGlhc2VzLlxuZXhwb3J0IGNvbnN0IG1zZSA9IG1lYW5TcXVhcmVkRXJyb3I7XG5leHBvcnQgY29uc3QgTVNFID0gbWVhblNxdWFyZWRFcnJvcjtcbmV4cG9ydCBjb25zdCBtYWUgPSBtZWFuQWJzb2x1dGVFcnJvcjtcbmV4cG9ydCBjb25zdCBNQUUgPSBtZWFuQWJzb2x1dGVFcnJvcjtcbmV4cG9ydCBjb25zdCBtYXBlID0gbWVhbkFic29sdXRlUGVyY2VudGFnZUVycm9yO1xuZXhwb3J0IGNvbnN0IE1BUEUgPSBtZWFuQWJzb2x1dGVQZXJjZW50YWdlRXJyb3I7XG5leHBvcnQgY29uc3QgY2F0ZWdvcmljYWxDcm9zc2VudHJvcHkgPSBjYXRlZ29yaWNhbENyb3NzZW50cm9weUxvc3M7XG5leHBvcnQgY29uc3QgY29zaW5lID0gY29zaW5lUHJveGltaXR5O1xuZXhwb3J0IGNvbnN0IHNwYXJzZUNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5ID0gc3BhcnNlQ2F0ZWdvcmljYWxDcm9zc2VudHJvcHlMb3NzO1xuXG4vLyBUT0RPKGNhaXMsIG5pZWxzZW5lKTogQWRkIHNlcmlhbGl6ZSgpLlxuXG5leHBvcnQgY29uc3QgbWV0cmljc01hcDoge1tmdW5jdGlvbk5hbWU6IHN0cmluZ106IExvc3NPck1ldHJpY0ZufSA9IHtcbiAgYmluYXJ5QWNjdXJhY3ksXG4gIGNhdGVnb3JpY2FsQWNjdXJhY3ksXG4gIHByZWNpc2lvbixcbiAgY2F0ZWdvcmljYWxDcm9zc2VudHJvcHksXG4gIHNwYXJzZUNhdGVnb3JpY2FsQ3Jvc3NlbnRyb3B5LFxuICBtc2UsXG4gIE1TRSxcbiAgbWFlLFxuICBNQUUsXG4gIG1hcGUsXG4gIE1BUEUsXG4gIGNvc2luZVxufTtcblxuZXhwb3J0IGZ1bmN0aW9uIGdldChpZGVudGlmaWVyOiBzdHJpbmd8TG9zc09yTWV0cmljRm4pOiBMb3NzT3JNZXRyaWNGbiB7XG4gIGlmICh0eXBlb2YgaWRlbnRpZmllciA9PT0gJ3N0cmluZycgJiYgaWRlbnRpZmllciBpbiBtZXRyaWNzTWFwKSB7XG4gICAgcmV0dXJuIG1ldHJpY3NNYXBbaWRlbnRpZmllcl07XG4gIH0gZWxzZSBpZiAodHlwZW9mIGlkZW50aWZpZXIgIT09ICdzdHJpbmcnICYmIGlkZW50aWZpZXIgIT0gbnVsbCkge1xuICAgIHJldHVybiBpZGVudGlmaWVyO1xuICB9IGVsc2Uge1xuICAgIHRocm93IG5ldyBWYWx1ZUVycm9yKGBVbmtub3duIG1ldHJpYyAke2lkZW50aWZpZXJ9YCk7XG4gIH1cbn1cblxuLyoqXG4gKiBHZXQgdGhlIHNob3J0Y3V0IGZ1bmN0aW9uIG5hbWUuXG4gKlxuICogSWYgdGhlIGZuIG5hbWUgaXMgYSBzdHJpbmcsXG4gKiAgIGRpcmVjdGx5IHJldHVybiB0aGUgc3RyaW5nIG5hbWUuXG4gKiBJZiB0aGUgZnVuY3Rpb24gaXMgaW5jbHVkZWQgaW4gbWV0cmljc01hcCBvciBsb3NzZXNNYXAsXG4gKiAgIHJldHVybiBrZXkgb2YgdGhlIG1hcC5cbiAqICAgLSBJZiB0aGUgZnVuY3Rpb24gcmVsYXRpdmUgdG8gbXVsdGlwbGUga2V5cyxcbiAqICAgICByZXR1cm4gdGhlIGZpcnN0IGZvdW5kIGtleSBhcyB0aGUgZnVuY3Rpb24gbmFtZS5cbiAqICAgLSBJZiB0aGUgZnVuY3Rpb24gZXhpc3RzIGluIGJvdGggbG9zc2VzTWFwIGFuZCBtZXRyaWNzTWFwLFxuICogICAgIHNlYXJjaCBsb3NzZXNNYXAgZmlyc3QuXG4gKiBJZiB0aGUgZnVuY3Rpb24gaXMgbm90IGluY2x1ZGVkIGluIG1ldHJpY3NNYXAgb3IgbG9zc2VzTWFwLFxuICogICByZXR1cm4gdGhlIGZ1bmN0aW9uIG5hbWUuXG4gKlxuICogQHBhcmFtIGZuIGxvc3MgZnVuY3Rpb24sIG1ldHJpYyBmdW5jdGlvbiwgb3Igc2hvcnQgY3V0IG5hbWUuXG4gKiBAcmV0dXJucyBMb3NzIG9yIE1ldHJpYyBuYW1lIGluIHN0cmluZy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExvc3NPck1ldHJpY05hbWUoZm46IHN0cmluZ3xMb3NzT3JNZXRyaWNGbik6IHN0cmluZyB7XG4gIHV0aWwuYXNzZXJ0KGZuICE9PSBudWxsLCBgVW5rbm93biBMb3NzT3JNZXRyaWNGbiAke2ZufWApO1xuICBpZiAodHlwZW9mIGZuID09PSAnc3RyaW5nJykge1xuICAgIHJldHVybiBmbjtcbiAgfSBlbHNlIHtcbiAgICBsZXQgZm5OYW1lO1xuICAgIGZvciAoY29uc3Qga2V5IG9mIE9iamVjdC5rZXlzKGxvc3Nlc01hcCkpIHtcbiAgICAgIGlmIChsb3NzZXNNYXBba2V5XSA9PT0gZm4pIHtcbiAgICAgICAgZm5OYW1lID0ga2V5O1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGZuTmFtZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gZm5OYW1lO1xuICAgIH1cbiAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhtZXRyaWNzTWFwKSkge1xuICAgICAgaWYgKG1ldHJpY3NNYXBba2V5XSA9PT0gZm4pIHtcbiAgICAgICAgZm5OYW1lID0ga2V5O1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGZuTmFtZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gZm5OYW1lO1xuICAgIH1cbiAgICByZXR1cm4gKGZuIGFzIEZ1bmN0aW9uKS5uYW1lO1xuICB9XG59XG4iXX0=