/** * @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. * ============================================================================= */ import { device_util, env } from '@tensorflow/tfjs-core'; import { getMaxTexturesInShader, getWebGLDisjointQueryTimerVersion, getWebGLMaxTextureSize, isCapableOfRenderingToFloatTexture, isDownloadFloatTextureEnabled, isWebGLFenceEnabled, isWebGLVersionEnabled } from './webgl_util'; const ENV = env(); /** * This file contains WebGL-specific flag registrations. */ /** * True if WebGL is supported. */ ENV.registerFlag('HAS_WEBGL', () => ENV.getNumber('WEBGL_VERSION') > 0); /** 0: No WebGL, 1: WebGL 1.0, 2: WebGL 2.0. */ ENV.registerFlag('WEBGL_VERSION', () => { if (isWebGLVersionEnabled(2)) { return 2; } else if (isWebGLVersionEnabled(1)) { return 1; } return 0; }); /** Whether to check for numerical representation problems. */ ENV.registerFlag('WEBGL_CHECK_NUMERICAL_PROBLEMS', () => false); ENV.registerFlag('WEBGL_BUFFER_SUPPORTED', () => ENV.get('WEBGL_VERSION') === 2); /** Whether the WebGL backend will sometimes forward ops to the CPU. */ ENV.registerFlag('WEBGL_CPU_FORWARD', () => true); /** Whether the WebGL backend will always use f16 textures for rendering. */ ENV.registerFlag('WEBGL_FORCE_F16_TEXTURES', () => false); /** Whether to turn all packing related flags on. */ ENV.registerFlag('WEBGL_PACK', () => ENV.getBool('HAS_WEBGL')); /** Whether we will pack the batchnormalization op. */ ENV.registerFlag('WEBGL_PACK_NORMALIZATION', () => ENV.getBool('WEBGL_PACK')); /** Whether we will pack the clip op. */ ENV.registerFlag('WEBGL_PACK_CLIP', () => ENV.getBool('WEBGL_PACK')); /** Whether we will pack the depthwise conv op. */ ENV.registerFlag('WEBGL_PACK_DEPTHWISECONV', () => ENV.getBool('WEBGL_PACK')); /** Whether we will pack binary ops. */ ENV.registerFlag('WEBGL_PACK_BINARY_OPERATIONS', () => ENV.getBool('WEBGL_PACK')); /** Whether we will pack unary ops. */ ENV.registerFlag('WEBGL_PACK_UNARY_OPERATIONS', () => ENV.getBool('WEBGL_PACK')); /** Whether we will pack array ops. */ ENV.registerFlag('WEBGL_PACK_ARRAY_OPERATIONS', () => ENV.getBool('WEBGL_PACK')); /** Whether we will pack image ops. */ ENV.registerFlag('WEBGL_PACK_IMAGE_OPERATIONS', () => ENV.getBool('WEBGL_PACK')); /** Whether we will pack reduce ops. */ ENV.registerFlag('WEBGL_PACK_REDUCE', () => ENV.getBool('WEBGL_PACK')); /** Whether packed WebGL kernels lazily unpack their outputs. */ ENV.registerFlag('WEBGL_LAZILY_UNPACK', () => ENV.getBool('WEBGL_PACK')); /** Whether we will use the im2col algorithm to speed up convolutions. */ ENV.registerFlag('WEBGL_CONV_IM2COL', () => ENV.getBool('WEBGL_PACK')); /** Whether we will pack conv2dTranspose op. */ ENV.registerFlag('WEBGL_PACK_CONV2DTRANSPOSE', () => ENV.getBool('WEBGL_PACK')); /** The maximum texture dimension. */ ENV.registerFlag('WEBGL_MAX_TEXTURE_SIZE', () => getWebGLMaxTextureSize(ENV.getNumber('WEBGL_VERSION'))); /** The maximum texture dimension. */ ENV.registerFlag('WEBGL_MAX_TEXTURES_IN_SHADER', () => getMaxTexturesInShader(ENV.getNumber('WEBGL_VERSION'))); /** * The disjoint_query_timer extension version. * 0: disabled, 1: EXT_disjoint_timer_query, 2: * EXT_disjoint_timer_query_webgl2. * In Firefox with WebGL 2.0, * EXT_disjoint_timer_query_webgl2 is not available, so we must use the * WebGL 1.0 extension. */ ENV.registerFlag('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION', () => { const webGLVersion = ENV.getNumber('WEBGL_VERSION'); if (webGLVersion === 0) { return 0; } return getWebGLDisjointQueryTimerVersion(webGLVersion); }); /** * Whether the timer object from the disjoint_query_timer extension gives * timing information that is reliable. */ ENV.registerFlag('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_RELIABLE', () => ENV.getNumber('WEBGL_DISJOINT_QUERY_TIMER_EXTENSION_VERSION') > 0 && !device_util.isMobile()); /** * Whether the device is physically capable of rendering to float32 textures. */ ENV.registerFlag('WEBGL_RENDER_FLOAT32_CAPABLE', () => isCapableOfRenderingToFloatTexture(ENV.getNumber('WEBGL_VERSION'))); /** * Whether rendering to float32 textures is enabled. If disabled, renders to * float16 textures. */ ENV.registerFlag('WEBGL_RENDER_FLOAT32_ENABLED', () => { return ENV.getBool('WEBGL_FORCE_F16_TEXTURES') ? false : ENV.getBool('WEBGL_RENDER_FLOAT32_CAPABLE'); }); /** * Whether downloading float textures is enabled (16 or 32 bit). If disabled, * uses IEEE 754 encoding of the float32 values to 4 uint8 when downloading. */ ENV.registerFlag('WEBGL_DOWNLOAD_FLOAT_ENABLED', () => isDownloadFloatTextureEnabled(ENV.getNumber('WEBGL_VERSION'))); /** Whether the fence API is available. */ ENV.registerFlag('WEBGL_FENCE_API_ENABLED', () => isWebGLFenceEnabled(ENV.getNumber('WEBGL_VERSION'))); /** * Tensors with size <= than this will be uploaded as uniforms, not textures. */ ENV.registerFlag('WEBGL_SIZE_UPLOAD_UNIFORM', () => { // Use uniform uploads only when 32bit floats are supported. In // 16bit // environments there are problems with comparing a 16bit texture value // with a 32bit uniform value. const useUniforms = ENV.getBool('WEBGL_RENDER_FLOAT32_ENABLED'); return useUniforms ? 4 : 0; }); /** * If the total number of bytes allocated on the GPU is greater than this * number, we will aggressively delete textures upon disposal with * gl.deleteMatrixTexture, rather than making them available for reuse. * * Default value -1 indicates that we will never aggressively delete textures. */ ENV.registerFlag('WEBGL_DELETE_TEXTURE_THRESHOLD', () => { return -1; }, threshold => { if (!(typeof threshold === 'number')) { throw new Error('WEBGL_DELETE_TEXTURE_THRESHOLD must be a number but ' + `got ${threshold}.`); } if (threshold < 0 && threshold !== -1) { throw new Error(`WEBGL_DELETE_TEXTURE_THRESHOLD must be -1 (indicating never ` + `delete) or at least 0, but got ${threshold}.`); } }); /** * Trigger a manual GL command flush if the threshold of time has passed since * previous Kernel execution. This can be useful for Andorid device where GL * command flush are delayed un til the end of javascript task. This value is * measured in millisecond. Typically you want to set this value to close to 1. * * Default value 1 for mobile chrome, and -1 for rest cases. -1 indicates that * we will not enforce manual flush and depend on system default flush schedule. */ ENV.registerFlag('WEBGL_FLUSH_THRESHOLD', () => { return device_util.isMobile() ? 1 : -1; }, threshold => { if (!(typeof threshold === 'number')) { throw new Error('WEBGL_FLUSH_THRESHOLD must be a number but got ' + `${threshold}.`); } if (threshold < 0 && threshold !== -1) { throw new Error(`WEBGL_FLUSH_THRESHOLD must be -1 (indicating never ` + `manual flush) or at least 0, but got ${threshold}.`); } }); /** * Threshold for input tensor size that determines whether WebGL backend will * delegate computation to CPU. * * Default value is 128. */ ENV.registerFlag('CPU_HANDOFF_SIZE_THRESHOLD', () => 128); /** Whether we will use shapes uniforms. */ ENV.registerFlag('WEBGL_USE_SHAPES_UNIFORMS', () => false); /** * Threshold for last dimension of input tensor that determines whether * WebGL backend for the Top K op will delegate computation to CPU. If input * is smaller than threshold then CPU will be used * * Default value is 100000. */ ENV.registerFlag('TOPK_LAST_DIM_CPU_HANDOFF_SIZE_THRESHOLD', () => 100000); /** * Threshold for K that determines whether * WebGL backend for the Top K op will delegate computation to CPU. If k * is larger than threshold then CPU will be used * * Default value is 128. */ ENV.registerFlag('TOPK_K_CPU_HANDOFF_THRESHOLD', () => 128); /** Whether we will use the experimental conv op. */ ENV.registerFlag('WEBGL_EXP_CONV', () => false); /** * If the device performance is low or if no hardware GPU is available, whether * software WebGL will be used. */ ENV.registerFlag('SOFTWARE_WEBGL_ENABLED', () => ENV.getBool('IS_TEST')); /** * For narrow texture (physical height or physical width is 1), if the length of * any texture edges exceed the threshold, the texture will be reshaped to be * more squarish. * * This flag is used to help some GPUs that could not provide correct * interpolations for long skinny triangles. We found Mali GPU probably has this * problem: https://github.com/tensorflow/tfjs/issues/6775. */ ENV.registerFlag('WEBGL_MAX_SIZE_FOR_NARROW_TEXTURE', () => Infinity); /** * If the flag is set to true, the max size of the narrow texture will be auto * computed and it will be considerred as a threshold to reshape the narrow * texture to be more squarish. * * This flag is used to help some GPUs that could not provide correct * interpolations for long skinny triangles. We found Mali GPU probably has this * problem: https://github.com/tensorflow/tfjs/issues/6775. */ ENV.registerFlag('WEBGL_AUTO_SQUARIFY_NARROW_TEXTURE_SHAPE', () => false); /** * Whether to use the customized isnan. It's only useful for webgl2 since webgl1 * doesn't have the builtin isnan. */ ENV.registerFlag('WEBGL2_ISNAN_CUSTOM', () => false); /** Experimental flag, whether enter compile only phase. */ ENV.registerFlag('ENGINE_COMPILE_ONLY', () => false); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmxhZ3Nfd2ViZ2wuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi90ZmpzLWJhY2tlbmQtd2ViZ2wvc3JjL2ZsYWdzX3dlYmdsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7R0FlRztBQUVILE9BQU8sRUFBQyxXQUFXLEVBQUUsR0FBRyxFQUFDLE1BQU0sdUJBQXVCLENBQUM7QUFFdkQsT0FBTyxFQUFDLHNCQUFzQixFQUFFLGlDQUFpQyxFQUFFLHNCQUFzQixFQUFFLGtDQUFrQyxFQUFFLDZCQUE2QixFQUFFLG1CQUFtQixFQUFFLHFCQUFxQixFQUFDLE1BQU0sY0FBYyxDQUFDO0FBRTlOLE1BQU0sR0FBRyxHQUFHLEdBQUcsRUFBRSxDQUFDO0FBRWxCOztHQUVHO0FBRUg7O0dBRUc7QUFDSCxHQUFHLENBQUMsWUFBWSxDQUFDLFdBQVcsRUFBRSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0FBRXhFLCtDQUErQztBQUMvQyxHQUFHLENBQUMsWUFBWSxDQUFDLGVBQWUsRUFBRSxHQUFHLEVBQUU7SUFDckMsSUFBSSxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsRUFBRTtRQUM1QixPQUFPLENBQUMsQ0FBQztLQUNWO1NBQU0sSUFBSSxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsRUFBRTtRQUNuQyxPQUFPLENBQUMsQ0FBQztLQUNWO0lBQ0QsT0FBTyxDQUFDLENBQUM7QUFDWCxDQUFDLENBQUMsQ0FBQztBQUVILDhEQUE4RDtBQUM5RCxHQUFHLENBQUMsWUFBWSxDQUFDLGdDQUFnQyxFQUFFLEdBQUcsRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBRWhFLEdBQUcsQ0FBQyxZQUFZLENBQ1osd0JBQXdCLEVBQUUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FB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QUFZLENBQUMscUJBQXFCLEVBQUUsR0FBRyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgMjAxOSBHb29nbGUgTExDLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICogTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKTtcbiAqIHlvdSBtYXkgbm90IHVzZSB0aGlzIGZpbGUgZXhjZXB0IGluIGNvbXBsaWFuY2Ugd2l0aCB0aGUgTGljZW5zZS5cbiAqIFlvdSBtYXkgb2J0YWluIGEgY29weSBvZiB0aGUgTGljZW5zZSBhdFxuICpcbiAqIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuICpcbiAqIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAqIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbiAqIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuICogU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICogbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICovXG5cbmltcG9ydCB7ZGV2aWNlX3V0aWwsIGVudn0gZnJvbSAnQHRlbnNvcmZsb3cvdGZqcy1jb3JlJztcblxuaW1wb3J0IHtnZXRNYXhUZXh0dXJlc0luU2hhZGVyLCBnZXRXZWJHTERpc2pvaW50UXVlcnlUaW1lclZlcnNpb24sIGdldFdlYkdMTWF4VGV4dHVyZVNpemUsIGlzQ2FwYWJsZU9mUmVuZGVyaW5nVG9GbG9hdFRleHR1cmUsIGlzRG93bmxvYWRGbG9hdFRleHR1cmVFbmFibGVkLCBpc1dlYkdMRmVuY2VFbmFibGVkLCBpc1dlYkdMVmVyc2lvbkVuYWJsZWR9IGZyb20gJy4vd2ViZ2xfdXRpbCc7XG5cbmNvbnN0IEVOViA9IGVudigpO1xuXG4vKipcbiAqIFRoaXMgZmlsZSBjb250YWlucyBXZWJHTC1zcGVjaWZpYyBmbGFnIHJlZ2lzdHJhdGlvbnMuXG4gKi9cblxuLyoqXG4gKiBUcnVlIGlmIFdlYkdMIGlzIHN1cHBvcnRlZC5cbiAqL1xuRU5WLnJlZ2lzdGVyRmxhZygnSEFTX1dFQkdMJywgKCkgPT4gRU5WLmdldE51bWJlcignV0VCR0xfVkVSU0lPTicpID4gMCk7XG5cbi8qKiAwOiBObyBXZWJHTCwgMTogV2ViR0wgMS4wLCAyOiBXZWJHTCAyLjAuICovXG5FTlYucmVnaXN0ZXJGbGFnKCdXRUJHTF9WRVJTSU9OJywgKCkgPT4ge1xuICBpZiAoaXNXZWJHTFZlcnNpb25FbmFibGVkKDIpKSB7XG4gICAgcmV0dXJuIDI7XG4gIH0gZWxzZSBpZiAoaXNXZWJHTFZlcnNpb25FbmFibGVkKDEpKSB7XG4gICAgcmV0dXJuIDE7XG4gIH1cbiAgcmV0dXJuIDA7XG59KTtcblxuLyoqIFdoZXRoZXIgdG8gY2hlY2sgZm9yIG51bWVyaWNhbCByZXByZXNlbnRhdGlvbiBwcm9ibGVtcy4gKi9cbkVOVi5yZWdpc3RlckZsYWcoJ1dFQkdMX0NIRUNLX05VTUVSSUNBTF9QUk9CTEVNUycsICgpID0+IGZhbHNlKTtcblxuRU5WLnJlZ2lzdGVyRmxhZyhcbiAgICAnV0VCR0xfQlVGRkVSX1NVUFBPUlRFRCcsICgpID0+IEVOVi5nZXQoJ1dFQkdMX1ZFUlNJT04nKSA9PT0gMik7XG5cbi8qKiBXaGV0aGVyIHRoZSBXZWJHTCBiYWNrZW5kIHdpbGwgc29tZXRpbWVzIGZvcndhcmQgb3BzIHRvIHRoZSBDUFUuICovXG5FTlYucmVnaXN0ZXJGbGFnKCdXRUJHTF9DUFVfRk9SV0FSRCcsICgpID0+IHRydWUpO1xuXG4vKiogV2hldGhlciB0aGUgV2ViR0wgYmFja2VuZCB3aWxsIGFsd2F5cyB1c2UgZjE2IHRleHR1cmVzIGZvciByZW5kZXJpbmcuICovXG5FTlYucmVnaXN0ZXJGbGFnKCdXRUJHTF9GT1JDRV9GMTZfVEVYVFVSRVMnLCAoKSA9PiBmYWxzZSk7XG5cbi8qKiBXaGV0aGVyIHRvIHR1cm4gYWxsIHBhY2tpbmcgcmVsYXRlZCBmbGFncyBvbi4gKi9cbkVOVi5yZWdpc3RlckZsYWcoJ1dFQkdMX1BBQ0snLCAoKSA9PiBFTlYuZ2V0Qm9vbCgnSEFTX1dFQkdMJykpO1xuXG4vKiogV2hldGhlciB3ZSB3aWxsIHBhY2sgdGhlIGJhdGNobm9ybWFsaXphdGlvbiBvcC4gKi9cbkVOVi5yZWdpc3RlckZsYWcoJ1dFQkdMX1BBQ0tfTk9STUFMSVpBVElPTicsICgpID0+IEVOVi5nZXRCb29sKCdXRUJHTF9QQUNLJykpO1xuXG4vKiogV2hldGhlciB3ZSB3aWxsIHBhY2sgdGhlIGNsaXAgb3AuICovXG5FTlYucmVnaXN0ZXJGbGFnKCdXRUJHTF9QQUNLX0NMSVAnLCAoKSA9PiBFTlYuZ2V0Qm9vbCgnV0VCR0xfUEFDSycpKTtcblxuLyoqIFdoZXRoZXIgd2Ugd2lsbCBwYWNrIHRoZSBkZXB0aHdpc2UgY29udiBvcC4gKi9cbkVOVi5yZWdpc3RlckZsYWcoJ1dFQkdMX1BBQ0tfREVQVEhXSVNFQ09OVicsICgpID0+IEVOVi5nZXRCb29sKCdXRUJHTF9QQUNLJykpO1xuXG4vKiogV2hldGhlciB3ZSB3aWxsIHBhY2sgYmluYXJ5IG9wcy4gKi9cbkVOVi5yZWdpc3RlckZsYWcoXG4gICAgJ1dFQkdMX1BBQ0tfQklOQVJZX09QRVJBVElPTlMnLCAoKSA9PiBFTlYuZ2V0Qm9vbCgnV0VCR0xfUEFDSycpKTtcblxuLyoqIFdoZXRoZXIgd2Ugd2lsbCBwYWNrIHVuYXJ5IG9wcy4gKi9cbkVOVi5yZWdpc3RlckZsYWcoXG4gICAgJ1dFQkdMX1BBQ0tfVU5BUllfT1BFUkFUSU9OUycsICgpID0+IEVOVi5nZXRCb29sKCdXRUJHTF9QQUNLJykpO1xuXG4vKiogV2hldGhlciB3ZSB3aWxsIHBhY2sgYXJyYXkgb3BzLiAqL1xuRU5WLnJlZ2lzdGVyRmxhZyhcbiAgICAnV0VCR0xfUEFDS19BUlJBWV9PUEVSQVRJT05TJywgKCkgPT4gRU5WLmdldEJvb2woJ1dFQkdMX1BBQ0snKSk7XG5cbi8qKiBXaGV0aGVyIHdlIHdpbGwgcGFjayBpbWFnZSBvcHMuICovXG5FTlYucmVnaXN0ZXJGbGFnKFxuICAgICdXRUJHTF9QQUNLX0lNQUdFX09QRVJBVElPTlMnLCAoKSA9PiBFTlYuZ2V0Qm9vbCgnV0VCR0xfUEFDSycpKTtcblxuLyoqIFdoZXRoZXIgd2Ugd2lsbCBwYWNrIHJlZHVjZSBvcHMuICovXG5FTlYucmVnaXN0ZXJGbGFnKCdXRUJHTF9QQUNLX1JFRFVDRScsICgpID0+IEVOVi5nZXRCb29sKCdXRUJHTF9QQUNLJykpO1xuXG4vKiogV2hldGhlciBwYWNrZWQgV2ViR0wga2VybmVscyBsYXppbHkgdW5wYWNrIHRoZWlyIG91dHB1dHMuICovXG5FTlYucmVnaXN0ZXJGbGFnKCdXRUJHTF9MQVpJTFlfVU5QQUNLJywgKCkgPT4gRU5WLmdldEJvb2woJ1dFQkdMX1BBQ0snKSk7XG5cbi8qKiBXaGV0aGVyIHdlIHdpbGwgdXNlIHRoZSBpbTJjb2wgYWxnb3JpdGhtIHRvIHNwZWVkIHVwIGNvbnZvbHV0aW9ucy4gKi9cbkVOVi5yZWdpc3RlckZsYWcoJ1dFQkdMX0NPTlZfSU0yQ09MJywgKCkgPT4gRU5WLmdldEJvb2woJ1dFQkdMX1BBQ0snKSk7XG5cbi8qKiBXaGV0aGVyIHdlIHdpbGwgcGFjayBjb252MmRUcmFuc3Bvc2Ugb3AuICovXG5FTlYucmVnaXN0ZXJGbGFnKCdXRUJHTF9QQUNLX0NPTlYyRFRSQU5TUE9TRScsICgpID0+IEVOVi5nZXRCb29sKCdXRUJHTF9QQUNLJykpO1xuXG4vKiogVGhlIG1heGltdW0gdGV4dHVyZSBkaW1lbnNpb24uICovXG5FTlYucmVnaXN0ZXJGbGFnKFxuICAgICdXRUJHTF9NQVhfVEVYVFVSRV9TSVpFJyxcbiAgICAoKSA9PiBnZXRXZWJHTE1heFRleHR1cmVTaXplKEVOVi5nZXROdW1iZXIoJ1dFQkdMX1ZFUlNJT04nKSkpO1xuXG4vKiogVGhlIG1heGltdW0gdGV4dHVyZSBkaW1lbnNpb24uICovXG5FTlYucmVnaXN0ZXJGbGFnKFxuICAgICdXRUJHTF9NQVhfVEVYVFVSRVNfSU5fU0hBREVSJyxcbiAgICAoKSA9PiBnZXRNYXhUZXh0dXJlc0luU2hhZGVyKEVOVi5nZXROdW1iZXIoJ1dFQkdMX1ZFUlNJT04nKSkpO1xuXG4vKipcbiAqIFRoZSBkaXNqb2ludF9xdWVyeV90aW1lciBleHRlbnNpb24gdmVyc2lvbi5cbiAqIDA6IGRpc2FibGVkLCAxOiBFWFRfZGlzam9pbnRfdGltZXJfcXVlcnksIDI6XG4gKiBFWFRfZGlzam9pbnRfdGltZXJfcXVlcnlfd2ViZ2wyLlxuICogSW4gRmlyZWZveCB3aXRoIFdlYkdMIDIuMCxcbiAqIEVYVF9kaXNqb2ludF90aW1lcl9xdWVyeV93ZWJnbDIgaXMgbm90IGF2YWlsYWJsZSwgc28gd2UgbXVzdCB1c2UgdGhlXG4gKiBXZWJHTCAxLjAgZXh0ZW5zaW9uLlxuICovXG5FTlYucmVnaXN0ZXJGbGFnKCdXRUJHTF9ESVNKT0lOVF9RVUVSWV9USU1FUl9FWFRFTlNJT05fVkVSU0lPTicsICgpID0+IHtcbiAgY29uc3Qgd2ViR0xWZXJzaW9uID0gRU5WLmdldE51bWJlcignV0VCR0xfVkVSU0lPTicpO1xuXG4gIGlmICh3ZWJHTFZlcnNpb24gPT09IDApIHtcbiAgICByZXR1cm4gMDtcbiAgfVxuICByZXR1cm4gZ2V0V2ViR0xEaXNqb2ludFF1ZXJ5VGltZXJWZXJzaW9uKHdlYkdMVmVyc2lvbik7XG59KTtcblxuLyoqXG4gKiBXaGV0aGVyIHRoZSB0aW1lciBvYmplY3QgZnJvbSB0aGUgZGlzam9pbnRfcXVlcnlfdGltZXIgZXh0ZW5zaW9uIGdpdmVzXG4gKiB0aW1pbmcgaW5mb3JtYXRpb24gdGhhdCBpcyByZWxpYWJsZS5cbiAqL1xuRU5WLnJlZ2lzdGVyRmxhZyhcbiAgICAnV0VCR0xfRElTSk9JTlRfUVVFUllfVElNRVJfRVhURU5TSU9OX1JFTElBQkxFJyxcbiAgICAoKSA9PiBFTlYuZ2V0TnVtYmVyKCdXRUJHTF9ESVNKT0lOVF9RVUVSWV9USU1FUl9FWFRFTlNJT05fVkVSU0lPTicpID4gMCAmJlxuICAgICAgICAhZGV2aWNlX3V0aWwuaXNNb2JpbGUoKSk7XG5cbi8qKlxuICogV2hldGhlciB0aGUgZGV2aWNlIGlzIHBoeXNpY2FsbHkgY2FwYWJsZSBvZiByZW5kZXJpbmcgdG8gZmxvYXQzMiB0ZXh0dXJlcy5cbiAqL1xuRU5WLnJlZ2lzdGVyRmxhZyhcbiAgICAnV0VCR0xfUkVOREVSX0ZMT0FUMzJfQ0FQQUJMRScsXG4gICAgKCkgPT4gaXNDYXBhYmxlT2ZSZW5kZXJpbmdUb0Zsb2F0VGV4dHVyZShFTlYuZ2V0TnVtYmVyKCdXRUJHTF9WRVJTSU9OJykpKTtcblxuLyoqXG4gKiBXaGV0aGVyIHJlbmRlcmluZyB0byBmbG9hdDMyIHRleHR1cmVzIGlzIGVuYWJsZWQuIElmIGRpc2FibGVkLCByZW5kZXJzIHRvXG4gKiBmbG9hdDE2IHRleHR1cmVzLlxuICovXG5FTlYucmVnaXN0ZXJGbGFnKCdXRUJHTF9SRU5ERVJfRkxPQVQzMl9FTkFCTEVEJywgKCkgPT4ge1xuICByZXR1cm4gRU5WLmdldEJvb2woJ1dFQkdMX0ZPUkNFX0YxNl9URVhUVVJFUycpID9cbiAgICAgIGZhbHNlIDpcbiAgICAgIEVOVi5nZXRCb29sKCdXRUJHTF9SRU5ERVJfRkxPQVQzMl9DQVBBQkxFJyk7XG59KTtcblxuLyoqXG4gKiBXaGV0aGVyIGRvd25sb2FkaW5nIGZsb2F0IHRleHR1cmVzIGlzIGVuYWJsZWQgKDE2IG9yIDMyIGJpdCkuIElmIGRpc2FibGVkLFxuICogdXNlcyBJRUVFIDc1NCBlbmNvZGluZyBvZiB0aGUgZmxvYXQzMiB2YWx1ZXMgdG8gNCB1aW50OCB3aGVuIGRvd25sb2FkaW5nLlxuICovXG5FTlYucmVnaXN0ZXJGbGFnKFxuICAgICdXRUJHTF9ET1dOTE9BRF9GTE9BVF9FTkFCTEVEJyxcbiAgICAoKSA9PiBpc0Rvd25sb2FkRmxvYXRUZXh0dXJlRW5hYmxlZChFTlYuZ2V0TnVtYmVyKCdXRUJHTF9WRVJTSU9OJykpKTtcblxuLyoqIFdoZXRoZXIgdGhlIGZlbmNlIEFQSSBpcyBhdmFpbGFibGUuICovXG5FTlYucmVnaXN0ZXJGbGFnKFxuICAgICdXRUJHTF9GRU5DRV9BUElfRU5BQkxFRCcsXG4gICAgKCkgPT4gaXNXZWJHTEZlbmNlRW5hYmxlZChFTlYuZ2V0TnVtYmVyKCdXRUJHTF9WRVJTSU9OJykpKTtcblxuLyoqXG4gKiBUZW5zb3JzIHdpdGggc2l6ZSA8PSB0aGFuIHRoaXMgd2lsbCBiZSB1cGxvYWRlZCBhcyB1bmlmb3Jtcywgbm90IHRleHR1cmVzLlxuICovXG5FTlYucmVnaXN0ZXJGbGFnKCdXRUJHTF9TSVpFX1VQTE9BRF9VTklGT1JNJywgKCkgPT4ge1xuICAvLyBVc2UgdW5pZm9ybSB1cGxvYWRzIG9ubHkgd2hlbiAzMmJpdCBmbG9hdHMgYXJlIHN1cHBvcnRlZC4gSW5cbiAgLy8gMTZiaXRcbiAgLy8gZW52aXJvbm1lbnRzIHRoZXJlIGFyZSBwcm9ibGVtcyB3aXRoIGNvbXBhcmluZyBhIDE2Yml0IHRleHR1cmUgdmFsdWVcbiAgLy8gd2l0aCBhIDMyYml0IHVuaWZvcm0gdmFsdWUuXG4gIGNvbnN0IHVzZVVuaWZvcm1zID0gRU5WLmdldEJvb2woJ1dFQkdMX1JFTkRFUl9GTE9BVDMyX0VOQUJMRUQnKTtcbiAgcmV0dXJuIHVzZVVuaWZvcm1zID8gNCA6IDA7XG59KTtcblxuLyoqXG4gKiBJZiB0aGUgdG90YWwgbnVtYmVyIG9mIGJ5dGVzIGFsbG9jYXRlZCBvbiB0aGUgR1BVIGlzIGdyZWF0ZXIgdGhhbiB0aGlzXG4gKiBudW1iZXIsIHdlIHdpbGwgYWdncmVzc2l2ZWx5IGRlbGV0ZSB0ZXh0dXJlcyB1cG9uIGRpc3Bvc2FsIHdpdGhcbiAqIGdsLmRlbGV0ZU1hdHJpeFRleHR1cmUsIHJhdGhlciB0aGFuIG1ha2luZyB0aGVtIGF2YWlsYWJsZSBmb3IgcmV1c2UuXG4gKlxuICogRGVmYXVsdCB2YWx1ZSAtMSBpbmRpY2F0ZXMgdGhhdCB3ZSB3aWxsIG5ldmVyIGFnZ3Jlc3NpdmVseSBkZWxldGUgdGV4dHVyZXMuXG4gKi9cbkVOVi5yZWdpc3RlckZsYWcoXG4gICAgJ1dFQkdMX0RFTEVURV9URVhUVVJFX1RIUkVTSE9MRCcsXG4gICAgKCkgPT4ge1xuICAgICAgcmV0dXJuIC0xO1xuICAgIH0sXG4gICAgdGhyZXNob2xkID0+IHtcbiAgICAgIGlmICghKHR5cGVvZiB0aHJlc2hvbGQgPT09ICdudW1iZXInKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1dFQkdMX0RFTEVURV9URVhUVVJFX1RIUkVTSE9MRCBtdXN0IGJlIGEgbnVtYmVyIGJ1dCAnICtcbiAgICAgICAgICAgIGBnb3QgJHt0aHJlc2hvbGR9LmApO1xuICAgICAgfVxuICAgICAgaWYgKHRocmVzaG9sZCA8IDAgJiYgdGhyZXNob2xkICE9PSAtMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgV0VCR0xfREVMRVRFX1RFWFRVUkVfVEhSRVNIT0xEIG11c3QgYmUgLTEgKGluZGljYXRpbmcgbmV2ZXIgYCArXG4gICAgICAgICAgICBgZGVsZXRlKSBvciBhdCBsZWFzdCAwLCBidXQgZ290ICR7dGhyZXNob2xkfS5gKTtcbiAgICAgIH1cbiAgICB9KTtcblxuLyoqXG4gKiBUcmlnZ2VyIGEgbWFudWFsIEdMIGNvbW1hbmQgZmx1c2ggaWYgdGhlIHRocmVzaG9sZCBvZiB0aW1lIGhhcyBwYXNzZWQgc2luY2VcbiAqIHByZXZpb3VzIEtlcm5lbCBleGVjdXRpb24uIFRoaXMgY2FuIGJlIHVzZWZ1bCBmb3IgQW5kb3JpZCBkZXZpY2Ugd2hlcmUgR0xcbiAqIGNvbW1hbmQgZmx1c2ggYXJlIGRlbGF5ZWQgdW4gdGlsIHRoZSBlbmQgb2YgamF2YXNjcmlwdCB0YXNrLiBUaGlzIHZhbHVlIGlzXG4gKiBtZWFzdXJlZCBpbiBtaWxsaXNlY29uZC4gVHlwaWNhbGx5IHlvdSB3YW50IHRvIHNldCB0aGlzIHZhbHVlIHRvIGNsb3NlIHRvIDEuXG4gKlxuICogRGVmYXVsdCB2YWx1ZSAxIGZvciBtb2JpbGUgY2hyb21lLCBhbmQgLTEgZm9yIHJlc3QgY2FzZXMuIC0xIGluZGljYXRlcyB0aGF0XG4gKiB3ZSB3aWxsIG5vdCBlbmZvcmNlIG1hbnVhbCBmbHVzaCBhbmQgZGVwZW5kIG9uIHN5c3RlbSBkZWZhdWx0IGZsdXNoIHNjaGVkdWxlLlxuICovXG5FTlYucmVnaXN0ZXJGbGFnKFxuICAgICdXRUJHTF9GTFVTSF9USFJFU0hPTEQnLFxuICAgICgpID0+IHtcbiAgICAgIHJldHVybiBkZXZpY2VfdXRpbC5pc01vYmlsZSgpID8gMSA6IC0xO1xuICAgIH0sXG4gICAgdGhyZXNob2xkID0+IHtcbiAgICAgIGlmICghKHR5cGVvZiB0aHJlc2hvbGQgPT09ICdudW1iZXInKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1dFQkdMX0ZMVVNIX1RIUkVTSE9MRCBtdXN0IGJlIGEgbnVtYmVyIGJ1dCBnb3QgJyArXG4gICAgICAgICAgICBgJHt0aHJlc2hvbGR9LmApO1xuICAgICAgfVxuICAgICAgaWYgKHRocmVzaG9sZCA8IDAgJiYgdGhyZXNob2xkICE9PSAtMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICBgV0VCR0xfRkxVU0hfVEhSRVNIT0xEIG11c3QgYmUgLTEgKGluZGljYXRpbmcgbmV2ZXIgYCArXG4gICAgICAgICAgICBgbWFudWFsIGZsdXNoKSBvciBhdCBsZWFzdCAwLCBidXQgZ290ICR7dGhyZXNob2xkfS5gKTtcbiAgICAgIH1cbiAgICB9KTtcblxuLyoqXG4gKiBUaHJlc2hvbGQgZm9yIGlucHV0IHRlbnNvciBzaXplIHRoYXQgZGV0ZXJtaW5lcyB3aGV0aGVyIFdlYkdMIGJhY2tlbmQgd2lsbFxuICogZGVsZWdhdGUgY29tcHV0YXRpb24gdG8gQ1BVLlxuICpcbiAqIERlZmF1bHQgdmFsdWUgaXMgMTI4LlxuICovXG5FTlYucmVnaXN0ZXJGbGFnKCdDUFVfSEFORE9GRl9TSVpFX1RIUkVTSE9MRCcsICgpID0+IDEyOCk7XG5cbi8qKiBXaGV0aGVyIHdlIHdpbGwgdXNlIHNoYXBlcyB1bmlmb3Jtcy4gKi9cbkVOVi5yZWdpc3RlckZsYWcoJ1dFQkdMX1VTRV9TSEFQRVNfVU5JRk9STVMnLCAoKSA9PiBmYWxzZSk7XG5cbi8qKlxuICogVGhyZXNob2xkIGZvciBsYXN0IGRpbWVuc2lvbiBvZiBpbnB1dCB0ZW5zb3IgdGhhdCBkZXRlcm1pbmVzIHdoZXRoZXJcbiAqIFdlYkdMIGJhY2tlbmQgZm9yIHRoZSBUb3AgSyBvcCB3aWxsIGRlbGVnYXRlIGNvbXB1dGF0aW9uIHRvIENQVS4gSWYgaW5wdXRcbiAqIGlzIHNtYWxsZXIgdGhhbiB0aHJlc2hvbGQgdGhlbiBDUFUgd2lsbCBiZSB1c2VkXG4gKlxuICogRGVmYXVsdCB2YWx1ZSBpcyAxMDAwMDAuXG4gKi9cbkVOVi5yZWdpc3RlckZsYWcoJ1RPUEtfTEFTVF9ESU1fQ1BVX0hBTkRPRkZfU0laRV9USFJFU0hPTEQnLCAoKSA9PiAxMDAwMDApO1xuXG4vKipcbiAqIFRocmVzaG9sZCBmb3IgSyB0aGF0IGRldGVybWluZXMgd2hldGhlclxuICogV2ViR0wgYmFja2VuZCBmb3IgdGhlIFRvcCBLIG9wIHdpbGwgZGVsZWdhdGUgY29tcHV0YXRpb24gdG8gQ1BVLiBJZiBrXG4gKiBpcyBsYXJnZXIgdGhhbiB0aHJlc2hvbGQgdGhlbiBDUFUgd2lsbCBiZSB1c2VkXG4gKlxuICogRGVmYXVsdCB2YWx1ZSBpcyAxMjguXG4gKi9cbkVOVi5yZWdpc3RlckZsYWcoJ1RPUEtfS19DUFVfSEFORE9GRl9USFJFU0hPTEQnLCAoKSA9PiAxMjgpO1xuXG4vKiogV2hldGhlciB3ZSB3aWxsIHVzZSB0aGUgZXhwZXJpbWVudGFsIGNvbnYgb3AuICovXG5FTlYucmVnaXN0ZXJGbGFnKCdXRUJHTF9FWFBfQ09OVicsICgpID0+IGZhbHNlKTtcblxuLyoqXG4gKiBJZiB0aGUgZGV2aWNlIHBlcmZvcm1hbmNlIGlzIGxvdyBvciBpZiBubyBoYXJkd2FyZSBHUFUgaXMgYXZhaWxhYmxlLCB3aGV0aGVyXG4gKiBzb2Z0d2FyZSBXZWJHTCB3aWxsIGJlIHVzZWQuXG4gKi9cbkVOVi5yZWdpc3RlckZsYWcoJ1NPRlRXQVJFX1dFQkdMX0VOQUJMRUQnLCAoKSA9PiBFTlYuZ2V0Qm9vbCgnSVNfVEVTVCcpKTtcblxuLyoqXG4gKiBGb3IgbmFycm93IHRleHR1cmUgKHBoeXNpY2FsIGhlaWdodCBvciBwaHlzaWNhbCB3aWR0aCBpcyAxKSwgaWYgdGhlIGxlbmd0aCBvZlxuICogYW55IHRleHR1cmUgZWRnZXMgZXhjZWVkIHRoZSB0aHJlc2hvbGQsIHRoZSB0ZXh0dXJlIHdpbGwgYmUgcmVzaGFwZWQgdG8gYmVcbiAqIG1vcmUgc3F1YXJpc2guXG4gKlxuICogVGhpcyBmbGFnIGlzIHVzZWQgdG8gaGVscCBzb21lIEdQVXMgdGhhdCBjb3VsZCBub3QgcHJvdmlkZSBjb3JyZWN0XG4gKiBpbnRlcnBvbGF0aW9ucyBmb3IgbG9uZyBza2lubnkgdHJpYW5nbGVzLiBXZSBmb3VuZCBNYWxpIEdQVSBwcm9iYWJseSBoYXMgdGhpc1xuICogcHJvYmxlbTogaHR0cHM6Ly9naXRodWIuY29tL3RlbnNvcmZsb3cvdGZqcy9pc3N1ZXMvNjc3NS5cbiAqL1xuRU5WLnJlZ2lzdGVyRmxhZygnV0VCR0xfTUFYX1NJWkVfRk9SX05BUlJPV19URVhUVVJFJywgKCkgPT4gSW5maW5pdHkpO1xuXG4vKipcbiAqIElmIHRoZSBmbGFnIGlzIHNldCB0byB0cnVlLCB0aGUgbWF4IHNpemUgb2YgdGhlIG5hcnJvdyB0ZXh0dXJlIHdpbGwgYmUgYXV0b1xuICogY29tcHV0ZWQgYW5kIGl0IHdpbGwgYmUgY29uc2lkZXJyZWQgYXMgYSB0aHJlc2hvbGQgdG8gcmVzaGFwZSB0aGUgbmFycm93XG4gKiB0ZXh0dXJlIHRvIGJlIG1vcmUgc3F1YXJpc2guXG4gKlxuICogVGhpcyBmbGFnIGlzIHVzZWQgdG8gaGVscCBzb21lIEdQVXMgdGhhdCBjb3VsZCBub3QgcHJvdmlkZSBjb3JyZWN0XG4gKiBpbnRlcnBvbGF0aW9ucyBmb3IgbG9uZyBza2lubnkgdHJpYW5nbGVzLiBXZSBmb3VuZCBNYWxpIEdQVSBwcm9iYWJseSBoYXMgdGhpc1xuICogcHJvYmxlbTogaHR0cHM6Ly9naXRodWIuY29tL3RlbnNvcmZsb3cvdGZqcy9pc3N1ZXMvNjc3NS5cbiAqL1xuRU5WLnJlZ2lzdGVyRmxhZygnV0VCR0xfQVVUT19TUVVBUklGWV9OQVJST1dfVEVYVFVSRV9TSEFQRScsICgpID0+IGZhbHNlKTtcblxuLyoqXG4gKiBXaGV0aGVyIHRvIHVzZSB0aGUgY3VzdG9taXplZCBpc25hbi4gSXQncyBvbmx5IHVzZWZ1bCBmb3Igd2ViZ2wyIHNpbmNlIHdlYmdsMVxuICogZG9lc24ndCBoYXZlIHRoZSBidWlsdGluIGlzbmFuLlxuICovXG5FTlYucmVnaXN0ZXJGbGFnKCdXRUJHTDJfSVNOQU5fQ1VTVE9NJywgKCkgPT4gZmFsc2UpO1xuXG4vKiogRXhwZXJpbWVudGFsIGZsYWcsIHdoZXRoZXIgZW50ZXIgY29tcGlsZSBvbmx5IHBoYXNlLiAqL1xuRU5WLnJlZ2lzdGVyRmxhZygnRU5HSU5FX0NPTVBJTEVfT05MWScsICgpID0+IGZhbHNlKTtcbiJdfQ==