UNPKG

@tensorflow/tfjs-data

Version:

TensorFlow Data API in JavaScript

135 lines 18.9 kB
/** * @license * Copyright 2019 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. * * ============================================================================= */ // tslint:disable-next-line: no-imports-from-dist import { ALL_ENVS, BROWSER_ENVS, describeWithFlags, NODE_ENVS, registerTestEnv } from '@tensorflow/tfjs-core/dist/jasmine_util'; // Provide fake video stream export function setupFakeVideoStream() { const width = 100; const height = 200; const canvasElement = document.createElement('canvas'); const ctx = canvasElement.getContext('2d'); ctx.fillStyle = 'rgb(1,2,3)'; ctx.fillRect(0, 0, width, height); // tslint:disable-next-line:no-any const stream = canvasElement.captureStream(60); navigator.mediaDevices.getUserMedia = async () => { return stream; }; } export async function replaceHTMLVideoElementSource(videoElement) { const source = document.createElement('source'); // tslint:disable:max-line-length source.src = 'data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAAAu1tZGF0AAACrQYF//+p3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE1NSByMjkwMSA3ZDBmZjIyIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxOCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTMgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MzoweDExMyBtZT1oZXggc3VibWU9NyBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0xIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MSA4eDhkY3Q9MSBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0tMiB0aHJlYWRzPTMgbG9va2FoZWFkX3RocmVhZHM9MSBzbGljZWRfdGhyZWFkcz0wIG5yPTAgZGVjaW1hdGU9MSBpbnRlcmxhY2VkPTAgYmx1cmF5X2NvbXBhdD0wIGNvbnN0cmFpbmVkX2ludHJhPTAgYmZyYW1lcz0zIGJfcHlyYW1pZD0yIGJfYWRhcHQ9MSBiX2JpYXM9MCBkaXJlY3Q9MSB3ZWlnaHRiPTEgb3Blbl9nb3A9MCB3ZWlnaHRwPTIga2V5aW50PTI1MCBrZXlpbnRfbWluPTEgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD00MCByYz1jcmYgbWJ0cmVlPTEgY3JmPTI4LjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IGlwX3JhdGlvPTEuNDAgYXE9MToxLjAwAIAAAAAwZYiEAD//8m+P5OXfBeLGOfKE3xkODvFZuBflHv/+VwJIta6cbpIo4ABLoKBaYTkTAAAC7m1vb3YAAABsbXZoZAAAAAAAAAAAAAAAAAAAA+gAAAPoAAEAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIYdHJhawAAAFx0a2hkAAAAAwAAAAAAAAAAAAAAAQAAAAAAAAPoAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAACgAAAAWgAAAAAAJGVkdHMAAAAcZWxzdAAAAAAAAAABAAAD6AAAAAAAAQAAAAABkG1kaWEAAAAgbWRoZAAAAAAAAAAAAAAAAAAAQAAAAEAAVcQAAAAAAC1oZGxyAAAAAAAAAAB2aWRlAAAAAAAAAAAAAAAAVmlkZW9IYW5kbGVyAAAAATttaW5mAAAAFHZtaGQAAAABAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAAD7c3RibAAAAJdzdHNkAAAAAAAAAAEAAACHYXZjMQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAACgAFoASAAAAEgAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABj//wAAADFhdmNDAWQACv/hABhnZAAKrNlCjfkhAAADAAEAAAMAAg8SJZYBAAZo6+JLIsAAAAAYc3R0cwAAAAAAAAABAAAAAQAAQAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAEAAAABAAAAFHN0c3oAAAAAAAAC5QAAAAEAAAAUc3RjbwAAAAAAAAABAAAAMAAAAGJ1ZHRhAAAAWm1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAALWlsc3QAAAAlqXRvbwAAAB1kYXRhAAAAAQAAAABMYXZmNTguMTIuMTAw'; source.type = 'video/mp4'; videoElement.srcObject = null; videoElement.appendChild(source); videoElement.play(); if (videoElement.readyState < 2) { await new Promise(resolve => { videoElement.addEventListener('loadeddata', () => resolve()); }); } } // Register backends. registerTestEnv({ name: 'cpu', backendName: 'cpu' }); registerTestEnv({ name: 'webgl2', backendName: 'webgl', flags: { 'WEBGL_VERSION': 2, 'WEBGL_CPU_FORWARD': false, 'WEBGL_SIZE_UPLOAD_UNIFORM': 0 } }); export const MEDIA_ENVS = { predicate: (env) => BROWSER_ENVS.predicate(env) && navigator.mediaDevices != null }; export function describeAllEnvs(testName, tests) { describeWithFlags(testName, ALL_ENVS, () => { tests(); }); } export function describeBrowserEnvs(testName, tests) { describeWithFlags(testName, BROWSER_ENVS, () => { tests(); }); } export function describeNodeEnvs(testName, tests) { describeWithFlags(testName, NODE_ENVS, () => { tests(); }); } /** * Testing Utilities for browser audio stream. */ export function setupFakeAudioStream() { navigator.mediaDevices.getUserMedia = async () => { const stream = new MediaStream(); return stream; }; // tslint:disable-next-line:no-any window.AudioContext = FakeAudioContext; } export class FakeAudioContext { constructor() { this.sampleRate = 44100; } static createInstance() { return new FakeAudioContext(); } createMediaStreamSource() { return new FakeMediaStreamAudioSourceNode(); } createAnalyser() { return new FakeAnalyser(); } close() { } } export class FakeAudioMediaStream { constructor() { } getTracks() { return []; } } class FakeMediaStreamAudioSourceNode { constructor() { } connect(node) { } } class FakeAnalyser { constructor() { this.x = 0; } getFloatFrequencyData(data) { const xs = []; for (let i = 0; i < this.fftSize / 2; ++i) { xs.push(this.x++); } data.set(new Float32Array(xs)); } getFloatTimeDomainData(data) { const xs = []; for (let i = 0; i < this.fftSize / 2; ++i) { xs.push(-(this.x++)); } data.set(new Float32Array(xs)); } disconnect() { } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdF91dGlscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3RmanMtZGF0YS9zcmMvdXRpbC90ZXN0X3V0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7O0dBZ0JHO0FBRUgsaURBQWlEO0FBQ2pELE9BQU8sRUFBQyxRQUFRLEVBQUUsWUFBWSxFQUFlLGlCQUFpQixFQUFFLFNBQVMsRUFBRSxlQUFlLEVBQUMsTUFBTSx5Q0FBeUMsQ0FBQztBQUUzSSw0QkFBNEI7QUFDNUIsTUFBTSxVQUFVLG9CQUFvQjtJQUNsQyxNQUFNLEtBQUssR0FBRyxHQUFHLENBQUM7SUFDbEIsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDO0lBQ25CLE1BQU0sYUFBYSxHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDdkQsTUFBTSxHQUFHLEdBQUcsYUFBYSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUMzQyxHQUFHLENBQUMsU0FBUyxHQUFHLFlBQVksQ0FBQztJQUM3QixHQUFHLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ2xDLGtDQUFrQztJQUNsQyxNQUFNLE1BQU0sR0FBSSxhQUFxQixDQUFDLGFBQWEsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN4RCxTQUFTLENBQUMsWUFBWSxDQUFDLFlBQVksR0FBRyxLQUFLLElBQUksRUFBRTtRQUMvQyxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDLENBQUM7QUFDSixDQUFDO0FBRUQsTUFBTSxDQUFDLEtBQUssVUFBVSw2QkFBNkIsQ0FDL0MsWUFBOEI7SUFDaEMsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNoRCxpQ0FBaUM7SUFDakMsTUFBTSxDQUFDLEdBQUc7UUFDTiw0aEVBQTRoRSxDQUFD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WUFBWTtJQUloQjtRQUNFLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2IsQ0FBQztJQUVELHFCQUFxQixDQUFDLElBQWtCO1FBQ3RDLE1BQU0sRUFBRSxHQUFhLEVBQUUsQ0FBQztRQUN4QixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLE9BQU8sR0FBRyxDQUFDLEVBQUUsRUFBRSxDQUFDLEVBQUU7WUFDekMsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztTQUNuQjtRQUNELElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxZQUFZLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUNqQyxDQUFDO0lBRUQsc0JBQXNCLENBQUMsSUFBa0I7UUFDdkMsTUFBTSxFQUFFLEdBQWEsRUFBRSxDQUFDO1FBQ3hCLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUMsT0FBTyxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsRUFBRTtZQUN6QyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1NBQ3RCO1FBQ0QsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLFlBQVksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ2pDLENBQUM7SUFFRCxVQUFVLEtBQVUsQ0FBQztDQUN0QiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCAyMDE5IEdvb2dsZSBMTEMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuICogeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICogWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4gKlxuICogaHR0cDovL3d3dy5hcGFjaGUub3JnL2xpY2Vuc2VzL0xJQ0VOU0UtMi4wXG4gKlxuICogVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZVxuICogZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICogV0lUSE9VVCBXQVJSQU5USUVTIE9SIENPTkRJVElPTlMgT0YgQU5ZIEtJTkQsIGVpdGhlciBleHByZXNzIG9yIGltcGxpZWQuXG4gKiBTZWUgdGhlIExpY2Vuc2UgZm9yIHRoZSBzcGVjaWZpYyBsYW5ndWFnZSBnb3Zlcm5pbmcgcGVybWlzc2lvbnMgYW5kXG4gKiBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICovXG5cbi8vIHRzbGludDpkaXNhYmxlLW5leHQtbGluZTogbm8taW1wb3J0cy1mcm9tLWRpc3RcbmltcG9ydCB7QUxMX0VOVlMsIEJST1dTRVJfRU5WUywgQ29uc3RyYWludHMsIGRlc2NyaWJlV2l0aEZsYWdzLCBOT0RFX0VOVlMsIHJlZ2lzdGVyVGVzdEVudn0gZnJvbSAnQHRlbnNvcmZsb3cvdGZqcy1jb3JlL2Rpc3QvamFzbWluZV91dGlsJztcblxuLy8gUHJvdmlkZSBmYWtlIHZpZGVvIHN0cmVhbVxuZXhwb3J0IGZ1bmN0aW9uIHNldHVwRmFrZVZpZGVvU3RyZWFtKCkge1xuICBjb25zdCB3aWR0aCA9IDEwMDtcbiAgY29uc3QgaGVpZ2h0ID0gMjAwO1xuICBjb25zdCBjYW52YXNFbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG4gIGNvbnN0IGN0eCA9IGNhbnZhc0VsZW1lbnQuZ2V0Q29udGV4dCgnMmQnKTtcbiAgY3R4LmZpbGxTdHlsZSA9ICdyZ2IoMSwyLDMpJztcbiAgY3R4LmZpbGxSZWN0KDAsIDAsIHdpZHRoLCBoZWlnaHQpO1xuICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tYW55XG4gIGNvbnN0IHN0cmVhbSA9IChjYW52YXNFbGVtZW50IGFzIGFueSkuY2FwdHVyZVN0cmVhbSg2MCk7XG4gIG5hdmlnYXRvci5tZWRpYURldmljZXMuZ2V0VXNlck1lZGlhID0gYXN5bmMgKCkgPT4ge1xuICAgIHJldHVybiBzdHJlYW07XG4gIH07XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZXBsYWNlSFRNTFZpZGVvRWxlbWVudFNvdXJjZShcbiAgICB2aWRlb0VsZW1lbnQ6IEhUTUxWaWRlb0VsZW1lbnQpIHtcbiAgY29uc3Qgc291cmNlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc291cmNlJyk7XG4gIC8vIHRzbGludDpkaXNhYmxlOm1heC1saW5lLWxlbmd0aFxuICBzb3VyY2Uuc3JjID1cbiAgICAgICdkYXRhOnZpZGVvL21wNDtiYXNlNjQsQUFBQUlHWjBlWEJwYzI5dEFBQUNBR2x6YjIxcGMyOHlZWFpqTVcxd05ERUFBQUFJWm5KbFpRQUFBdTF0WkdGMEFBQUNyUVlGLy8rcDNFWHB2ZWJaU0xlV0xOZ2cyU1B1NzNneU5qUWdMU0JqYjNKbElERTFOU0J5TWprd01TQTNaREJtWmpJeUlDMGdTQzR5TmpRdlRWQkZSeTAwSUVGV1F5QmpiMlJsWXlBdElFTnZjSGxzWldaMElESXdNRE10TWpBeE9DQXRJR2gwZEhBNkx5OTNkM2N1ZG1sa1pXOXNZVzR1YjNKbkwzZ3lOalF1YUhSdGJDQXRJRzl3ZEdsdmJuTTZJR05oWW1GalBURWdjbVZtUFRNZ1pHVmliRzlqYXoweE9qQTZNQ0JoYm1Gc2VYTmxQVEI0TXpvd2VERXhNeUJ0WlQxb1pYZ2djM1ZpYldVOU55QndjM2s5TVNCd2MzbGZjbVE5TVM0d01Eb3dMakF3SUcxcGVHVmtYM0psWmoweElHMWxYM0poYm1kbFBURTJJR05vY205dFlWOXRaVDB4SUhSeVpXeHNhWE05TVNBNGVEaGtZM1E5TVNCamNXMDlNQ0JrWldGa2VtOXVaVDB5TVN3eE1TQm1ZWE4wWDNCemEybHdQVEVnWTJoeWIyMWhYM0Z3WDI5bVpuTmxkRDB0TWlCMGFISmxZV1J6UFRNZ2JHOXZhMkZvWldGa1gzUm9jbVZoWkhNOU1TQnpiR2xqWldSZmRHaHlaV0ZrY3owd0lHNXlQVEFnWkdWamFXMWhkR1U5TVNCcGJuUmxjbXhoWTJWa1BUQWdZbXgxY21GNVgyTnZiWEJoZEQwd0lHTnZibk4wY21GcGJtVmtYMmx1ZEhKaFBUQWdZbVp5WVcxbGN6MHpJR0pmY0hseVlXMXBaRDB5SUdKZllXUmhjSFE5TVNCaVgySnBZWE05TUNCa2FYSmxZM1E5TVNCM1pXbG5hSFJpUFRFZ2IzQmxibDluYjNBOU1DQjNaV2xuYUhSd1BUSWdhMlY1YVc1MFBUSTFNQ0JyWlhscGJuUmZiV2x1UFRFZ2MyTmxibVZqZFhROU5EQWdhVzUwY21GZmNtVm1jbVZ6YUQwd0lISmpYMnh2YjJ0aGFHVmhaRDAwTUNCeVl6MWpjbVlnYldKMGNtVmxQVEVnWTNKbVBUSTRMakFnY1dOdmJYQTlNQzQyTUNCeGNHMXBiajB3SUhGd2JXRjRQVFk1SUhGd2MzUmxjRDAwSUdsd1gzSmhkR2x2UFRFdU5EQWdZWEU5TVRveExqQXdBSUFBQUFBd1pZaUVBRC8vOG0rUDVPWGZCZUxHT2ZLRTN4a09EdkZadUJmbEh2LytWd0pJdGE2Y2JwSW80QUJMb0tCYVlUa1RBQUFDN20xdmIzWUFBQUJzYlhab1pBQUFBQUFBQUFBQUFBQUFBQUFBQStnQUFBUG9BQUVBQUFFQUFBQUFBQUFBQUFBQUFBQUJBQUFBQUFBQUFBQUFBQUFBQUFBQUFRQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBSUFBQUlZZEhKaGF3QUFBRngwYTJoa0FBQUFBd0FBQUFBQUFBQUFBQUFBQVFBQUFBQUFBQVBvQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQUFBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFBQUFBQUFBQUFBQUFBQVFBQUFBQUNnQUFBQVdnQUFBQUFBSkdWa2RITUFBQUFjWld4emRBQUFBQUFBQUFBQkFBQUQ2QUFBQUFBQUFRQUFBQUFCa0cxa2FXRUFBQUFnYldSb1pBQUFBQUFBQUFBQUFBQUFBQUFBUUFBQUFFQUFWY1FBQUFBQUFDMW9aR3h5QUFBQUFBQUFBQUIyYVdSbEFBQUFBQUFBQUFBQUFBQUFWbWxrWlc5SVlXNWtiR1Z5QUFBQUFUdHRhVzVtQUFBQUZIWnRhR1FBQUFBQkFBQUFBQUFBQUFBQUFBQWtaR2x1WmdBQUFCeGtjbVZtQUFBQUFBQUFBQUVBQUFBTWRYSnNJQUFBQUFFQUFBRDdjM1JpYkFBQUFKZHpkSE5rQUFBQUFBQUFBQUVBQUFDSFlYWmpNUUFBQUFBQUFBQUJBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQ2dBRm9BU0FBQUFFZ0FBQUFBQUFBQUFRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUJqLy93QUFBREZoZG1OREFXUUFDdi9oQUJoblpBQUtyTmxDamZraEFBQURBQUVBQUFNQUFnOFNKWllCQUFabzYrSkxJc0FBQUFBWWMzUjBjd0FBQUFBQUFBQUJBQUFBQVFBQVFBQUFBQUFjYzNSell3QUFBQUFBQUFBQkFBQUFBUUFBQUFFQUFBQUJBQUFBRkhOMGMzb0FBQUFBQUFBQzVRQUFBQUVBQUFBVWMzUmpid0FBQUFBQUFBQUJBQUFBTUFBQUFHSjFaSFJoQUFBQVdtMWxkR0VBQUFBQUFBQUFJV2hrYkhJQUFBQUFBQUFBQUcxa2FYSmhjSEJzQUFBQUFBQUFBQUFBQUFBQUxXbHNjM1FBQUFBbHFYUnZid0FBQUIxa1lYUmhBQUFBQVFBQUFBQk1ZWFptTlRndU1USXVNVEF3JztcbiAgc291cmNlLnR5cGUgPSAndmlkZW8vbXA0JztcbiAgdmlkZW9FbGVtZW50LnNyY09iamVjdCA9IG51bGw7XG4gIHZpZGVvRWxlbWVudC5hcHBlbmRDaGlsZChzb3VyY2UpO1xuICB2aWRlb0VsZW1lbnQucGxheSgpO1xuXG4gIGlmICh2aWRlb0VsZW1lbnQucmVhZHlTdGF0ZSA8IDIpIHtcbiAgICBhd2FpdCBuZXcgUHJvbWlzZTx2b2lkPihyZXNvbHZlID0+IHtcbiAgICAgIHZpZGVvRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCdsb2FkZWRkYXRhJywgKCkgPT4gcmVzb2x2ZSgpKTtcbiAgICB9KTtcbiAgfVxufVxuXG4vLyBSZWdpc3RlciBiYWNrZW5kcy5cbnJlZ2lzdGVyVGVzdEVudih7bmFtZTogJ2NwdScsIGJhY2tlbmROYW1lOiAnY3B1J30pO1xucmVnaXN0ZXJUZXN0RW52KHtcbiAgbmFtZTogJ3dlYmdsMicsXG4gIGJhY2tlbmROYW1lOiAnd2ViZ2wnLFxuICBmbGFnczoge1xuICAgICdXRUJHTF9WRVJTSU9OJzogMixcbiAgICAnV0VCR0xfQ1BVX0ZPUldBUkQnOiBmYWxzZSxcbiAgICAnV0VCR0xfU0laRV9VUExPQURfVU5JRk9STSc6IDBcbiAgfVxufSk7XG5cbmV4cG9ydCBjb25zdCBNRURJQV9FTlZTOiBDb25zdHJhaW50cyA9IHtcbiAgcHJlZGljYXRlOiAoZW52KSA9PiBCUk9XU0VSX0VOVlMucHJlZGljYXRlKGVudilcbiAgICAmJiBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzICE9IG51bGxcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBkZXNjcmliZUFsbEVudnModGVzdE5hbWU6IHN0cmluZywgdGVzdHM6ICgpID0+IHZvaWQpIHtcbiAgZGVzY3JpYmVXaXRoRmxhZ3ModGVzdE5hbWUsIEFMTF9FTlZTLCAoKSA9PiB7XG4gICAgdGVzdHMoKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBkZXNjcmliZUJyb3dzZXJFbnZzKHRlc3ROYW1lOiBzdHJpbmcsIHRlc3RzOiAoKSA9PiB2b2lkKSB7XG4gIGRlc2NyaWJlV2l0aEZsYWdzKHRlc3ROYW1lLCBCUk9XU0VSX0VOVlMsICgpID0+IHtcbiAgICB0ZXN0cygpO1xuICB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRlc2NyaWJlTm9kZUVudnModGVzdE5hbWU6IHN0cmluZywgdGVzdHM6ICgpID0+IHZvaWQpIHtcbiAgZGVzY3JpYmVXaXRoRmxhZ3ModGVzdE5hbWUsIE5PREVfRU5WUywgKCkgPT4ge1xuICAgIHRlc3RzKCk7XG4gIH0pO1xufVxuXG4vKipcbiAqIFRlc3RpbmcgVXRpbGl0aWVzIGZvciBicm93c2VyIGF1ZGlvIHN0cmVhbS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNldHVwRmFrZUF1ZGlvU3RyZWFtKCkge1xuICBuYXZpZ2F0b3IubWVkaWFEZXZpY2VzLmdldFVzZXJNZWRpYSA9IGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBzdHJlYW0gPSBuZXcgTWVkaWFTdHJlYW0oKTtcbiAgICByZXR1cm4gc3RyZWFtO1xuICB9O1xuICAvLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tYW55XG4gICh3aW5kb3cgYXMgYW55KS5BdWRpb0NvbnRleHQgPSBGYWtlQXVkaW9Db250ZXh0O1xufVxuXG5leHBvcnQgY2xhc3MgRmFrZUF1ZGlvQ29udGV4dCB7XG4gIHJlYWRvbmx5IHNhbXBsZVJhdGUgPSA0NDEwMDtcblxuICBzdGF0aWMgY3JlYXRlSW5zdGFuY2UoKSB7XG4gICAgcmV0dXJuIG5ldyBGYWtlQXVkaW9Db250ZXh0KCk7XG4gIH1cblxuICBjcmVhdGVNZWRpYVN0cmVhbVNvdXJjZSgpIHtcbiAgICByZXR1cm4gbmV3IEZha2VNZWRpYVN0cmVhbUF1ZGlvU291cmNlTm9kZSgpO1xuICB9XG5cbiAgY3JlYXRlQW5hbHlzZXIoKSB7XG4gICAgcmV0dXJuIG5ldyBGYWtlQW5hbHlzZXIoKTtcbiAgfVxuXG4gIGNsb3NlKCk6IHZvaWQge31cbn1cblxuZXhwb3J0IGNsYXNzIEZha2VBdWRpb01lZGlhU3RyZWFtIHtcbiAgY29uc3RydWN0b3IoKSB7fVxuICBnZXRUcmFja3MoKTogQXJyYXk8e30+IHtcbiAgICByZXR1cm4gW107XG4gIH1cbn1cblxuY2xhc3MgRmFrZU1lZGlhU3RyZWFtQXVkaW9Tb3VyY2VOb2RlIHtcbiAgY29uc3RydWN0b3IoKSB7fVxuICBjb25uZWN0KG5vZGU6IHt9KTogdm9pZCB7fVxufVxuXG5jbGFzcyBGYWtlQW5hbHlzZXIge1xuICBmZnRTaXplOiBudW1iZXI7XG4gIHNtb290aGluZ1RpbWVDb25zdGFudDogbnVtYmVyO1xuICBwcml2YXRlIHg6IG51bWJlcjtcbiAgY29uc3RydWN0b3IoKSB7XG4gICAgdGhpcy54ID0gMDtcbiAgfVxuXG4gIGdldEZsb2F0RnJlcXVlbmN5RGF0YShkYXRhOiBGbG9hdDMyQXJyYXkpOiB2b2lkIHtcbiAgICBjb25zdCB4czogbnVtYmVyW10gPSBbXTtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRoaXMuZmZ0U2l6ZSAvIDI7ICsraSkge1xuICAgICAgeHMucHVzaCh0aGlzLngrKyk7XG4gICAgfVxuICAgIGRhdGEuc2V0KG5ldyBGbG9hdDMyQXJyYXkoeHMpKTtcbiAgfVxuXG4gIGdldEZsb2F0VGltZURvbWFpbkRhdGEoZGF0YTogRmxvYXQzMkFycmF5KTogdm9pZCB7XG4gICAgY29uc3QgeHM6IG51bWJlcltdID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLmZmdFNpemUgLyAyOyArK2kpIHtcbiAgICAgIHhzLnB1c2goLSh0aGlzLngrKykpO1xuICAgIH1cbiAgICBkYXRhLnNldChuZXcgRmxvYXQzMkFycmF5KHhzKSk7XG4gIH1cblxuICBkaXNjb25uZWN0KCk6IHZvaWQge31cbn1cbiJdfQ==