@tensorflow/tfjs-data
Version:
TensorFlow Data API in JavaScript
135 lines • 18.9 kB
JavaScript
/**
* @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==