UNPKG

@tensorflow/tfjs-data

Version:

TensorFlow Data API in JavaScript

163 lines 22.7 kB
/** * @license * Copyright 2018 Google LLC. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ============================================================================= */ import * as tf from '@tensorflow/tfjs-core'; import { div, max, min, sub } from '@tensorflow/tfjs-core'; /** * Provides a function that scales numeric values into the [0, 1] interval. * * @param min the lower bound of the inputs, which should be mapped to 0. * @param max the upper bound of the inputs, which should be mapped to 1, * @return A function that maps an input ElementArray to a scaled ElementArray. */ export function scaleTo01(min, max) { const range = max - min; const minTensor = tf.scalar(min); const rangeTensor = tf.scalar(range); return (value) => { if (typeof (value) === 'string') { throw new Error('Can\'t scale a string.'); } else { if (value instanceof tf.Tensor) { const result = div(sub(value, minTensor), rangeTensor); return result; } else if (value instanceof Array) { return value.map(v => (v - min) / range); } else { return (value - min) / range; } } }; } /** * Provides a function that calculates column level statistics, i.e. min, max, * variance, stddev. * * @param dataset The Dataset object whose statistics will be calculated. * @param sampleSize (Optional) If set, statistics will only be calculated * against a subset of the whole data. * @param shuffleWindowSize (Optional) If set, shuffle provided dataset before * calculating statistics. * @return A DatasetStatistics object that contains NumericColumnStatistics of * each column. */ export async function computeDatasetStatistics(dataset, sampleSize, shuffleWindowSize) { let sampleDataset = dataset; // TODO(soergel): allow for deep shuffle where possible. if (shuffleWindowSize != null) { sampleDataset = sampleDataset.shuffle(shuffleWindowSize); } if (sampleSize != null) { sampleDataset = sampleDataset.take(sampleSize); } // TODO(soergel): prepare the column objects based on a schema. const result = {}; await sampleDataset.forEachAsync(e => { for (const key of Object.keys(e)) { const value = e[key]; if (typeof (value) === 'string') { // No statistics for string element. } else { let previousMean = 0; let previousLength = 0; let previousVariance = 0; let columnStats = result[key]; if (columnStats == null) { columnStats = { min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY, mean: 0, variance: 0, stddev: 0, length: 0 }; result[key] = columnStats; } else { previousMean = columnStats.mean; previousLength = columnStats.length; previousVariance = columnStats.variance; } let recordMin; let recordMax; // Calculate accumulated mean and variance following tf.Transform // implementation let valueLength = 0; let valueMean = 0; let valueVariance = 0; let combinedLength = 0; let combinedMean = 0; let combinedVariance = 0; if (value instanceof tf.Tensor) { recordMin = min(value).dataSync()[0]; recordMax = max(value).dataSync()[0]; const valueMoment = tf.moments(value); valueMean = valueMoment.mean.dataSync()[0]; valueVariance = valueMoment.variance.dataSync()[0]; valueLength = value.size; } else if (value instanceof Array) { recordMin = value.reduce((a, b) => Math.min(a, b)); recordMax = value.reduce((a, b) => Math.max(a, b)); const valueMoment = tf.moments(value); valueMean = valueMoment.mean.dataSync()[0]; valueVariance = valueMoment.variance.dataSync()[0]; valueLength = value.length; } else if (!isNaN(value) && isFinite(value)) { recordMin = value; recordMax = value; valueMean = value; valueVariance = 0; valueLength = 1; } else { columnStats = null; continue; } combinedLength = previousLength + valueLength; combinedMean = previousMean + (valueLength / combinedLength) * (valueMean - previousMean); combinedVariance = previousVariance + (valueLength / combinedLength) * (valueVariance + ((valueMean - combinedMean) * (valueMean - previousMean)) - previousVariance); columnStats.min = Math.min(columnStats.min, recordMin); columnStats.max = Math.max(columnStats.max, recordMax); columnStats.length = combinedLength; columnStats.mean = combinedMean; columnStats.variance = combinedVariance; columnStats.stddev = Math.sqrt(combinedVariance); } } }); // Variance and stddev should be NaN for the case of a single element. for (const key in result) { const stat = result[key]; if (stat.length === 1) { stat.variance = NaN; stat.stddev = NaN; } } return result; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGlzdGljcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3RmanMtZGF0YS9zcmMvc3RhdGlzdGljcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRztBQUVILE9BQU8sS0FBSyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDNUMsT0FBTyxFQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBQyxNQUFNLHVCQUF1QixDQUFDO0FBOEN6RDs7Ozs7O0dBTUc7QUFDSCxNQUFNLFVBQVUsU0FBUyxDQUFDLEdBQVcsRUFBRSxHQUFXO0lBRWhELE1BQU0sS0FBSyxHQUFHLEdBQUcsR0FBRyxHQUFHLENBQUM7SUFDeEIsTUFBTSxTQUFTLEdBQWMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM1QyxNQUFNLFdBQVcsR0FBYyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2hELE9BQU8sQ0FBQyxLQUFtQixFQUFnQixFQUFFO1FBQzNDLElBQUksT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLFFBQVEsRUFBRTtZQUMvQixNQUFNLElBQUksS0FBSyxDQUFDLHdCQUF3QixDQUFDLENBQUM7U0FDM0M7YUFBTTtZQUNMLElBQUksS0FBSyxZQUFZLEVBQUUsQ0FBQyxNQUFNLEVBQUU7Z0JBQzlCLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFFLFNBQVMsQ0FBQyxFQUFFLFdBQVcsQ0FBQyxDQUFDO2dCQUN2RCxPQUFPLE1BQU0sQ0FBQzthQUNmO2lCQUFNLElBQUksS0FBSyxZQUFZLEtBQUssRUFBRTtnQkFDakMsT0FBTyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDLEdBQUcsS0FBSyxDQUFDLENBQUM7YUFDMUM7aUJBQU07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aWNlbnNlXG4gKiBDb3B5cmlnaHQgMjAxOCBHb29nbGUgTExDLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKlxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqL1xuXG5pbXBvcnQgKiBhcyB0ZiBmcm9tICdAdGVuc29yZmxvdy90ZmpzLWNvcmUnO1xuaW1wb3J0IHtkaXYsIG1heCwgbWluLCBzdWJ9IGZyb20gJ0B0ZW5zb3JmbG93L3RmanMtY29yZSc7XG5cbmltcG9ydCB7RGF0YXNldH0gZnJvbSAnLi9kYXRhc2V0JztcblxuLy8gVE9ETyhrYW5neWl6aGFuZyk6IGVsaW1pbmF0ZSB0aGUgbmVlZCBmb3IgRWxlbWVudEFycmF5IGFuZCBUYWJ1bGFyUmVjb3JkLCBieVxuLy8gY29tcHV0aW5nIHN0YXRzIG9uIG5lc3RlZCBzdHJ1Y3R1cmVzIHZpYSBkZWVwTWFwL2RlZXBaaXAuXG5cbi8qKlxuICogVGhlIHZhbHVlIGFzc29jaWF0ZWQgd2l0aCBhIGdpdmVuIGtleSBmb3IgYSBzaW5nbGUgZWxlbWVudC5cbiAqXG4gKiBTdWNoIGEgdmFsdWUgbWF5IG5vdCBoYXZlIGEgYmF0Y2ggZGltZW5zaW9uLiAgQSB2YWx1ZSBtYXkgYmUgYSBzY2FsYXIgb3IgYW5cbiAqIG4tZGltZW5zaW9uYWwgYXJyYXkuXG4gKi9cbmV4cG9ydCB0eXBlIEVsZW1lbnRBcnJheSA9IG51bWJlcnxudW1iZXJbXXx0Zi5UZW5zb3J8c3RyaW5nO1xuXG4vKipcbiAqIEEgbWFwIGZyb20gc3RyaW5nIGtleXMgKGFrYSBjb2x1bW4gbmFtZXMpIHRvIHZhbHVlcyBmb3IgYSBzaW5nbGUgZWxlbWVudC5cbiAqL1xuZXhwb3J0IHR5cGUgVGFidWxhclJlY29yZCA9IHtcbiAgW2tleTogc3RyaW5nXTogRWxlbWVudEFycmF5XG59O1xuXG4vLyBUT0RPKGthbmd5aXpoYW5nKTogRmxlc2ggb3V0IGNvbGxlY3RlZCBzdGF0aXN0aWNzLlxuLy8gRm9yIG51bWVyaWMgY29sdW1ucyB3ZSBzaG91bGQgcHJvdmlkZSBtZWFuLCBzdGRkZXYsIGhpc3RvZ3JhbSwgZXRjLlxuLy8gRm9yIHN0cmluZyBjb2x1bW5zIHdlIHNob3VsZCBwcm92aWRlIGEgdm9jYWJ1bGFyeSAoYXQgbGVhc3QsIHRvcC1rKSwgbWF5YmUgYVxuLy8gbGVuZ3RoIGhpc3RvZ3JhbSwgZXRjLlxuLy8gQ29sbGVjdGluZyBvbmx5IG51bWVyaWMgbWluIGFuZCBtYXggaXMganVzdCB0aGUgYmFyZSBtaW5pbXVtIGZvciBub3cuXG5cbi8qKiBBbiBpbnRlcmZhY2UgcmVwcmVzZW50aW5nIG51bWVyaWMgc3RhdGlzdGljcyBvZiBhIGNvbHVtbi4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTnVtZXJpY0NvbHVtblN0YXRpc3RpY3Mge1xuICBtaW46IG51bWJlcjtcbiAgbWF4OiBudW1iZXI7XG4gIG1lYW46IG51bWJlcjtcbiAgdmFyaWFuY2U6IG51bWJlcjtcbiAgc3RkZGV2OiBudW1iZXI7XG4gIGxlbmd0aDogbnVtYmVyO1xufVxuXG4vKipcbiAqIEFuIGludGVyZmFjZSByZXByZXNlbnRpbmcgY29sdW1uIGxldmVsIE51bWVyaWNDb2x1bW5TdGF0aXN0aWNzIGZvciBhXG4gKiBEYXRhc2V0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIERhdGFzZXRTdGF0aXN0aWNzIHtcbiAgW2tleTogc3RyaW5nXTogTnVtZXJpY0NvbHVtblN0YXRpc3RpY3M7XG59XG5cbi8qKlxuICogUHJvdmlkZXMgYSBmdW5jdGlvbiB0aGF0IHNjYWxlcyBudW1lcmljIHZhbHVlcyBpbnRvIHRoZSBbMCwgMV0gaW50ZXJ2YWwuXG4gKlxuICogQHBhcmFtIG1pbiB0aGUgbG93ZXIgYm91bmQgb2YgdGhlIGlucHV0cywgd2hpY2ggc2hvdWxkIGJlIG1hcHBlZCB0byAwLlxuICogQHBhcmFtIG1heCB0aGUgdXBwZXIgYm91bmQgb2YgdGhlIGlucHV0cywgd2hpY2ggc2hvdWxkIGJlIG1hcHBlZCB0byAxLFxuICogQHJldHVybiBBIGZ1bmN0aW9uIHRoYXQgbWFwcyBhbiBpbnB1dCBFbGVtZW50QXJyYXkgdG8gYSBzY2FsZWQgRWxlbWVudEFycmF5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2NhbGVUbzAxKG1pbjogbnVtYmVyLCBtYXg6IG51bWJlcik6ICh2YWx1ZTogRWxlbWVudEFycmF5KSA9PlxuICAgIEVsZW1lbnRBcnJheSB7XG4gIGNvbnN0IHJhbmdlID0gbWF4IC0gbWluO1xuICBjb25zdCBtaW5UZW5zb3I6IHRmLlRlbnNvciA9IHRmLnNjYWxhcihtaW4pO1xuICBjb25zdCByYW5nZVRlbnNvcjogdGYuVGVuc29yID0gdGYuc2NhbGFyKHJhbmdlKTtcbiAgcmV0dXJuICh2YWx1ZTogRWxlbWVudEFycmF5KTogRWxlbWVudEFycmF5ID0+IHtcbiAgICBpZiAodHlwZW9mICh2YWx1ZSkgPT09ICdzdHJpbmcnKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NhblxcJ3Qgc2NhbGUgYSBzdHJpbmcuJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICh2YWx1ZSBpbnN0YW5jZW9mIHRmLlRlbnNvcikge1xuICAgICAgICBjb25zdCByZXN1bHQgPSBkaXYoc3ViKHZhbHVlLCBtaW5UZW5zb3IpLCByYW5nZVRlbnNvcik7XG4gICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICB9IGVsc2UgaWYgKHZhbHVlIGluc3RhbmNlb2YgQXJyYXkpIHtcbiAgICAgICAgcmV0dXJuIHZhbHVlLm1hcCh2ID0+ICh2IC0gbWluKSAvIHJhbmdlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiAodmFsdWUgLSBtaW4pIC8gcmFuZ2U7XG4gICAgICB9XG4gICAgfVxuICB9O1xufVxuXG4vKipcbiAqIFByb3ZpZGVzIGEgZnVuY3Rpb24gdGhhdCBjYWxjdWxhdGVzIGNvbHVtbiBsZXZlbCBzdGF0aXN0aWNzLCBpLmUuIG1pbiwgbWF4LFxuICogdmFyaWFuY2UsIHN0ZGRldi5cbiAqXG4gKiBAcGFyYW0gZGF0YXNldCBUaGUgRGF0YXNldCBvYmplY3Qgd2hvc2Ugc3RhdGlzdGljcyB3aWxsIGJlIGNhbGN1bGF0ZWQuXG4gKiBAcGFyYW0gc2FtcGxlU2l6ZSAoT3B0aW9uYWwpIElmIHNldCwgc3RhdGlzdGljcyB3aWxsIG9ubHkgYmUgY2FsY3VsYXRlZFxuICogICAgIGFnYWluc3QgYSBzdWJzZXQgb2YgdGhlIHdob2xlIGRhdGEuXG4gKiBAcGFyYW0gc2h1ZmZsZVdpbmRvd1NpemUgKE9wdGlvbmFsKSBJZiBzZXQsIHNodWZmbGUgcHJvdmlkZWQgZGF0YXNldCBiZWZvcmVcbiAqICAgICBjYWxjdWxhdGluZyBzdGF0aXN0aWNzLlxuICogQHJldHVybiBBIERhdGFzZXRTdGF0aXN0aWNzIG9iamVjdCB0aGF0IGNvbnRhaW5zIE51bWVyaWNDb2x1bW5TdGF0aXN0aWNzIG9mXG4gKiAgICAgZWFjaCBjb2x1bW4uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjb21wdXRlRGF0YXNldFN0YXRpc3RpY3MoXG4gICAgZGF0YXNldDogRGF0YXNldDxUYWJ1bGFyUmVjb3JkPiwgc2FtcGxlU2l6ZT86IG51bWJlcixcbiAgICBzaHVmZmxlV2luZG93U2l6ZT86IG51bWJlcik6IFByb21pc2U8RGF0YXNldFN0YXRpc3RpY3M+IHtcbiAgbGV0IHNhbXBsZURhdGFzZXQgPSBkYXRhc2V0O1xuICAvLyBUT0RPKHNvZXJnZWwpOiBhbGxvdyBmb3IgZGVlcCBzaHVmZmxlIHdoZXJlIHBvc3NpYmxlLlxuICBpZiAoc2h1ZmZsZVdpbmRvd1NpemUgIT0gbnVsbCkge1xuICAgIHNhbXBsZURhdGFzZXQgPSBzYW1wbGVEYXRhc2V0LnNodWZmbGUoc2h1ZmZsZVdpbmRvd1NpemUpO1xuICB9XG4gIGlmIChzYW1wbGVTaXplICE9IG51bGwpIHtcbiAgICBzYW1wbGVEYXRhc2V0ID0gc2FtcGxlRGF0YXNldC50YWtlKHNhbXBsZVNpemUpO1xuICB9XG5cbiAgLy8gVE9ETyhzb2VyZ2VsKTogcHJlcGFyZSB0aGUgY29sdW1uIG9iamVjdHMgYmFzZWQgb24gYSBzY2hlbWEuXG4gIGNvbnN0IHJlc3VsdDogRGF0YXNldFN0YXRpc3RpY3MgPSB7fTtcblxuICBhd2FpdCBzYW1wbGVEYXRhc2V0LmZvckVhY2hBc3luYyhlID0+IHtcbiAgICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhlKSkge1xuICAgICAgY29uc3QgdmFsdWUgPSBlW2tleV07XG4gICAgICBpZiAodHlwZW9mICh2YWx1ZSkgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIC8vIE5vIHN0YXRpc3RpY3MgZm9yIHN0cmluZyBlbGVtZW50LlxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IHByZXZpb3VzTWVhbiA9IDA7XG4gICAgICAgIGxldCBwcmV2aW91c0xlbmd0aCA9IDA7XG4gICAgICAgIGxldCBwcmV2aW91c1ZhcmlhbmNlID0gMDtcbiAgICAgICAgbGV0IGNvbHVtblN0YXRzOiBOdW1lcmljQ29sdW1uU3RhdGlzdGljcyA9IHJlc3VsdFtrZXldO1xuICAgICAgICBpZiAoY29sdW1uU3RhdHMgPT0gbnVsbCkge1xuICAgICAgICAgIGNvbHVtblN0YXRzID0ge1xuICAgICAgICAgICAgbWluOiBOdW1iZXIuUE9TSVRJVkVfSU5GSU5JVFksXG4gICAgICAgICAgICBtYXg6IE51bWJlci5ORUdBVElWRV9JTkZJTklUWSxcbiAgICAgICAgICAgIG1lYW46IDAsXG4gICAgICAgICAgICB2YXJpYW5jZTogMCxcbiAgICAgICAgICAgIHN0ZGRldjogMCxcbiAgICAgICAgICAgIGxlbmd0aDogMFxuICAgICAgICAgIH07XG4gICAgICAgICAgcmVzdWx0W2tleV0gPSBjb2x1bW5TdGF0cztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBwcmV2aW91c01lYW4gPSBjb2x1bW5TdGF0cy5tZWFuO1xuICAgICAgICAgIHByZXZpb3VzTGVuZ3RoID0gY29sdW1uU3RhdHMubGVuZ3RoO1xuICAgICAgICAgIHByZXZpb3VzVmFyaWFuY2UgPSBjb2x1bW5TdGF0cy52YXJpYW5jZTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcmVjb3JkTWluOiBudW1iZXI7XG4gICAgICAgIGxldCByZWNvcmRNYXg6IG51bWJlcjtcblxuICAgICAgICAvLyBDYWxjdWxhdGUgYWNjdW11bGF0ZWQgbWVhbiBhbmQgdmFyaWFuY2UgZm9sbG93aW5nIHRmLlRyYW5zZm9ybVxuICAgICAgICAvLyBpbXBsZW1lbnRhdGlvblxuICAgICAgICBsZXQgdmFsdWVMZW5ndGggPSAwO1xuICAgICAgICBsZXQgdmFsdWVNZWFuID0gMDtcbiAgICAgICAgbGV0IHZhbHVlVmFyaWFuY2UgPSAwO1xuICAgICAgICBsZXQgY29tYmluZWRMZW5ndGggPSAwO1xuICAgICAgICBsZXQgY29tYmluZWRNZWFuID0gMDtcbiAgICAgICAgbGV0IGNvbWJpbmVkVmFyaWFuY2UgPSAwO1xuXG4gICAgICAgIGlmICh2YWx1ZSBpbnN0YW5jZW9mIHRmLlRlbnNvcikge1xuICAgICAgICAgIHJlY29yZE1pbiA9IG1pbih2YWx1ZSkuZGF0YVN5bmMoKVswXTtcbiAgICAgICAgICByZWNvcmRNYXggPSBtYXgodmFsdWUpLmRhdGFTeW5jKClbMF07XG4gICAgICAgICAgY29uc3QgdmFsdWVNb21lbnQgPSB0Zi5tb21lbnRzKHZhbHVlKTtcbiAgICAgICAgICB2YWx1ZU1lYW4gPSB2YWx1ZU1vbWVudC5tZWFuLmRhdGFTeW5jKClbMF07XG4gICAgICAgICAgdmFsdWVWYXJpYW5jZSA9IHZhbHVlTW9tZW50LnZhcmlhbmNlLmRhdGFTeW5jKClbMF07XG4gICAgICAgICAgdmFsdWVMZW5ndGggPSB2YWx1ZS5zaXplO1xuXG4gICAgICAgIH0gZWxzZSBpZiAodmFsdWUgaW5zdGFuY2VvZiBBcnJheSkge1xuICAgICAgICAgIHJlY29yZE1pbiA9IHZhbHVlLnJlZHVjZSgoYSwgYikgPT4gTWF0aC5taW4oYSwgYikpO1xuICAgICAgICAgIHJlY29yZE1heCA9IHZhbHVlLnJlZHVjZSgoYSwgYikgPT4gTWF0aC5tYXgoYSwgYikpO1xuICAgICAgICAgIGNvbnN0IHZhbHVlTW9tZW50ID0gdGYubW9tZW50cyh2YWx1ZSk7XG4gICAgICAgICAgdmFsdWVNZWFuID0gdmFsdWVNb21lbnQubWVhbi5kYXRhU3luYygpWzBdO1xuICAgICAgICAgIHZhbHVlVmFyaWFuY2UgPSB2YWx1ZU1vbWVudC52YXJpYW5jZS5kYXRhU3luYygpWzBdO1xuICAgICAgICAgIHZhbHVlTGVuZ3RoID0gdmFsdWUubGVuZ3RoO1xuXG4gICAgICAgIH0gZWxzZSBpZiAoIWlzTmFOKHZhbHVlKSAmJiBpc0Zpbml0ZSh2YWx1ZSkpIHtcbiAgICAgICAgICByZWNvcmRNaW4gPSB2YWx1ZTtcbiAgICAgICAgICByZWNvcmRNYXggPSB2YWx1ZTtcbiAgICAgICAgICB2YWx1ZU1lYW4gPSB2YWx1ZTtcbiAgICAgICAgICB2YWx1ZVZhcmlhbmNlID0gMDtcbiAgICAgICAgICB2YWx1ZUxlbmd0aCA9IDE7XG5cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb2x1bW5TdGF0cyA9IG51bGw7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgY29tYmluZWRMZW5ndGggPSBwcmV2aW91c0xlbmd0aCArIHZhbHVlTGVuZ3RoO1xuICAgICAgICBjb21iaW5lZE1lYW4gPSBwcmV2aW91c01lYW4gK1xuICAgICAgICAgICAgKHZhbHVlTGVuZ3RoIC8gY29tYmluZWRMZW5ndGgpICogKHZhbHVlTWVhbiAtIHByZXZpb3VzTWVhbik7XG4gICAgICAgIGNvbWJpbmVkVmFyaWFuY2UgPSBwcmV2aW91c1ZhcmlhbmNlICtcbiAgICAgICAgICAgICh2YWx1ZUxlbmd0aCAvIGNvbWJpbmVkTGVuZ3RoKSAqXG4gICAgICAgICAgICAgICAgKHZhbHVlVmFyaWFuY2UgK1xuICAgICAgICAgICAgICAgICAoKHZhbHVlTWVhbiAtIGNvbWJpbmVkTWVhbikgKiAodmFsdWVNZWFuIC0gcHJldmlvdXNNZWFuKSkgLVxuICAgICAgICAgICAgICAgICBwcmV2aW91c1ZhcmlhbmNlKTtcblxuICAgICAgICBjb2x1bW5TdGF0cy5taW4gPSBNYXRoLm1pbihjb2x1bW5TdGF0cy5taW4sIHJlY29yZE1pbik7XG4gICAgICAgIGNvbHVtblN0YXRzLm1heCA9IE1hdGgubWF4KGNvbHVtblN0YXRzLm1heCwgcmVjb3JkTWF4KTtcbiAgICAgICAgY29sdW1uU3RhdHMubGVuZ3RoID0gY29tYmluZWRMZW5ndGg7XG4gICAgICAgIGNvbHVtblN0YXRzLm1lYW4gPSBjb21iaW5lZE1lYW47XG4gICAgICAgIGNvbHVtblN0YXRzLnZhcmlhbmNlID0gY29tYmluZWRWYXJpYW5jZTtcbiAgICAgICAgY29sdW1uU3RhdHMuc3RkZGV2ID0gTWF0aC5zcXJ0KGNvbWJpbmVkVmFyaWFuY2UpO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG4gIC8vIFZhcmlhbmNlIGFuZCBzdGRkZXYgc2hvdWxkIGJlIE5hTiBmb3IgdGhlIGNhc2Ugb2YgYSBzaW5nbGUgZWxlbWVudC5cbiAgZm9yIChjb25zdCBrZXkgaW4gcmVzdWx0KSB7XG4gICAgY29uc3Qgc3RhdDogTnVtZXJpY0NvbHVtblN0YXRpc3RpY3MgPSByZXN1bHRba2V5XTtcbiAgICBpZiAoc3RhdC5sZW5ndGggPT09IDEpIHtcbiAgICAgIHN0YXQudmFyaWFuY2UgPSBOYU47XG4gICAgICBzdGF0LnN0ZGRldiA9IE5hTjtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cbiJdfQ==